From 8018c9cc444975caaafe0d3048f542107035b6b7 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Mon, 9 Jan 2017 17:09:19 +0100 Subject: [PATCH 001/235] Add GMP MPFR CGAL to build script --- nix/build-all.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/nix/build-all.py b/nix/build-all.py index b8413d1224..782d836dd3 100644 --- a/nix/build-all.py +++ b/nix/build-all.py @@ -56,6 +56,9 @@ PCRE_VERSION="8.38" LIBXML_VERSION="2.9.3" CMAKE_VERSION="3.4.1" ICU_VERSION="56.1" +GMP_VERSION="6.1.2" +MPFR_VERSION="3.1.5" + # binaries cp="cp" @@ -161,7 +164,7 @@ cecho(""" - How many compiler processes may be run in parallel. # Check that required tools are in PATH -for cmd in [git, bunzip2, tar, cc, cplusplus, autoconf, automake, yacc, make]: +for cmd in [git, bunzip2, tar, cc, cplusplus, autoconf, automake, yacc, make, "m4"]: if which(cmd) is None: raise ValueError("Required tool '%s' not installed or not added to PATH" % (cmd,)) @@ -415,6 +418,8 @@ for FL in ["C", "CXX"]: shutil.rmtree(CMAKE_FLAG_EXTRACT_DIR) build_dependency(name="pcre-%s" % (PCRE_VERSION,), mode="autoconf", build_tool_args=["--disable-shared"], download_url="ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/", download_name="pcre-%s.tar.bz2" % (PCRE_VERSION,)) +build_dependency(name="gmp-%s" % (GMP_VERSION,), mode="autoconf", build_tool_args=[], 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=["--with-gmp=%s/install/gmp-%s" % (DEPS_DIR, GMP_VERSION)], download_url="http://www.mpfr.org/mpfr-current/", download_name="mpfr-%s.tar.bz2" % (MPFR_VERSION,)) # An issue exists with swig-1.3 and python >= 3.2 # Therefore, build a recent copy from source @@ -446,6 +451,8 @@ os.environ["CFLAGS"]=OLD_C_FLAGS str_concat = lambda prefix: lambda postfix: "=".join((prefix, postfix.strip())) build_dependency("boost-%s" % (BOOST_VERSION,), mode="bjam", build_tool_args=["--stagedir=%s/install/boost-%s" % (DEPS_DIR, BOOST_VERSION), "--with-system", "--with-program_options", "--with-regex", "--with-thread", "--with-date_time", "link=static"]+BOOST_ADDRESS_MODEL+list(map(str_concat("cxxflags"), CXXFLAGS.strip().split(' '))) + list(map(str_concat("linkflags"), LDFLAGS.strip().split(' '))) + ["stage"], download_url="http://downloads.sourceforge.net/project/boost/boost/%s/" % (BOOST_VERSION,), download_name="boost_%s.tar.bz2" % (BOOST_VERSION_UNDERSCORE,)) +build_dependency(name="cgal-master", 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)], download_url="https://github.com/CGAL/cgal.git", download_name="cgal", download_tool=download_tool_git) + build_dependency(name="icu-%s" % (ICU_VERSION,), mode="icu", build_tool_args=["--enable-static", "--disable-shared"], download_url="http://download.icu-project.org/files/icu4c/%s/" % (ICU_VERSION,), download_name="icu4c-%s-src.tgz" % (ICU_VERSION_UNDERSCORE,)) cecho("Building IfcOpenShell:", GREEN) From 7e3f96e4108604abb4273be43d678ccd9570ec51 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Mon, 9 Jan 2017 17:13:32 +0100 Subject: [PATCH 002/235] Add GMP MPFR CGAL to build script --- nix/build-all.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/nix/build-all.py b/nix/build-all.py index 782d836dd3..9fd36bd27d 100644 --- a/nix/build-all.py +++ b/nix/build-all.py @@ -50,7 +50,8 @@ logger.addHandler(ch) PROJECT_NAME="IfcOpenShell" OCE_VERSION="0.16" -PYTHON_VERSIONS=["2.7.10", "3.2.6", "3.3.6", "3.4.4", "3.5.1"] +# Don't care about python wrapper for time being +PYTHON_VERSIONS=[] # "2.7.10", "3.2.6", "3.3.6", "3.4.4", "3.5.1"] BOOST_VERSION="1.59.0" PCRE_VERSION="8.38" LIBXML_VERSION="2.9.3" @@ -231,10 +232,14 @@ OPENCOLLADA_COMMIT="f99d59e73e565a41715eaebc00c7664e1ee5e628" 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.mkdir(install_dir) if not os.path.exists(configure_path): __check_call__([bash, "./autogen.sh"], cwd=os.path.realpath(os.path.join(cwd, ".."))) # only run autogen.sh in the directory it is located and use cwd to achieve that in order to not mess up things # Using `sh` over `bash` fixes issues with building swig - __check_call__(["/bin/sh", "../configure"]+configure_args+["--prefix=%s" % (os.path.realpath("%s/install/%s" % (DEPS_DIR, arg1)),)], cwd=cwd) + __check_call__(["/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: @@ -242,7 +247,7 @@ def run_cmake(arg1, cmake_args, cmake_dir=None, cwd=None): else: P=cmake_dir cmake_path= os.path.join(DEPS_DIR, "install", "cmake-%s" % (CMAKE_VERSION,), "bin", "cmake") - __check_call__([cmake_path, P]+cmake_args+["-DCMAKE_BUILD_TYPE=%s" % (BUILD_TYPE,)], cwd=cwd) + __check_call__([cmake_path, P]+cmake_args+["-DCMAKE_BUILD_TYPE=%s" % (BUILD_CFG,)], cwd=cwd) def run_icu(arg1, icu_args, cwd): PLATFORM=get_os() @@ -418,8 +423,8 @@ for FL in ["C", "CXX"]: shutil.rmtree(CMAKE_FLAG_EXTRACT_DIR) build_dependency(name="pcre-%s" % (PCRE_VERSION,), mode="autoconf", build_tool_args=["--disable-shared"], download_url="ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/", download_name="pcre-%s.tar.bz2" % (PCRE_VERSION,)) -build_dependency(name="gmp-%s" % (GMP_VERSION,), mode="autoconf", build_tool_args=[], 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=["--with-gmp=%s/install/gmp-%s" % (DEPS_DIR, GMP_VERSION)], download_url="http://www.mpfr.org/mpfr-current/", download_name="mpfr-%s.tar.bz2" % (MPFR_VERSION,)) +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-current/", download_name="mpfr-%s.tar.bz2" % (MPFR_VERSION,)) # An issue exists with swig-1.3 and python >= 3.2 # Therefore, build a recent copy from source @@ -451,7 +456,12 @@ os.environ["CFLAGS"]=OLD_C_FLAGS str_concat = lambda prefix: lambda postfix: "=".join((prefix, postfix.strip())) build_dependency("boost-%s" % (BOOST_VERSION,), mode="bjam", build_tool_args=["--stagedir=%s/install/boost-%s" % (DEPS_DIR, BOOST_VERSION), "--with-system", "--with-program_options", "--with-regex", "--with-thread", "--with-date_time", "link=static"]+BOOST_ADDRESS_MODEL+list(map(str_concat("cxxflags"), CXXFLAGS.strip().split(' '))) + list(map(str_concat("linkflags"), LDFLAGS.strip().split(' '))) + ["stage"], download_url="http://downloads.sourceforge.net/project/boost/boost/%s/" % (BOOST_VERSION,), download_name="boost_%s.tar.bz2" % (BOOST_VERSION_UNDERSCORE,)) -build_dependency(name="cgal-master", 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)], download_url="https://github.com/CGAL/cgal.git", download_name="cgal", download_tool=download_tool_git) +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", 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/" % (DEPS_DIR,)], download_url="https://github.com/CGAL/cgal.git", download_name="cgal", download_tool=download_tool_git) +BUILD_CFG = OLD_BUILD_CFG build_dependency(name="icu-%s" % (ICU_VERSION,), mode="icu", build_tool_args=["--enable-static", "--disable-shared"], download_url="http://download.icu-project.org/files/icu4c/%s/" % (ICU_VERSION,), download_name="icu4c-%s-src.tgz" % (ICU_VERSION_UNDERSCORE,)) From 4fa7f293d62f3102b33006710436f539f90aca99 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 13 Jan 2017 18:11:05 +0100 Subject: [PATCH 003/235] cd to correct repository folder --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 58b4d225b6..62d7dff990 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,7 +46,7 @@ script: - cd .. - cd .. - pwd - - cd IfcOpenShell + - cd IfcOpenShell_CGAL - pwd - cd cmake - mkdir build-ifc2x3 build-ifc4 From d17f714dc5355134ba084ac711aac1e7c145cc05 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 13 Jan 2017 17:59:05 +0100 Subject: [PATCH 004/235] Isolate geometry processing code into separate opencascade kernel --- cmake/CMakeLists.txt | 22 +- src/examples/IfcAdvancedHouse.cpp | 1 + src/examples/IfcOpenHouse.cpp | 2 + src/ifcconvert/ColladaSerializer.h | 2 +- src/ifcconvert/GeometrySerializer.h | 2 +- src/ifcconvert/IfcConvert.cpp | 7 +- src/ifcconvert/IgesSerializer.h | 6 +- src/ifcconvert/OpenCascadeBasedSerializer.cpp | 20 +- src/ifcconvert/OpenCascadeBasedSerializer.h | 4 +- src/ifcconvert/StepSerializer.h | 5 +- src/ifcconvert/SvgSerializer.cpp | 17 +- src/ifcconvert/SvgSerializer.h | 2 +- src/ifcconvert/WavefrontObjSerializer.h | 2 +- src/ifcconvert/XmlSerializer.cpp | 4 +- src/ifcgeom/ConversionResult.h | 87 +++ src/ifcgeom/IfcGeom.h | 147 +---- src/ifcgeom/IfcGeomAbstractKernel.cpp | 248 +++++++++ src/ifcgeom/IfcGeomElement.h | 32 +- src/ifcgeom/IfcGeomIterator.h | 81 +-- src/ifcgeom/IfcGeomRenderStyles.cpp | 6 +- src/ifcgeom/IfcGeomRepresentation.h | 247 ++------- src/ifcgeom/IfcRegisterConvertCurve.h | 6 - src/ifcgeom/IfcRegisterConvertFace.h | 6 - src/ifcgeom/IfcRegisterConvertWire.h | 6 - src/ifcgeom/IfcRegisterCreateCache.h | 6 - src/ifcgeom/IfcRegisterPurgeCache.h | 6 - src/ifcgeom/IfcRepresentationShapeItem.h | 53 -- .../opencascade/EntityMapping.cpp} | 39 +- .../opencascade/EntityMapping.h} | 4 +- .../opencascade/EntityMappingCreateCache.h | 6 + .../kernels/opencascade/EntityMappingCurve.h | 6 + .../opencascade/EntityMappingDeclaration.h} | 8 +- .../opencascade/EntityMappingDefine.h} | 0 .../kernels/opencascade/EntityMappingFace.h | 6 + .../opencascade/EntityMappingPurgeCache.h | 6 + .../opencascade/EntityMappingShape.h} | 6 +- .../opencascade/EntityMappingShapeType.h} | 6 +- .../opencascade/EntityMappingShapes.h} | 6 +- .../opencascade/EntityMappingUndefine.h} | 0 .../kernels/opencascade/EntityMappingWire.h | 6 + .../opencascade}/IfcGeomCurves.cpp | 17 +- .../opencascade}/IfcGeomFaces.cpp | 75 +-- .../opencascade}/IfcGeomFunctions.cpp | 505 +++++------------- .../opencascade}/IfcGeomHelpers.cpp | 81 +-- .../IfcGeomOpenCascadeSerialization.cpp} | 18 +- .../opencascade}/IfcGeomSerialisation.cpp | 10 +- .../opencascade}/IfcGeomShapes.cpp | 126 ++--- .../opencascade}/IfcGeomWires.cpp | 41 +- .../opencascade/OpenCascadeConversionResult.h | 86 +++ .../kernels/opencascade/OpenCascadeKernel.h | 155 ++++++ .../opencascade/OpenCascadeSerialization.h | 34 ++ .../kernels/opencascade/OpenCascadeShape.cpp | 194 +++++++ 52 files changed, 1369 insertions(+), 1099 deletions(-) create mode 100644 src/ifcgeom/ConversionResult.h create mode 100644 src/ifcgeom/IfcGeomAbstractKernel.cpp delete mode 100644 src/ifcgeom/IfcRegisterConvertCurve.h delete mode 100644 src/ifcgeom/IfcRegisterConvertFace.h delete mode 100644 src/ifcgeom/IfcRegisterConvertWire.h delete mode 100644 src/ifcgeom/IfcRegisterCreateCache.h delete mode 100644 src/ifcgeom/IfcRegisterPurgeCache.h delete mode 100644 src/ifcgeom/IfcRepresentationShapeItem.h rename src/ifcgeom/{IfcRegister.cpp => kernels/opencascade/EntityMapping.cpp} (76%) rename src/ifcgeom/{IfcRegister.h => kernels/opencascade/EntityMapping.h} (98%) create mode 100644 src/ifcgeom/kernels/opencascade/EntityMappingCreateCache.h create mode 100644 src/ifcgeom/kernels/opencascade/EntityMappingCurve.h rename src/ifcgeom/{IfcRegisterGeomHeader.h => kernels/opencascade/EntityMappingDeclaration.h} (60%) rename src/ifcgeom/{IfcRegisterDef.h => kernels/opencascade/EntityMappingDefine.h} (100%) create mode 100644 src/ifcgeom/kernels/opencascade/EntityMappingFace.h create mode 100644 src/ifcgeom/kernels/opencascade/EntityMappingPurgeCache.h rename src/ifcgeom/{IfcRegisterConvertShape.h => kernels/opencascade/EntityMappingShape.h} (88%) rename src/ifcgeom/{IfcRegisterShapeType.h => kernels/opencascade/EntityMappingShapeType.h} (76%) rename src/ifcgeom/{IfcRegisterConvertShapes.h => kernels/opencascade/EntityMappingShapes.h} (84%) rename src/ifcgeom/{IfcRegisterUndef.h => kernels/opencascade/EntityMappingUndefine.h} (100%) create mode 100644 src/ifcgeom/kernels/opencascade/EntityMappingWire.h rename src/ifcgeom/{ => kernels/opencascade}/IfcGeomCurves.cpp (90%) rename src/ifcgeom/{ => kernels/opencascade}/IfcGeomFaces.cpp (90%) rename src/ifcgeom/{ => kernels/opencascade}/IfcGeomFunctions.cpp (75%) rename src/ifcgeom/{ => kernels/opencascade}/IfcGeomHelpers.cpp (78%) rename src/ifcgeom/{IfcGeomRepresentation.cpp => kernels/opencascade/IfcGeomOpenCascadeSerialization.cpp} (81%) rename src/ifcgeom/{ => kernels/opencascade}/IfcGeomSerialisation.cpp (98%) rename src/ifcgeom/{ => kernels/opencascade}/IfcGeomShapes.cpp (85%) rename src/ifcgeom/{ => kernels/opencascade}/IfcGeomWires.cpp (90%) create mode 100644 src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h create mode 100644 src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h create mode 100644 src/ifcgeom/kernels/opencascade/OpenCascadeSerialization.h create mode 100644 src/ifcgeom/kernels/opencascade/OpenCascadeShape.cpp diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 187a0916e5..4084d02f24 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -541,8 +541,8 @@ IF(UNICODE_SUPPORT) ENDIF() # IfcGeom -file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/*.h) -file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/*.cpp) +file(GLOB_RECURSE IFCGEOM_H_FILES ../src/ifcgeom/*.h) +file(GLOB_RECURSE IFCGEOM_CPP_FILES ../src/ifcgeom/*.cpp) set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES}) add_library(IfcGeom ${IFCGEOM_FILES}) @@ -568,14 +568,14 @@ if ((NOT WIN32) AND BUILD_SHARED_LIBS) endif() # IfcGeomServer -file(GLOB CPP_FILES ../src/ifcgeomserver/*.cpp) -file(GLOB H_FILES ../src/ifcgeomserver/*.h) -set(SOURCE_FILES ${CPP_FILES} ${H_FILES}) -ADD_EXECUTABLE(IfcGeomServer ${SOURCE_FILES}) -TARGET_LINK_LIBRARIES(IfcGeomServer ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${ICU_LIBRARIES}) -if ((NOT WIN32) AND BUILD_SHARED_LIBS) - SET_INSTALL_RPATHS(IfcGeomServer "${IFCOPENSHELL_LIBARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS};${ICU_LIBRARY_DIR}") -endif() +# file(GLOB CPP_FILES ../src/ifcgeomserver/*.cpp) +# file(GLOB H_FILES ../src/ifcgeomserver/*.h) +# set(SOURCE_FILES ${CPP_FILES} ${H_FILES}) +# ADD_EXECUTABLE(IfcGeomServer ${SOURCE_FILES}) +# TARGET_LINK_LIBRARIES(IfcGeomServer ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${ICU_LIBRARIES}) +# if ((NOT WIN32) AND BUILD_SHARED_LIBS) +# SET_INSTALL_RPATHS(IfcGeomServer "${IFCOPENSHELL_LIBARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS};${ICU_LIBRARY_DIR}") +# endif() IF(BUILD_IFCPYTHON) ADD_SUBDIRECTORY(../src/ifcwrap ifcwrap) @@ -598,7 +598,7 @@ INSTALL(FILES ${IFCGEOM_H_FILES} DESTINATION ${INCLUDEDIR}/ifcgeom ) -INSTALL(TARGETS IfcParse IfcGeom IfcConvert IfcGeomServer +INSTALL(TARGETS IfcParse IfcGeom IfcConvert # IfcGeomServer ARCHIVE DESTINATION ${LIBDIR} LIBRARY DESTINATION ${LIBDIR} RUNTIME DESTINATION ${BINDIR} diff --git a/src/examples/IfcAdvancedHouse.cpp b/src/examples/IfcAdvancedHouse.cpp index 76cda1d4d6..197a74f09a 100644 --- a/src/examples/IfcAdvancedHouse.cpp +++ b/src/examples/IfcAdvancedHouse.cpp @@ -47,6 +47,7 @@ #include "../ifcparse/IfcUtil.h" #include "../ifcparse/IfcHierarchyHelper.h" #include "../ifcgeom/IfcGeom.h" +#include "../ifcgeom/kernels/opencascade/OpenCascadeSerialization.h" #if USE_VLD #include diff --git a/src/examples/IfcOpenHouse.cpp b/src/examples/IfcOpenHouse.cpp index 88adc574b6..18b329ba5c 100644 --- a/src/examples/IfcOpenHouse.cpp +++ b/src/examples/IfcOpenHouse.cpp @@ -30,6 +30,7 @@ #include #include +#include #ifdef USE_IFC4 #include "../ifcparse/Ifc4.h" @@ -40,6 +41,7 @@ #include "../ifcparse/IfcUtil.h" #include "../ifcparse/IfcHierarchyHelper.h" #include "../ifcgeom/IfcGeom.h" +#include "../ifcgeom/kernels/opencascade/OpenCascadeSerialization.h" #if USE_VLD #include diff --git a/src/ifcconvert/ColladaSerializer.h b/src/ifcconvert/ColladaSerializer.h index b9be98e15a..8dfeb6a7ef 100644 --- a/src/ifcconvert/ColladaSerializer.h +++ b/src/ifcconvert/ColladaSerializer.h @@ -188,7 +188,7 @@ public: bool ready(); void writeHeader(); void write(const IfcGeom::TriangulationElement* o); - void write(const IfcGeom::BRepElement* /*o*/) {} + void write(const IfcGeom::NativeElement* /*o*/) {} void finalize(); bool isTesselated() const { return true; } void setUnitNameAndMagnitude(const std::string& name, float magnitude) { diff --git a/src/ifcconvert/GeometrySerializer.h b/src/ifcconvert/GeometrySerializer.h index c2ee0f6416..95d12362a9 100644 --- a/src/ifcconvert/GeometrySerializer.h +++ b/src/ifcconvert/GeometrySerializer.h @@ -36,7 +36,7 @@ public: virtual bool isTesselated() const = 0; virtual void write(const IfcGeom::TriangulationElement* o) = 0; - virtual void write(const IfcGeom::BRepElement* o) = 0; + virtual void write(const IfcGeom::NativeElement* o) = 0; virtual void setUnitNameAndMagnitude(const std::string& name, float magnitude) = 0; const IfcGeom::IteratorSettings& settings() const { return settings_; } diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index af0baf5cd6..7015190a78 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -483,6 +483,8 @@ int main(int argc, char** argv) { int old_progress = -1; if (center_model) { + throw std::runtime_error("Not implemented"); + /* double* offset = serializer->settings().offset; gp_XYZ center = (context_iterator.bounds_min() + context_iterator.bounds_max()) * 0.5; offset[0] = -center.X(); @@ -491,6 +493,7 @@ int main(int argc, char** argv) { std::stringstream msg; msg << "Using model offset (" << offset[0] << "," << offset[1] << "," << offset[2] << ")"; Logger::Message(Logger::LOG_NOTICE, msg.str()); + */ } Logger::Status("Creating geometry..."); @@ -498,7 +501,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 @@ -512,7 +515,7 @@ int main(int argc, char** argv) { if (is_tesselated) { serializer->write(static_cast*>(geom_object)); } else { - serializer->write(static_cast*>(geom_object)); + serializer->write(static_cast*>(geom_object)); } const int progress = context_iterator.progress() / 2; if (old_progress != progress) Logger::ProgressBar(progress); diff --git a/src/ifcconvert/IgesSerializer.h b/src/ifcconvert/IgesSerializer.h index fb8045c2de..c166b75306 100644 --- a/src/ifcconvert/IgesSerializer.h +++ b/src/ifcconvert/IgesSerializer.h @@ -25,6 +25,8 @@ #include #include +#include "../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h" + class IgesSerializer : public OpenCascadeBasedSerializer { private: @@ -36,8 +38,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()); diff --git a/src/ifcconvert/OpenCascadeBasedSerializer.cpp b/src/ifcconvert/OpenCascadeBasedSerializer.cpp index cf5ae2df62..5ad6777217 100644 --- a/src/ifcconvert/OpenCascadeBasedSerializer.cpp +++ b/src/ifcconvert/OpenCascadeBasedSerializer.cpp @@ -22,8 +22,11 @@ #include #include +#include #include "OpenCascadeBasedSerializer.h" +#include "../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h" +#include "../ifcgeom/kernels/opencascade/OpenCascadeKernel.h" bool OpenCascadeBasedSerializer::ready() { std::ofstream test_file(out_filename.c_str(), std::ios_base::binary); @@ -33,11 +36,11 @@ bool OpenCascadeBasedSerializer::ready() { return succeeded; } -void OpenCascadeBasedSerializer::write(const IfcGeom::BRepElement* o) { - for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = o->geometry().begin(); it != o->geometry().end(); ++ it) { - gp_GTrsf gtrsf = it->Placement(); +void OpenCascadeBasedSerializer::write(const IfcGeom::NativeElement* o) { + for (IfcGeom::ConversionResults::const_iterator it = o->geometry().begin(); it != o->geometry().end(); ++ it) { + gp_GTrsf gtrsf = *(IfcGeom::OpenCascadePlacement*) it->Placement(); - const gp_Trsf& o_trsf = o->transformation().data(); + const gp_GTrsf& o_trsf = *(IfcGeom::OpenCascadePlacement*) o->transformation().data(); gtrsf.PreMultiply(o_trsf); if (o->geometry().settings().get(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS)) { @@ -46,10 +49,11 @@ void OpenCascadeBasedSerializer::write(const IfcGeom::BRepElement* o) { gtrsf.PreMultiply(scale); } - const TopoDS_Shape& s = it->Shape(); - const TopoDS_Shape moved_shape = IfcGeom::Kernel::apply_transformation(s, gtrsf); - - writeShape(moved_shape); + const TopoDS_Shape& s = *(IfcGeom::OpenCascadeShape*) it->Shape(); + const TopoDS_Shape moved_shape = IfcGeom::OpenCascadeKernel::apply_transformation(s, gtrsf); + + IfcGeom::OpenCascadeShape shp(moved_shape); + writeShape(&shp); } } diff --git a/src/ifcconvert/OpenCascadeBasedSerializer.h b/src/ifcconvert/OpenCascadeBasedSerializer.h index f36a844609..5989fc68ed 100644 --- a/src/ifcconvert/OpenCascadeBasedSerializer.h +++ b/src/ifcconvert/OpenCascadeBasedSerializer.h @@ -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* /*o*/) {} - void write(const IfcGeom::BRepElement* o); + void write(const IfcGeom::NativeElement* o); bool isTesselated() const { return false; } void setFile(IfcParse::IfcFile*) {} }; diff --git a/src/ifcconvert/StepSerializer.h b/src/ifcconvert/StepSerializer.h index 99fff685b8..9c1c70cdf8 100644 --- a/src/ifcconvert/StepSerializer.h +++ b/src/ifcconvert/StepSerializer.h @@ -26,6 +26,7 @@ #include "../ifcgeom/IfcGeomIterator.h" #include "../ifcconvert/OpenCascadeBasedSerializer.h" +#include "../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h" class StepSerializer : public OpenCascadeBasedSerializer { @@ -36,10 +37,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, STEPControl_AsIs); std::cout.rdbuf(sb); } void finalize() { diff --git a/src/ifcconvert/SvgSerializer.cpp b/src/ifcconvert/SvgSerializer.cpp index bf64e82db4..e8ab86b889 100644 --- a/src/ifcconvert/SvgSerializer.cpp +++ b/src/ifcconvert/SvgSerializer.cpp @@ -26,8 +26,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -46,6 +48,9 @@ #include "SvgSerializer.h" +#include "../ifcgeom/kernels/opencascade/OpenCascadeKernel.h" +#include "../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h" + const double PI2 = M_PI * 2.; bool SvgSerializer::ready() { @@ -166,7 +171,7 @@ SvgSerializer::path_object& SvgSerializer::start_path(IfcSchema::IfcBuildingStor return p; } -void SvgSerializer::write(const IfcGeom::BRepElement* o) +void SvgSerializer::write(const IfcGeom::NativeElement* o) { IfcSchema::IfcBuildingStorey* storey = 0; IfcSchema::IfcObjectDefinition* obdef = static_cast(file->entityById(o->id())); @@ -213,14 +218,14 @@ void SvgSerializer::write(const IfcGeom::BRepElement* o) path_object& p = start_path(storey, nameElement(o)); - for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = o->geometry().begin(); it != o->geometry().end(); ++ it) { - gp_GTrsf gtrsf = it->Placement(); + for (IfcGeom::ConversionResults::const_iterator it = o->geometry().begin(); it != o->geometry().end(); ++ it) { + gp_GTrsf gtrsf = *(IfcGeom::OpenCascadePlacement*) it->Placement(); - const gp_Trsf& o_trsf = o->transformation().data(); + const gp_GTrsf& o_trsf = *(IfcGeom::OpenCascadePlacement*) o->transformation().data(); gtrsf.PreMultiply(o_trsf); - const TopoDS_Shape& s = it->Shape(); - const TopoDS_Shape moved_shape = IfcGeom::Kernel::apply_transformation(s, gtrsf); + const TopoDS_Shape& s = *(IfcGeom::OpenCascadeShape*) it->Shape(); + const TopoDS_Shape moved_shape = IfcGeom::OpenCascadeKernel::apply_transformation(s, gtrsf); const double inf = std::numeric_limits::infinity(); double zmin = inf; diff --git a/src/ifcconvert/SvgSerializer.h b/src/ifcconvert/SvgSerializer.h index 96099ba1e5..169dae579c 100644 --- a/src/ifcconvert/SvgSerializer.h +++ b/src/ifcconvert/SvgSerializer.h @@ -60,7 +60,7 @@ public: void writeHeader(); bool ready(); void write(const IfcGeom::TriangulationElement* /*o*/) {} - void write(const IfcGeom::BRepElement* o); + void write(const IfcGeom::NativeElement* o); void write(path_object& p, const TopoDS_Wire& wire); path_object& start_path(IfcSchema::IfcBuildingStorey* storey, const std::string& id); bool isTesselated() const { return false; } diff --git a/src/ifcconvert/WavefrontObjSerializer.h b/src/ifcconvert/WavefrontObjSerializer.h index bdbc642ad0..cfb3cd2c62 100644 --- a/src/ifcconvert/WavefrontObjSerializer.h +++ b/src/ifcconvert/WavefrontObjSerializer.h @@ -47,7 +47,7 @@ public: void writeHeader(); void writeMaterial(const IfcGeom::Material& style); void write(const IfcGeom::TriangulationElement* o); - void write(const IfcGeom::BRepElement* /*o*/) {} + void write(const IfcGeom::NativeElement* /*o*/) {} void finalize() {} bool isTesselated() const { return true; } void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {} diff --git a/src/ifcconvert/XmlSerializer.cpp b/src/ifcconvert/XmlSerializer.cpp index a3dbaafc87..dcb574e0cd 100644 --- a/src/ifcconvert/XmlSerializer.cpp +++ b/src/ifcconvert/XmlSerializer.cpp @@ -30,6 +30,8 @@ #include "../ifcparse/IfcSIPrefix.h" #include "../ifcgeom/IfcGeom.h" +#include "../ifcgeom/kernels/opencascade/OpenCascadeKernel.h" + using boost::property_tree::ptree; using namespace IfcSchema; @@ -109,7 +111,7 @@ boost::optional format_attribute(const Argument* argument, IfcUtil: } else if (e->is(IfcSchema::Type::IfcLocalPlacement)) { IfcSchema::IfcLocalPlacement* placement = e->as(); gp_Trsf trsf; - IfcGeom::Kernel kernel; + IfcGeom::OpenCascadeKernel kernel; if (kernel.convert(placement, trsf)) { std::stringstream stream; for (int i = 1; i < 5; ++i) { diff --git a/src/ifcgeom/ConversionResult.h b/src/ifcgeom/ConversionResult.h new file mode 100644 index 0000000000..1c1051f8c4 --- /dev/null +++ b/src/ifcgeom/ConversionResult.h @@ -0,0 +1,87 @@ +/******************************************************************************** + * * + * 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 . * + * * + ********************************************************************************/ + +#ifndef IFCSHAPELIST_H +#define IFCSHAPELIST_H + +#include "../ifcgeom/IfcGeomRenderStyles.h" +#include "../ifcgeom/IfcGeomIteratorSettings.h" + +namespace IfcGeom { + + namespace Representation { + template + class IFC_GEOM_API Triangulation; + } + + class IFC_GEOM_API ConversionResultPlacement { + public: + virtual void Multiply(const ConversionResultPlacement*) = 0; + virtual void PreMultiply(const ConversionResultPlacement*) = 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* t, int surface_style_id) const = 0; + virtual void Serialize(std::string&) const = 0; + virtual ConversionResultShape* clone() const = 0; + virtual ~ConversionResultShape() {} + }; + + class IFC_GEOM_API ConversionResult { + private: + ConversionResultPlacement* placement; + ConversionResultShape* shape; + const SurfaceStyle* style; + public: + ConversionResult(const ConversionResultPlacement* placement, const ConversionResultShape* shape, const SurfaceStyle* style) + : placement(placement->clone()), shape(shape->clone()), style(style) {} + ConversionResult(const ConversionResultPlacement* placement, const ConversionResultShape* shape) + : placement(placement->clone()), shape(shape->clone()), style(0) {} + ConversionResult(const ConversionResultShape* shape, const SurfaceStyle* style) + : placement(0), shape(shape->clone()), style(style) {} + ConversionResult(const ConversionResultShape* shape) + : 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* style) { this->style = style; } + }; + + typedef std::vector ConversionResults; +} +#endif diff --git a/src/ifcgeom/IfcGeom.h b/src/ifcgeom/IfcGeom.h index c485d6e347..bb3a8dc371 100644 --- a/src/ifcgeom/IfcGeom.h +++ b/src/ifcgeom/IfcGeom.h @@ -29,57 +29,18 @@ inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance=ALMO return fabs(a-b) < tolerance; } -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "../ifcparse/IfcParse.h" #include "../ifcparse/IfcUtil.h" +#include "../ifcgeom/ConversionResult.h" #include "../ifcgeom/IfcGeomElement.h" #include "../ifcgeom/IfcGeomRepresentation.h" -#include "../ifcgeom/IfcRepresentationShapeItem.h" #include "../ifcgeom/IfcGeomShapeType.h" #include "ifc_geom_api.h" -// Define this in case you want to conserve memory usage at all cost. This has been -// benchmarked extensively: https://github.com/IfcOpenShell/IfcOpenShell/pull/47 -// #define NO_CACHE - -#ifdef NO_CACHE - -#define IN_CACHE(T,E,t,e) -#define CACHE(T,E,e) - -#else - -#define IN_CACHE(T,E,t,e) std::map::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 - namespace IfcGeom { -class IFC_GEOM_API Cache { -public: -#include "IfcRegisterCreateCache.h" - std::map Shape; -}; - -class IFC_GEOM_API Kernel { +class IFC_GEOM_API AbstractKernel { private: double deflection_tolerance; @@ -91,15 +52,11 @@ private: double modelling_precision; double dimensionality; -#ifndef NO_CACHE - Cache cache; -#endif - std::map style_cache; const SurfaceStyle* internalize_surface_style(const std::pair& shading_style); public: - Kernel() + AbstractKernel() : deflection_tolerance(0.001) , wire_creation_tolerance(0.0001) , point_equality_tolerance(0.00001) @@ -110,11 +67,11 @@ public: , dimensionality(1.) {} - Kernel(const Kernel& other) { + AbstractKernel(const AbstractKernel& other) { *this = other; } - Kernel& operator=(const Kernel& other) { + AbstractKernel& operator=(const AbstractKernel& other) { setValue(GV_DEFLECTION_TOLERANCE, other.getValue(GV_DEFLECTION_TOLERANCE)); setValue(GV_WIRE_CREATION_TOLERANCE, other.getValue(GV_WIRE_CREATION_TOLERANCE)); setValue(GV_POINT_EQUALITY_TOLERANCE, other.getValue(GV_POINT_EQUALITY_TOLERANCE)); @@ -161,87 +118,29 @@ public: GV_DIMENSIONALITY }; - bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face); - bool convert_curve_to_wire(const Handle(Geom_Curve)& curve, TopoDS_Wire& wire); - bool convert_shapes(const IfcUtil::IfcBaseClass* L, IfcRepresentationShapeItems& result); - IfcGeom::ShapeType shape_type(const IfcUtil::IfcBaseClass* L); - bool convert_shape(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result); - bool flatten_shape_list(const IfcGeom::IfcRepresentationShapeItems& shapes, TopoDS_Shape& result, bool fuse); - bool convert_wire(const IfcUtil::IfcBaseClass* L, TopoDS_Wire& result); - 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_layerset(const IfcSchema::IfcProduct*, std::vector&, std::vector&, std::vector&); - bool apply_layerset(const IfcRepresentationShapeItems&, const std::vector&, const std::vector&, IfcRepresentationShapeItems&); - bool apply_folded_layerset(const IfcRepresentationShapeItems&, const std::vector< std::vector >&, const std::vector&, IfcRepresentationShapeItems&); - bool fold_layers(const IfcSchema::IfcWall*, const IfcRepresentationShapeItems&, const std::vector&, const std::vector&, std::vector< std::vector >&); - - 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&); - - const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const Handle_Geom_Surface&); - const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const TopoDS_Face&); - const Handle_Geom_Curve intersect(const TopoDS_Face&, const Handle_Geom_Surface&); - bool intersect(const Handle_Geom_Curve&, const Handle_Geom_Surface&, gp_Pnt&); - bool intersect(const Handle_Geom_Curve&, const TopoDS_Face&, gp_Pnt&); - bool intersect(const Handle_Geom_Curve&, const TopoDS_Shape&, std::vector&); - bool intersect(const Handle_Geom_Surface&, const TopoDS_Shape&, std::vector< std::pair >&); - bool closest(const gp_Pnt&, const std::vector&, gp_Pnt&); - bool project(const Handle_Geom_Curve&, const gp_Pnt&, gp_Pnt& p, double& u, double& d); - bool project(const Handle_Geom_Surface&, const TopoDS_Shape&, double& u1, double& v1, double& u2, double& v2, double widen=0.1); - int count(const TopoDS_Shape&, TopAbs_ShapeEnum); - - bool find_wall_end_points(const IfcSchema::IfcWall*, gp_Pnt& start, gp_Pnt& end); - IfcSchema::IfcSurfaceStyleShading* get_surface_style(IfcSchema::IfcRepresentationItem* item); const IfcSchema::IfcRepresentationItem* find_item_carrying_style(const IfcSchema::IfcRepresentationItem* item); - bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& solid); - bool create_solid_from_faces(const TopTools_ListOfShape& face_list, TopoDS_Shape& solid); - bool is_compound(const TopoDS_Shape& shape); - bool is_convex(const TopoDS_Wire& wire); - TopoDS_Shape halfspace_from_plane(const gp_Pln& pln,const gp_Pnt& cent); - gp_Pln plane_from_face(const TopoDS_Face& face); - gp_Pnt point_above_plane(const gp_Pln& pln, bool agree=true); - const TopoDS_Shape& ensure_fit_for_subtraction(const TopoDS_Shape& shape, TopoDS_Shape& solid); - bool profile_helper(int numVerts, double* verts, int numFillets, int* filletIndices, double* filletRadii, gp_Trsf2d trsf, TopoDS_Shape& face); - double shape_volume(const TopoDS_Shape& s); - double face_area(const TopoDS_Face& f); - void apply_tolerance(TopoDS_Shape& s, double t); - void setValue(GeomValue var, double value); - double getValue(GeomValue var) const; - bool fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape); - void remove_duplicate_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.); - void remove_collinear_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.); - bool wire_to_sequence_of_point(const TopoDS_Wire&, TColgp_SequenceOfPnt&); - void sequence_of_point_to_wire(const TColgp_SequenceOfPnt&, TopoDS_Wire&, bool closed); - bool approximate_plane_through_wire(const TopoDS_Wire&, gp_Pln&); - bool flatten_wire(TopoDS_Wire&); - - 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*); - + void setValue(GeomValue var, double value); + double getValue(GeomValue var) const; + IfcSchema::IfcRelVoidsElement::list::ptr find_openings(IfcSchema::IfcProduct* product); - IfcSchema::IfcRepresentation* find_representation(const IfcSchema::IfcProduct*, const std::string&); - std::pair initializeUnits(IfcSchema::IfcUnitAssignment*); - IfcSchema::IfcObjectDefinition* get_decomposing_entity(IfcSchema::IfcProduct*); - template - IfcGeom::BRepElement

* create_brep_for_representation_and_product( - const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*); + virtual bool is_identity_transform(IfcUtil::IfcBaseClass*) = 0; - template - IfcGeom::BRepElement

* create_brep_for_processed_representation( - const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::BRepElement

*); + virtual IfcGeom::NativeElement* create_brep_for_representation_and_product( + const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*) = 0; + + virtual IfcGeom::NativeElement* create_brep_for_processed_representation( + const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::NativeElement*) = 0; const SurfaceStyle* get_style(const IfcSchema::IfcRepresentationItem*); const SurfaceStyle* get_style(const IfcSchema::IfcMaterial*); + + static AbstractKernel* kernel_by_name(const std::string&); template std::pair _get_surface_style(const IfcSchema::IfcStyledItem* si) { #ifdef USE_IFC4 @@ -292,21 +191,7 @@ public: return std::make_pair(0,0); } - void purge_cache() { - // Rather hack-ish, but a stopgap solution to keep memory under control - // for large files. SurfaceStyles need to be kept at all costs, as they - // are read later on when serializing Collada files. -#ifndef NO_CACHE - cache = Cache(); -#endif - } - -#include "IfcRegisterGeomHeader.h" - }; -IFC_GEOM_API IfcSchema::IfcProductDefinitionShape* tesselate(const TopoDS_Shape& shape, double deflection); -IFC_GEOM_API IfcSchema::IfcProductDefinitionShape* serialise(const TopoDS_Shape& shape, bool advanced); - } #endif diff --git a/src/ifcgeom/IfcGeomAbstractKernel.cpp b/src/ifcgeom/IfcGeomAbstractKernel.cpp new file mode 100644 index 0000000000..a5669d44f6 --- /dev/null +++ b/src/ifcgeom/IfcGeomAbstractKernel.cpp @@ -0,0 +1,248 @@ +#include "../ifcparse/IfcSIPrefix.h" + +#include "IfcGeom.h" +#include "kernels/opencascade/OpenCascadeKernel.h" + +void IfcGeom::AbstractKernel::setValue(GeomValue var, double value) { + switch (var) { + case GV_DEFLECTION_TOLERANCE: + deflection_tolerance = value; + break; + case GV_WIRE_CREATION_TOLERANCE: + wire_creation_tolerance = value; + break; + case GV_POINT_EQUALITY_TOLERANCE: + point_equality_tolerance = value; + break; + case GV_MAX_FACES_TO_SEW: + max_faces_to_sew = 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_WIRE_CREATION_TOLERANCE: + return wire_creation_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_MAX_FACES_TO_SEW: + return max_faces_to_sew; + 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; +} + +IfcSchema::IfcRelVoidsElement::list::ptr IfcGeom::AbstractKernel::find_openings(IfcSchema::IfcProduct* product) { + + IfcSchema::IfcRelVoidsElement::list::ptr openings(new IfcSchema::IfcRelVoidsElement::list); + if (product->is(IfcSchema::Type::IfcElement) && !product->is(IfcSchema::Type::IfcOpeningElement)) { + IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)product; + openings = element->HasOpenings(); + } + + // Is the IfcElement a decomposition of an IfcElement with any IfcOpeningElements? + IfcSchema::IfcObjectDefinition* obdef = product->as(); + for (;;) { +#ifdef USE_IFC4 + IfcSchema::IfcRelAggregates::list::ptr decomposes = obdef->Decomposes(); +#else + IfcSchema::IfcRelDecomposes::list::ptr decomposes = obdef->Decomposes(); +#endif + if (decomposes->size() != 1) break; + IfcSchema::IfcObjectDefinition* rel_obdef = (*decomposes->begin())->RelatingObject(); + if (rel_obdef->is(IfcSchema::Type::IfcElement) && !rel_obdef->is(IfcSchema::Type::IfcOpeningElement)) { + IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)rel_obdef; + openings->push(element->HasOpenings()); + } + + obdef = rel_obdef; + } + + return openings; +} + +IfcSchema::IfcObjectDefinition* IfcGeom::AbstractKernel::get_decomposing_entity(IfcSchema::IfcProduct* product) { + IfcSchema::IfcObjectDefinition* parent = 0; + + // In case of an opening element, parent to the RelatingBuildingElement + if (product->is(IfcSchema::Type::IfcOpeningElement)) { + IfcSchema::IfcOpeningElement* opening = (IfcSchema::IfcOpeningElement*)product; + IfcSchema::IfcRelVoidsElement::list::ptr voids = opening->VoidsElements(); + if (voids->size()) { + IfcSchema::IfcRelVoidsElement* ifc_void = *voids->begin(); + parent = ifc_void->RelatingBuildingElement(); + } + } else if (product->is(IfcSchema::Type::IfcElement)) { + IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)product; + IfcSchema::IfcRelFillsElement::list::ptr fills = element->FillsVoids(); + // Incase of a RelatedBuildingElement parent to the opening element + if (fills->size()) { + for (IfcSchema::IfcRelFillsElement::list::it it = fills->begin(); it != fills->end(); ++it) { + IfcSchema::IfcRelFillsElement* fill = *it; + IfcSchema::IfcObjectDefinition* ifc_objectdef = fill->RelatingOpeningElement(); + if (product == ifc_objectdef) continue; + parent = ifc_objectdef; + } + } + // Else simply parent to the containing structure + if (!parent) { + IfcSchema::IfcRelContainedInSpatialStructure::list::ptr parents = element->ContainedInStructure(); + if (parents->size()) { + IfcSchema::IfcRelContainedInSpatialStructure* container = *parents->begin(); + parent = container->RelatingStructure(); + } + } + } + // Parent decompositions to the RelatingObject + if (!parent) { + IfcEntityList::ptr parents = product->entity->getInverse(IfcSchema::Type::IfcRelAggregates, -1); + parents->push(product->entity->getInverse(IfcSchema::Type::IfcRelNests, -1)); + for (IfcEntityList::it it = parents->begin(); it != parents->end(); ++it) { + IfcSchema::IfcRelDecomposes* decompose = (IfcSchema::IfcRelDecomposes*)*it; + IfcSchema::IfcObjectDefinition* ifc_objectdef; +#ifdef USE_IFC4 + if (decompose->is(IfcSchema::Type::IfcRelAggregates)) { + ifc_objectdef = ((IfcSchema::IfcRelAggregates*)decompose)->RelatingObject(); + } else { + continue; + } +#else + ifc_objectdef = decompose->RelatingObject(); +#endif + if (product == ifc_objectdef) continue; + parent = ifc_objectdef; + } + } + return parent; +} + +std::pair IfcGeom::AbstractKernel::initializeUnits(IfcSchema::IfcUnitAssignment* unit_assignment) { + // Set default units, set length to meters, angles to undefined + setValue(IfcGeom::AbstractKernel::GV_LENGTH_UNIT, 1.0); + setValue(IfcGeom::AbstractKernel::GV_PLANEANGLE_UNIT, -1.0); + + std::string unit_name = "METER"; + double unit_magnitude = 1.; + + try { + IfcEntityList::ptr units = unit_assignment->Units(); + if (!units || !units->size()) { + Logger::Message(Logger::LOG_ERROR, "No unit information found"); + } else { + for (IfcEntityList::it it = units->begin(); it != units->end(); ++it) { + IfcUtil::IfcBaseClass* base = *it; + if (base->is(IfcSchema::Type::IfcNamedUnit)) { + IfcSchema::IfcNamedUnit* named_unit = base->as(); + if (named_unit->UnitType() == IfcSchema::IfcUnitEnum::IfcUnit_LENGTHUNIT || + named_unit->UnitType() == IfcSchema::IfcUnitEnum::IfcUnit_PLANEANGLEUNIT) + { + std::string current_unit_name; + const double current_unit_magnitude = IfcParse::get_SI_equivalent(named_unit); + if (current_unit_magnitude != 0.) { + if (named_unit->is(IfcSchema::Type::IfcConversionBasedUnit)) { + IfcSchema::IfcConversionBasedUnit* u = (IfcSchema::IfcConversionBasedUnit*)base; + current_unit_name = u->Name(); + } else if (named_unit->is(IfcSchema::Type::IfcSIUnit)) { + IfcSchema::IfcSIUnit* si_unit = named_unit->as(); + if (si_unit->hasPrefix()) { + current_unit_name = IfcSchema::IfcSIPrefix::ToString(si_unit->Prefix()) + unit_name; + } + current_unit_name += IfcSchema::IfcSIUnitName::ToString(si_unit->Name()); + } + if (named_unit->UnitType() == IfcSchema::IfcUnitEnum::IfcUnit_LENGTHUNIT) { + unit_name = current_unit_name; + unit_magnitude = current_unit_magnitude; + setValue(IfcGeom::AbstractKernel::GV_LENGTH_UNIT, current_unit_magnitude); + } else { + setValue(IfcGeom::AbstractKernel::GV_PLANEANGLE_UNIT, current_unit_magnitude); + } + } + } + } + } + } + } catch (const IfcParse::IfcException& ex) { + std::stringstream ss; + ss << "Failed to determine unit information '" << ex.what() << "'"; + Logger::Message(Logger::LOG_ERROR, ss.str()); + } + + return std::pair(unit_name, unit_magnitude); +} + +IfcSchema::IfcRepresentation* IfcGeom::AbstractKernel::find_representation(const IfcSchema::IfcProduct* product, const std::string& identifier) { + if (!product->hasRepresentation()) return 0; + IfcSchema::IfcProductRepresentation* prod_rep = product->Representation(); + IfcSchema::IfcRepresentation::list::ptr reps = prod_rep->Representations(); + for (IfcSchema::IfcRepresentation::list::it it = reps->begin(); it != reps->end(); ++it) { + if ((**it).hasRepresentationIdentifier() && (**it).RepresentationIdentifier() == identifier) { + return *it; + } + } + return 0; +} + +const IfcSchema::IfcRepresentationItem* IfcGeom::AbstractKernel::find_item_carrying_style(const IfcSchema::IfcRepresentationItem* item) { + if (item->StyledByItem()->size()) { + return item; + } + + while (item->is(IfcSchema::Type::IfcBooleanClippingResult)) { + // All instantiations of IfcBooleanOperand (type of FirstOperand) are subtypes of + // IfcGeometricRepresentationItem + item = (IfcSchema::IfcGeometricRepresentationItem*) ((IfcSchema::IfcBooleanClippingResult*) item)->FirstOperand(); + if (item->StyledByItem()->size()) { + return item; + } + } + + // TODO: Ideally this would be done for other entities (such as IfcCsgSolid) as well. + // But neither are these very prevalent, nor does the current IfcOpenShell style + // mechanism enable to conveniently style subshapes, which would be necessary for + // distinctly styled union operands. + + return item; +} + +IfcGeom::AbstractKernel* IfcGeom::AbstractKernel::kernel_by_name(const std::string& name) { + if (name == "opencascade") { + return new OpenCascadeKernel(); + } else if (name == "cgal") { + throw std::runtime_error("Not implemented"); + } else { + throw std::runtime_error("No kernel named " + name); + } +} \ No newline at end of file diff --git a/src/ifcgeom/IfcGeomElement.h b/src/ifcgeom/IfcGeomElement.h index 7d1410c938..adab841ee0 100644 --- a/src/ifcgeom/IfcGeomElement.h +++ b/src/ifcgeom/IfcGeomElement.h @@ -36,7 +36,7 @@ namespace IfcGeom { private: std::vector

_data; public: - Matrix(const ElementSettings& settings, const gp_Trsf& trsf) { + Matrix(const ElementSettings& settings, const 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 @@ -44,7 +44,7 @@ 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 trsf_value = trsf->Value(j,i); const double matrix_value = i == 4 && settings.get(IteratorSettings::CONVERT_BACK_UNITS) ? trsf_value / settings.unit_magnitude() : trsf_value; @@ -58,14 +58,14 @@ namespace IfcGeom { template class Transformation { private: - gp_Trsf trsf; + ConversionResultPlacement* trsf; Matrix

_matrix; public: - Transformation(const ElementSettings& settings, const gp_Trsf& trsf) - : trsf(trsf) + Transformation(const ElementSettings& settings, const ConversionResultPlacement* trsf) + : trsf(trsf->clone()) , _matrix(settings, trsf) {} - const gp_Trsf& data() const { return trsf; } + const ConversionResultPlacement* data() const { return trsf; } const Matrix

& matrix() const { return _matrix; } }; @@ -89,7 +89,7 @@ namespace IfcGeom { const std::string& context() const { return _context; } const std::string& unique_id() const { return _unique_id; } const Transformation

& transformation() const { return _transformation; } - Element(const ElementSettings& settings, int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const std::string& context, const gp_Trsf& trsf) + 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 ConversionResultPlacement* trsf) : _id(id), _parent_id(parent_id), _name(name), _type(type), _guid(guid), _context(context), _transformation(settings, trsf) { std::ostringstream oss; @@ -106,19 +106,19 @@ namespace IfcGeom { }; template - class BRepElement : public Element

{ + class NativeElement : public Element

{ private: - boost::shared_ptr _geometry; + boost::shared_ptr _geometry; public: - const boost::shared_ptr& 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& geometry) + const boost::shared_ptr& geometry_pointer() const { return _geometry; } + const Representation::Native& geometry() const { return *_geometry; } + NativeElement(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const std::string& context, const ConversionResultPlacement* trsf, const boost::shared_ptr& geometry) : Element

(geometry->settings(),id,parent_id,name,type,guid,context,trsf) , _geometry(geometry) {} private: - BRepElement(const BRepElement& other); - BRepElement& operator=(const BRepElement& other); + NativeElement(const NativeElement& other); + NativeElement& operator=(const NativeElement& other); }; template @@ -128,7 +128,7 @@ namespace IfcGeom { public: const Representation::Triangulation

& geometry() const { return *_geometry; } const boost::shared_ptr< Representation::Triangulation

>& geometry_pointer() const { return _geometry; } - TriangulationElement(const BRepElement

& shape_model) + TriangulationElement(const NativeElement

& shape_model) : Element

(shape_model) , _geometry(boost::shared_ptr >(new Representation::Triangulation

(shape_model.geometry()))) {} @@ -147,7 +147,7 @@ namespace IfcGeom { Representation::Serialization* _geometry; public: const Representation::Serialization& geometry() const { return *_geometry; } - SerializedElement(const BRepElement

& shape_model) + SerializedElement(const NativeElement

& shape_model) : Element

(shape_model) , _geometry(new Representation::Serialization(shape_model.geometry())) {} diff --git a/src/ifcgeom/IfcGeomIterator.h b/src/ifcgeom/IfcGeomIterator.h index b9c50730f1..150c6899f7 100644 --- a/src/ifcgeom/IfcGeomIterator.h +++ b/src/ifcgeom/IfcGeomIterator.h @@ -67,20 +67,13 @@ #include #include -#include -#include -#include -#include -#include -#include - #include "../ifcparse/IfcFile.h" #include "../ifcgeom/IfcGeom.h" #include "../ifcgeom/IfcGeomElement.h" #include "../ifcgeom/IfcGeomMaterial.h" #include "../ifcgeom/IfcGeomIteratorSettings.h" -#include "../ifcgeom/IfcRepresentationShapeItem.h" +#include "../ifcgeom/ConversionResult.h" // The infamous min & max Win32 #defines can leak here from OCE depending on the build configuration #ifdef min @@ -98,7 +91,7 @@ namespace IfcGeom { Iterator(const Iterator&); // N/I Iterator& operator=(const Iterator&); // N/I - Kernel kernel; + AbstractKernel* kernel; IteratorSettings settings; IfcParse::IfcFile* ifc_file; @@ -109,7 +102,7 @@ namespace IfcGeom { // The object is fetched beforehand to be sure that get() returns a valid element TriangulationElement

* current_triangulation; - BRepElement

* current_shape_model; + NativeElement

* current_shape_model; SerializedElement

* current_serialization; // A container and iterator for IfcBuildingElements for the current IfcRepresentation referenced by *representation_iterator @@ -122,14 +115,14 @@ namespace IfcGeom { std::string unit_name; // double? P unit_magnitude; - gp_XYZ bounds_min_; - gp_XYZ bounds_max_; + /* gp_XYZ bounds_min_; + gp_XYZ bounds_max_; */ void initUnits() { IfcSchema::IfcProject::list::ptr projects = ifc_file->entitiesByType(); if (projects->size() == 1) { IfcSchema::IfcProject* project = *projects->begin(); - std::pair length_unit = kernel.initializeUnits(project->UnitsInContext()); + std::pair length_unit = kernel->initializeUnits(project->UnitsInContext()); unit_name = length_unit.first; unit_magnitude = static_cast

(length_unit.second); } @@ -253,12 +246,12 @@ namespace IfcGeom { 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); + kernel->setValue(IfcGeom::AbstractKernel::GV_PRECISION, 1.e-7); } else { - kernel.setValue(IfcGeom::Kernel::GV_PRECISION, lowest_precision_encountered); + kernel->setValue(IfcGeom::AbstractKernel::GV_PRECISION, lowest_precision_encountered); } } else { - kernel.setValue(IfcGeom::Kernel::GV_PRECISION, 1.e-5); + kernel->setValue(IfcGeom::AbstractKernel::GV_PRECISION, 1.e-5); } if (representations->size() == 0) { @@ -276,7 +269,8 @@ namespace IfcGeom { done = 0; total = representations->size(); - for (int i = 1; i < 4; ++i) { + /* + for (int i = 1; i < 4; ++i) { bounds_min_.SetCoord(i, std::numeric_limits::infinity()); bounds_max_.SetCoord(i, -std::numeric_limits::infinity()); } @@ -289,7 +283,7 @@ namespace IfcGeom { gp_Trsf trsf; bool success = false; try { - success = kernel.convert(product->ObjectPlacement(), trsf); + success = kernel->convert(product->ObjectPlacement(), trsf); } catch (...) {} if (!success) { continue; @@ -304,6 +298,7 @@ namespace IfcGeom { bounds_max_.SetZ(std::max(bounds_max_.Z(), pos.Z())); } } + */ return true; } @@ -362,8 +357,10 @@ namespace IfcGeom { return boost::regex(str); } + /* const gp_XYZ& bounds_min() const { return bounds_min_; } const gp_XYZ& bounds_max() const { return bounds_max_; } + */ private: // Move to the next IfcRepresentation @@ -371,10 +368,14 @@ namespace IfcGeom { // In order to conserve memory and reduce cache insertion times, the cache is // cleared after an arbitary number of processed representations. This has been // benchmarked extensively: https://github.com/IfcOpenShell/IfcOpenShell/pull/47 + + /* static const int clear_interval = 64; if (done % clear_interval == clear_interval - 1) { - kernel.purge_cache(); + kernel->purge_cache(); } + */ + ifcproducts.reset(); ++ representation_iterator; ++ done; @@ -382,7 +383,7 @@ namespace IfcGeom { std::set mapped_representations_processed; - BRepElement

* create_shape_model_for_next_entity() { + NativeElement

* create_shape_model_for_next_entity() { for (;;) { IfcSchema::IfcRepresentation* representation; @@ -423,7 +424,7 @@ namespace IfcGeom { bool has_layers = false; for (IfcSchema::IfcProduct::list::it it = unfiltered_products->begin(); it != unfiltered_products->end(); ++it) { - if (kernel.find_openings(*it)->size()) { + if (kernel->find_openings(*it)->size()) { has_openings = true; } IfcSchema::IfcRelAssociates::list::ptr associations = (*it)->HasAssociations(); @@ -438,7 +439,7 @@ namespace IfcGeom { } // With world coords enabled, object transformations are directly applied to - // the BRep. There is no way to re-use the geometry for multiple products. + // the Native. There is no way to re-use the geometry for multiple products. const bool process_maps_for_current_representation = !settings.get(IteratorSettings::USE_WORLD_COORDS) && (!has_openings || settings.get(IteratorSettings::DISABLE_OPENING_SUBTRACTIONS)) && (!has_layers || !settings.get(IteratorSettings::APPLY_LAYERSETS)); @@ -453,9 +454,9 @@ namespace IfcGeom { if (item->is(IfcSchema::Type::IfcMappedItem)) { if (item->StyledByItem()->size() == 0) { IfcSchema::IfcMappedItem* mapped_item = item->as(); - if (kernel.is_identity_transform(mapped_item->MappingTarget())) { + if (kernel->is_identity_transform(mapped_item->MappingTarget())) { IfcSchema::IfcRepresentationMap* map = mapped_item->MappingSource(); - if (kernel.is_identity_transform(map->MappingOrigin())) { + if (kernel->is_identity_transform(map->MappingOrigin())) { representation_mapped_to = map->MappedRepresentation(); IfcSchema::IfcProductRepresentation::list::ptr prodreps = representation_mapped_to->OfProductRepresentation(); @@ -466,7 +467,7 @@ namespace IfcGeom { IfcSchema::IfcProduct::list::ptr products_of_prodrep = (*it)->entity->getInverse(IfcSchema::Type::IfcProduct, -1)->as(); products->push(products_of_prodrep); for (IfcSchema::IfcProduct::list::it jt = products_of_prodrep->begin(); jt != products_of_prodrep->end(); ++jt) { - if (kernel.find_openings(*jt)->size() > 0 && !settings.get(IteratorSettings::DISABLE_OPENING_SUBTRACTIONS)) { + if (kernel->find_openings(*jt)->size() > 0 && !settings.get(IteratorSettings::DISABLE_OPENING_SUBTRACTIONS)) { all_product_without_openings = false; break; } @@ -501,13 +502,13 @@ namespace IfcGeom { if (process_maps_for_current_representation && maps->size() == 1) { IfcSchema::IfcRepresentationMap* map = *maps->begin(); - if (kernel.is_identity_transform(map->MappingOrigin())) { + if (kernel->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 (!kernel.is_identity_transform(item->MappingTarget())) { + if (!kernel->is_identity_transform(item->MappingTarget())) { continue; } @@ -519,7 +520,7 @@ namespace IfcGeom { for (IfcSchema::IfcProductRepresentation::list::it kt = prodreps->begin(); kt != prodreps->end(); ++kt) { IfcSchema::IfcProduct::list::ptr prods = (*kt)->entity->getInverse(IfcSchema::Type::IfcProduct, -1)->as(); for (IfcSchema::IfcProduct::list::it lt = prods->begin(); lt != prods->end(); ++lt) { - if (kernel.find_openings(*lt)->size() == 0 || settings.get(IteratorSettings::DISABLE_OPENING_SUBTRACTIONS)) { + if (kernel->find_openings(*lt)->size() == 0 || settings.get(IteratorSettings::DISABLE_OPENING_SUBTRACTIONS)) { if (!unfiltered_products->contains(*lt)) { unfiltered_products->push(*lt); } @@ -549,7 +550,7 @@ namespace IfcGeom { if (!type_found && traverse) { foreach(IfcSchema::Type::Enum type, entities_to_include_or_exclude) { IfcSchema::IfcProduct* parent, * current = prod; - while ((parent = static_cast(kernel.get_decomposing_entity(current))) != 0) { + while ((parent = static_cast(kernel->get_decomposing_entity(current))) != 0) { if (parent->is(type)) { type_found = true; break; @@ -573,7 +574,7 @@ namespace IfcGeom { if (!name_found && traverse) { foreach(const boost::regex& r, names_to_include_or_exclude) { IfcSchema::IfcProduct* parent, *current = prod; - while ((parent = static_cast(kernel.get_decomposing_entity(current))) != 0) { + while ((parent = static_cast(kernel->get_decomposing_entity(current))) != 0) { if (parent->hasName() && boost::regex_match(parent->Name(), r)) { name_found = true; break; @@ -604,11 +605,11 @@ namespace IfcGeom { Logger::SetProduct(product); - BRepElement

* element; + NativeElement

* element; if (ifcproduct_iterator == ifcproducts->begin() || !settings.get(IteratorSettings::USE_WORLD_COORDS)) { - element = kernel.create_brep_for_representation_and_product

(settings, representation, product); + element = kernel->create_brep_for_representation_and_product(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); @@ -655,6 +656,7 @@ namespace IfcGeom { return ret; } + /* const Element

* getObject(int id) { gp_Trsf trsf; @@ -672,14 +674,14 @@ namespace IfcGeom { parent_id = -1; try { - IfcSchema::IfcObjectDefinition* parent_object = kernel.get_decomposing_entity(ifc_product); + IfcSchema::IfcObjectDefinition* parent_object = kernel->get_decomposing_entity(ifc_product); if (parent_object) { parent_id = parent_object->entity->id(); } } catch (...) {} try { - kernel.convert(ifc_product->ObjectPlacement(), trsf); + kernel->convert(ifc_product->ObjectPlacement(), trsf); } catch (...) {} } } catch(...) {} @@ -689,11 +691,12 @@ namespace IfcGeom { return ifc_object; } + */ bool create() { bool success = true; - IfcGeom::BRepElement

* next_shape_model = 0; + IfcGeom::NativeElement

* next_shape_model = 0; IfcGeom::SerializedElement

* next_serialization = 0; IfcGeom::TriangulationElement

* next_triangulation = 0; @@ -747,8 +750,10 @@ namespace IfcGeom { unit_name = "METER"; unit_magnitude = 1.f; - kernel.setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_SEW, settings.get(IteratorSettings::SEW_SHELLS) ? 1000 : -1); - kernel.setValue(IfcGeom::Kernel::GV_DIMENSIONALITY, (settings.get(IteratorSettings::INCLUDE_CURVES) + kernel = IfcGeom::AbstractKernel::kernel_by_name("opencascade"); + + kernel->setValue(IfcGeom::AbstractKernel::GV_MAX_FACES_TO_SEW, settings.get(IteratorSettings::SEW_SHELLS) ? 1000 : -1); + kernel->setValue(IfcGeom::AbstractKernel::GV_DIMENSIONALITY, (settings.get(IteratorSettings::INCLUDE_CURVES) ? (settings.get(IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES) ? -1. : 0.) : +1.)); } diff --git a/src/ifcgeom/IfcGeomRenderStyles.cpp b/src/ifcgeom/IfcGeomRenderStyles.cpp index 39c0d4ef37..398c13679b 100644 --- a/src/ifcgeom/IfcGeomRenderStyles.cpp +++ b/src/ifcgeom/IfcGeomRenderStyles.cpp @@ -50,7 +50,7 @@ bool process_colour(IfcSchema::IfcColourOrFactor* colour_or_factor, double* rgb) } } -const IfcGeom::SurfaceStyle* IfcGeom::Kernel::internalize_surface_style(const std::pair& shading_styles) { +const IfcGeom::SurfaceStyle* IfcGeom::AbstractKernel::internalize_surface_style(const std::pair& shading_styles) { if (shading_styles.second == 0) { return 0; } @@ -106,11 +106,11 @@ const IfcGeom::SurfaceStyle* IfcGeom::Kernel::internalize_surface_style(const st return &(style_cache[surface_style_id] = surface_style); } -const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepresentationItem* item) { +const IfcGeom::SurfaceStyle* IfcGeom::AbstractKernel::get_style(const IfcSchema::IfcRepresentationItem* item) { return internalize_surface_style(get_surface_style(item)); } -const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcMaterial* material) { +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(); diff --git a/src/ifcgeom/IfcGeomRepresentation.h b/src/ifcgeom/IfcGeomRepresentation.h index 7a18dc4bab..52f3ddceed 100644 --- a/src/ifcgeom/IfcGeomRepresentation.h +++ b/src/ifcgeom/IfcGeomRepresentation.h @@ -20,22 +20,9 @@ #ifndef IFCGEOMREPRESENTATION_H #define IFCGEOMREPRESENTATION_H -#include -#include - -#include -#include -#include - -#include -#include - -#include -#include - #include "../ifcgeom/IfcGeomIteratorSettings.h" #include "../ifcgeom/IfcGeomMaterial.h" -#include "../ifcgeom/IfcRepresentationShapeItem.h" +#include "../ifcgeom/ConversionResult.h" namespace IfcGeom { @@ -54,22 +41,22 @@ namespace IfcGeom { virtual ~Representation() {} }; - class IFC_GEOM_API BRep : public Representation { + class IFC_GEOM_API Native : public Representation { private: unsigned int id; - const IfcGeom::IfcRepresentationShapeItems _shapes; - BRep(const BRep& other); - BRep& operator=(const BRep& other); + const IfcGeom::ConversionResults _shapes; + Native(const Native& other); + Native& operator=(const Native& other); public: - BRep(const ElementSettings& settings, unsigned int id, const IfcGeom::IfcRepresentationShapeItems& shapes) + Native(const ElementSettings& settings, unsigned int id, const IfcGeom::ConversionResults& 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; } + virtual ~Native() {} + 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 unsigned int& getId() const { return id; } }; @@ -82,7 +69,7 @@ namespace IfcGeom { int id() const { return _id; } const std::string& brep_data() const { return _brep_data; } const std::vector& surface_styles() const { return _surface_styles; } - Serialization(const BRep& brep); + Serialization(const Native& brep); virtual ~Serialization() {} private: Serialization(); @@ -91,8 +78,8 @@ namespace IfcGeom { }; template - class Triangulation : public Representation { - private: + class IFC_GEOM_API Triangulation : public Representation { + protected: // 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 > Coordinate; @@ -112,6 +99,7 @@ namespace IfcGeom { public: int id() const { return _id; } + const std::vector

& verts() const { return _verts; } const std::vector& faces() const { return _faces; } const std::vector& edges() const { return _edges; } @@ -119,12 +107,20 @@ namespace IfcGeom { const std::vector

& uvs() const { return uvs_; } const std::vector& material_ids() const { return _material_ids; } const std::vector& materials() const { return _materials; } - - Triangulation(const BRep& shape_model) + + std::vector

& verts() { return _verts; } + std::vector& faces() { return _faces; } + std::vector& edges() { return _edges; } + std::vector

& normals() { return _normals; } + std::vector

& uvs() { return uvs_; } + std::vector& material_ids() { return _material_ids; } + std::vector& materials() { return _materials; } + + Triangulation(const Native& shape_model) : Representation(shape_model.settings()) , _id(shape_model.getId()) { - for ( IfcGeom::IfcRepresentationShapeItems::const_iterator iit = shape_model.begin(); iit != shape_model.end(); ++ iit ) { + for (IfcGeom::ConversionResults::const_iterator iit = shape_model.begin(); iit != shape_model.end(); ++iit) { int surface_style_id = -1; if (iit->hasStyle()) { @@ -149,185 +145,10 @@ namespace IfcGeom { } } - const TopoDS_Shape& s = iit->Shape(); - const gp_GTrsf& trsf = iit->Placement(); - - // Triangulate the shape - try { - BRepMesh_IncrementalMesh(s, settings().deflection_tolerance()); - } catch(...) { - - // TODO: Catch outside - // Logger::Message(Logger::LOG_ERROR,"Failed to triangulate shape:",ifc_file->entityById(_id)->entity); - Logger::Message(Logger::LOG_ERROR,"Failed to triangulate shape"); - 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,int> edgecount; - std::vector > edges_temp; - - const TColgp_Array1OfPnt& nodes = tri->Nodes(); - const TColgp_Array1OfPnt2d& uvs = tri->UVNodes(); - std::vector coords; - BRepGProp_Face prop(face); - std::map 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() > ALMOST_ZERO) { - normal = gp_Dir(normal_direction.XYZ() * rotation_matrix); - } - _normals.push_back(static_cast

(normal.X())); - _normals.push_back(static_cast

(normal.Y())); - _normals.push_back(static_cast

(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 >::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

(p2.X())); - _verts.push_back(static_cast

(p2.Y())); - _verts.push_back(static_cast

(p2.Z())); - _verts.push_back(static_cast

(p3.X())); - _verts.push_back(static_cast

(p3.Y())); - _verts.push_back(static_cast

(p3.Z())); - */ - - trsf.Transforms(p); - - _material_ids.push_back(surface_style_id); - - _verts.push_back(static_cast

(p.X())); - _verts.push_back(static_cast

(p.Y())); - _verts.push_back(static_cast

(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); + iit->Shape()->Triangulate(settings(), iit->Placement(), this, surface_style_id); } - } + } + virtual ~Triangulation() {} /// Generates UVs for a single mesh using box projection. @@ -360,13 +181,13 @@ namespace IfcGeom { return uvs; } - private: + public: // Welds vertices that belong to different faces - int addVertex(int material_index, const gp_XYZ& p) { + int addVertex(int material_index, P X, P Y, P Z) { const bool convert = settings().get(IteratorSettings::CONVERT_BACK_UNITS); - const P X = static_cast

(convert ? (p.X() / settings().unit_magnitude()) : p.X()); - const P Y = static_cast

(convert ? (p.Y() / settings().unit_magnitude()) : p.Y()); - const P Z = static_cast

(convert ? (p.Z() / settings().unit_magnitude()) : p.Z()); + X = static_cast

(convert ? (X / settings().unit_magnitude()) : X); + Y = static_cast

(convert ? (Y / settings().unit_magnitude()) : Y); + Z = static_cast

(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))); @@ -386,6 +207,8 @@ namespace IfcGeom { else edgecount[e] ++; edges_temp.push_back(e); } + + private: Triangulation(); Triangulation(const Triangulation&); Triangulation& operator=(const Triangulation&); diff --git a/src/ifcgeom/IfcRegisterConvertCurve.h b/src/ifcgeom/IfcRegisterConvertCurve.h deleted file mode 100644 index e67aa45807..0000000000 --- a/src/ifcgeom/IfcRegisterConvertCurve.h +++ /dev/null @@ -1,6 +0,0 @@ -#include "IfcRegisterUndef.h" -#define CURVE(T) \ - if ( l->is(T::Class()) ) return convert((T*)l,r); -#include "IfcRegisterDef.h" - -#include "IfcRegister.h" \ No newline at end of file diff --git a/src/ifcgeom/IfcRegisterConvertFace.h b/src/ifcgeom/IfcRegisterConvertFace.h deleted file mode 100644 index 04d524d315..0000000000 --- a/src/ifcgeom/IfcRegisterConvertFace.h +++ /dev/null @@ -1,6 +0,0 @@ -#include "IfcRegisterUndef.h" -#define FACE(T) \ - if ( l->is(T::Class()) ) return convert((T*)l,r); -#include "IfcRegisterDef.h" - -#include "IfcRegister.h" \ No newline at end of file diff --git a/src/ifcgeom/IfcRegisterConvertWire.h b/src/ifcgeom/IfcRegisterConvertWire.h deleted file mode 100644 index cd914b5c81..0000000000 --- a/src/ifcgeom/IfcRegisterConvertWire.h +++ /dev/null @@ -1,6 +0,0 @@ -#include "IfcRegisterUndef.h" -#define WIRE(T) \ - if ( l->is(T::Class()) ) return convert((T*)l,r); -#include "IfcRegisterDef.h" - -#include "IfcRegister.h" \ No newline at end of file diff --git a/src/ifcgeom/IfcRegisterCreateCache.h b/src/ifcgeom/IfcRegisterCreateCache.h deleted file mode 100644 index c1425d071f..0000000000 --- a/src/ifcgeom/IfcRegisterCreateCache.h +++ /dev/null @@ -1,6 +0,0 @@ -#include "IfcRegisterUndef.h" -#define CLASS(T,V) \ - std::map T; -#include "IfcRegisterDef.h" - -#include "IfcRegister.h" \ No newline at end of file diff --git a/src/ifcgeom/IfcRegisterPurgeCache.h b/src/ifcgeom/IfcRegisterPurgeCache.h deleted file mode 100644 index 1afa070943..0000000000 --- a/src/ifcgeom/IfcRegisterPurgeCache.h +++ /dev/null @@ -1,6 +0,0 @@ -#include "IfcRegisterUndef.h" -#define CLASS(T,V) \ - T.clear(); -#include "IfcRegisterDef.h" - -#include "IfcRegister.h" \ No newline at end of file diff --git a/src/ifcgeom/IfcRepresentationShapeItem.h b/src/ifcgeom/IfcRepresentationShapeItem.h deleted file mode 100644 index 29d5ca264b..0000000000 --- a/src/ifcgeom/IfcRepresentationShapeItem.h +++ /dev/null @@ -1,53 +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 . * - * * - ********************************************************************************/ - -#ifndef IFCSHAPELIST_H -#define IFCSHAPELIST_H - -#include -#include - -#include "../ifcgeom/IfcGeomRenderStyles.h" - -namespace IfcGeom { - class IFC_GEOM_API IfcRepresentationShapeItem { - private: - gp_GTrsf placement; - TopoDS_Shape shape; - const SurfaceStyle* style; - public: - IfcRepresentationShapeItem(const gp_GTrsf& placement, const TopoDS_Shape& shape, const SurfaceStyle* style) - : placement(placement), shape(shape), style(style) {} - IfcRepresentationShapeItem(const gp_GTrsf& placement, const TopoDS_Shape& shape) - : placement(placement), shape(shape), style(0) {} - IfcRepresentationShapeItem(const TopoDS_Shape& shape, const SurfaceStyle* style) - : shape(shape), style(style) {} - IfcRepresentationShapeItem(const TopoDS_Shape& shape) - : 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* style) { this->style = style; } - }; - typedef std::vector IfcRepresentationShapeItems; -} -#endif diff --git a/src/ifcgeom/IfcRegister.cpp b/src/ifcgeom/kernels/opencascade/EntityMapping.cpp similarity index 76% rename from src/ifcgeom/IfcRegister.cpp rename to src/ifcgeom/kernels/opencascade/EntityMapping.cpp index ba119c12bc..a04bc28e5d 100644 --- a/src/ifcgeom/IfcRegister.cpp +++ b/src/ifcgeom/kernels/opencascade/EntityMapping.cpp @@ -17,33 +17,36 @@ * * ********************************************************************************/ -#include "IfcGeom.h" -#include "IfcGeomShapeType.h" +#include "../../../ifcgeom/IfcGeomShapeType.h" +#include "../../../ifcgeom/IfcGeom.h" + +#include "OpenCascadeKernel.h" +#include "OpenCascadeConversionResult.h" using namespace IfcSchema; using namespace IfcUtil; -bool IfcGeom::Kernel::convert_shapes(const IfcBaseClass* l, IfcRepresentationShapeItems& r) { +bool IfcGeom::OpenCascadeKernel::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(shp, get_style(l->as()))); + r.push_back(IfcGeom::ConversionResult(new OpenCascadeShape(shp), get_style(l->as()))); return true; } return false; } -#include "IfcRegisterConvertShapes.h" +#include "EntityMappingShapes.h" Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity); return false; } -IfcGeom::ShapeType IfcGeom::Kernel::shape_type(const IfcBaseClass* l) { -#include "IfcRegisterShapeType.h" +IfcGeom::ShapeType IfcGeom::OpenCascadeKernel::shape_type(const IfcBaseClass* l) { +#include "EntityMappingShapeType.h" return ST_OTHER; } -bool IfcGeom::Kernel::convert_shape(const IfcBaseClass* l, TopoDS_Shape& r) { +bool IfcGeom::OpenCascadeKernel::convert_shape(const IfcBaseClass* l, TopoDS_Shape& r) { const unsigned int id = l->entity->id(); bool success = false; bool processed = false; @@ -60,10 +63,10 @@ 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" +#include "EntityMappingShape.h" } else if (st == ST_FACE && include_solids_and_surfaces) { processed = true; success = convert_face(l, r); @@ -99,24 +102,24 @@ bool IfcGeom::Kernel::convert_shape(const IfcBaseClass* l, TopoDS_Shape& r) { return success; } -bool IfcGeom::Kernel::convert_wire(const IfcBaseClass* l, TopoDS_Wire& r) { -#include "IfcRegisterConvertWire.h" +bool IfcGeom::OpenCascadeKernel::convert_wire(const IfcBaseClass* l, TopoDS_Wire& r) { +#include "EntityMappingWire.h" Handle(Geom_Curve) curve; - if (IfcGeom::Kernel::convert_curve(l, curve)) { - return IfcGeom::Kernel::convert_curve_to_wire(curve, r); + if (convert_curve(l, curve)) { + return convert_curve_to_wire(curve, r); } Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity); return false; } -bool IfcGeom::Kernel::convert_face(const IfcBaseClass* l, TopoDS_Shape& r) { -#include "IfcRegisterConvertFace.h" +bool IfcGeom::OpenCascadeKernel::convert_face(const IfcBaseClass* l, TopoDS_Shape& r) { +#include "EntityMappingFace.h" Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity); return false; } -bool IfcGeom::Kernel::convert_curve(const IfcBaseClass* l, Handle(Geom_Curve)& r) { -#include "IfcRegisterConvertCurve.h" +bool IfcGeom::OpenCascadeKernel::convert_curve(const IfcBaseClass* l, Handle(Geom_Curve)& r) { +#include "EntityMappingCurve.h" Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity); return false; } \ No newline at end of file diff --git a/src/ifcgeom/IfcRegister.h b/src/ifcgeom/kernels/opencascade/EntityMapping.h similarity index 98% rename from src/ifcgeom/IfcRegister.h rename to src/ifcgeom/kernels/opencascade/EntityMapping.h index 2e6f20297d..a892f4eadd 100644 --- a/src/ifcgeom/IfcRegister.h +++ b/src/ifcgeom/kernels/opencascade/EntityMapping.h @@ -38,8 +38,8 @@ #include #include -#include "../ifcparse/IfcUtil.h" -#include "../ifcparse/IfcParse.h" +#include "../../../ifcparse/IfcUtil.h" +#include "../../../ifcparse/IfcParse.h" SHAPES(IfcShellBasedSurfaceModel); SHAPES(IfcFaceBasedSurfaceModel); diff --git a/src/ifcgeom/kernels/opencascade/EntityMappingCreateCache.h b/src/ifcgeom/kernels/opencascade/EntityMappingCreateCache.h new file mode 100644 index 0000000000..274ecf5833 --- /dev/null +++ b/src/ifcgeom/kernels/opencascade/EntityMappingCreateCache.h @@ -0,0 +1,6 @@ +#include "EntityMappingUndefine.h" +#define CLASS(T,V) \ + std::map T; +#include "EntityMappingDefine.h" + +#include "EntityMapping.h" diff --git a/src/ifcgeom/kernels/opencascade/EntityMappingCurve.h b/src/ifcgeom/kernels/opencascade/EntityMappingCurve.h new file mode 100644 index 0000000000..3b2b139edb --- /dev/null +++ b/src/ifcgeom/kernels/opencascade/EntityMappingCurve.h @@ -0,0 +1,6 @@ +#include "EntityMappingUndefine.h" +#define CURVE(T) \ + if ( l->is(T::Class()) ) return convert((T*)l,r); +#include "EntityMappingDefine.h" + +#include "EntityMapping.h" \ No newline at end of file diff --git a/src/ifcgeom/IfcRegisterGeomHeader.h b/src/ifcgeom/kernels/opencascade/EntityMappingDeclaration.h similarity index 60% rename from src/ifcgeom/IfcRegisterGeomHeader.h rename to src/ifcgeom/kernels/opencascade/EntityMappingDeclaration.h index 9969d5e2db..abbf45b59c 100644 --- a/src/ifcgeom/IfcRegisterGeomHeader.h +++ b/src/ifcgeom/kernels/opencascade/EntityMappingDeclaration.h @@ -1,10 +1,10 @@ -#include "IfcRegisterUndef.h" +#include "EntityMappingUndefine.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) #define CURVE(T) CLASS(T,Handle(Geom_Curve)) -#include "IfcRegisterDef.h" +#include "EntityMappingDefine.h" -#include "IfcRegister.h" \ No newline at end of file +#include "EntityMapping.h" \ No newline at end of file diff --git a/src/ifcgeom/IfcRegisterDef.h b/src/ifcgeom/kernels/opencascade/EntityMappingDefine.h similarity index 100% rename from src/ifcgeom/IfcRegisterDef.h rename to src/ifcgeom/kernels/opencascade/EntityMappingDefine.h diff --git a/src/ifcgeom/kernels/opencascade/EntityMappingFace.h b/src/ifcgeom/kernels/opencascade/EntityMappingFace.h new file mode 100644 index 0000000000..68917d90de --- /dev/null +++ b/src/ifcgeom/kernels/opencascade/EntityMappingFace.h @@ -0,0 +1,6 @@ +#include "EntityMappingUndefine.h" +#define FACE(T) \ + if ( l->is(T::Class()) ) return convert((T*)l,r); +#include "EntityMappingDefine.h" + +#include "EntityMapping.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/EntityMappingPurgeCache.h b/src/ifcgeom/kernels/opencascade/EntityMappingPurgeCache.h new file mode 100644 index 0000000000..19164b2847 --- /dev/null +++ b/src/ifcgeom/kernels/opencascade/EntityMappingPurgeCache.h @@ -0,0 +1,6 @@ +#include "EntityMappingUndefine.h" +#define CLASS(T,V) \ + T.clear(); +#include "EntityMappingDefine.h" + +#include "EntityMapping.h" \ No newline at end of file diff --git a/src/ifcgeom/IfcRegisterConvertShape.h b/src/ifcgeom/kernels/opencascade/EntityMappingShape.h similarity index 88% rename from src/ifcgeom/IfcRegisterConvertShape.h rename to src/ifcgeom/kernels/opencascade/EntityMappingShape.h index 81a2703ee0..76d742dca2 100644 --- a/src/ifcgeom/IfcRegisterConvertShape.h +++ b/src/ifcgeom/kernels/opencascade/EntityMappingShape.h @@ -1,4 +1,4 @@ -#include "IfcRegisterUndef.h" +#include "EntityMappingUndefine.h" #define SHAPE(T) \ if ( !processed && l->is(T::Class()) ) { \ processed = true; \ @@ -21,6 +21,6 @@ return false; \ } \ } -#include "IfcRegisterDef.h" +#include "EntityMappingDefine.h" -#include "IfcRegister.h" \ No newline at end of file +#include "EntityMapping.h" \ No newline at end of file diff --git a/src/ifcgeom/IfcRegisterShapeType.h b/src/ifcgeom/kernels/opencascade/EntityMappingShapeType.h similarity index 76% rename from src/ifcgeom/IfcRegisterShapeType.h rename to src/ifcgeom/kernels/opencascade/EntityMappingShapeType.h index d11d64c9b0..92b553559e 100644 --- a/src/ifcgeom/IfcRegisterShapeType.h +++ b/src/ifcgeom/kernels/opencascade/EntityMappingShapeType.h @@ -1,4 +1,4 @@ -#include "IfcRegisterUndef.h" +#include "EntityMappingUndefine.h" #define SHAPES(T) \ if ( l->is(T::Class()) ) return ST_SHAPELIST; #define SHAPE(T) \ @@ -9,6 +9,6 @@ if ( l->is(T::Class()) ) return ST_FACE; #define CURVE(T) \ if ( l->is(T::Class()) ) return ST_CURVE; -#include "IfcRegisterDef.h" +#include "EntityMappingDefine.h" -#include "IfcRegister.h" \ No newline at end of file +#include "EntityMapping.h" diff --git a/src/ifcgeom/IfcRegisterConvertShapes.h b/src/ifcgeom/kernels/opencascade/EntityMappingShapes.h similarity index 84% rename from src/ifcgeom/IfcRegisterConvertShapes.h rename to src/ifcgeom/kernels/opencascade/EntityMappingShapes.h index 9f61849ba6..be302d5475 100644 --- a/src/ifcgeom/IfcRegisterConvertShapes.h +++ b/src/ifcgeom/kernels/opencascade/EntityMappingShapes.h @@ -1,4 +1,4 @@ -#include "IfcRegisterUndef.h" +#include "EntityMappingUndefine.h" #define SHAPES(T) \ if ( l->is(T::Class()) ) { \ try { \ @@ -13,6 +13,6 @@ } \ return false; \ } -#include "IfcRegisterDef.h" +#include "EntityMappingDefine.h" -#include "IfcRegister.h" \ No newline at end of file +#include "EntityMapping.h" diff --git a/src/ifcgeom/IfcRegisterUndef.h b/src/ifcgeom/kernels/opencascade/EntityMappingUndefine.h similarity index 100% rename from src/ifcgeom/IfcRegisterUndef.h rename to src/ifcgeom/kernels/opencascade/EntityMappingUndefine.h diff --git a/src/ifcgeom/kernels/opencascade/EntityMappingWire.h b/src/ifcgeom/kernels/opencascade/EntityMappingWire.h new file mode 100644 index 0000000000..77ffc2394e --- /dev/null +++ b/src/ifcgeom/kernels/opencascade/EntityMappingWire.h @@ -0,0 +1,6 @@ +#include "EntityMappingUndefine.h" +#define WIRE(T) \ + if ( l->is(T::Class()) ) return convert((T*)l,r); +#include "EntityMappingDefine.h" + +#include "EntityMapping.h" diff --git a/src/ifcgeom/IfcGeomCurves.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomCurves.cpp similarity index 90% rename from src/ifcgeom/IfcGeomCurves.cpp rename to src/ifcgeom/kernels/opencascade/IfcGeomCurves.cpp index 76f36f6e15..b4aaf97612 100644 --- a/src/ifcgeom/IfcGeomCurves.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomCurves.cpp @@ -19,7 +19,7 @@ /******************************************************************************** * * - * Implementations of the various conversion functions defined in IfcRegister.h * + * Implementations of the various conversion functions defined in EntityMapping.h * * * ********************************************************************************/ @@ -81,9 +81,10 @@ #include #endif -#include "../ifcgeom/IfcGeom.h" +#include "../../../ifcgeom/IfcGeom.h" +#include "OpenCascadeKernel.h" -bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircle* l, Handle(Geom_Curve)& curve) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcCircle* l, Handle(Geom_Curve)& curve) { const double r = l->Radius() * getValue(GV_LENGTH_UNIT); if ( r < ALMOST_ZERO ) { Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l->entity); @@ -92,17 +93,17 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircle* l, Handle(Geom_Curve)& gp_Trsf trsf; IfcSchema::IfcAxis2Placement* placement = l->Position(); if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) { - IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf); + IfcGeom::OpenCascadeKernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf); } else { gp_Trsf2d trsf2d; - IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf2d); + IfcGeom::OpenCascadeKernel::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf2d); trsf = trsf2d; } gp_Ax2 ax = gp_Ax2().Transformed(trsf); curve = new Geom_Circle(ax, r); return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipse* l, Handle(Geom_Curve)& curve) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcEllipse* l, Handle(Geom_Curve)& curve) { double x = l->SemiAxis1() * getValue(GV_LENGTH_UNIT); double y = l->SemiAxis2() * getValue(GV_LENGTH_UNIT); if (x < ALMOST_ZERO || y < ALMOST_ZERO) { @@ -132,7 +133,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipse* l, Handle(Geom_Curve) curve = new Geom_Ellipse(ax, x, y); return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcLine* l, Handle(Geom_Curve)& curve) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcLine* l, Handle(Geom_Curve)& curve) { gp_Pnt pnt;gp_Vec vec; convert(l->Pnt(),pnt); convert(l->Dir(),vec); @@ -142,7 +143,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcLine* l, Handle(Geom_Curve)& c } #ifdef USE_IFC4 -bool IfcGeom::Kernel::convert(const IfcSchema::IfcBSplineCurveWithKnots* l, Handle(Geom_Curve)& curve) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcBSplineCurveWithKnots* l, Handle(Geom_Curve)& curve) { const bool is_rational = l->is(IfcSchema::Type::IfcRationalBSplineCurveWithKnots); diff --git a/src/ifcgeom/IfcGeomFaces.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomFaces.cpp similarity index 90% rename from src/ifcgeom/IfcGeomFaces.cpp rename to src/ifcgeom/kernels/opencascade/IfcGeomFaces.cpp index d937848433..22e59c2fff 100644 --- a/src/ifcgeom/IfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomFaces.cpp @@ -19,7 +19,7 @@ /******************************************************************************** * * - * Implementations of the various conversion functions defined in IfcRegister.h * + * Implementations of the various conversion functions defined in EntityMapping.h * * * ********************************************************************************/ @@ -101,9 +101,10 @@ #include #endif -#include "../ifcgeom/IfcGeom.h" +#include "../../../ifcgeom/IfcGeom.h" +#include "OpenCascadeKernel.h" -bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) { IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds(); Handle(Geom_Surface) face_surface; @@ -347,7 +348,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) { return success; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryClosedProfileDef* l, TopoDS_Shape& face) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcArbitraryClosedProfileDef* l, TopoDS_Shape& face) { TopoDS_Wire wire; if ( ! convert_wire(l->OuterCurve(),wire) ) return false; @@ -357,7 +358,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryClosedProfileDef* l, return success; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryProfileDefWithVoids* l, TopoDS_Shape& face) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcArbitraryProfileDefWithVoids* l, TopoDS_Shape& face) { TopoDS_Wire profile; if ( ! convert_wire(l->OuterCurve(),profile) ) return false; BRepBuilderAPI_MakeFace mf(profile); @@ -374,7 +375,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryProfileDefWithVoids* return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleProfileDef* l, TopoDS_Shape& face) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcRectangleProfileDef* l, TopoDS_Shape& face) { const double x = l->XDim() / 2.0f * getValue(GV_LENGTH_UNIT); const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT); @@ -389,14 +390,14 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleProfileDef* l, TopoDS has_position = l->hasPosition(); #endif if (has_position) { - IfcGeom::Kernel::convert(l->Position(), trsf2d); + IfcGeom::OpenCascadeKernel::convert(l->Position(), trsf2d); } double coords[8] = {-x,-y,x,-y,x,y,-x,y}; return profile_helper(4,coords,0,0,0,trsf2d,face); } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcRoundedRectangleProfileDef* l, TopoDS_Shape& face) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcRoundedRectangleProfileDef* l, TopoDS_Shape& face) { const double x = l->XDim() / 2.0f * getValue(GV_LENGTH_UNIT); const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT); const double r = l->RoundingRadius() * getValue(GV_LENGTH_UNIT); @@ -412,7 +413,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRoundedRectangleProfileDef* l, has_position = l->hasPosition(); #endif if (has_position) { - IfcGeom::Kernel::convert(l->Position(), trsf2d); + IfcGeom::OpenCascadeKernel::convert(l->Position(), trsf2d); } double coords[8] = {-x,-y, x,-y, x,y, -x,y}; @@ -421,7 +422,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRoundedRectangleProfileDef* l, return profile_helper(4,coords,4,fillets,radii,trsf2d,face); } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleHollowProfileDef* l, TopoDS_Shape& face) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcRectangleHollowProfileDef* l, TopoDS_Shape& face) { const double x = l->XDim() / 2.0f * getValue(GV_LENGTH_UNIT); const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT); const double d = l->WallThickness() * getValue(GV_LENGTH_UNIT); @@ -446,7 +447,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleHollowProfileDef* l, has_position = l->hasPosition(); #endif if (has_position) { - IfcGeom::Kernel::convert(l->Position(), trsf2d); + IfcGeom::OpenCascadeKernel::convert(l->Position(), trsf2d); } double coords1[8] = {-x ,-y, x ,-y, x, y, -x, y }; @@ -475,7 +476,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleHollowProfileDef* l, return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrapeziumProfileDef* l, TopoDS_Shape& face) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcTrapeziumProfileDef* l, TopoDS_Shape& 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); @@ -492,14 +493,14 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrapeziumProfileDef* l, TopoDS has_position = l->hasPosition(); #endif if (has_position) { - IfcGeom::Kernel::convert(l->Position(), trsf2d); + IfcGeom::OpenCascadeKernel::convert(l->Position(), trsf2d); } double coords[8] = {-x1,-y, x1,-y, dx+w-x1,y, dx-x1,y}; return profile_helper(4,coords,0,0,0,trsf2d,face); } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcIShapeProfileDef* l, TopoDS_Shape& face) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcIShapeProfileDef* l, TopoDS_Shape& 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); @@ -537,7 +538,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcIShapeProfileDef* l, TopoDS_Sh has_position = l->hasPosition(); #endif if (has_position) { - IfcGeom::Kernel::convert(l->Position(), trsf2d); + IfcGeom::OpenCascadeKernel::convert(l->Position(), trsf2d); } double coords[24] = {-x1,-y, x1,-y, x1,-y+dy1, d1,-y+dy1, d1,y-dy2, x2,y-dy2, x2,y, -x2,y, -x2,y-dy2, -d1,y-dy2, -d1,-y+dy1, -x1,-y+dy1}; @@ -546,7 +547,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcIShapeProfileDef* l, TopoDS_Sh return profile_helper(12,coords,(doFillet1||doFillet2) ? 4 : 0,fillets,radii,trsf2d,face); } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcZShapeProfileDef* l, TopoDS_Shape& face) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcZShapeProfileDef* l, TopoDS_Shape& 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); @@ -576,7 +577,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcZShapeProfileDef* l, TopoDS_Sh has_position = l->hasPosition(); #endif if (has_position) { - IfcGeom::Kernel::convert(l->Position(), trsf2d); + IfcGeom::OpenCascadeKernel::convert(l->Position(), trsf2d); } double coords[16] = {-dx,-y, x,-y, x,-y+dy, dx,-y+dy, dx,y, -x,y, -x,y-dy, -dx,y-dy}; @@ -585,7 +586,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcZShapeProfileDef* l, TopoDS_Sh return profile_helper(8,coords,(doFillet || doEdgeFillet) ? 4 : 0,fillets,radii,trsf2d,face); } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcCShapeProfileDef* l, TopoDS_Shape& face) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcCShapeProfileDef* l, TopoDS_Shape& 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); @@ -609,7 +610,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCShapeProfileDef* l, TopoDS_Sh has_position = l->hasPosition(); #endif if (has_position) { - IfcGeom::Kernel::convert(l->Position(), trsf2d); + IfcGeom::OpenCascadeKernel::convert(l->Position(), trsf2d); } double coords[24] = {-x,-y,x,-y,x,-y+d2,x-d1,-y+d2,x-d1,-y+d1,-x+d1,-y+d1,-x+d1,y-d1,x-d1,y-d1,x-d1,y-d2,x,y-d2,x,y,-x,y}; @@ -618,7 +619,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCShapeProfileDef* l, TopoDS_Sh return profile_helper(12,coords,doFillet ? 8 : 0,fillets,radii,trsf2d,face); } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcLShapeProfileDef* l, TopoDS_Shape& face) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcLShapeProfileDef* l, TopoDS_Shape& face) { const bool hasSlope = l->hasLegSlope(); const bool doEdgeFillet = l->hasEdgeRadius(); const bool doFillet = l->hasFilletRadius(); @@ -684,7 +685,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcLShapeProfileDef* l, TopoDS_Sh has_position = l->hasPosition(); #endif if (has_position) { - IfcGeom::Kernel::convert(l->Position(), trsf2d); + IfcGeom::OpenCascadeKernel::convert(l->Position(), trsf2d); } double coords[12] = {-x,-y, x,-y, x,-y+d-dy1, xx, xy, -x+d-dx1,y, -x,y}; @@ -693,7 +694,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcLShapeProfileDef* l, TopoDS_Sh return profile_helper(6,coords,doFillet ? 3 : 0,fillets,radii,trsf2d,face); } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcUShapeProfileDef* l, TopoDS_Shape& face) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcUShapeProfileDef* l, TopoDS_Shape& face) { const bool doEdgeFillet = l->hasEdgeRadius(); const bool doFillet = l->hasFilletRadius(); const bool hasSlope = l->hasFlangeSlope(); @@ -732,7 +733,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcUShapeProfileDef* l, TopoDS_Sh has_position = l->hasPosition(); #endif if (has_position) { - IfcGeom::Kernel::convert(l->Position(), trsf2d); + IfcGeom::OpenCascadeKernel::convert(l->Position(), trsf2d); } double coords[16] = {-x,-y, x,-y, x,-y+d2-dy2, -x+d1,-y+d2+dy1, -x+d1,y-d2-dy1, x,y-d2+dy2, x,y, -x,y}; @@ -741,7 +742,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcUShapeProfileDef* l, TopoDS_Sh return profile_helper(8, coords, (doFillet || doEdgeFillet) ? 4 : 0, fillets, radii, trsf2d, face); } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Shape& face) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Shape& face) { const bool doFlangeEdgeFillet = l->hasFlangeEdgeRadius(); const bool doWebEdgeFillet = l->hasWebEdgeRadius(); const bool doFillet = l->hasFilletRadius(); @@ -821,7 +822,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Sh has_position = l->hasPosition(); #endif if (has_position) { - IfcGeom::Kernel::convert(l->Position(), trsf2d); + IfcGeom::OpenCascadeKernel::convert(l->Position(), trsf2d); } double coords[16] = {d1/2.-dx2,-y, xx,xy, x,y-d2+dy2, x,y, -x,y, -x,y-d2+dy2, -xx,xy, -d1/2.+dx2,-y}; @@ -830,7 +831,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Sh return profile_helper(8, coords, (doFillet || doWebEdgeFillet || doFlangeEdgeFillet) ? 6 : 0, fillets, radii, trsf2d, face); } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircleProfileDef* l, TopoDS_Shape& face) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcCircleProfileDef* l, TopoDS_Shape& face) { const double r = l->Radius() * getValue(GV_LENGTH_UNIT); if ( r == 0.0f ) { Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); @@ -843,7 +844,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircleProfileDef* l, TopoDS_Sh has_position = l->hasPosition(); #endif if (has_position) { - IfcGeom::Kernel::convert(l->Position(), trsf2d); + IfcGeom::OpenCascadeKernel::convert(l->Position(), trsf2d); } gp_Ax2 ax = gp_Ax2().Transformed(trsf2d); @@ -860,7 +861,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircleProfileDef* l, TopoDS_Sh return success; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircleHollowProfileDef* l, TopoDS_Shape& face) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcCircleHollowProfileDef* l, TopoDS_Shape& face) { const double r = l->Radius() * getValue(GV_LENGTH_UNIT); const double t = l->WallThickness() * getValue(GV_LENGTH_UNIT); @@ -875,7 +876,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircleHollowProfileDef* l, Top has_position = l->hasPosition(); #endif if (has_position) { - IfcGeom::Kernel::convert(l->Position(), trsf2d); + IfcGeom::OpenCascadeKernel::convert(l->Position(), trsf2d); } gp_Ax2 ax = gp_Ax2().Transformed(trsf2d); @@ -896,7 +897,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircleHollowProfileDef* l, Top return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipseProfileDef* l, TopoDS_Shape& face) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcEllipseProfileDef* l, TopoDS_Shape& face) { double rx = l->SemiAxis1() * getValue(GV_LENGTH_UNIT); double ry = l->SemiAxis2() * getValue(GV_LENGTH_UNIT); @@ -913,7 +914,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipseProfileDef* l, TopoDS_S has_position = l->hasPosition(); #endif if (has_position) { - IfcGeom::Kernel::convert(l->Position(), trsf2d); + IfcGeom::OpenCascadeKernel::convert(l->Position(), trsf2d); } gp_Ax2 ax = gp_Ax2(); @@ -934,7 +935,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipseProfileDef* l, TopoDS_S return success; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcCenterLineProfileDef* l, TopoDS_Shape& face) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcCenterLineProfileDef* l, TopoDS_Shape& face) { const double d = l->Thickness() * getValue(GV_LENGTH_UNIT) / 2.; TopoDS_Wire wire; @@ -983,7 +984,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCenterLineProfileDef* l, TopoD return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeProfileDef* l, TopoDS_Shape& face) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcCompositeProfileDef* l, TopoDS_Shape& face) { // BRepBuilderAPI_MakeFace mf; TopoDS_Compound compound; @@ -1013,10 +1014,10 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeProfileDef* l, TopoDS return !face.IsNull(); } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcDerivedProfileDef* l, TopoDS_Shape& face) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcDerivedProfileDef* l, TopoDS_Shape& face) { TopoDS_Face f; gp_Trsf2d trsf2d; - if (convert_face(l->ParentProfile(), f) && IfcGeom::Kernel::convert(l->Operator(), trsf2d)) { + if (convert_face(l->ParentProfile(), f) && IfcGeom::OpenCascadeKernel::convert(l->Operator(), trsf2d)) { gp_Trsf trsf = trsf2d; face = TopoDS::Face(BRepBuilderAPI_Transform(f, trsf)); return true; @@ -1025,7 +1026,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcDerivedProfileDef* l, TopoDS_S } } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcPlane* l, TopoDS_Shape& face) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcPlane* l, TopoDS_Shape& face) { gp_Pln pln; convert(l, pln); Handle_Geom_Surface surf = new Geom_Plane(pln); @@ -1039,7 +1040,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPlane* l, TopoDS_Shape& face) #ifdef USE_IFC4 -bool IfcGeom::Kernel::convert(const IfcSchema::IfcBSplineSurfaceWithKnots* l, TopoDS_Shape& face) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcBSplineSurfaceWithKnots* l, TopoDS_Shape& face) { boost::shared_ptr< IfcTemplatedEntityListList > cps = l->ControlPointsList(); std::vector uknots = l->UKnots(); std::vector vknots = l->VKnots(); diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp similarity index 75% rename from src/ifcgeom/IfcGeomFunctions.cpp rename to src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp index 2e6e501771..fc13aa24c4 100644 --- a/src/ifcgeom/IfcGeomFunctions.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp @@ -130,9 +130,13 @@ #include -#include "../ifcparse/IfcSIPrefix.h" -#include "../ifcparse/IfcFile.h" -#include "../ifcgeom/IfcGeom.h" +#include "../../../ifcparse/IfcSIPrefix.h" +#include "../../../ifcparse/IfcFile.h" +#include "../../../ifcgeom/IfcGeom.h" + +#include "../opencascade/OpenCascadeConversionResult.h" + +#include "OpenCascadeKernel.h" #if OCC_VERSION_HEX < 0x60900 #ifdef _MSC_VER @@ -142,7 +146,7 @@ #endif #endif -bool IfcGeom::Kernel::create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& shape) { +bool IfcGeom::OpenCascadeKernel::create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& shape) { TopTools_ListOfShape face_list; TopExp_Explorer exp(compound, TopAbs_FACE); for (; exp.More(); exp.Next()) { @@ -157,7 +161,7 @@ bool IfcGeom::Kernel::create_solid_from_compound(const TopoDS_Shape& compound, T return create_solid_from_faces(face_list, shape); } -bool IfcGeom::Kernel::create_solid_from_faces(const TopTools_ListOfShape& face_list, TopoDS_Shape& shape) { +bool IfcGeom::OpenCascadeKernel::create_solid_from_faces(const TopTools_ListOfShape& face_list, TopoDS_Shape& shape) { bool valid_shell = false; TopTools_ListIteratorOfListOfShape face_iterator; @@ -220,7 +224,7 @@ bool IfcGeom::Kernel::create_solid_from_faces(const TopTools_ListOfShape& face_l return valid_shell; } -bool IfcGeom::Kernel::is_compound(const TopoDS_Shape& shape) { +bool IfcGeom::OpenCascadeKernel::is_compound(const TopoDS_Shape& shape) { bool has_solids = TopExp_Explorer(shape,TopAbs_SOLID).More() != 0; bool has_shells = TopExp_Explorer(shape,TopAbs_SHELL).More() != 0; bool has_compounds = TopExp_Explorer(shape,TopAbs_COMPOUND).More() != 0; @@ -228,7 +232,7 @@ bool IfcGeom::Kernel::is_compound(const TopoDS_Shape& shape) { return has_compounds && has_faces && !has_solids && !has_shells; } -const TopoDS_Shape& IfcGeom::Kernel::ensure_fit_for_subtraction(const TopoDS_Shape& shape, TopoDS_Shape& solid) { +const TopoDS_Shape& IfcGeom::OpenCascadeKernel::ensure_fit_for_subtraction(const TopoDS_Shape& shape, TopoDS_Shape& solid) { const bool is_comp = is_compound(shape); if (!is_comp) { return solid = shape; @@ -246,14 +250,14 @@ const TopoDS_Shape& IfcGeom::Kernel::ensure_fit_for_subtraction(const TopoDS_Sha return solid; } -bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, - const IfcGeom::IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::IfcRepresentationShapeItems& cut_shapes) { +bool IfcGeom::OpenCascadeKernel::convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, + const IfcGeom::ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::ConversionResults& cut_shapes) { // TODO: Refactor convert_openings() convert_openings_fast() and convert(IfcBooleanResult) to use // the same code base and conform to the same checks and logging messages. // Iterate over IfcOpeningElements - IfcGeom::IfcRepresentationShapeItems opening_shapes; + IfcGeom::ConversionResults opening_shapes; unsigned int last_size = 0; for ( IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++ it ) { IfcSchema::IfcRelVoidsElement* v = *it; @@ -281,27 +285,34 @@ bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, cons const unsigned int current_size = (const unsigned int) opening_shapes.size(); for ( unsigned int i = last_size; i < current_size; ++ i ) { - opening_shapes[i].prepend(opening_trsf); + OpenCascadePlacement p((gp_GTrsf)opening_trsf); + opening_shapes[i].prepend(&p); } last_size = current_size; } } // Iterate over the shapes of the IfcProduct - for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) { + for ( IfcGeom::ConversionResults::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) { TopoDS_Shape entity_shape_solid; - const TopoDS_Shape& entity_shape_unlocated = ensure_fit_for_subtraction(it3->Shape(),entity_shape_solid); - const gp_GTrsf& entity_shape_gtrsf = it3->Placement(); - if ( entity_shape_gtrsf.Form() == gp_Other ) { - Logger::Message(Logger::LOG_WARNING, "Applying non uniform transformation to:", entity->entity); + const TopoDS_Shape& entity_shape_unlocated = ensure_fit_for_subtraction(*(OpenCascadeShape*)it3->Shape(),entity_shape_solid); + const OpenCascadePlacement* entity_shape_gtrsf = (OpenCascadePlacement*) it3->Placement(); + + TopoDS_Shape entity_shape; + if (entity_shape_gtrsf != 0) { + if (entity_shape_gtrsf->trsf().Form() == gp_Other) { + Logger::Message(Logger::LOG_WARNING, "Applying non uniform transformation to:", entity->entity); + } + entity_shape = apply_transformation(entity_shape_unlocated, entity_shape_gtrsf->trsf()); + } else { + entity_shape = entity_shape_unlocated; } - TopoDS_Shape entity_shape = apply_transformation(entity_shape_unlocated, entity_shape_gtrsf); // Iterate over the shapes of the IfcOpeningElements - for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it4 = opening_shapes.begin(); it4 != opening_shapes.end(); ++ it4 ) { + for ( IfcGeom::ConversionResults::const_iterator it4 = opening_shapes.begin(); it4 != opening_shapes.end(); ++ it4 ) { TopoDS_Shape opening_shape_solid; - const TopoDS_Shape& opening_shape_unlocated = ensure_fit_for_subtraction(it4->Shape(),opening_shape_solid); - const gp_GTrsf& opening_shape_gtrsf = it4->Placement(); + const TopoDS_Shape& opening_shape_unlocated = ensure_fit_for_subtraction(*(OpenCascadeShape*)it4->Shape(),opening_shape_solid); + const gp_GTrsf& opening_shape_gtrsf = *(OpenCascadePlacement*)it4->Placement(); if ( opening_shape_gtrsf.Form() == gp_Other ) { Logger::Message(Logger::LOG_WARNING,"Applying non uniform transformation to opening of:",entity->entity); } @@ -409,15 +420,15 @@ bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, cons } } - cut_shapes.push_back(IfcGeom::IfcRepresentationShapeItem(entity_shape, &it3->Style())); + cut_shapes.push_back(IfcGeom::ConversionResult(new OpenCascadeShape(entity_shape), &it3->Style())); } return true; } #if OCC_VERSION_HEX < 0x60900 -bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, - const IfcGeom::IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::IfcRepresentationShapeItems& cut_shapes) { +bool IfcGeom::OpenCascadeKernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, + const IfcGeom::ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::ConversionResults& cut_shapes) { // Create a compound of all opening shapes in order to speed up the boolean operations TopoDS_Compound opening_compound; @@ -444,16 +455,16 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, IfcSchema::IfcProductRepresentation* prodrep = fes->Representation(); IfcSchema::IfcRepresentation::list::ptr reps = prodrep->Representations(); - IfcGeom::IfcRepresentationShapeItems opening_shapes; + 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 ) { - gp_GTrsf gtrsf = opening_shapes[i].Placement(); + gp_GTrsf gtrsf = *(OpenCascadePlacement*) opening_shapes[i].Placement(); gtrsf.PreMultiply(opening_trsf); - TopoDS_Shape opening_shape = apply_transformation(opening_shapes[i].Shape(), gtrsf); + TopoDS_Shape opening_shape = apply_transformation(*(OpenCascadeShape*)opening_shapes[i].Shape(), gtrsf); builder.Add(opening_compound, opening_shape); } @@ -461,10 +472,10 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, } // Iterate over the shapes of the IfcProduct - for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) { + for ( IfcGeom::ConversionResults::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) { TopoDS_Shape entity_shape_solid; - const TopoDS_Shape& entity_shape_unlocated = ensure_fit_for_subtraction(it3->Shape(),entity_shape_solid); - const gp_GTrsf& entity_shape_gtrsf = it3->Placement(); + const TopoDS_Shape& entity_shape_unlocated = ensure_fit_for_subtraction(*(OpenCascadeShape*)it3->Shape(),entity_shape_solid); + const gp_GTrsf& entity_shape_gtrsf = *(OpenCascadePlacement*)it3->Placement(); if (entity_shape_gtrsf.Form() == gp_Other) { Logger::Message(Logger::LOG_WARNING, "Applying non uniform transformation to:", entity->entity); } @@ -479,7 +490,7 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, BRepCheck_Analyzer analyser(brep_cut_result); is_valid = analyser.IsValid() != 0; if ( is_valid ) { - cut_shapes.push_back(IfcGeom::IfcRepresentationShapeItem(brep_cut_result, &it3->Style())); + cut_shapes.push_back(IfcGeom::ConversionResult(new OpenCascadeShape(brep_cut_result), &it3->Style())); } } if ( !is_valid ) { @@ -494,8 +505,8 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, return true; } #else -bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, - const IfcGeom::IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::IfcRepresentationShapeItems& cut_shapes) { +bool IfcGeom::OpenCascadeKernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, + const IfcGeom::ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::ConversionResults& cut_shapes) { TopTools_ListOfShape opening_shapelist; @@ -519,16 +530,16 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, IfcSchema::IfcProductRepresentation* prodrep = fes->Representation(); IfcSchema::IfcRepresentation::list::ptr reps = prodrep->Representations(); - IfcGeom::IfcRepresentationShapeItems opening_shapes; + 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 ) { - gp_GTrsf gtrsf = opening_shapes[i].Placement(); + gp_GTrsf gtrsf = *(OpenCascadePlacement*)opening_shapes[i].Placement(); gtrsf.PreMultiply(opening_trsf); - TopoDS_Shape opening_shape = apply_transformation(opening_shapes[i].Shape(), gtrsf); + TopoDS_Shape opening_shape = apply_transformation(*(OpenCascadeShape*)opening_shapes[i].Shape(), gtrsf); opening_shapelist.Append(opening_shape); } @@ -536,10 +547,10 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, } // Iterate over the shapes of the IfcProduct - for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) { + for ( IfcGeom::ConversionResults::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) { TopoDS_Shape entity_shape_solid; - const TopoDS_Shape& entity_shape_unlocated = ensure_fit_for_subtraction(it3->Shape(),entity_shape_solid); - const gp_GTrsf& entity_shape_gtrsf = it3->Placement(); + const TopoDS_Shape& entity_shape_unlocated = ensure_fit_for_subtraction(*(OpenCascadeShape*)it3->Shape(),entity_shape_solid); + const gp_GTrsf& entity_shape_gtrsf = *(OpenCascadePlacement*)it3->Placement(); if (entity_shape_gtrsf.Form() == gp_Other) { Logger::Message(Logger::LOG_WARNING, "Applying non uniform transformation to:", entity->entity); } @@ -560,7 +571,7 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, BRepCheck_Analyzer analyser(brep_cut_result); is_valid = analyser.IsValid() != 0; if ( is_valid ) { - cut_shapes.push_back(IfcGeom::IfcRepresentationShapeItem(brep_cut_result, &it3->Style())); + cut_shapes.push_back(IfcGeom::ConversionResult(new OpenCascadeShape(brep_cut_result), &it3->Style())); } } if ( !is_valid ) { @@ -576,7 +587,7 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, } #endif -bool IfcGeom::Kernel::convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face) { +bool IfcGeom::OpenCascadeKernel::convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face) { BRepBuilderAPI_MakeFace mf(wire, false); BRepBuilderAPI_FaceError er = mf.Error(); if ( er == BRepBuilderAPI_NotPlanar ) { @@ -591,14 +602,14 @@ bool IfcGeom::Kernel::convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& return true; } -bool IfcGeom::Kernel::convert_curve_to_wire(const Handle(Geom_Curve)& curve, TopoDS_Wire& wire) { +bool IfcGeom::OpenCascadeKernel::convert_curve_to_wire(const Handle(Geom_Curve)& curve, TopoDS_Wire& wire) { try { wire = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(curve)); } catch(...) { return false; } return true; } -bool IfcGeom::Kernel::profile_helper(int numVerts, double* verts, int numFillets, int* filletIndices, double* filletRadii, gp_Trsf2d trsf, TopoDS_Shape& face_shape) { +bool IfcGeom::OpenCascadeKernel::profile_helper(int numVerts, double* verts, int numFillets, int* filletIndices, double* filletRadii, gp_Trsf2d trsf, TopoDS_Shape& face_shape) { TopoDS_Vertex* vertices = new TopoDS_Vertex[numVerts]; for ( int i = 0; i < numVerts; i ++ ) { @@ -634,17 +645,17 @@ bool IfcGeom::Kernel::profile_helper(int numVerts, double* verts, int numFillets delete[] vertices; return true; } -double IfcGeom::Kernel::shape_volume(const TopoDS_Shape& s) { +double IfcGeom::OpenCascadeKernel::shape_volume(const TopoDS_Shape& s) { GProp_GProps prop; BRepGProp::VolumeProperties(s, prop); return prop.Mass(); } -double IfcGeom::Kernel::face_area(const TopoDS_Face& f) { +double IfcGeom::OpenCascadeKernel::face_area(const TopoDS_Face& f) { GProp_GProps prop; BRepGProp::SurfaceProperties(f,prop); return prop.Mass(); } -bool IfcGeom::Kernel::is_convex(const TopoDS_Wire& wire) { +bool IfcGeom::OpenCascadeKernel::is_convex(const TopoDS_Wire& wire) { for ( TopExp_Explorer exp1(wire,TopAbs_VERTEX); exp1.More(); exp1.Next() ) { TopoDS_Vertex V1 = TopoDS::Vertex(exp1.Current()); gp_Pnt P1 = BRep_Tool::Pnt(V1); @@ -690,11 +701,11 @@ bool IfcGeom::Kernel::is_convex(const TopoDS_Wire& wire) { } return true; } -TopoDS_Shape IfcGeom::Kernel::halfspace_from_plane(const gp_Pln& pln,const gp_Pnt& cent) { +TopoDS_Shape IfcGeom::OpenCascadeKernel::halfspace_from_plane(const gp_Pln& pln,const gp_Pnt& cent) { TopoDS_Face face = BRepBuilderAPI_MakeFace(pln).Face(); return BRepPrimAPI_MakeHalfSpace(face,cent).Solid(); } -gp_Pln IfcGeom::Kernel::plane_from_face(const TopoDS_Face& face) { +gp_Pln IfcGeom::OpenCascadeKernel::plane_from_face(const TopoDS_Face& face) { BRepGProp_Face prop(face); Standard_Real u1,u2,v1,v2; prop.Bounds(u1,u2,v1,v2); @@ -705,7 +716,7 @@ gp_Pln IfcGeom::Kernel::plane_from_face(const TopoDS_Face& face) { prop.Normal(u,v,p,n); return gp_Pln(p,n); } -gp_Pnt IfcGeom::Kernel::point_above_plane(const gp_Pln& pln, bool agree) { +gp_Pnt IfcGeom::OpenCascadeKernel::point_above_plane(const gp_Pln& pln, bool agree) { if ( agree ) { return pln.Location().Translated(pln.Axis().Direction()); } else { @@ -713,73 +724,11 @@ gp_Pnt IfcGeom::Kernel::point_above_plane(const gp_Pln& pln, bool agree) { } } -void IfcGeom::Kernel::apply_tolerance(TopoDS_Shape& s, double t) { +void IfcGeom::OpenCascadeKernel::apply_tolerance(TopoDS_Shape& s, double t) { ShapeFix_ShapeTolerance tol; tol.SetTolerance(s, t); } -void IfcGeom::Kernel::setValue(GeomValue var, double value) { - switch (var) { - case GV_DEFLECTION_TOLERANCE: - deflection_tolerance = value; - break; - case GV_WIRE_CREATION_TOLERANCE: - wire_creation_tolerance = value; - break; - case GV_POINT_EQUALITY_TOLERANCE: - point_equality_tolerance = value; - break; - case GV_MAX_FACES_TO_SEW: - max_faces_to_sew = 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::Kernel::getValue(GeomValue var) const { - switch (var) { - case GV_DEFLECTION_TOLERANCE: - return deflection_tolerance; - case GV_WIRE_CREATION_TOLERANCE: - return wire_creation_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_MAX_FACES_TO_SEW: - return max_faces_to_sew; - 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; -} - // Returns the vertex part of an TopoDS_Edge edge that is not TopoDS_Vertex vertex TopoDS_Vertex find_other(const TopoDS_Edge& edge, const TopoDS_Vertex& vertex) { TopExp_Explorer exp(edge, TopAbs_VERTEX); @@ -805,7 +754,7 @@ TopoDS_Edge find_next(const TopTools_IndexedMapOfShape& edge_set, const TopTools return TopoDS_Edge(); } -bool IfcGeom::Kernel::fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape) { +bool IfcGeom::OpenCascadeKernel::fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape) { BRepOffsetAPI_Sewing sew; sew.Add(shape); @@ -886,22 +835,22 @@ bool IfcGeom::Kernel::fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& sha return true; } -bool IfcGeom::Kernel::flatten_shape_list(const IfcGeom::IfcRepresentationShapeItems& shapes, TopoDS_Shape& result, bool fuse) { +bool IfcGeom::OpenCascadeKernel::flatten_shape_list(const IfcGeom::ConversionResults& shapes, TopoDS_Shape& result, bool fuse) { TopoDS_Compound compound; BRep_Builder builder; builder.MakeCompound(compound); result = TopoDS_Shape(); - for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) { + for ( IfcGeom::ConversionResults::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) { TopoDS_Shape merged; - const TopoDS_Shape& s = it->Shape(); + const TopoDS_Shape& s = *(OpenCascadeShape*)it->Shape(); if (fuse) { ensure_fit_for_subtraction(s, merged); } else { merged = s; } - const gp_GTrsf& trsf = it->Placement(); + const gp_GTrsf& trsf = *(OpenCascadePlacement*)it->Placement(); const TopoDS_Shape moved_shape = apply_transformation(merged, trsf); if (shapes.size() == 1) { @@ -947,7 +896,7 @@ bool IfcGeom::Kernel::flatten_shape_list(const IfcGeom::IfcRepresentationShapeIt return success; } -void IfcGeom::Kernel::remove_duplicate_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol) { +void IfcGeom::OpenCascadeKernel::remove_duplicate_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol) { if (tol <= 0.) tol = getValue(GV_PRECISION); tol *= tol; @@ -971,7 +920,7 @@ void IfcGeom::Kernel::remove_duplicate_points_from_loop(TColgp_SequenceOfPnt& po } } -void IfcGeom::Kernel::remove_collinear_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol) { +void IfcGeom::OpenCascadeKernel::remove_collinear_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol) { if (tol <= 0.) tol = getValue(GV_PRECISION); const int start = closed ? 1 : 2; const int end = polygon.Length() - (closed ? 0 : 1); @@ -996,7 +945,7 @@ void IfcGeom::Kernel::remove_collinear_points_from_loop(TColgp_SequenceOfPnt& po } } -bool IfcGeom::Kernel::wire_to_sequence_of_point(const TopoDS_Wire& w, TColgp_SequenceOfPnt& p) { +bool IfcGeom::OpenCascadeKernel::wire_to_sequence_of_point(const TopoDS_Wire& w, TColgp_SequenceOfPnt& p) { TopExp_Explorer exp(w, TopAbs_EDGE); for (; exp.More(); exp.Next()) { double a, b; @@ -1023,7 +972,7 @@ bool IfcGeom::Kernel::wire_to_sequence_of_point(const TopoDS_Wire& w, TColgp_Seq return true; } -void IfcGeom::Kernel::sequence_of_point_to_wire(const TColgp_SequenceOfPnt& p, TopoDS_Wire& w, bool close) { +void IfcGeom::OpenCascadeKernel::sequence_of_point_to_wire(const TColgp_SequenceOfPnt& p, TopoDS_Wire& w, bool close) { BRepBuilderAPI_MakePolygon builder; for (int i = 1; i <= p.Length(); ++i) { builder.Add(p.Value(i)); @@ -1034,41 +983,11 @@ void IfcGeom::Kernel::sequence_of_point_to_wire(const TColgp_SequenceOfPnt& p, T w = builder.Wire(); } -IfcSchema::IfcRelVoidsElement::list::ptr IfcGeom::Kernel::find_openings(IfcSchema::IfcProduct* product) { - - IfcSchema::IfcRelVoidsElement::list::ptr openings(new IfcSchema::IfcRelVoidsElement::list); - if ( product->is(IfcSchema::Type::IfcElement) && !product->is(IfcSchema::Type::IfcOpeningElement) ) { - IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)product; - openings = element->HasOpenings(); - } - - // Is the IfcElement a decomposition of an IfcElement with any IfcOpeningElements? - IfcSchema::IfcObjectDefinition* obdef = product->as(); - for (;;) { -#ifdef USE_IFC4 - IfcSchema::IfcRelAggregates::list::ptr decomposes = obdef->Decomposes(); -#else - IfcSchema::IfcRelDecomposes::list::ptr decomposes = obdef->Decomposes(); -#endif - if (decomposes->size() != 1) break; - IfcSchema::IfcObjectDefinition* rel_obdef = (*decomposes->begin())->RelatingObject(); - if ( rel_obdef->is(IfcSchema::Type::IfcElement) && !rel_obdef->is(IfcSchema::Type::IfcOpeningElement) ) { - IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)rel_obdef; - openings->push(element->HasOpenings()); - } - - obdef = rel_obdef; - } - - return openings; -} - -template -IfcGeom::BRepElement

* IfcGeom::Kernel::create_brep_for_representation_and_product( +IfcGeom::NativeElement* IfcGeom::OpenCascadeKernel::create_brep_for_representation_and_product( const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product) { - IfcGeom::Representation::BRep* shape; - IfcGeom::IfcRepresentationShapeItems shapes, shapes2; + IfcGeom::Representation::Native* shape; + IfcGeom::ConversionResults shapes, shapes2; if ( !convert_shapes(representation, shapes) ) { return 0; @@ -1121,7 +1040,7 @@ IfcGeom::BRepElement

* IfcGeom::Kernel::create_brep_for_representation_and_pro ElementSettings element_settings(settings, getValue(GV_LENGTH_UNIT), product_type); if (!settings.get(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && openings && openings->size()) { - IfcGeom::IfcRepresentationShapeItems opened_shapes; + IfcGeom::ConversionResults opened_shapes; try { #if OCC_VERSION_HEX < 0x60900 const bool faster_booleans = settings.get(IteratorSettings::FASTER_BOOLEANS); @@ -1141,20 +1060,20 @@ IfcGeom::BRepElement

* IfcGeom::Kernel::create_brep_for_representation_and_pro Logger::Message(Logger::LOG_ERROR,"Error processing openings for:",product->entity); } if (settings.get(IteratorSettings::USE_WORLD_COORDS)) { - for ( IfcGeom::IfcRepresentationShapeItems::iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) { - it->prepend(trsf); + for ( IfcGeom::ConversionResults::iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) { + it->prepend(new OpenCascadePlacement(trsf)); } trsf = gp_Trsf(); } - shape = new IfcGeom::Representation::BRep(element_settings, representation->entity->id(), opened_shapes); + shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), opened_shapes); } else if (settings.get(IteratorSettings::USE_WORLD_COORDS)) { - for ( IfcGeom::IfcRepresentationShapeItems::iterator it = shapes.begin(); it != shapes.end(); ++ it ) { - it->prepend(trsf); + for ( IfcGeom::ConversionResults::iterator it = shapes.begin(); it != shapes.end(); ++ it ) { + it->prepend(new OpenCascadePlacement(trsf)); } trsf = gp_Trsf(); - shape = new IfcGeom::Representation::BRep(element_settings, representation->entity->id(), shapes); + shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), shapes); } else { - shape = new IfcGeom::Representation::BRep(element_settings, representation->entity->id(), shapes); + shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), shapes); } std::string context_string = ""; @@ -1164,22 +1083,21 @@ IfcGeom::BRepElement

* IfcGeom::Kernel::create_brep_for_representation_and_pro context_string = representation->ContextOfItems()->ContextType(); } - return new BRepElement

( + return new NativeElement( product->entity->id(), parent_id, name, product_type, guid, context_string, - trsf, - boost::shared_ptr(shape) + new OpenCascadePlacement(trsf), + boost::shared_ptr(shape) ); } -template -IfcGeom::BRepElement

* IfcGeom::Kernel::create_brep_for_processed_representation( +IfcGeom::NativeElement* IfcGeom::OpenCascadeKernel::create_brep_for_processed_representation( const IteratorSettings& /*settings*/, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, - IfcGeom::BRepElement

* brep) + IfcGeom::NativeElement* brep) { int parent_id = -1; try { @@ -1206,138 +1124,19 @@ IfcGeom::BRepElement

* IfcGeom::Kernel::create_brep_for_processed_representati const std::string product_type = IfcSchema::Type::ToString(product->type()); - return new BRepElement

( + return new NativeElement( product->entity->id(), parent_id, name, product_type, guid, context_string, - trsf, + new OpenCascadePlacement(trsf), brep->geometry_pointer() ); } -IfcSchema::IfcObjectDefinition* IfcGeom::Kernel::get_decomposing_entity(IfcSchema::IfcProduct* product) { - IfcSchema::IfcObjectDefinition* parent = 0; - - // In case of an opening element, parent to the RelatingBuildingElement - if ( product->is(IfcSchema::Type::IfcOpeningElement ) ) { - IfcSchema::IfcOpeningElement* opening = (IfcSchema::IfcOpeningElement*)product; - IfcSchema::IfcRelVoidsElement::list::ptr voids = opening->VoidsElements(); - if ( voids->size() ) { - IfcSchema::IfcRelVoidsElement* ifc_void = *voids->begin(); - parent = ifc_void->RelatingBuildingElement(); - } - } else if ( product->is(IfcSchema::Type::IfcElement ) ) { - IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)product; - IfcSchema::IfcRelFillsElement::list::ptr fills = element->FillsVoids(); - // Incase of a RelatedBuildingElement parent to the opening element - if ( fills->size() ) { - for ( IfcSchema::IfcRelFillsElement::list::it it = fills->begin(); it != fills->end(); ++ it ) { - IfcSchema::IfcRelFillsElement* fill = *it; - IfcSchema::IfcObjectDefinition* ifc_objectdef = fill->RelatingOpeningElement(); - if ( product == ifc_objectdef ) continue; - parent = ifc_objectdef; - } - } - // Else simply parent to the containing structure - if (!parent) { - IfcSchema::IfcRelContainedInSpatialStructure::list::ptr parents = element->ContainedInStructure(); - if ( parents->size() ) { - IfcSchema::IfcRelContainedInSpatialStructure* container = *parents->begin(); - parent = container->RelatingStructure(); - } - } - } - // Parent decompositions to the RelatingObject - if (!parent) { - IfcEntityList::ptr parents = product->entity->getInverse(IfcSchema::Type::IfcRelAggregates, -1); - parents->push(product->entity->getInverse(IfcSchema::Type::IfcRelNests, -1)); - for ( IfcEntityList::it it = parents->begin(); it != parents->end(); ++ it ) { - IfcSchema::IfcRelDecomposes* decompose = (IfcSchema::IfcRelDecomposes*)*it; - IfcSchema::IfcObjectDefinition* ifc_objectdef; -#ifdef USE_IFC4 - if (decompose->is(IfcSchema::Type::IfcRelAggregates)) { - ifc_objectdef = ((IfcSchema::IfcRelAggregates*)decompose)->RelatingObject(); - } else { - continue; - } -#else - ifc_objectdef = decompose->RelatingObject(); -#endif - if ( product == ifc_objectdef ) continue; - parent = ifc_objectdef; - } - } - return parent; -} - -template IFC_GEOM_API IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_representation_and_product( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); -template IFC_GEOM_API IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_representation_and_product( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); - -template IFC_GEOM_API IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_processed_representation( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::BRepElement* brep); -template IFC_GEOM_API IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_processed_representation( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::BRepElement* brep); - -std::pair IfcGeom::Kernel::initializeUnits(IfcSchema::IfcUnitAssignment* unit_assignment) { - // Set default units, set length to meters, angles to undefined - setValue(IfcGeom::Kernel::GV_LENGTH_UNIT, 1.0); - setValue(IfcGeom::Kernel::GV_PLANEANGLE_UNIT, -1.0); - - std::string unit_name = "METER"; - double unit_magnitude = 1.; - - try { - IfcEntityList::ptr units = unit_assignment->Units(); - if (!units || !units->size()) { - Logger::Message(Logger::LOG_ERROR, "No unit information found"); - } else { - for (IfcEntityList::it it = units->begin(); it != units->end(); ++it) { - IfcUtil::IfcBaseClass* base = *it; - if (base->is(IfcSchema::Type::IfcNamedUnit)) { - IfcSchema::IfcNamedUnit* named_unit = base->as(); - if (named_unit->UnitType() == IfcSchema::IfcUnitEnum::IfcUnit_LENGTHUNIT || - named_unit->UnitType() == IfcSchema::IfcUnitEnum::IfcUnit_PLANEANGLEUNIT) - { - std::string current_unit_name; - const double current_unit_magnitude = IfcParse::get_SI_equivalent(named_unit); - if (current_unit_magnitude != 0.) { - if (named_unit->is(IfcSchema::Type::IfcConversionBasedUnit)) { - IfcSchema::IfcConversionBasedUnit* u = (IfcSchema::IfcConversionBasedUnit*)base; - current_unit_name = u->Name(); - } else if (named_unit->is(IfcSchema::Type::IfcSIUnit)) { - IfcSchema::IfcSIUnit* si_unit = named_unit->as(); - if (si_unit->hasPrefix()) { - current_unit_name = IfcSchema::IfcSIPrefix::ToString(si_unit->Prefix()) + unit_name; - } - current_unit_name += IfcSchema::IfcSIUnitName::ToString(si_unit->Name()); - } - if (named_unit->UnitType() == IfcSchema::IfcUnitEnum::IfcUnit_LENGTHUNIT) { - unit_name = current_unit_name; - unit_magnitude = current_unit_magnitude; - setValue(IfcGeom::Kernel::GV_LENGTH_UNIT, current_unit_magnitude); - } else { - setValue(IfcGeom::Kernel::GV_PLANEANGLE_UNIT, current_unit_magnitude); - } - } - } - } - } - } - } catch (const IfcParse::IfcException& ex) { - std::stringstream ss; - ss << "Failed to determine unit information '" << ex.what() << "'"; - Logger::Message(Logger::LOG_ERROR, ss.str()); - } - - return std::pair(unit_name, unit_magnitude); -} - -bool IfcGeom::Kernel::convert_layerset(const IfcSchema::IfcProduct* product, std::vector& surfaces, std::vector& styles, std::vector& thicknesses) { +bool IfcGeom::OpenCascadeKernel::convert_layerset(const IfcSchema::IfcProduct* product, std::vector& surfaces, std::vector& styles, std::vector& thicknesses) { IfcSchema::IfcMaterialLayerSetUsage* usage = 0; Handle_Geom_Surface reference_surface; @@ -1363,9 +1162,9 @@ bool IfcGeom::Kernel::convert_layerset(const IfcSchema::IfcProduct* product, std return false; } - IfcRepresentationShapeItems axis_items; + ConversionResults axis_items; { - Kernel temp = *this; + OpenCascadeKernel temp = *this; temp.setValue(GV_DIMENSIONALITY, -1.); temp.convert_shapes(axis_representation, axis_items); } @@ -1465,7 +1264,7 @@ bool IfcGeom::Kernel::convert_layerset(const IfcSchema::IfcProduct* product, std return true; } -const Handle_Geom_Curve IfcGeom::Kernel::intersect(const Handle_Geom_Surface& a, const Handle_Geom_Surface& b) { +const Handle_Geom_Curve IfcGeom::OpenCascadeKernel::intersect(const Handle_Geom_Surface& a, const Handle_Geom_Surface& b) { GeomAPI_IntSS x(a, b, 1.e-7); if (x.IsDone() && x.NbLines() == 1) { return x.Line(1); @@ -1474,15 +1273,15 @@ const Handle_Geom_Curve IfcGeom::Kernel::intersect(const Handle_Geom_Surface& a, } } -const Handle_Geom_Curve IfcGeom::Kernel::intersect(const Handle_Geom_Surface& a, const TopoDS_Face& b) { +const Handle_Geom_Curve IfcGeom::OpenCascadeKernel::intersect(const Handle_Geom_Surface& a, const TopoDS_Face& b) { return intersect(a, BRep_Tool::Surface(b)); } -const Handle_Geom_Curve IfcGeom::Kernel::intersect(const TopoDS_Face& a, const Handle_Geom_Surface& b) { +const Handle_Geom_Curve IfcGeom::OpenCascadeKernel::intersect(const TopoDS_Face& a, const Handle_Geom_Surface& b) { return intersect(BRep_Tool::Surface(a), b); } -bool IfcGeom::Kernel::intersect(const Handle_Geom_Curve& a, const Handle_Geom_Surface& b, gp_Pnt& p) { +bool IfcGeom::OpenCascadeKernel::intersect(const Handle_Geom_Curve& a, const Handle_Geom_Surface& b, gp_Pnt& p) { GeomAPI_IntCS x(a, b); if (x.IsDone() && x.NbPoints() == 1) { p = x.Point(1); @@ -1492,11 +1291,11 @@ bool IfcGeom::Kernel::intersect(const Handle_Geom_Curve& a, const Handle_Geom_Su } } -bool IfcGeom::Kernel::intersect(const Handle_Geom_Curve& a, const TopoDS_Face& b, gp_Pnt &c) { +bool IfcGeom::OpenCascadeKernel::intersect(const Handle_Geom_Curve& a, const TopoDS_Face& b, gp_Pnt &c) { return intersect(a, BRep_Tool::Surface(b), c); } -bool IfcGeom::Kernel::intersect(const Handle_Geom_Curve& a, const TopoDS_Shape& b, std::vector& out) { +bool IfcGeom::OpenCascadeKernel::intersect(const Handle_Geom_Curve& a, const TopoDS_Shape& b, std::vector& out) { TopExp_Explorer exp(b, TopAbs_FACE); gp_Pnt p; for (; exp.More(); exp.Next()) { @@ -1507,7 +1306,7 @@ bool IfcGeom::Kernel::intersect(const Handle_Geom_Curve& a, const TopoDS_Shape& return !out.empty(); } -bool IfcGeom::Kernel::intersect(const Handle_Geom_Surface& a, const TopoDS_Shape& b, std::vector< std::pair >& out) { +bool IfcGeom::OpenCascadeKernel::intersect(const Handle_Geom_Surface& a, const TopoDS_Shape& b, std::vector< std::pair >& out) { TopExp_Explorer exp(b, TopAbs_FACE); for (; exp.More(); exp.Next()) { const TopoDS_Face& f = TopoDS::Face(exp.Current()); @@ -1520,7 +1319,7 @@ bool IfcGeom::Kernel::intersect(const Handle_Geom_Surface& a, const TopoDS_Shape return !out.empty(); } -bool IfcGeom::Kernel::closest(const gp_Pnt& a, const std::vector& b, gp_Pnt& c) { +bool IfcGeom::OpenCascadeKernel::closest(const gp_Pnt& a, const std::vector& b, gp_Pnt& c) { double minimal_distance = std::numeric_limits::infinity(); for (std::vector::const_iterator it = b.begin(); it != b.end(); ++it) { const double d = a.Distance(*it); @@ -1532,14 +1331,14 @@ bool IfcGeom::Kernel::closest(const gp_Pnt& a, const std::vector& b, gp_ return minimal_distance != std::numeric_limits::infinity(); } -bool IfcGeom::Kernel::project(const Handle_Geom_Curve& crv, const gp_Pnt& pt, gp_Pnt& p, double& u, double& d) { +bool IfcGeom::OpenCascadeKernel::project(const Handle_Geom_Curve& crv, const gp_Pnt& pt, gp_Pnt& p, double& u, double& d) { ShapeAnalysis_Curve sac; sac.Project(crv, pt, 1e-3, p, u, false); d = pt.Distance(p); return true; } -int IfcGeom::Kernel::count(const TopoDS_Shape& s, TopAbs_ShapeEnum t) { +int IfcGeom::OpenCascadeKernel::count(const TopoDS_Shape& s, TopAbs_ShapeEnum t) { int i = 0; TopExp_Explorer exp(s, t); for (; exp.More(); exp.Next()) { @@ -1548,22 +1347,22 @@ int IfcGeom::Kernel::count(const TopoDS_Shape& s, TopAbs_ShapeEnum t) { return i; } -bool IfcGeom::Kernel::find_wall_end_points(const IfcSchema::IfcWall* wall, gp_Pnt& start, gp_Pnt& end) { +bool IfcGeom::OpenCascadeKernel::find_wall_end_points(const IfcSchema::IfcWall* wall, gp_Pnt& start, gp_Pnt& end) { IfcSchema::IfcRepresentation* axis_representation = find_representation(wall, "Axis"); if (!axis_representation) { return false; } - IfcRepresentationShapeItems items; + ConversionResults items; { - Kernel temp = *this; + OpenCascadeKernel temp = *this; temp.setValue(GV_DIMENSIONALITY, -1.); temp.convert_shapes(axis_representation, items); } TopoDS_Vertex a, b; - for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) { - TopExp_Explorer exp(it->Shape(), TopAbs_VERTEX); + for (ConversionResults::const_iterator it = items.begin(); it != items.end(); ++it) { + TopExp_Explorer exp(*(OpenCascadeShape*)it->Shape(), TopAbs_VERTEX); for (; exp.More(); exp.Next()) { b = TopoDS::Vertex(exp.Current()); if (a.IsNull()) { @@ -1582,7 +1381,7 @@ bool IfcGeom::Kernel::find_wall_end_points(const IfcSchema::IfcWall* wall, gp_Pn return true; } -bool IfcGeom::Kernel::fold_layers(const IfcSchema::IfcWall* wall, const IfcRepresentationShapeItems& items, const std::vector& surfaces, const std::vector& thicknesses, std::vector< std::vector >& result) { +bool IfcGeom::OpenCascadeKernel::fold_layers(const IfcSchema::IfcWall* wall, const ConversionResults& items, const std::vector& surfaces, const std::vector& thicknesses, std::vector< std::vector >& result) { bool folds_made = false; IfcSchema::IfcRelConnectsPathElements::list::ptr connections(new IfcSchema::IfcRelConnectsPathElements::list); @@ -1725,9 +1524,9 @@ bool IfcGeom::Kernel::fold_layers(const IfcSchema::IfcWall* wall, const IfcRepre IfcSchema::IfcRepresentation* axis_representation = find_representation(other_wall, "Axis"); - IfcRepresentationShapeItems axis_items; + ConversionResults axis_items; { - Kernel temp = *this; + OpenCascadeKernel temp = *this; temp.setValue(GV_DIMENSIONALITY, -1.); temp.convert_shapes(axis_representation, axis_items); } @@ -1888,7 +1687,7 @@ bool IfcGeom::Kernel::fold_layers(const IfcSchema::IfcWall* wall, const IfcRepre return folds_made; } -bool IfcGeom::Kernel::apply_folded_layerset(const IfcRepresentationShapeItems& items, const std::vector< std::vector >& surfaces, const std::vector& styles, IfcRepresentationShapeItems& result) { +bool IfcGeom::OpenCascadeKernel::apply_folded_layerset(const ConversionResults& items, const std::vector< std::vector >& surfaces, const std::vector& styles, ConversionResults& result) { Bnd_Box bb; TopoDS_Shape input; flatten_shape_list(items, input, false); @@ -1968,11 +1767,11 @@ bool IfcGeom::Kernel::apply_folded_layerset(const IfcRepresentationShapeItems& i } else if (shells.size() == 1) { - for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) { + for (ConversionResults::const_iterator it = items.begin(); it != items.end(); ++it) { TopoDS_Shape a,b; - if (split_solid_by_shell(it->Shape(), shells[0], a, b)) { - result.push_back(IfcRepresentationShapeItem(it->Placement(), b, styles[0] ? styles[0] : &it->Style())); - result.push_back(IfcRepresentationShapeItem(it->Placement(), a, styles[1] ? styles[1] : &it->Style())); + if (split_solid_by_shell(*(OpenCascadeShape*)it->Shape(), shells[0], a, b)) { + result.push_back(ConversionResult(it->Placement(), new OpenCascadeShape(b), styles[0] ? styles[0] : &it->Style())); + result.push_back(ConversionResult(it->Placement(), new OpenCascadeShape(a), styles[1] ? styles[1] : &it->Style())); } else { continue; } @@ -1985,8 +1784,8 @@ bool IfcGeom::Kernel::apply_folded_layerset(const IfcRepresentationShapeItems& i typedef std::vector< std::vector > temp_t; temp_t temp; - for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) { - const TopoDS_Shape& s = it->Shape(); + for (ConversionResults::const_iterator it = items.begin(); it != items.end(); ++it) { + const TopoDS_Shape& s = *(OpenCascadeShape*)it->Shape(); TopoDS_Solid sld; ensure_fit_for_subtraction(s, sld); std::vector temp2; @@ -2008,13 +1807,13 @@ bool IfcGeom::Kernel::apply_folded_layerset(const IfcRepresentationShapeItems& i } } - IfcRepresentationShapeItems::const_iterator it1 = items.begin(); + ConversionResults::const_iterator it1 = items.begin(); temp_t::const_iterator it2 = temp.begin(); for(; it1 != items.end(); ++it1, ++it2) { std::vector::const_iterator it4 = styles.begin(); for (temp_t::value_type::const_iterator it3 = it2->begin(); it3 != it2->end(); ++it3, ++it4) { - result.push_back(IfcRepresentationShapeItem(it1->Placement(), *it3, (*it4) ? (*it4) : &it1->Style())); + result.push_back(ConversionResult(it1->Placement(), new OpenCascadeShape(*it3), (*it4) ? (*it4) : &it1->Style())); } } @@ -2024,18 +1823,18 @@ bool IfcGeom::Kernel::apply_folded_layerset(const IfcRepresentationShapeItems& i } -bool IfcGeom::Kernel::apply_layerset(const IfcRepresentationShapeItems& items, const std::vector& surfaces, const std::vector& styles, IfcRepresentationShapeItems& result) { +bool IfcGeom::OpenCascadeKernel::apply_layerset(const ConversionResults& items, const std::vector& surfaces, const std::vector& styles, ConversionResults& result) { if (surfaces.size() < 3) { return false; } else if (surfaces.size() == 3) { - for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) { + for (ConversionResults::const_iterator it = items.begin(); it != items.end(); ++it) { TopoDS_Shape a,b; - if (split_solid_by_surface(it->Shape(), surfaces[1], a, b)) { - result.push_back(IfcRepresentationShapeItem(it->Placement(), b, styles[0] ? styles[0] : &it->Style())); - result.push_back(IfcRepresentationShapeItem(it->Placement(), a, styles[1] ? styles[1] : &it->Style())); + if (split_solid_by_surface(*(OpenCascadeShape*)it->Shape(), surfaces[1], a, b)) { + result.push_back(ConversionResult(it->Placement(), new OpenCascadeShape(b), styles[0] ? styles[0] : &it->Style())); + result.push_back(ConversionResult(it->Placement(), new OpenCascadeShape(a), styles[1] ? styles[1] : &it->Style())); } else { continue; } @@ -2049,7 +1848,7 @@ bool IfcGeom::Kernel::apply_layerset(const IfcRepresentationShapeItems& items, c // Determine whether sequence of surfaces is consistent with surface normal, so that // layer operations are applied in the correct order. This seems to be always the case. Bnd_Box bb; - for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) { + for (ConversionResults::const_iterator it = items.begin(); it != items.end(); ++it) { BRepBndLib::Add(it->Shape(), bb); } @@ -2077,9 +1876,9 @@ bool IfcGeom::Kernel::apply_layerset(const IfcRepresentationShapeItems& items, c typedef std::vector< std::vector > temp_t; temp_t temp; - for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) { + for (ConversionResults::const_iterator it = items.begin(); it != items.end(); ++it) { // No transformation on purpose in order not interfere with layerset alignment - const TopoDS_Shape& s = it->Shape(); + const TopoDS_Shape& s = *(OpenCascadeShape*)it->Shape(); TopoDS_Solid sld; ensure_fit_for_subtraction(s, sld); std::vector temp2; @@ -2101,13 +1900,13 @@ bool IfcGeom::Kernel::apply_layerset(const IfcRepresentationShapeItems& items, c } } - IfcRepresentationShapeItems::const_iterator it1 = items.begin(); + ConversionResults::const_iterator it1 = items.begin(); temp_t::const_iterator it2 = temp.begin(); for(; it1 != items.end(); ++it1, ++it2) { std::vector::const_iterator it4 = styles.begin(); for (temp_t::value_type::const_iterator it3 = it2->begin(); it3 != it2->end(); ++it3, ++it4) { - result.push_back(IfcRepresentationShapeItem(it1->Placement(), *it3, (*it4) ? (*it4) : &it1->Style())); + result.push_back(ConversionResult(it1->Placement(), new OpenCascadeShape(*it3), (*it4) ? (*it4) : &it1->Style())); } } @@ -2115,19 +1914,7 @@ bool IfcGeom::Kernel::apply_layerset(const IfcRepresentationShapeItems& items, c } } -IfcSchema::IfcRepresentation* IfcGeom::Kernel::find_representation(const IfcSchema::IfcProduct* product, const std::string& identifier) { - if (!product->hasRepresentation()) return 0; - IfcSchema::IfcProductRepresentation* prod_rep = product->Representation(); - IfcSchema::IfcRepresentation::list::ptr reps = prod_rep->Representations(); - for (IfcSchema::IfcRepresentation::list::it it = reps->begin(); it != reps->end(); ++it) { - if ((**it).hasRepresentationIdentifier() && (**it).RepresentationIdentifier() == identifier) { - return *it; - } - } - return 0; -} - -bool IfcGeom::Kernel::split_solid_by_surface(const TopoDS_Shape& input, const Handle_Geom_Surface& surface, TopoDS_Shape& front, TopoDS_Shape& back) { +bool IfcGeom::OpenCascadeKernel::split_solid_by_surface(const TopoDS_Shape& input, const Handle_Geom_Surface& surface, TopoDS_Shape& front, TopoDS_Shape& back) { // Use an unbounded surface, that isolate part of the input shape, // to split this shape into two parts. Make sure that the addition // of the two result volumes matches that of the input. @@ -2148,7 +1935,7 @@ bool IfcGeom::Kernel::split_solid_by_surface(const TopoDS_Shape& input, const Ha return b; } -bool IfcGeom::Kernel::split_solid_by_shell(const TopoDS_Shape& input, const TopoDS_Shape& shell, TopoDS_Shape& front, TopoDS_Shape& back) { +bool IfcGeom::OpenCascadeKernel::split_solid_by_shell(const TopoDS_Shape& input, const TopoDS_Shape& shell, TopoDS_Shape& front, TopoDS_Shape& back) { // Use a shell, typically one or more connected faces, that isolate part // of the input shape, to split this shape into two parts. Make sure that // the addition of the two result volumes matches that of the input. @@ -2207,7 +1994,7 @@ bool IfcGeom::Kernel::split_solid_by_shell(const TopoDS_Shape& input, const Topo return ALMOST_THE_SAME(ab, a+b, 1.e-3); } -bool IfcGeom::Kernel::project(const Handle_Geom_Surface& srf, const TopoDS_Shape& shp, double& u1, double& v1, double& u2, double& v2, double widen) { +bool IfcGeom::OpenCascadeKernel::project(const Handle_Geom_Surface& srf, const TopoDS_Shape& shp, double& u1, double& v1, double& u2, double& v2, double widen) { ShapeAnalysis_Surface sas(srf); u1 = v1 = +std::numeric_limits::infinity(); @@ -2259,29 +2046,7 @@ bool IfcGeom::Kernel::project(const Handle_Geom_Surface& srf, const TopoDS_Shape return true; } -const IfcSchema::IfcRepresentationItem* IfcGeom::Kernel::find_item_carrying_style(const IfcSchema::IfcRepresentationItem* item) { - if (item->StyledByItem()->size()) { - return item; - } - - while (item->is(IfcSchema::Type::IfcBooleanClippingResult)) { - // All instantiations of IfcBooleanOperand (type of FirstOperand) are subtypes of - // IfcGeometricRepresentationItem - item = (IfcSchema::IfcGeometricRepresentationItem*) ((IfcSchema::IfcBooleanClippingResult*) item)->FirstOperand(); - if (item->StyledByItem()->size()) { - return item; - } - } - - // TODO: Ideally this would be done for other entities (such as IfcCsgSolid) as well. - // But neither are these very prevalent, nor does the current IfcOpenShell style - // mechanism enable to conveniently style subshapes, which would be necessary for - // distinctly styled union operands. - - return item; -} - -bool IfcGeom::Kernel::is_identity_transform(IfcUtil::IfcBaseClass* l) { +bool IfcGeom::OpenCascadeKernel::is_identity_transform(IfcUtil::IfcBaseClass* l) { IfcSchema::IfcAxis2Placement2D* ax2d; IfcSchema::IfcAxis2Placement3D* ax3d; @@ -2319,7 +2084,7 @@ bool IfcGeom::Kernel::is_identity_transform(IfcUtil::IfcBaseClass* l) { } } -bool IfcGeom::Kernel::approximate_plane_through_wire(const TopoDS_Wire& wire, gp_Pln& plane) { +bool IfcGeom::OpenCascadeKernel::approximate_plane_through_wire(const TopoDS_Wire& wire, gp_Pln& plane) { // Newell's Method is used for the normal calculation // as a simple edge cross product can give opposite results // for a concave face boundary. @@ -2369,7 +2134,7 @@ bool IfcGeom::Kernel::approximate_plane_through_wire(const TopoDS_Wire& wire, gp return true; } -bool IfcGeom::Kernel::flatten_wire(TopoDS_Wire& wire) { +bool IfcGeom::OpenCascadeKernel::flatten_wire(TopoDS_Wire& wire) { gp_Pln pln; if (!approximate_plane_through_wire(wire, pln)) { return false; @@ -2391,7 +2156,7 @@ bool IfcGeom::Kernel::flatten_wire(TopoDS_Wire& wire) { } -TopoDS_Shape IfcGeom::Kernel::apply_transformation(const TopoDS_Shape& s, const gp_Trsf& t) { +TopoDS_Shape IfcGeom::OpenCascadeKernel::apply_transformation(const TopoDS_Shape& s, const gp_Trsf& t) { if (t.Form() == gp_Identity) { return s; } else { @@ -2404,7 +2169,7 @@ TopoDS_Shape IfcGeom::Kernel::apply_transformation(const TopoDS_Shape& s, const } } -TopoDS_Shape IfcGeom::Kernel::apply_transformation(const TopoDS_Shape& s, const gp_GTrsf& t) { +TopoDS_Shape IfcGeom::OpenCascadeKernel::apply_transformation(const TopoDS_Shape& s, const gp_GTrsf& t) { if (t.Form() == gp_Other) { return BRepBuilderAPI_GTransform(s, t, true); } else { diff --git a/src/ifcgeom/IfcGeomHelpers.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomHelpers.cpp similarity index 78% rename from src/ifcgeom/IfcGeomHelpers.cpp rename to src/ifcgeom/kernels/opencascade/IfcGeomHelpers.cpp index 29851a2627..9f22441f96 100644 --- a/src/ifcgeom/IfcGeomHelpers.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomHelpers.cpp @@ -19,7 +19,7 @@ /******************************************************************************** * * - * Implementations of the various conversion functions defined in IfcRegister.h * + * Implementations of the various conversion functions defined in EntityMapping.h * * * ********************************************************************************/ @@ -75,7 +75,8 @@ #include -#include "../ifcgeom/IfcGeom.h" +#include "../../../ifcgeom/IfcGeom.h" +#include "OpenCascadeKernel.h" // Helper functions (re)set gp_(G)Trsf(2d) forms explicitly to 'Identity' // so that it can be easily identified in the IfcMappedItem processing @@ -124,7 +125,7 @@ bool is_identity(const T& t, double tolerance) { return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianPoint* l, gp_Pnt& point) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcCartesianPoint* l, gp_Pnt& point) { IN_CACHE(IfcCartesianPoint,l,gp_Pnt,point) std::vector xyz = l->Coordinates(); point = gp_Pnt( @@ -136,7 +137,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianPoint* l, gp_Pnt& poi return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcDirection* l, gp_Dir& dir) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcDirection* l, gp_Dir& dir) { IN_CACHE(IfcDirection,l,gp_Dir,dir) std::vector xyz = l->DirectionRatios(); dir = gp_Dir( @@ -148,22 +149,22 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcDirection* l, gp_Dir& dir) { return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcVector* l, gp_Vec& v) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcVector* l, gp_Vec& v) { IN_CACHE(IfcVector,l,gp_Vec,v) gp_Dir d; - IfcGeom::Kernel::convert(l->Orientation(),d); + IfcGeom::OpenCascadeKernel::convert(l->Orientation(),d); v = l->Magnitude() * getValue(GV_LENGTH_UNIT) * d; CACHE(IfcVector,l,v) return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement3D* l, gp_Trsf& trsf) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcAxis2Placement3D* l, gp_Trsf& trsf) { IN_CACHE(IfcAxis2Placement3D,l,gp_Trsf,trsf) gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1);gp_Dir refDirection; - IfcGeom::Kernel::convert(l->Location(),o); + IfcGeom::OpenCascadeKernel::convert(l->Location(),o); bool hasRef = l->hasRefDirection(); - if ( l->hasAxis() ) IfcGeom::Kernel::convert(l->Axis(),axis); - if ( hasRef ) IfcGeom::Kernel::convert(l->RefDirection(),refDirection); + if ( l->hasAxis() ) IfcGeom::OpenCascadeKernel::convert(l->Axis(),axis); + if ( hasRef ) IfcGeom::OpenCascadeKernel::convert(l->RefDirection(),refDirection); gp_Ax3 ax3; if ( hasRef ) ax3 = gp_Ax3(o,axis,refDirection); else ax3 = gp_Ax3(o,axis); @@ -176,26 +177,26 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement3D* l, gp_Trsf& return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis1Placement* l, gp_Ax1& ax) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcAxis1Placement* l, gp_Ax1& ax) { IN_CACHE(IfcAxis1Placement,l,gp_Ax1,ax) gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1); - IfcGeom::Kernel::convert(l->Location(),o); - if ( l->hasAxis() ) IfcGeom::Kernel::convert(l->Axis(), axis); + IfcGeom::OpenCascadeKernel::convert(l->Location(),o); + if ( l->hasAxis() ) IfcGeom::OpenCascadeKernel::convert(l->Axis(), axis); ax = gp_Ax1(o, axis); CACHE(IfcAxis1Placement,l,ax) return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperator3D* l, gp_Trsf& trsf) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcCartesianTransformationOperator3D* l, gp_Trsf& trsf) { IN_CACHE(IfcCartesianTransformationOperator3D,l,gp_Trsf,trsf) gp_Pnt origin; - IfcGeom::Kernel::convert(l->LocalOrigin(),origin); + IfcGeom::OpenCascadeKernel::convert(l->LocalOrigin(),origin); gp_Dir axis1 (1.,0.,0.); gp_Dir axis2 (0.,1.,0.); gp_Dir axis3 (0.,0.,1.); - if ( l->hasAxis1() ) IfcGeom::Kernel::convert(l->Axis1(),axis1); - if ( l->hasAxis2() ) IfcGeom::Kernel::convert(l->Axis2(),axis2); - if ( l->hasAxis3() ) IfcGeom::Kernel::convert(l->Axis3(),axis3); + if ( l->hasAxis1() ) IfcGeom::OpenCascadeKernel::convert(l->Axis1(),axis1); + if ( l->hasAxis2() ) IfcGeom::OpenCascadeKernel::convert(l->Axis2(),axis2); + if ( l->hasAxis3() ) IfcGeom::OpenCascadeKernel::convert(l->Axis3(),axis3); gp_Ax3 ax3 (origin,axis3,axis1); if ( axis2.Dot(ax3.YDirection()) < 0 ) ax3.YReverse(); @@ -212,16 +213,16 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperator2D* l, gp_Trsf2d& trsf) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcCartesianTransformationOperator2D* l, gp_Trsf2d& trsf) { IN_CACHE(IfcCartesianTransformationOperator2D,l,gp_Trsf2d,trsf) gp_Pnt origin; gp_Dir axis1 (1.,0.,0.); gp_Dir axis2 (0.,1.,0.); - IfcGeom::Kernel::convert(l->LocalOrigin(),origin); - if ( l->hasAxis1() ) IfcGeom::Kernel::convert(l->Axis1(),axis1); - if ( l->hasAxis2() ) IfcGeom::Kernel::convert(l->Axis2(),axis2); + IfcGeom::OpenCascadeKernel::convert(l->LocalOrigin(),origin); + if ( l->hasAxis1() ) IfcGeom::OpenCascadeKernel::convert(l->Axis1(),axis1); + if ( l->hasAxis2() ) IfcGeom::OpenCascadeKernel::convert(l->Axis2(),axis2); const gp_Pnt2d origin2d(origin.X(), origin.Y()); const gp_Dir2d axis12d(axis1.X(), axis1.Y()); @@ -251,17 +252,17 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperator3DnonUniform* l, gp_GTrsf& gtrsf) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcCartesianTransformationOperator3DnonUniform* l, gp_GTrsf& gtrsf) { IN_CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gp_GTrsf,gtrsf) gp_Trsf trsf; gp_Pnt origin; - IfcGeom::Kernel::convert(l->LocalOrigin(),origin); + IfcGeom::OpenCascadeKernel::convert(l->LocalOrigin(),origin); gp_Dir axis1 (1.,0.,0.); gp_Dir axis2 (0.,1.,0.); gp_Dir axis3 (0.,0.,1.); - if ( l->hasAxis1() ) IfcGeom::Kernel::convert(l->Axis1(),axis1); - if ( l->hasAxis2() ) IfcGeom::Kernel::convert(l->Axis2(),axis2); - if ( l->hasAxis3() ) IfcGeom::Kernel::convert(l->Axis3(),axis3); + if ( l->hasAxis1() ) IfcGeom::OpenCascadeKernel::convert(l->Axis1(),axis1); + if ( l->hasAxis2() ) IfcGeom::OpenCascadeKernel::convert(l->Axis2(),axis2); + if ( l->hasAxis3() ) IfcGeom::OpenCascadeKernel::convert(l->Axis3(),axis3); gp_Ax3 ax3 (origin,axis3,axis1); if ( axis2.Dot(ax3.YDirection()) < 0 ) ax3.YReverse(); trsf.SetTransformation(ax3); @@ -283,7 +284,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperator2DnonUniform* l, gp_GTrsf2d& gtrsf) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcCartesianTransformationOperator2DnonUniform* l, gp_GTrsf2d& gtrsf) { IN_CACHE(IfcCartesianTransformationOperator2DnonUniform,l,gp_GTrsf2d,gtrsf) gp_Trsf2d trsf; @@ -291,9 +292,9 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato gp_Dir axis1 (1.,0.,0.); gp_Dir axis2 (0.,1.,0.); - IfcGeom::Kernel::convert(l->LocalOrigin(),origin); - if ( l->hasAxis1() ) IfcGeom::Kernel::convert(l->Axis1(),axis1); - if ( l->hasAxis2() ) IfcGeom::Kernel::convert(l->Axis2(),axis2); + IfcGeom::OpenCascadeKernel::convert(l->LocalOrigin(),origin); + if ( l->hasAxis1() ) IfcGeom::OpenCascadeKernel::convert(l->Axis1(),axis1); + if ( l->hasAxis2() ) IfcGeom::OpenCascadeKernel::convert(l->Axis2(),axis2); const gp_Pnt2d origin2d(origin.X(), origin.Y()); const gp_Dir2d axis12d(axis1.X(), axis1.Y()); @@ -324,14 +325,14 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCartesianTransformationOperato return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcPlane* pln, gp_Pln& plane) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcPlane* pln, gp_Pln& plane) { IN_CACHE(IfcPlane,pln,gp_Pln,plane) IfcSchema::IfcAxis2Placement3D* l = pln->Position(); gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1);gp_Dir refDirection; - IfcGeom::Kernel::convert(l->Location(),o); + IfcGeom::OpenCascadeKernel::convert(l->Location(),o); bool hasRef = l->hasRefDirection(); - if ( l->hasAxis() ) IfcGeom::Kernel::convert(l->Axis(),axis); - if ( hasRef ) IfcGeom::Kernel::convert(l->RefDirection(),refDirection); + if ( l->hasAxis() ) IfcGeom::OpenCascadeKernel::convert(l->Axis(),axis); + if ( hasRef ) IfcGeom::OpenCascadeKernel::convert(l->RefDirection(),refDirection); gp_Ax3 ax3; if ( hasRef ) ax3 = gp_Ax3(o,axis,refDirection); else ax3 = gp_Ax3(o,axis); @@ -340,12 +341,12 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPlane* pln, gp_Pln& plane) { return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement2D* l, gp_Trsf2d& trsf) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcAxis2Placement2D* l, gp_Trsf2d& trsf) { IN_CACHE(IfcAxis2Placement2D,l,gp_Trsf2d,trsf) gp_Pnt P; gp_Dir V (1,0,0); - IfcGeom::Kernel::convert(l->Location(),P); + IfcGeom::OpenCascadeKernel::convert(l->Location(),P); if ( l->hasRefDirection() ) - IfcGeom::Kernel::convert(l->RefDirection(),V); + IfcGeom::OpenCascadeKernel::convert(l->RefDirection(),V); gp_Ax2d axis(gp_Pnt2d(P.X(),P.Y()), gp_Dir2d(V.X(),V.Y())); @@ -357,7 +358,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement2D* l, gp_Trsf2d return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& trsf) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& trsf) { IN_CACHE(IfcObjectPlacement,l,gp_Trsf,trsf) if ( ! l->is(IfcSchema::Type::IfcLocalPlacement) ) { Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l->entity); @@ -368,7 +369,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& t gp_Trsf trsf2; IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement(); if ( relplacement->is(IfcSchema::Type::IfcAxis2Placement3D) ) { - IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2); + IfcGeom::OpenCascadeKernel::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2); trsf.PreMultiply(trsf2); } if ( current->hasPlacementRelTo() ) { diff --git a/src/ifcgeom/IfcGeomRepresentation.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomOpenCascadeSerialization.cpp similarity index 81% rename from src/ifcgeom/IfcGeomRepresentation.cpp rename to src/ifcgeom/kernels/opencascade/IfcGeomOpenCascadeSerialization.cpp index c5ecc7623c..82802cc1c4 100644 --- a/src/ifcgeom/IfcGeomRepresentation.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomOpenCascadeSerialization.cpp @@ -23,20 +23,22 @@ #include -#include "../ifcgeom/IfcGeom.h" +#include "../../../ifcgeom/IfcGeom.h" +#include "../../../ifcgeom/IfcGeomRepresentation.h" -#include "IfcGeomRepresentation.h" +#include "../opencascade/OpenCascadeKernel.h" +#include "../opencascade/OpenCascadeConversionResult.h" -IfcGeom::Representation::Serialization::Serialization(const BRep& brep) +IfcGeom::Representation::Serialization::Serialization(const Native& brep) : Representation(brep.settings()) , _id(brep.getId()) { TopoDS_Compound compound; BRep_Builder builder; builder.MakeCompound(compound); - for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = brep.begin(); it != brep.end(); ++ it) { - const TopoDS_Shape& s = it->Shape(); - gp_GTrsf trsf = it->Placement(); + for (IfcGeom::ConversionResults::const_iterator it = brep.begin(); it != brep.end(); ++ it) { + const TopoDS_Shape& s = ((OpenCascadeShape*) it->Shape())->shape(); + gp_GTrsf trsf = ((OpenCascadePlacement*)it->Placement())->trsf(); if (it->hasStyle() && it->Style().Diffuse()) { const IfcGeom::SurfaceStyle::ColorComponent& clr = *it->Style().Diffuse(); @@ -60,11 +62,11 @@ IfcGeom::Representation::Serialization::Serialization(const BRep& brep) trsf.PreMultiply(scale); } - const TopoDS_Shape moved_shape = IfcGeom::Kernel::apply_transformation(s, trsf); + const TopoDS_Shape moved_shape = IfcGeom::OpenCascadeKernel::apply_transformation(s, trsf); builder.Add(compound, moved_shape); } std::stringstream sstream; BRepTools::Write(compound,sstream); _brep_data = sstream.str(); -} \ No newline at end of file +} diff --git a/src/ifcgeom/IfcGeomSerialisation.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomSerialisation.cpp similarity index 98% rename from src/ifcgeom/IfcGeomSerialisation.cpp rename to src/ifcgeom/kernels/opencascade/IfcGeomSerialisation.cpp index 1cbdcd097c..7e228a3d13 100644 --- a/src/ifcgeom/IfcGeomSerialisation.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomSerialisation.cpp @@ -1,3 +1,8 @@ +#include +#include +#include +#include + #include #include #include @@ -14,7 +19,10 @@ #include #include -#include "IfcGeom.h" +#include "../../../ifcgeom/IfcGeom.h" + +#include "OpenCascadeKernel.h" +#include "OpenCascadeSerialization.h" template int convert_to_ifc(const T& t, U*& u, bool /*advanced*/) { diff --git a/src/ifcgeom/IfcGeomShapes.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp similarity index 85% rename from src/ifcgeom/IfcGeomShapes.cpp rename to src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp index 32ac0bd88a..7ee9edb92b 100644 --- a/src/ifcgeom/IfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp @@ -19,7 +19,7 @@ /******************************************************************************** * * - * Implementations of the various conversion functions defined in IfcRegister.h * + * Implementations of the various conversion functions defined in EntityMapping.h * * * ********************************************************************************/ @@ -101,9 +101,12 @@ #include -#include "../ifcgeom/IfcGeom.h" +#include "../../../ifcgeom/IfcGeom.h" -bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolid* l, TopoDS_Shape& shape) { +#include "OpenCascadeKernel.h" +#include "OpenCascadeConversionResult.h" + +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcExtrudedAreaSolid* l, TopoDS_Shape& shape) { const double height = l->Depth() * getValue(GV_LENGTH_UNIT); if (height < getValue(GV_PRECISION)) { Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", l->entity); @@ -119,7 +122,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolid* l, TopoDS_S has_position = l->hasPosition(); #endif if (has_position) { - IfcGeom::Kernel::convert(l->Position(), trsf); + IfcGeom::OpenCascadeKernel::convert(l->Position(), trsf); } gp_Dir dir; @@ -163,7 +166,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolid* l, TopoDS_S } #ifdef USE_IFC4 -bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* l, TopoDS_Shape& shape) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* l, TopoDS_Shape& shape) { const double height = l->Depth() * getValue(GV_LENGTH_UNIT); if (height < getValue(GV_PRECISION)) { Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", l->entity); @@ -180,7 +183,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* l, T has_position = l->hasPosition(); #endif if (has_position) { - IfcGeom::Kernel::convert(l->Position(), trsf); + IfcGeom::OpenCascadeKernel::convert(l->Position(), trsf); } gp_Dir dir; @@ -264,7 +267,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* l, T } #endif -bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfLinearExtrusion* l, TopoDS_Shape& shape) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcSurfaceOfLinearExtrusion* l, TopoDS_Shape& shape) { TopoDS_Wire wire; if ( !convert_wire(l->SweptCurve(), wire) ) { TopoDS_Face face; @@ -280,7 +283,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfLinearExtrusion* l, T has_position = l->hasPosition(); #endif if (has_position) { - IfcGeom::Kernel::convert(l->Position(), trsf); + IfcGeom::OpenCascadeKernel::convert(l->Position(), trsf); } gp_Dir dir; @@ -297,7 +300,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfLinearExtrusion* l, T return !shape.IsNull(); } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfRevolution* l, TopoDS_Shape& shape) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcSurfaceOfRevolution* l, TopoDS_Shape& shape) { TopoDS_Wire wire; if ( !convert_wire(l->SweptCurve(), wire) ) { TopoDS_Face face; @@ -307,7 +310,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfRevolution* l, TopoDS } gp_Ax1 ax1; - IfcGeom::Kernel::convert(l->AxisPosition(), ax1); + IfcGeom::OpenCascadeKernel::convert(l->AxisPosition(), ax1); gp_Trsf trsf; bool has_position = true; @@ -315,7 +318,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfRevolution* l, TopoDS has_position = l->hasPosition(); #endif if (has_position) { - IfcGeom::Kernel::convert(l->Position(), trsf); + IfcGeom::OpenCascadeKernel::convert(l->Position(), trsf); } shape = BRepPrimAPI_MakeRevol(wire, ax1); @@ -329,14 +332,14 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfRevolution* l, TopoDS return !shape.IsNull(); } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcRevolvedAreaSolid* l, TopoDS_Shape& shape) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcRevolvedAreaSolid* l, TopoDS_Shape& shape) { const double ang = l->Angle() * getValue(GV_PLANEANGLE_UNIT); TopoDS_Face face; if ( ! convert_face(l->SweptArea(),face) ) return false; gp_Ax1 ax1; - IfcGeom::Kernel::convert(l->Axis(), ax1); + IfcGeom::OpenCascadeKernel::convert(l->Axis(), ax1); gp_Trsf trsf; bool has_position = true; @@ -344,7 +347,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRevolvedAreaSolid* l, TopoDS_S has_position = l->hasPosition(); #endif if (has_position) { - IfcGeom::Kernel::convert(l->Position(), trsf); + IfcGeom::OpenCascadeKernel::convert(l->Position(), trsf); } if (ang >= M_PI * 2. - ALMOST_ZERO) { @@ -362,7 +365,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::OpenCascadeKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, ConversionResults& shape) { TopoDS_Shape s; const SurfaceStyle* collective_style = get_style(l); if (convert_shape(l->Outer(),s) ) { @@ -387,13 +390,13 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, IfcRepre } } - shape.push_back(IfcRepresentationShapeItem(s, indiv_style ? indiv_style : collective_style)); + shape.push_back(ConversionResult(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::OpenCascadeKernel::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); @@ -401,29 +404,29 @@ 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(s, shell_style ? shell_style : collective_style)); + shapes.push_back(ConversionResult(new OpenCascadeShape(s), shell_style ? shell_style : collective_style)); part_success |= true; } } return part_success; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, TopoDS_Shape& shape) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, TopoDS_Shape& shape) { IfcSchema::IfcSurface* surface = l->BaseSurface(); if ( ! surface->is(IfcSchema::Type::IfcPlane) ) { Logger::Message(Logger::LOG_ERROR, "Unsupported BaseSurface:", surface->entity); return false; } gp_Pln pln; - IfcGeom::Kernel::convert((IfcSchema::IfcPlane*)surface,pln); + IfcGeom::OpenCascadeKernel::convert((IfcSchema::IfcPlane*)surface,pln); const gp_Pnt pnt = pln.Location().Translated( l->AgreementFlag() ? -pln.Axis().Direction() : pln.Axis().Direction()); shape = BRepPrimAPI_MakeHalfSpace(BRepBuilderAPI_MakeFace(pln),pnt).Solid(); return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace* l, TopoDS_Shape& shape) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace* l, TopoDS_Shape& shape) { TopoDS_Shape halfspace; - if ( ! IfcGeom::Kernel::convert((IfcSchema::IfcHalfSpaceSolid*)l,halfspace) ) return false; + if ( ! IfcGeom::OpenCascadeKernel::convert((IfcSchema::IfcHalfSpaceSolid*)l,halfspace) ) return false; TopoDS_Wire wire; if ( ! convert_wire(l->PolygonalBoundary(),wire) || ! wire.Closed() ) return false; @@ -455,7 +458,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace* l, return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, IfcRepresentationShapeItems& shapes) { +bool IfcGeom::OpenCascadeKernel::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 ) { @@ -465,16 +468,16 @@ 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(s, shell_style ? shell_style : collective_style)); + shapes.push_back(ConversionResult(new OpenCascadeShape(s), shell_style ? shell_style : collective_style)); } } return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape& shape) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape& shape) { TopoDS_Shape s1, s2; - IfcRepresentationShapeItems items1, items2; + ConversionResults items1, items2; TopoDS_Wire boundary_wire; IfcSchema::IfcBooleanOperand* operand1 = l->FirstOperand(); IfcSchema::IfcBooleanOperand* operand2 = l->SecondOperand(); @@ -623,7 +626,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape return false; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Shape& shape) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Shape& shape) { IfcSchema::IfcFace::list::ptr faces = l->CfsFaces(); TopTools_ListOfShape face_list; @@ -666,31 +669,31 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Sh return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcMappedItem* l, IfcRepresentationShapeItems& shapes) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcMappedItem* l, ConversionResults& shapes) { gp_GTrsf gtrsf; IfcSchema::IfcCartesianTransformationOperator* transform = l->MappingTarget(); if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3DnonUniform) ) { - IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator3DnonUniform*)transform,gtrsf); + IfcGeom::OpenCascadeKernel::convert((IfcSchema::IfcCartesianTransformationOperator3DnonUniform*)transform,gtrsf); } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2DnonUniform) ) { Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); return false; } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3D) ) { gp_Trsf trsf; - IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,trsf); + IfcGeom::OpenCascadeKernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,trsf); gtrsf = trsf; } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2D) ) { gp_Trsf2d trsf_2d; - IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator2D*)transform,trsf_2d); + IfcGeom::OpenCascadeKernel::convert((IfcSchema::IfcCartesianTransformationOperator2D*)transform,trsf_2d); gtrsf = (gp_Trsf) trsf_2d; } IfcSchema::IfcRepresentationMap* map = l->MappingSource(); IfcSchema::IfcAxis2Placement* placement = map->MappingOrigin(); gp_Trsf trsf; if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) { - IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf); + IfcGeom::OpenCascadeKernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf); } else { gp_Trsf2d trsf_2d; - IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf_2d); + IfcGeom::OpenCascadeKernel::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf_2d); trsf = trsf_2d; } gtrsf.Multiply(trsf); @@ -701,7 +704,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); + IfcGeom::OpenCascadePlacement 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 @@ -713,7 +717,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcMappedItem* l, IfcRepresentati return b; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcRepresentation* l, IfcRepresentationShapeItems& shapes) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcRepresentation* l, ConversionResults& shapes) { IfcSchema::IfcRepresentationItem::list::ptr items = l->Items(); bool part_succes = false; if ( items->size() ) { @@ -724,7 +728,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRepresentation* l, IfcRepresen } else { TopoDS_Shape s; if (convert_shape(representation_item,s)) { - shapes.push_back(IfcRepresentationShapeItem(s, get_style(representation_item))); + shapes.push_back(ConversionResult(new OpenCascadeShape(s), get_style(representation_item))); part_succes |= true; } } @@ -733,7 +737,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::OpenCascadeKernel::convert(const IfcSchema::IfcGeometricSet* l, ConversionResults& shapes) { IfcEntityList::ptr elements = l->Elements(); if ( !elements->size() ) return false; bool part_succes = false; @@ -751,20 +755,20 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcGeometricSet* l, IfcRepresenta } else if (element->is(IfcSchema::Type::IfcSurface)) { style = get_style((IfcSchema::IfcSurface*) element); } - shapes.push_back(IfcRepresentationShapeItem(s, style ? style : parent_style)); + shapes.push_back(ConversionResult(new OpenCascadeShape(s), style ? style : parent_style)); } } return part_succes; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcBlock* l, TopoDS_Shape& shape) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcBlock* l, TopoDS_Shape& 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); BRepPrimAPI_MakeBox builder(dx, dy, dz); gp_Trsf trsf; - IfcGeom::Kernel::convert(l->Position(),trsf); + IfcGeom::OpenCascadeKernel::convert(l->Position(),trsf); // IfcCsgPrimitive3D.Position has unit scale factor shape = builder.Solid().Moved(trsf); @@ -772,7 +776,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBlock* l, TopoDS_Shape& shape) return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangularPyramid* l, TopoDS_Shape& shape) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcRectangularPyramid* l, TopoDS_Shape& 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); @@ -789,18 +793,18 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangularPyramid* l, TopoDS_ #endif ); - IfcGeom::Kernel::convert(l->Position(), trsf1); + IfcGeom::OpenCascadeKernel::convert(l->Position(), trsf1); shape = BRepBuilderAPI_Transform(builder.Solid(), trsf1 * trsf2); return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcRightCircularCylinder* l, TopoDS_Shape& shape) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, TopoDS_Shape& shape) { const double r = l->Radius() * getValue(GV_LENGTH_UNIT); const double h = l->Height() * getValue(GV_LENGTH_UNIT); BRepPrimAPI_MakeCylinder builder(r, h); gp_Trsf trsf; - IfcGeom::Kernel::convert(l->Position(),trsf); + IfcGeom::OpenCascadeKernel::convert(l->Position(),trsf); // IfcCsgPrimitive3D.Position has unit scale factor shape = builder.Solid().Moved(trsf); @@ -808,13 +812,13 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRightCircularCylinder* l, Topo return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcRightCircularCone* l, TopoDS_Shape& shape) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcRightCircularCone* l, TopoDS_Shape& shape) { const double r = l->BottomRadius() * getValue(GV_LENGTH_UNIT); const double h = l->Height() * getValue(GV_LENGTH_UNIT); BRepPrimAPI_MakeCone builder(r, 0., h); gp_Trsf trsf; - IfcGeom::Kernel::convert(l->Position(),trsf); + IfcGeom::OpenCascadeKernel::convert(l->Position(),trsf); // IfcCsgPrimitive3D.Position has unit scale factor shape = builder.Solid().Moved(trsf); @@ -822,12 +826,12 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRightCircularCone* l, TopoDS_S return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcSphere* l, TopoDS_Shape& shape) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcSphere* l, TopoDS_Shape& shape) { const double r = l->Radius() * getValue(GV_LENGTH_UNIT); BRepPrimAPI_MakeSphere builder(r); gp_Trsf trsf; - IfcGeom::Kernel::convert(l->Position(),trsf); + IfcGeom::OpenCascadeKernel::convert(l->Position(),trsf); // IfcCsgPrimitive3D.Position has unit scale factor shape = builder.Solid().Moved(trsf); @@ -835,13 +839,13 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSphere* l, TopoDS_Shape& shape return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcCsgSolid* l, TopoDS_Shape& shape) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcCsgSolid* l, TopoDS_Shape& shape) { return convert_shape(l->TreeRootExpression(), shape); } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcCurveBoundedPlane* l, TopoDS_Shape& face) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcCurveBoundedPlane* l, TopoDS_Shape& face) { gp_Pln pln; - IfcGeom::Kernel::convert(l->BasisSurface(), pln); + IfcGeom::OpenCascadeKernel::convert(l->BasisSurface(), pln); gp_Trsf trsf; trsf.SetTransformation(pln.Position(), gp::XOY()); @@ -870,13 +874,13 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCurveBoundedPlane* l, TopoDS_S return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangularTrimmedSurface* l, TopoDS_Shape& face) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcRectangularTrimmedSurface* l, TopoDS_Shape& face) { if (!l->BasisSurface()->is(IfcSchema::Type::IfcPlane)) { Logger::Message(Logger::LOG_ERROR, "Unsupported BasisSurface:", l->BasisSurface()->entity); return false; } gp_Pln pln; - IfcGeom::Kernel::convert((IfcSchema::IfcPlane*) l->BasisSurface(), pln); + IfcGeom::OpenCascadeKernel::convert((IfcSchema::IfcPlane*) l->BasisSurface(), pln); BRepBuilderAPI_MakeFace mf(pln, l->U1(), l->U2(), l->V1(), l->V2()); @@ -885,7 +889,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangularTrimmedSurface* l, return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l, TopoDS_Shape& shape) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l, TopoDS_Shape& shape) { gp_Trsf directrix, position; TopoDS_Shape face; TopoDS_Wire wire, section; @@ -901,7 +905,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l, has_position = l->hasPosition(); #endif if (has_position) { - IfcGeom::Kernel::convert(l->Position(), trsf); + IfcGeom::OpenCascadeKernel::convert(l->Position(), trsf); } if (!convert_face(l->SweptArea(), face) || @@ -913,7 +917,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l, gp_Pnt directrix_origin; gp_Vec directrix_tangent; bool directrix_on_plane = true; - IfcGeom::Kernel::convert((IfcSchema::IfcPlane*) l->ReferenceSurface(), pln); + IfcGeom::OpenCascadeKernel::convert((IfcSchema::IfcPlane*) l->ReferenceSurface(), pln); // As per Informal propositions 2: The Directrix shall lie on the ReferenceSurface. // This is not always the case with the test files in the repository. I am not sure @@ -971,7 +975,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l, return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcSweptDiskSolid* l, TopoDS_Shape& shape) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcSweptDiskSolid* l, TopoDS_Shape& shape) { TopoDS_Wire wire, section1, section2; bool hasInnerRadius = l->hasInnerRadius(); @@ -1053,9 +1057,9 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSweptDiskSolid* l, TopoDS_Shap #ifdef USE_IFC4 -bool IfcGeom::Kernel::convert(const IfcSchema::IfcCylindricalSurface* l, TopoDS_Shape& face) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcCylindricalSurface* l, TopoDS_Shape& face) { gp_Trsf trsf; - IfcGeom::Kernel::convert(l->Position(),trsf); + IfcGeom::OpenCascadeKernel::convert(l->Position(),trsf); // IfcElementarySurface.Position has unit scale factor #if OCC_VERSION_HEX < 0x60502 @@ -1066,11 +1070,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCylindricalSurface* l, TopoDS_ return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcAdvancedBrep* l, TopoDS_Shape& shape) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcAdvancedBrep* l, TopoDS_Shape& shape) { return convert(l->Outer(), shape); } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, TopoDS_Shape& shape) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, TopoDS_Shape& shape) { IfcSchema::IfcCartesianPointList3D* point_list = l->Coordinates(); const std::vector< std::vector > coordinates = point_list->CoordList(); std::vector points; diff --git a/src/ifcgeom/IfcGeomWires.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomWires.cpp similarity index 90% rename from src/ifcgeom/IfcGeomWires.cpp rename to src/ifcgeom/kernels/opencascade/IfcGeomWires.cpp index 714244ae96..fb102dd6fc 100644 --- a/src/ifcgeom/IfcGeomWires.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomWires.cpp @@ -19,7 +19,7 @@ /******************************************************************************** * * - * Implementations of the various conversion functions defined in IfcRegister.h * + * Implementations of the various conversion functions defined in EntityMapping.h * * * ********************************************************************************/ @@ -86,9 +86,10 @@ #include #include -#include "../ifcgeom/IfcGeom.h" +#include "../../../ifcgeom/IfcGeom.h" +#include "OpenCascadeKernel.h" -bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire& wire) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire& wire) { if ( getValue(GV_PLANEANGLE_UNIT)<0 ) { Logger::Message(Logger::LOG_WARNING,"Creating a composite curve without unit information:",l->entity); @@ -103,13 +104,13 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire // First try radians TopoDS_Wire wire_radians, wire_degrees; try { - succes_radians = IfcGeom::Kernel::convert(l,wire_radians); + succes_radians = IfcGeom::OpenCascadeKernel::convert(l,wire_radians); } catch (...) {} // Now try degrees setValue(GV_PLANEANGLE_UNIT,0.0174532925199433); try { - succes_degrees = IfcGeom::Kernel::convert(l,wire_degrees); + succes_degrees = IfcGeom::OpenCascadeKernel::convert(l,wire_degrees); } catch (...) {} // Restore to unknown unit state @@ -197,7 +198,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire& wire) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire& wire) { IfcSchema::IfcCurve* basis_curve = l->BasisCurve(); bool isConic = basis_curve->is(IfcSchema::Type::IfcConic); double parameterFactor = isConic ? getValue(GV_PLANEANGLE_UNIT) : getValue(GV_LENGTH_UNIT); @@ -215,7 +216,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire& for ( IfcEntityList::it it = trims1->begin(); it != trims1->end(); it ++ ) { IfcUtil::IfcBaseClass* i = *it; if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) { - IfcGeom::Kernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[sense_agreement] ); + IfcGeom::OpenCascadeKernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[sense_agreement] ); has_pnts[sense_agreement] = true; } else if ( i->is(IfcSchema::Type::IfcParameterValue) ) { const double value = *((IfcSchema::IfcParameterValue*)i); @@ -226,7 +227,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire& for ( IfcEntityList::it it = trims2->begin(); it != trims2->end(); it ++ ) { IfcUtil::IfcBaseClass* i = *it; if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) { - IfcGeom::Kernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[1-sense_agreement] ); + IfcGeom::OpenCascadeKernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[1-sense_agreement] ); has_pnts[1-sense_agreement] = true; } else if ( i->is(IfcSchema::Type::IfcParameterValue) ) { const double value = *((IfcSchema::IfcParameterValue*)i); @@ -294,14 +295,14 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire& } } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyline* l, TopoDS_Wire& result) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcPolyline* l, TopoDS_Wire& result) { IfcSchema::IfcCartesianPoint::list::ptr points = l->Points(); // Parse and store the points in a sequence TColgp_SequenceOfPnt polygon; for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) { gp_Pnt pnt; - IfcGeom::Kernel::convert(*it, pnt); + IfcGeom::OpenCascadeKernel::convert(*it, pnt); polygon.Append(pnt); } @@ -317,14 +318,14 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyline* l, TopoDS_Wire& resu return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyLoop* l, TopoDS_Wire& result) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcPolyLoop* l, TopoDS_Wire& result) { IfcSchema::IfcCartesianPoint::list::ptr points = l->Polygon(); // Parse and store the points in a sequence TColgp_SequenceOfPnt polygon; for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) { gp_Pnt pnt; - IfcGeom::Kernel::convert(*it, pnt); + IfcGeom::OpenCascadeKernel::convert(*it, pnt); polygon.Append(pnt); } @@ -359,11 +360,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyLoop* l, TopoDS_Wire& resu return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryOpenProfileDef* l, TopoDS_Wire& result) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcArbitraryOpenProfileDef* l, TopoDS_Wire& result) { return convert_wire(l->Curve(), result); } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeCurve* l, TopoDS_Wire& result) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcEdgeCurve* l, TopoDS_Wire& result) { IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) l->EdgeStart())->VertexGeometry(); IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) l->EdgeEnd())->VertexGeometry(); if (!pnt1->is(IfcSchema::Type::IfcCartesianPoint) || !pnt2->is(IfcSchema::Type::IfcCartesianPoint)) { @@ -372,8 +373,8 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeCurve* l, TopoDS_Wire& res } gp_Pnt p1, p2; - if (!IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) || - !IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2)) + if (!IfcGeom::OpenCascadeKernel::convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) || + !IfcGeom::OpenCascadeKernel::convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2)) { return false; } @@ -441,7 +442,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeCurve* l, TopoDS_Wire& res } } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeLoop* l, TopoDS_Wire& result) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcEdgeLoop* l, TopoDS_Wire& result) { IfcSchema::IfcOrientedEdge::list::ptr li = l->EdgeList(); BRepBuilderAPI_MakeWire mw; for (IfcSchema::IfcOrientedEdge::list::it it = li->begin(); it != li->end(); ++it) { @@ -454,7 +455,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeLoop* l, TopoDS_Wire& resu return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdge* l, TopoDS_Wire& result) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcEdge* l, TopoDS_Wire& result) { if (!l->EdgeStart()->is(IfcSchema::Type::IfcVertexPoint) || !l->EdgeEnd()->is(IfcSchema::Type::IfcVertexPoint)) { Logger::Message(Logger::LOG_ERROR, "Only IfcVertexPoints are supported for EdgeStart and -End", l->entity); return false; @@ -481,7 +482,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdge* l, TopoDS_Wire& result) return true; } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcOrientedEdge* l, TopoDS_Wire& result) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcOrientedEdge* l, TopoDS_Wire& result) { if (convert_wire(l->EdgeElement(), result)) { if (!l->Orientation()) { result.Reverse(); @@ -492,7 +493,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcOrientedEdge* l, TopoDS_Wire& } } -bool IfcGeom::Kernel::convert(const IfcSchema::IfcSubedge* l, TopoDS_Wire& result) { +bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcSubedge* l, TopoDS_Wire& result) { TopoDS_Wire temp; if (convert_wire(l->ParentEdge(), result) && convert((IfcSchema::IfcEdge*) l, temp)) { TopExp_Explorer exp(result, TopAbs_EDGE); diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h new file mode 100644 index 0000000000..297c72f6fb --- /dev/null +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h @@ -0,0 +1,86 @@ +/******************************************************************************** +* * +* This file is part of IfcOpenShell. * +* * +* IfcOpenShell is free software: you can redistribute it and/or modify * +* it under the terms of the Lesser GNU General Public License as published by * +* the Free Software Foundation, either version 3.0 of the License, or * +* (at your option) any later version. * +* * +* IfcOpenShell is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* Lesser GNU General Public License for more details. * +* * +* You should have received a copy of the Lesser GNU General Public License * +* along with this program. If not, see . * +* * +********************************************************************************/ + +#ifndef IFCGEOMOPENCASCADEREPRESENTATION_H +#define IFCGEOMOPENCASCADEREPRESENTATION_H + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +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_); + } + 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* 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_); + } + private: + TopoDS_Shape shape_; + }; + +} + +#endif \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h new file mode 100644 index 0000000000..2ed4ae65ee --- /dev/null +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h @@ -0,0 +1,155 @@ +/******************************************************************************** +* * +* 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 . * +* * +********************************************************************************/ + +#ifndef OPENCASADE_KERNEL_H +#define OPENCASADE_KERNEL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Define this in case you want to conserve memory usage at all cost. This has been +// benchmarked extensively: https://github.com/IfcOpenShell/IfcOpenShell/pull/47 +// #define NO_CACHE + +#ifdef NO_CACHE + +#define IN_CACHE(T,E,t,e) +#define CACHE(T,E,e) + +#else + +#define IN_CACHE(T,E,t,e) std::map::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 + +namespace IfcGeom { + + class IFC_GEOM_API Cache { + public: +#include "EntityMappingCreateCache.h" + std::map Shape; + }; + + class IFC_GEOM_API OpenCascadeKernel : public AbstractKernel { + public: + +#ifndef NO_CACHE + Cache cache; +#endif + + IfcGeom::ShapeType shape_type(const IfcUtil::IfcBaseClass* L); + + 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, ConversionResults& result); + bool convert_shape(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result); + 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_layerset(const IfcSchema::IfcProduct*, std::vector&, std::vector&, std::vector&); + bool apply_layerset(const ConversionResults&, const std::vector&, const std::vector&, ConversionResults&); + bool apply_folded_layerset(const ConversionResults&, const std::vector< std::vector >&, const std::vector&, ConversionResults&); + bool fold_layers(const IfcSchema::IfcWall*, const ConversionResults&, const std::vector&, const std::vector&, std::vector< std::vector >&); + + 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&); + + const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const Handle_Geom_Surface&); + const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const TopoDS_Face&); + const Handle_Geom_Curve intersect(const TopoDS_Face&, const Handle_Geom_Surface&); + bool intersect(const Handle_Geom_Curve&, const Handle_Geom_Surface&, gp_Pnt&); + bool intersect(const Handle_Geom_Curve&, const TopoDS_Face&, gp_Pnt&); + bool intersect(const Handle_Geom_Curve&, const TopoDS_Shape&, std::vector&); + bool intersect(const Handle_Geom_Surface&, const TopoDS_Shape&, std::vector< std::pair >&); + bool closest(const gp_Pnt&, const std::vector&, gp_Pnt&); + bool project(const Handle_Geom_Curve&, const gp_Pnt&, gp_Pnt& p, double& u, double& d); + bool project(const Handle_Geom_Surface&, const TopoDS_Shape&, double& u1, double& v1, double& u2, double& v2, double widen = 0.1); + int count(const TopoDS_Shape&, TopAbs_ShapeEnum); + + + bool find_wall_end_points(const IfcSchema::IfcWall*, gp_Pnt& start, gp_Pnt& end); + + bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& solid); + bool create_solid_from_faces(const TopTools_ListOfShape& face_list, TopoDS_Shape& solid); + bool is_compound(const TopoDS_Shape& shape); + bool is_convex(const TopoDS_Wire& wire); + TopoDS_Shape halfspace_from_plane(const gp_Pln& pln, const gp_Pnt& cent); + gp_Pln plane_from_face(const TopoDS_Face& face); + gp_Pnt point_above_plane(const gp_Pln& pln, bool agree = true); + const TopoDS_Shape& ensure_fit_for_subtraction(const TopoDS_Shape& shape, TopoDS_Shape& solid); + bool profile_helper(int numVerts, double* verts, int numFillets, int* filletIndices, double* filletRadii, gp_Trsf2d trsf, TopoDS_Shape& face); + double shape_volume(const TopoDS_Shape& s); + double face_area(const TopoDS_Face& f); + void apply_tolerance(TopoDS_Shape& s, double t); + + bool fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape); + void remove_duplicate_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol = -1.); + void remove_collinear_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol = -1.); + bool wire_to_sequence_of_point(const TopoDS_Wire&, TColgp_SequenceOfPnt&); + void sequence_of_point_to_wire(const TColgp_SequenceOfPnt&, TopoDS_Wire&, bool closed); + bool approximate_plane_through_wire(const TopoDS_Wire&, gp_Pln&); + bool flatten_wire(TopoDS_Wire&); + + static TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_Trsf&); + static TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_GTrsf&); + + bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, ConversionResults& cut_shapes); + bool convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, ConversionResults& cut_shapes); + + 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 = Cache(); +#endif + } + + virtual bool is_identity_transform(IfcUtil::IfcBaseClass*); + virtual IfcGeom::NativeElement* create_brep_for_representation_and_product( + const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*); + virtual IfcGeom::NativeElement* create_brep_for_processed_representation( + const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::NativeElement*); + +#include "EntityMappingDeclaration.h" + + }; + +} + +#endif \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeSerialization.h b/src/ifcgeom/kernels/opencascade/OpenCascadeSerialization.h new file mode 100644 index 0000000000..c2937df7f6 --- /dev/null +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeSerialization.h @@ -0,0 +1,34 @@ +/******************************************************************************** +* * +* This file is part of IfcOpenShell. * +* * +* IfcOpenShell is free software: you can redistribute it and/or modify * +* it under the terms of the Lesser GNU General Public License as published by * +* the Free Software Foundation, either version 3.0 of the License, or * +* (at your option) any later version. * +* * +* IfcOpenShell is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* Lesser GNU General Public License for more details. * +* * +* You should have received a copy of the Lesser GNU General Public License * +* along with this program. If not, see . * +* * +********************************************************************************/ + +#ifndef OPENCASCADESERIALIZATION_H +#define OPENCASCADESERIALIZATION_H + +#include "../../../ifcparse/IfcParse.h" + +#include + +namespace IfcGeom { + + IfcSchema::IfcProductDefinitionShape* tesselate(const TopoDS_Shape& shape, double deflection); + IfcSchema::IfcProductDefinitionShape* serialise(const TopoDS_Shape& shape, bool advanced); + +} + +#endif \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeShape.cpp b/src/ifcgeom/kernels/opencascade/OpenCascadeShape.cpp new file mode 100644 index 0000000000..fcc94b52e3 --- /dev/null +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeShape.cpp @@ -0,0 +1,194 @@ + + +#include "../../../ifcgeom/IfcGeom.h" +#include "../../../ifcgeom/IfcGeomIteratorSettings.h" +#include "../../../ifcgeom/ConversionResult.h" + +#include "OpenCascadeConversionResult.h" + +#include + +void IfcGeom::OpenCascadeShape::Triangulate(const IfcGeom::IteratorSettings& settings, const IfcGeom::ConversionResultPlacement* place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const { + + const TopoDS_Shape& s = shape_; + const gp_GTrsf& trsf = dynamic_cast(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, int> edgecount; + std::vector > edges_temp; + + const TColgp_Array1OfPnt& nodes = tri->Nodes(); + const TColgp_Array1OfPnt2d& uvs = tri->UVNodes(); + std::vector coords; + BRepGProp_Face prop(face); + std::map 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()); + 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() > ALMOST_ZERO) { + normal = gp_Dir(normal_direction.XYZ() * rotation_matrix); + } + t->normals().push_back(static_cast(normal.X())); + t->normals().push_back(static_cast(normal.Y())); + t->normals().push_back(static_cast(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->faces().push_back(dict[n1]); + t->faces().push_back(dict[n2]); + t->faces().push_back(dict[n3]); + + t->material_ids().push_back(surface_style_id); + + 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 >::const_iterator jt = edges_temp.begin(); jt != edges_temp.end(); ++jt) { + if (edgecount[*jt] == 1) { + // non manifold edge, face boundary + t->edges().push_back(jt->first); + t->edges().push_back(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

(p2.X())); + _verts.push_back(static_cast

(p2.Y())); + _verts.push_back(static_cast

(p2.Z())); + _verts.push_back(static_cast

(p3.X())); + _verts.push_back(static_cast

(p3.Y())); + _verts.push_back(static_cast

(p3.Z())); + */ + + trsf.Transforms(p); + + t->material_ids().push_back(surface_style_id); + + t->verts().push_back(static_cast(p.X())); + t->verts().push_back(static_cast(p.Y())); + t->verts().push_back(static_cast(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); +} From 3958204c1cbe94986dbd5bd5216c2bacc72b3225 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 13 Jan 2017 19:31:50 +0100 Subject: [PATCH 005/235] Don't build Python wrapper on Travis --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 62d7dff990..7fe6cc4b3c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,7 +52,7 @@ script: - mkdir build-ifc2x3 build-ifc4 - cd build-ifc2x3 - cmake -DCOLLADA_SUPPORT=True -DOPENCOLLADA_INCLUDE_DIR=/usr/local/include/opencollada -DOPENCOLLADA_LIBRARY_DIR=/usr/local/lib/opencollada -DPCRE_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu -DUSE_IFC4=False -DBUILD_IFCPYTHON=True -DUNICODE_SUPPORT=True -DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu .. - - make -j + - make -j IfcConvert - cd ../build-ifc4 - cmake -DCOLLADA_SUPPORT=True -DOPENCOLLADA_INCLUDE_DIR=/usr/local/include/opencollada -DOPENCOLLADA_LIBRARY_DIR=/usr/local/lib/opencollada -DPCRE_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu -DUSE_IFC4=True -DBUILD_IFCPYTHON=True -DUNICODE_SUPPORT=True -DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu .. - - make -j + - make -j IfcConvert From 4d12bf7e8df4bd144526eeb5994802d308b40297 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Mon, 16 Jan 2017 14:04:31 +0100 Subject: [PATCH 006/235] Cgal kernel skeleton (#3) Cgal kernel skeleton --- src/ifcconvert/IfcConvert.cpp | 67 ++++--- src/ifcgeom/IfcGeomAbstractKernel.cpp | 3 +- src/ifcgeom/IfcGeomIterator.h | 20 +- src/ifcgeom/IfcGeomIteratorSettings.h | 1 + .../kernels/cgal/CgalConversionFunctions.cpp | 28 +++ .../kernels/cgal/CgalConversionResult.cpp | 6 + .../kernels/cgal/CgalConversionResult.h | 77 ++++++++ .../kernels/cgal/CgalEntityMapping.cpp | 100 ++++++++++ src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 35 ++++ .../cgal/CgalEntityMappingCreateCache.h | 6 + .../kernels/cgal/CgalEntityMappingCurve.h | 6 + .../cgal/CgalEntityMappingDeclaration.h | 10 + .../kernels/cgal/CgalEntityMappingDefine.h | 18 ++ .../kernels/cgal/CgalEntityMappingFace.h | 6 + .../cgal/CgalEntityMappingPurgeCache.h | 6 + .../kernels/cgal/CgalEntityMappingShape.h | 20 ++ .../kernels/cgal/CgalEntityMappingShapeType.h | 14 ++ .../kernels/cgal/CgalEntityMappingShapes.h | 13 ++ .../kernels/cgal/CgalEntityMappingUndefine.h | 18 ++ .../kernels/cgal/CgalEntityMappingWire.h | 6 + src/ifcgeom/kernels/cgal/CgalKernel.cpp | 171 ++++++++++++++++++ src/ifcgeom/kernels/cgal/CgalKernel.h | 93 ++++++++++ 22 files changed, 688 insertions(+), 36 deletions(-) create mode 100644 src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp create mode 100644 src/ifcgeom/kernels/cgal/CgalConversionResult.cpp create mode 100644 src/ifcgeom/kernels/cgal/CgalConversionResult.h create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMapping.h create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingCreateCache.h create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingCurve.h create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingDeclaration.h create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingDefine.h create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingFace.h create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingPurgeCache.h create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingShape.h create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingShapeType.h create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingShapes.h create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingUndefine.h create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingWire.h create mode 100644 src/ifcgeom/kernels/cgal/CgalKernel.cpp create mode 100644 src/ifcgeom/kernels/cgal/CgalKernel.h diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 7015190a78..5b9057a73b 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -129,6 +129,7 @@ int main(int argc, char** argv) { std::vector entity_vector, names; double deflection_tolerance; + std::string kernel; boost::program_options::options_description geom_options("Geometry options"); geom_options.add_options() ("plan", @@ -143,7 +144,7 @@ int main(int argc, char** argv) { "vector will only contain unique xyz-triplets. This results in a " "manifold mesh which is useful for modelling applications, but might " "result in unwanted shading artefacts in rendering applications.") - ("use-world-coords", + ("use-world-coords", "Specifies whether to apply the local placements of building elements " "directly to the coordinates of the representation mesh rather than " "to represent the local placement in the 4x3 matrix, which will in that " @@ -152,7 +153,7 @@ int main(int argc, char** argv) { "Specifies whether to convert back geometrical output back to the " "unit of measure in which it is defined in the IFC file. Default is " "to use meters.") - ("sew-shells", + ("sew-shells", "Specifies whether to sew the faces of IfcConnectedFaceSets together. " "This is a potentially time consuming operation, but guarantees a " "consistent orientation of surface normals, even if the faces are not " @@ -162,45 +163,46 @@ int main(int argc, char** argv) { // arguments where not introduced yet and a work-around was implemented to // subtract multiple openings as a single compound. This hack is obsolete // for newer versions of Open CASCADE. - ("merge-boolean-operands", + ("merge-boolean-operands", "Specifies whether to merge all IfcOpeningElement operands into a single " "operand before applying the subtraction operation. This may " "introduce a performance improvement at the risk of failing, in " "which case the subtraction is applied one-by-one.") #endif - ("disable-opening-subtractions", + ("disable-opening-subtractions", "Specifies whether to disable the boolean subtraction of " "IfcOpeningElement Representations from their RelatingElements.") - ("enable-layerset-slicing", + ("enable-layerset-slicing", "Specifies whether to enable the slicing of products according " "to their associated IfcMaterialLayerSet.") - ("include", - "Specifies that the entities and/or names listed after --entities and/or --names are to be included") - ("exclude", - "Specifies that the entities and/or names listed after --entities and/or --names are to be excluded") + ("include", + "Specifies that the entities and/or names listed after --entities and/or --names are to be included") + ("exclude", + "Specifies that the entities and/or names listed after --entities and/or --names are to be excluded") ("entities", boost::program_options::value< std::vector >(&entity_vector)->multitoken(), "A list of entities that should be included in or excluded from the " "geometrical output, depending on whether --exclude or --include is specified. " - "Defaults to IfcOpeningElement and IfcSpace to be excluded. SVG output defaults " - "to IfcSpace to be included." - "The names are handled case-insensitively. Cannot be placed right before input file argument.") - ("names", boost::program_options::value< std::vector >(&names)->multitoken(), - "A list of names or wildcard patterns that should be included in or excluded from the " - "geometrical output, depending on whether --exclude or --include is specified. " - "The names are handled case-sensitively. Cannot be placed right before input file argument.") - ("no-normals", - "Disables computation of normals. Saves time and file size and is useful " - "in instances where you're going to recompute normals for the exported " - "model in other modelling application in any case.") - ("deflection-tolerance", boost::program_options::value(&deflection_tolerance), - "Sets the deflection tolerance of the mesher, 1e-3 by default if not specified.") - ("generate-uvs", - "Generates UVs (texture coordinates) by using simple box projection. Requires normals. " - "Not guaranteed to work properly if used with --weld-vertices.") - ("traverse", - "Applies --include or --exclude also to the decomposition and/or containment (IsDecomposedBy, " - "HasOpenings, FillsVoid, ContainedInStructure) of the filtered entity, e.g. " - "--include --traverse --names \"Level 1\" includes entity with name \"Level 1\" and all of its children."); + "Defaults to IfcOpeningElement and IfcSpace to be excluded. SVG output defaults " + "to IfcSpace to be included." + "The names are handled case-insensitively. Cannot be placed right before input file argument.") + ("names", boost::program_options::value< std::vector >(&names)->multitoken(), + "A list of names or wildcard patterns that should be included in or excluded from the " + "geometrical output, depending on whether --exclude or --include is specified. " + "The names are handled case-sensitively. Cannot be placed right before input file argument.") + ("no-normals", + "Disables computation of normals. Saves time and file size and is useful " + "in instances where you're going to recompute normals for the exported " + "model in other modelling application in any case.") + ("deflection-tolerance", boost::program_options::value(&deflection_tolerance), + "Sets the deflection tolerance of the mesher, 1e-3 by default if not specified.") + ("generate-uvs", + "Generates UVs (texture coordinates) by using simple box projection. Requires normals. " + "Not guaranteed to work properly if used with --weld-vertices.") + ("traverse", + "Applies --include or --exclude also to the decomposition and/or containment (IsDecomposedBy, " + "HasOpenings, FillsVoid, ContainedInStructure) of the filtered entity, e.g. " + "--include --traverse --names \"Level 1\" includes entity with name \"Level 1\" and all of its children.") + ("kernel", "Geometry kernel to use ('opencascade' or 'cgal'). Defaults to 'cgal'."); std::string bounds; boost::program_options::options_description serializer_options("Serialization options"); @@ -284,6 +286,11 @@ int main(int argc, char** argv) { const bool traverse = vmap.count("traverse") != 0; const bool deflection_tolerance_specified = vmap.count("deflection-tolerance") != 0 ; + if (vmap.count("kernel") == 0) { + std::cerr << "Using default CGAL based kernel" << std::endl; + kernel = "cgal"; + } + int bounding_width = -1, bounding_height = -1; if (vmap.count("bounds") == 1) { int w, h; @@ -434,7 +441,7 @@ int main(int argc, char** argv) { settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true); } - IfcGeom::Iterator context_iterator(settings, input_filename); + IfcGeom::Iterator context_iterator(settings, input_filename, kernel.c_str()); try { if (include_entities) { diff --git a/src/ifcgeom/IfcGeomAbstractKernel.cpp b/src/ifcgeom/IfcGeomAbstractKernel.cpp index a5669d44f6..76d49892c2 100644 --- a/src/ifcgeom/IfcGeomAbstractKernel.cpp +++ b/src/ifcgeom/IfcGeomAbstractKernel.cpp @@ -2,6 +2,7 @@ #include "IfcGeom.h" #include "kernels/opencascade/OpenCascadeKernel.h" +#include "kernels/cgal/CgalKernel.h" void IfcGeom::AbstractKernel::setValue(GeomValue var, double value) { switch (var) { @@ -241,7 +242,7 @@ IfcGeom::AbstractKernel* IfcGeom::AbstractKernel::kernel_by_name(const std::stri if (name == "opencascade") { return new OpenCascadeKernel(); } else if (name == "cgal") { - throw std::runtime_error("Not implemented"); + return new CgalKernel(); } else { throw std::runtime_error("No kernel named " + name); } diff --git a/src/ifcgeom/IfcGeomIterator.h b/src/ifcgeom/IfcGeomIterator.h index 150c6899f7..2ada29a2cf 100644 --- a/src/ifcgeom/IfcGeomIterator.h +++ b/src/ifcgeom/IfcGeomIterator.h @@ -737,6 +737,8 @@ namespace IfcGeom { return success; } private: + const char* const kernel_name_; + void _initialize() { current_triangulation = 0; current_shape_model = 0; @@ -750,7 +752,11 @@ namespace IfcGeom { unit_name = "METER"; unit_magnitude = 1.f; - kernel = IfcGeom::AbstractKernel::kernel_by_name("opencascade"); + const char* kn = kernel_name_; + if (kn == 0) { + kn = "cgal"; + } + kernel = IfcGeom::AbstractKernel::kernel_by_name(kn); kernel->setValue(IfcGeom::AbstractKernel::GV_MAX_FACES_TO_SEW, settings.get(IteratorSettings::SEW_SHELLS) ? 1000 : -1); kernel->setValue(IfcGeom::AbstractKernel::GV_DIMENSIONALITY, (settings.get(IteratorSettings::INCLUDE_CURVES) @@ -759,33 +765,37 @@ namespace IfcGeom { bool owns_ifc_file; public: - Iterator(const IteratorSettings& settings, IfcParse::IfcFile* file) + Iterator(const IteratorSettings& settings, IfcParse::IfcFile* file, const char* const kernel_name=0) : settings(settings) , ifc_file(file) , owns_ifc_file(false) + , kernel_name_(kernel_name) { _initialize(); } - Iterator(const IteratorSettings& settings, const std::string& filename) + Iterator(const IteratorSettings& settings, const std::string& filename, const char* const kernel_name = 0) : settings(settings) , ifc_file(new IfcParse::IfcFile) , owns_ifc_file(true) + , kernel_name_(kernel_name) { ifc_file->Init(filename); _initialize(); } - Iterator(const IteratorSettings& settings, void* data, int length) + Iterator(const IteratorSettings& settings, void* data, int length, const char* const kernel_name = 0) : settings(settings) , ifc_file(new IfcParse::IfcFile) , owns_ifc_file(true) + , kernel_name_(kernel_name) { ifc_file->Init(data, length); _initialize(); } - Iterator(const IteratorSettings& settings, std::istream& filestream, int length) + Iterator(const IteratorSettings& settings, std::istream& filestream, int length, const char* const kernel_name = 0) : settings(settings) , ifc_file(new IfcParse::IfcFile) , owns_ifc_file(true) + , kernel_name_(kernel_name) { ifc_file->Init(filestream, length); _initialize(); diff --git a/src/ifcgeom/IfcGeomIteratorSettings.h b/src/ifcgeom/IfcGeomIteratorSettings.h index e3fcd353b9..ebd21af247 100644 --- a/src/ifcgeom/IfcGeomIteratorSettings.h +++ b/src/ifcgeom/IfcGeomIteratorSettings.h @@ -23,6 +23,7 @@ #include "ifc_geom_api.h" #include "../ifcparse/IfcException.h" #include "../ifcparse/IfcUtil.h" +#include "../ifcparse/IfcLogger.h" namespace IfcGeom { diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp new file mode 100644 index 0000000000..68d9224029 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -0,0 +1,28 @@ +#include "../../../ifcparse/IfcParse.h" + +#include "CgalKernel.h" +#include "CgalConversionResult.h" + +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(new CgalShape(s), get_style(representation_item))); + part_succes |= true; + } + } + } + } + return part_succes; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid*, cgal_shape_t&) { + throw std::runtime_error("Not implemented IfcExtrudedAreaSolid"); +} diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp new file mode 100644 index 0000000000..e2da8ecd97 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -0,0 +1,6 @@ +#include "CgalKernel.h" +#include "CgalConversionResult.h" + +void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const { + throw std::runtime_error("Not implemented Triangulate()"); +} diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.h b/src/ifcgeom/kernels/cgal/CgalConversionResult.h new file mode 100644 index 0000000000..3fb4bb7e67 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.h @@ -0,0 +1,77 @@ +/******************************************************************************** +* * +* 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 . * +* * +********************************************************************************/ + +#ifndef CGALCONVERSIONRESULT_H +#define CGALCONVERSIONRESULT_H + +#include "../../../ifcgeom/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 { + // Get cell from placement as 4x3 matrix as implemented in OCCT. We'll have to check exact semantics. + throw std::runtime_error("Not implemented"); + } + virtual void Multiply(const ConversionResultPlacement* other) { + // Multiply matrix as implemented in OCCT. We'll have to check exact semantics. + throw std::runtime_error("Not implemented"); + } + virtual void PreMultiply(const ConversionResultPlacement* other) { + // PreMultiply matrix as implemented in OCCT. We'll have to check exact semantics. + throw std::runtime_error("Not implemented"); + } + virtual ConversionResultPlacement* clone() const { + return new CgalPlacement(trsf_); + } + 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* 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_); + } + private: + cgal_shape_t shape_; + }; + +} + +#endif \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp new file mode 100644 index 0000000000..f3002292d4 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp @@ -0,0 +1,100 @@ +/******************************************************************************** +* * +* This file is part of IfcOpenShell. * +* * +* IfcOpenShell is free software: you can redistribute it and/or modify * +* it under the terms of the Lesser GNU General Public License as published by * +* the Free Software Foundation, either version 3.0 of the License, or * +* (at your option) any later version. * +* * +* IfcOpenShell is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* Lesser GNU General Public License for more details. * +* * +* You should have received a copy of the Lesser GNU General Public License * +* along with this program. If not, see . * +* * +********************************************************************************/ + +#include "../../../ifcgeom/IfcGeomShapeType.h" +#include "../../../ifcgeom/IfcGeom.h" + +#include "CgalKernel.h" +#include "CgalConversionResult.h" + +using namespace IfcSchema; +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(new CgalShape(shp), get_style(l->as()))); + return true; + } + return false; + } + +#include "CgalEntityMappingShapes.h" + Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity); + 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->entity->id(); + bool success = false; + bool processed = false; + bool ignored = false; + +#ifndef NO_CACHE + std::map::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->entity); + } + 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->entity); + 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->entity); + 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->entity); + return false; +} diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h new file mode 100644 index 0000000000..eb2ecedf38 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -0,0 +1,35 @@ +/******************************************************************************** +* * +* This file is part of IfcOpenShell. * +* * +* IfcOpenShell is free software: you can redistribute it and/or modify * +* it under the terms of the Lesser GNU General Public License as published by * +* the Free Software Foundation, either version 3.0 of the License, or * +* (at your option) any later version. * +* * +* IfcOpenShell is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* Lesser GNU General Public License for more details. * +* * +* You should have received a copy of the Lesser GNU General Public License * +* along with this program. If not, see . * +* * +********************************************************************************/ + +/******************************************************************************** + * * + * 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/IfcUtil.h" +#include "../../../ifcparse/IfcParse.h" + +SHAPES(IfcRepresentation); + +SHAPE(IfcExtrudedAreaSolid); + +CLASS(IfcCartesianPoint,cgal_point_t); diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingCreateCache.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingCreateCache.h new file mode 100644 index 0000000000..ebfb8daca7 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingCreateCache.h @@ -0,0 +1,6 @@ +#include "CgalEntityMappingUndefine.h" +#define CLASS(T,V) \ + std::map T; +#include "CgalEntityMappingDefine.h" + +#include "CgalEntityMapping.h" diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingCurve.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingCurve.h new file mode 100644 index 0000000000..ac6736626a --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingCurve.h @@ -0,0 +1,6 @@ +#include "CgalEntityMappingUndefine.h" +#define CURVE(T) \ + if ( l->is(T::Class()) ) return convert((T*)l,r); +#include "CgalEntityMappingDefine.h" + +#include "CgalEntityMapping.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingDeclaration.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingDeclaration.h new file mode 100644 index 0000000000..7101613c26 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingDeclaration.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" \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingDefine.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingDefine.h new file mode 100644 index 0000000000..65f8704a81 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingDefine.h @@ -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 \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingFace.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingFace.h new file mode 100644 index 0000000000..ccebad4e33 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingFace.h @@ -0,0 +1,6 @@ +#include "CgalEntityMappingUndefine.h" +#define FACE(T) \ + if ( l->is(T::Class()) ) return convert((T*)l,r); +#include "CgalEntityMappingDefine.h" + +#include "CgalEntityMapping.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingPurgeCache.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingPurgeCache.h new file mode 100644 index 0000000000..ea8c2c2554 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingPurgeCache.h @@ -0,0 +1,6 @@ +#include "CgalEntityMappingUndefine.h" +#define CLASS(T,V) \ + T.clear(); +#include "CgalEntityMappingDefine.h" + +#include "CgalEntityMapping.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingShape.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingShape.h new file mode 100644 index 0000000000..736df52c62 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingShape.h @@ -0,0 +1,20 @@ +#include "CgalEntityMappingUndefine.h" +#define SHAPE(T) \ + if ( !processed && l->is(T::Class()) ) { \ + processed = true; \ + try { \ + if ( convert((T*)l,r) ) { \ + success = true; \ + } \ + } catch (const std::exception& e) { \ + Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l->entity); \ + return false; \ + } \ + if (!success) { \ + Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \ + return false; \ + } \ + } +#include "CgalEntityMappingDefine.h" + +#include "CgalEntityMapping.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingShapeType.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingShapeType.h new file mode 100644 index 0000000000..21e6a0cd31 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingShapeType.h @@ -0,0 +1,14 @@ +#include "CgalEntityMappingUndefine.h" +#define SHAPES(T) \ + if ( l->is(T::Class()) ) return ST_SHAPELIST; +#define SHAPE(T) \ + if ( l->is(T::Class()) ) return ST_SHAPE; +#define WIRE(T) \ + if ( l->is(T::Class()) ) return ST_WIRE; +#define FACE(T) \ + if ( l->is(T::Class()) ) return ST_FACE; +#define CURVE(T) \ + if ( l->is(T::Class()) ) return ST_CURVE; +#include "CgalEntityMappingDefine.h" + +#include "CgalEntityMapping.h" diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingShapes.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingShapes.h new file mode 100644 index 0000000000..778a5399ac --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingShapes.h @@ -0,0 +1,13 @@ +#include "CgalEntityMappingUndefine.h" +#define SHAPES(T) \ + if ( l->is(T::Class()) ) { \ + try { \ + return convert((T*)l,r); \ + } catch (const std::exception& e) { \ + Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l->entity); \ + } \ + return false; \ + } +#include "CgalEntityMappingDefine.h" + +#include "CgalEntityMapping.h" diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingUndefine.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingUndefine.h new file mode 100644 index 0000000000..d2d537a073 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingUndefine.h @@ -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 \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingWire.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingWire.h new file mode 100644 index 0000000000..ed5461ba75 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingWire.h @@ -0,0 +1,6 @@ +#include "CgalEntityMappingUndefine.h" +#define WIRE(T) \ + if ( l->is(T::Class()) ) return convert((T*)l,r); +#include "CgalEntityMappingDefine.h" + +#include "CgalEntityMapping.h" diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp new file mode 100644 index 0000000000..f4f830cbee --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -0,0 +1,171 @@ +/******************************************************************************** +* * +* This file is part of IfcOpenShell. * +* * +* IfcOpenShell is free software: you can redistribute it and/or modify * +* it under the terms of the Lesser GNU General Public License as published by * +* the Free Software Foundation, either version 3.0 of the License, or * +* (at your option) any later version. * +* * +* IfcOpenShell is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* Lesser GNU General Public License for more details. * +* * +* You should have received a copy of the Lesser GNU General Public License * +* along with this program. If not, see . * +* * +********************************************************************************/ + +#include "../../../ifcgeom/IfcGeomShapeType.h" +#include "../../../ifcgeom/IfcGeom.h" + +#include "CgalKernel.h" +#include "CgalConversionResult.h" + +bool IfcGeom::CgalKernel::is_identity_transform(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()) != 0) { + gp_GTrsf2d gtrsf2d; + convert(op2dnonu, gtrsf2d); + return gtrsf2d.Form() == gp_Identity; + } else if ((op2d = l->as()) != 0) { + gp_Trsf2d trsf2d; + convert(op2d, trsf2d); + return trsf2d.Form() == gp_Identity; + } else if ((op3dnonu = l->as()) != 0) { + gp_GTrsf gtrsf; + convert(op3dnonu, gtrsf); + return gtrsf.Form() == gp_Identity; + } else if ((op3d = l->as()) != 0) { + gp_Trsf trsf; + convert(op3d, trsf); + return trsf.Form() == gp_Identity; + } else if ((ax2d = l->as()) != 0) { + gp_Trsf2d trsf2d; + convert(ax2d, trsf2d); + return trsf2d.Form() == gp_Identity; + } else if ((ax3d = l->as()) != 0) { + gp_Trsf trsf; + convert(ax3d, trsf); + return trsf.Form() == gp_Identity; + } else { + throw IfcParse::IfcException("Invalid valuation for IfcAxis2Placement / IfcCartesianTransformationOperator"); + } + */ +} + +IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representation_and_product( + const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product) +{ + IfcGeom::Representation::Native* shape; + IfcGeom::ConversionResults shapes, shapes2; + + if (!convert_shapes(representation, shapes)) { + return 0; + } + + if (settings.get(IteratorSettings::APPLY_LAYERSETS)) { + Logger::Message(Logger::LOG_ERROR, "Not implemented APPLY_LAYERSETS"); + } + + int parent_id = -1; + try { + IfcSchema::IfcObjectDefinition* parent_object = get_decomposing_entity(product); + if (parent_object) { + parent_id = parent_object->entity->id(); + } + } catch (...) {} + + const std::string name = product->hasName() ? product->Name() : ""; + const std::string guid = product->GlobalId(); + + cgal_placement_t trsf; + try { + // convert(product->ObjectPlacement(), trsf); + } catch (...) {} + + // Does the IfcElement have any IfcOpenings? + // Note that openings for IfcOpeningElements are not processed + IfcSchema::IfcRelVoidsElement::list::ptr openings = find_openings(product); + + const std::string product_type = IfcSchema::Type::ToString(product->type()); + ElementSettings element_settings(settings, getValue(GV_LENGTH_UNIT), product_type); + + if (!settings.get(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && openings && openings->size()) { + Logger::Message(Logger::LOG_ERROR, "Not implemented opening subtractions"); + } + + shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), shapes); + + std::string context_string = ""; + if (representation->hasRepresentationIdentifier()) { + context_string = representation->RepresentationIdentifier(); + } else if (representation->ContextOfItems()->hasContextType()) { + context_string = representation->ContextOfItems()->ContextType(); + } + + return new NativeElement( + product->entity->id(), + parent_id, + name, + product_type, + guid, + context_string, + new CgalPlacement(trsf), + boost::shared_ptr(shape) + ); +} + +IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_processed_representation( + const IteratorSettings& /*settings*/, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, + IfcGeom::NativeElement* brep) +{ + int parent_id = -1; + try { + IfcSchema::IfcObjectDefinition* parent_object = get_decomposing_entity(product); + if (parent_object) { + parent_id = parent_object->entity->id(); + } + } catch (...) {} + + const std::string name = product->hasName() ? product->Name() : ""; + const std::string guid = product->GlobalId(); + + cgal_placement_t trsf; + try { + // convert(product->ObjectPlacement(), trsf); + } catch (...) {} + + 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 = IfcSchema::Type::ToString(product->type()); + + return new NativeElement( + product->entity->id(), + parent_id, + name, + product_type, + guid, + context_string, + new CgalPlacement(trsf), + brep->geometry_pointer() + ); +} diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h new file mode 100644 index 0000000000..a3e7167624 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -0,0 +1,93 @@ +/******************************************************************************** +* * +* 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 . * +* * +********************************************************************************/ + +#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::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 "../../../ifcgeom/IfcGeom.h" + +typedef void* cgal_shape_t; +typedef void* cgal_face_t; +typedef void* cgal_wire_t; +typedef void* cgal_curve_t; +typedef void* cgal_placement_t; +typedef void* cgal_point_t; + +namespace IfcGeom { + + class IFC_GEOM_API CgalCache { + public: +#include "CgalEntityMappingCreateCache.h" + std::map Shape; + }; + + class IFC_GEOM_API CgalKernel : public AbstractKernel { + public: + +#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_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, ConversionResults& cut_shapes); + + 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(IfcUtil::IfcBaseClass*); + virtual IfcGeom::NativeElement* create_brep_for_representation_and_product( + const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*); + virtual IfcGeom::NativeElement* create_brep_for_processed_representation( + const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::NativeElement*); + +#include "CgalEntityMappingDeclaration.h" + + }; + +} + +#endif \ No newline at end of file From a4264f31433eee1553b4c08f6f6c4f9a8272aae4 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 27 Jan 2017 15:31:22 -0600 Subject: [PATCH 007/235] Replaced macros, added basic CGAL definitions --- src/ifcconvert/ColladaSerializer.cpp | 6 +++--- src/ifcconvert/XmlSerializer.cpp | 8 ++++---- src/ifcgeom/IfcGeomIterator.h | 14 +++++++------- src/ifcgeom/kernels/cgal/CgalKernel.h | 23 +++++++++++++++-------- src/ifcparse/IfcUtil.h | 2 +- 5 files changed, 30 insertions(+), 23 deletions(-) diff --git a/src/ifcconvert/ColladaSerializer.cpp b/src/ifcconvert/ColladaSerializer.cpp index c8272aba64..e9108f6e80 100644 --- a/src/ifcconvert/ColladaSerializer.cpp +++ b/src/ifcconvert/ColladaSerializer.cpp @@ -208,7 +208,7 @@ void ColladaSerializer::ColladaExporter::ColladaScene::add( node.addMatrix(matrix_array); COLLADASW::InstanceGeometry instanceGeometry(mSW); instanceGeometry.setUrl ("#" + geom_name); - foreach(std::string material_name, material_ids) { + for (std::string material_name: material_ids) { /// @todo This is done 6 times in this file, try to perform this once and be done with the material naming for the export. collada_id(material_name); COLLADASW::InstanceMaterial material (material_name, "#" + material_name); @@ -276,7 +276,7 @@ bool ColladaSerializer::ColladaExporter::ColladaMaterials::contains(const IfcGeo void ColladaSerializer::ColladaExporter::ColladaMaterials::write() { effects.close(); - foreach(const IfcGeom::Material& material, materials) { + for (const IfcGeom::Material& material: materials) { std::string material_name = (serializer->settings().get(IfcGeom::IteratorSettings::USE_MATERIAL_NAMES) ? material.original_name() : material.name()); std::string material_name_unescaped = material_name; // workaround double-escaping that would occur in addInstanceEffect() @@ -307,7 +307,7 @@ void ColladaSerializer::ColladaExporter::write(const IfcGeom::TriangulationEleme const std::string representation_id = "representation-" + boost::lexical_cast(o->geometry().id()); std::vector material_references; - foreach(const IfcGeom::Material& material, mesh.materials()) { + for (const IfcGeom::Material& material: mesh.materials()) { if (!materials.contains(material)) { materials.add(material); } diff --git a/src/ifcconvert/XmlSerializer.cpp b/src/ifcconvert/XmlSerializer.cpp index dcb574e0cd..b6cdec851d 100644 --- a/src/ifcconvert/XmlSerializer.cpp +++ b/src/ifcconvert/XmlSerializer.cpp @@ -341,16 +341,16 @@ void XmlSerializer::finalize() { ptree root, header, units, decomposition, properties, types, layers; // Write the SPF header as XML nodes. - foreach(const std::string& s, file->header().file_description().description()) { + for (const std::string& s: file->header().file_description().description()) { header.add_child("file_description.description", ptree(s)); } - foreach(const std::string& s, file->header().file_name().author()) { + for (const std::string& s: file->header().file_name().author()) { header.add_child("file_name.author", ptree(s)); } - foreach(const std::string& s, file->header().file_name().organization()) { + for (const std::string& s: file->header().file_name().organization()) { header.add_child("file_name.organization", ptree(s)); } - foreach(const std::string& s, file->header().file_schema().schema_identifiers()) { + for (const std::string& s: file->header().file_schema().schema_identifiers()) { header.add_child("file_schema.schema_identifiers", ptree(s)); } header.put("file_description.implementation_level", file->header().file_description().implementation_level()); diff --git a/src/ifcgeom/IfcGeomIterator.h b/src/ifcgeom/IfcGeomIterator.h index 2ada29a2cf..2d2c8fe312 100644 --- a/src/ifcgeom/IfcGeomIterator.h +++ b/src/ifcgeom/IfcGeomIterator.h @@ -329,7 +329,7 @@ namespace IfcGeom { void include_entity_names(const std::vector& names) { names_to_include_or_exclude.clear(); - foreach(const std::string &name, names) + for (const std::string &name: names) names_to_include_or_exclude.insert(wildcard_string_to_regex(name)); include_names_in_processing_ = true; } @@ -338,7 +338,7 @@ namespace IfcGeom { void exclude_entity_names(const std::vector& names) { names_to_include_or_exclude.clear(); - foreach(const std::string &name, names) + for (const std::string &name: names) names_to_include_or_exclude.insert(wildcard_string_to_regex(name)); include_names_in_processing_ = false; } @@ -347,7 +347,7 @@ namespace IfcGeom { { // Escape all non-"*?" regex special chars std::string special_chars = "\\^.$|()[]+/"; - foreach(char c, special_chars) { + for (char c: special_chars) { std::string char_str(1, c); boost::replace_all(str, char_str, "\\" + char_str); } @@ -540,7 +540,7 @@ namespace IfcGeom { IfcSchema::IfcProduct* prod = *jt; bool type_found = false; // The set is iterated over to able to filter on subtypes. - foreach(IfcSchema::Type::Enum type, entities_to_include_or_exclude) { + for (IfcSchema::Type::Enum type: entities_to_include_or_exclude) { if (prod->is(type)) { type_found = true; break; @@ -548,7 +548,7 @@ namespace IfcGeom { } if (!type_found && traverse) { - foreach(IfcSchema::Type::Enum type, entities_to_include_or_exclude) { + for (IfcSchema::Type::Enum type: entities_to_include_or_exclude) { IfcSchema::IfcProduct* parent, * current = prod; while ((parent = static_cast(kernel->get_decomposing_entity(current))) != 0) { if (parent->is(type)) { @@ -564,7 +564,7 @@ namespace IfcGeom { } bool name_found = false; - foreach(const boost::regex& r, names_to_include_or_exclude) { + for (const boost::regex& r: names_to_include_or_exclude) { if (prod->hasName() && boost::regex_match(prod->Name(), r)) { name_found = true; break; @@ -572,7 +572,7 @@ namespace IfcGeom { } if (!name_found && traverse) { - foreach(const boost::regex& r, names_to_include_or_exclude) { + for (const boost::regex& r: names_to_include_or_exclude) { IfcSchema::IfcProduct* parent, *current = prod; while ((parent = static_cast(kernel->get_decomposing_entity(current))) != 0) { if (parent->hasName() && boost::regex_match(parent->Name(), r)) { diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index a3e7167624..5a9fe325a8 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -1,4 +1,4 @@ -/******************************************************************************** +/******************************************************************************** * * * This file is part of IfcOpenShell. * * * @@ -37,12 +37,19 @@ if ( it != cache.T.end() ) { e = it->second; return true; } #include "../../../ifcgeom/IfcGeom.h" -typedef void* cgal_shape_t; -typedef void* cgal_face_t; -typedef void* cgal_wire_t; -typedef void* cgal_curve_t; -typedef void* cgal_placement_t; -typedef void* cgal_point_t; +#undef Handle + +#include +#include + +typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; + +typedef CGAL::Nef_polyhedron_3 *cgal_shape_t; +typedef std::vector *cgal_face_t; +typedef std::vector *cgal_wire_t; +typedef std::vector *cgal_curve_t; +typedef Kernel::Aff_transformation_3 *cgal_placement_t; +typedef Kernel::Point_3 *cgal_point_t; namespace IfcGeom { @@ -90,4 +97,4 @@ namespace IfcGeom { } -#endif \ No newline at end of file +#endif diff --git a/src/ifcparse/IfcUtil.h b/src/ifcparse/IfcUtil.h index 13eeb4a134..8b5259b111 100644 --- a/src/ifcparse/IfcUtil.h +++ b/src/ifcparse/IfcUtil.h @@ -38,7 +38,7 @@ #include #include -#define foreach BOOST_FOREACH +//#define foreach BOOST_FOREACH #define rforeach BOOST_REVERSE_FOREACH class Argument; From cac9c91c56397ee6ad0791abf489b9f9bb17b51c Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 27 Jan 2017 15:31:37 -0600 Subject: [PATCH 008/235] Mac metadata --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c8a6b575ee..f7b2047913 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ __pycache__ # Visual Studio Code files .vscode +.DS_Store From 0821dd4702d554bfe9a441ab2a6da8e69d4bf5e3 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 27 Jan 2017 18:40:38 -0600 Subject: [PATCH 009/235] Skeleton for IfcManifoldSolidBrep and IfcConnectedFaceSet --- .../kernels/cgal/CgalEntityMapping.cpp | 74 +++++++++++++++++++ src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 7 ++ 2 files changed, 81 insertions(+) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp index f3002292d4..ea7e417a15 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp @@ -81,6 +81,80 @@ bool IfcGeom::CgalKernel::convert_shape(const IfcBaseClass* l, cgal_shape_t& r) return success; } +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, ConversionResults& shape) { + cgal_shape_t s; + const SurfaceStyle* collective_style = get_style(l); + if (convert_shape(l->Outer(),s) ) { +// const SurfaceStyle* indiv_style = get_style(l->Outer()); +// +// IfcSchema::IfcClosedShell::list::ptr voids(new IfcSchema::IfcClosedShell::list); +// if (l->is(IfcSchema::Type::IfcFacetedBrepWithVoids)) { +// voids = l->as()->Voids(); +// } +//#ifdef USE_IFC4 +// if (l->is(IfcSchema::Type::IfcAdvancedBrepWithVoids)) { +// voids = l->as()->Voids(); +// } +//#endif +// +// for (IfcSchema::IfcClosedShell::list::it it = voids->begin(); it != voids->end(); ++it) { +// TopoDS_Shape s2; +// /// @todo No extensive shapefixing since shells should be disjoint. +// /// @todo Awaiting generalized boolean ops module with appropriate checking +// if (convert_shape(l->Outer(), s2)) { +// s = BRepAlgoAPI_Cut(s, s2).Shape(); +// } +// } +// +// shape.push_back(ConversionResult(new OpenCascadeShape(s), indiv_style ? indiv_style : collective_style)); +// return true; + } + return false; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_shape_t& shape) { + IfcSchema::IfcFace::list::ptr faces = l->CfsFaces(); + +// TopTools_ListOfShape 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)->entity); + continue; + } + +// if (face_area(face) > getValue(GV_MINIMAL_FACE_AREA)) { +// face_list.Append(face); +// } else { +// Logger::Message(Logger::LOG_WARNING, "Invalid face:", (*it)->entity); +// } + } +// +// if (face_list.Extent() == 0) { +// return false; +// } +// +// if (face_list.Extent() > getValue(GV_MAX_FACES_TO_SEW) || !create_solid_from_faces(face_list, shape)) { +// TopoDS_Compound compound; +// BRep_Builder builder; +// builder.MakeCompound(compound); +// +// TopTools_ListIteratorOfListOfShape face_iterator; +// for (face_iterator.Initialize(face_list); face_iterator.More(); face_iterator.Next()) { +// builder.Add(compound, face_iterator.Value()); +// } +// shape = compound; +// } + + return true; +} + 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->entity); diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index eb2ecedf38..d8760aa233 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -31,5 +31,12 @@ SHAPES(IfcRepresentation); SHAPE(IfcExtrudedAreaSolid); +// IfcFacetedBrep included +// IfcAdvancedBrep included +// IfcFacetedBrepWithVoids included +// IfcAdvancedBrepWithVoids included +SHAPES(IfcManifoldSolidBrep); + +SHAPE(IfcConnectedFaceSet); CLASS(IfcCartesianPoint,cgal_point_t); From 9c21e0518454087d45fd44d3d423953494113df6 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 31 Jan 2017 18:53:00 -0600 Subject: [PATCH 010/235] Skeleton reaching all the way up to points, to be filled in --- .../kernels/cgal/CgalConversionFunctions.cpp | 12 + .../kernels/cgal/CgalEntityMapping.cpp | 264 +++++++++++++++++- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 9 +- 3 files changed, 281 insertions(+), 4 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 68d9224029..f226d7c9e4 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -26,3 +26,15 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRepresentation* l, Convers bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid*, cgal_shape_t&) { throw std::runtime_error("Not implemented IfcExtrudedAreaSolid"); } + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_point_t& point) { +// IN_CACHE(IfcCartesianPoint,l,gp_Pnt,point) +// std::vector xyz = l->Coordinates(); +// point = gp_Pnt( +// 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 +// ); +// CACHE(IfcCartesianPoint,l,point) + return true; +} diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp index ea7e417a15..c04005e65d 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp @@ -1,4 +1,4 @@ -/******************************************************************************** +/******************************************************************************** * * * This file is part of IfcOpenShell. * * * @@ -167,6 +167,268 @@ bool IfcGeom::CgalKernel::convert_face(const IfcBaseClass* l, cgal_face_t& r) { return false; } +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcFace* l, cgal_face_t& face) { + IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds(); + +// Handle(Geom_Surface) face_surface; +// const bool is_face_surface = l->is(IfcSchema::Type::IfcFaceSurface); +// +// if (is_face_surface) { +// IfcSchema::IfcFaceSurface* fs = (IfcSchema::IfcFaceSurface*) l; +// fs->FaceSurface(); +// // FIXME: Surfaces are interpreted as a TopoDS_Shape +// TopoDS_Shape surface_shape; +// if (!convert_shape(fs->FaceSurface(), surface_shape)) return false; +// +// // FIXME: Assert this obtaines the only face +// TopExp_Explorer exp(surface_shape, TopAbs_FACE); +// if (!exp.More()) return false; +// +// TopoDS_Face surface = TopoDS::Face(exp.Current()); +// face_surface = BRep_Tool::Surface(surface); +// } +// +// const int num_bounds = bounds->size(); +// int num_outer_bounds = 0; +// +// for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) { +// IfcSchema::IfcFaceBound* bound = *it; +// if (bound->is(IfcSchema::Type::IfcFaceOuterBound)) num_outer_bounds ++; +// } +// +// // The number of outer bounds should be one according to the schema. Also Open Cascade +// // expects this, but it is not strictly checked. Regardless, if the number is greater, +// // the face will still be processed as long as there are no holes. A compound of faces +// // is returned in that case. +// if (num_bounds > 1 && num_outer_bounds > 1 && num_bounds != num_outer_bounds) { +// Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l->entity); +// return false; +// } +// +// TopoDS_Compound compound; +// BRep_Builder builder; +// if (num_outer_bounds > 1) { +// builder.MakeCompound(compound); +// } +// +// TopTools_DataMapOfShapeInteger wire_senses; +// +// // The builder is initialized on the heap because of the various different moments +// // of initialization depending on the configuration of surfaces and boundaries. +// BRepBuilderAPI_MakeFace* mf = 0; +// +// bool success = false; +// int processed = 0; +// +// for (int process_interior = 0; process_interior <= 1; ++process_interior) { + for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) { + IfcSchema::IfcFaceBound* bound = *it; + IfcSchema::IfcLoop* loop = bound->Bound(); + +// bool same_sense = bound->Orientation(); +// const bool is_interior = +// !bound->is(IfcSchema::Type::IfcFaceOuterBound) && +// (num_bounds > 1) && +// (num_outer_bounds < num_bounds); +// +// // The exterior face boundary is processed first +// if (is_interior == !process_interior) continue; +// + cgal_wire_t wire; + if (!convert_wire(loop, wire)) { +// Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop->entity); +// delete mf; +// return false; + } +// +// if (!same_sense) { +// wire.Reverse(); +// } +// +// wire_senses.Bind(wire.Oriented(TopAbs_FORWARD), same_sense ? TopAbs_FORWARD : TopAbs_REVERSED); +// +// bool flattened_wire = false; +// +// if (!mf) { +// process_wire: +// +// if (face_surface.IsNull()) { +// mf = new BRepBuilderAPI_MakeFace(wire); +// } else { +// /// @todo check necessity of false here +// mf = new BRepBuilderAPI_MakeFace(face_surface, wire, false); +// } +// +// /* BRepBuilderAPI_FaceError er = mf->Error(); +// if (er == BRepBuilderAPI_NotPlanar) { +// ShapeFix_ShapeTolerance FTol; +// FTol.SetTolerance(wire, getValue(GV_PRECISION), TopAbs_WIRE); +// delete mf; +// mf = new BRepBuilderAPI_MakeFace(wire); +// } */ +// +// if (mf->IsDone()) { +// TopoDS_Face outer_face_bound = mf->Face(); +// +// // In case of (non-planar) face surface, p-curves need to be computed. +// // For planar faces, Open Cascade generates p-curves on the fly. +// if (!face_surface.IsNull()) { +// TopExp_Explorer exp(outer_face_bound, TopAbs_EDGE); +// for (; exp.More(); exp.Next()) { +// const TopoDS_Edge& edge = TopoDS::Edge(exp.Current()); +// ShapeFix_Edge fix_edge; +// fix_edge.FixAddPCurve(edge, outer_face_bound, false, getValue(GV_PRECISION)); +// } +// } +// +// if (BRepCheck_Face(outer_face_bound).OrientationOfWires() == BRepCheck_BadOrientationOfSubshape) { +// wire.Reverse(); +// same_sense = !same_sense; +// delete mf; +// if (face_surface.IsNull()) { +// mf = new BRepBuilderAPI_MakeFace(wire); +// } else { +// mf = new BRepBuilderAPI_MakeFace(face_surface, wire); +// } +// ShapeFix_Face fix(mf->Face()); +// fix.FixOrientation(); +// outer_face_bound = fix.Face(); +// } +// +// if (num_outer_bounds > 1) { +// builder.Add(compound, outer_face_bound); +// delete mf; mf = 0; +// } else if (num_bounds > 1) { +// // Reinitialize the builder to the outer face +// // bound in order to add holes more robustly. +// delete mf; +// // TODO: What about the face_surface? +// mf = new BRepBuilderAPI_MakeFace(outer_face_bound); +// } else { +// face = outer_face_bound; +// success = true; +// } +// } else { +// const bool non_planar = mf->Error() == BRepBuilderAPI_NotPlanar; +// delete mf; +// if (!non_planar || flattened_wire || !flatten_wire(wire)) { +// Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary", bound->entity); +// return false; +// } else { +// Logger::Message(Logger::LOG_ERROR, "Flattening face boundary", bound->entity); +// flattened_wire = true; +// goto process_wire; +// } +// } +// +// } else { +// mf->Add(wire); +// } +// processed ++; + } +// } +// +// if (!success) { +// success = processed == num_bounds; +// if (success) { +// if (num_outer_bounds > 1) { +// face = compound; +// } else { +// success = success && mf->IsDone(); +// if (success) { +// face = mf->Face(); +// } +// +// ShapeFix_Face sfs(TopoDS::Face(face)); +// TopTools_DataMapOfShapeListOfShape wire_map; +// sfs.FixOrientation(wire_map); +// +// TopoDS_Iterator jt(face, false); +// for (; jt.More(); jt.Next()) { +// const TopoDS_Wire& w = TopoDS::Wire(jt.Value()); +// if (wire_map.IsBound(w)) { +// const TopTools_ListOfShape& shapes = wire_map.Find(w); +// TopTools_ListIteratorOfListOfShape it(shapes); +// for (; it.More(); it.Next()) { +// // Apparently the wire got reversed, so register it with opposite orientation in the map +// wire_senses.Bind(it.Value(), wire_senses.Find(w) == TopAbs_FORWARD ? TopAbs_REVERSED : TopAbs_FORWARD); +// } +// } +// } +// +// face = TopoDS::Face(sfs.Face()); +// } +// } +// } +// +// if (success) { +// // If the wires are reversed the face needs to be reversed as well in order +// // to maintain the counter-clock-wise ordering of the bounding wire's vertices. +// if (num_bounds == 1 || true) { +// bool all_reversed = true; +// TopoDS_Iterator jt(face, false); +// for (; jt.More(); jt.Next()) { +// const TopoDS_Wire& w = TopoDS::Wire(jt.Value()); +// if (!wire_senses.IsBound(w.Oriented(TopAbs_FORWARD)) || (w.Orientation() == wire_senses.Find(w.Oriented(TopAbs_FORWARD)))) { +// all_reversed = false; +// } +// } +// +// if (all_reversed) { +// face.Reverse(); +// } +// } +// +// ShapeFix_ShapeTolerance FTol; +// FTol.SetTolerance(face, getValue(GV_PRECISION), TopAbs_FACE); +// } +// +// delete mf; + return true; +} + +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 +// TColgp_SequenceOfPnt polygon; + for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) { + cgal_point_t pnt; + IfcGeom::CgalKernel::convert(*it, pnt); +// polygon.Append(pnt); + } +// +// // A loop should consist of at least three vertices +// int original_count = polygon.Length(); +// if (original_count < 3) { +// Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity); +// return false; +// } +// +// // Remove points that are too close to one another +// remove_duplicate_points_from_loop(polygon, true); +// +// int count = polygon.Length(); +// if (original_count - count != 0) { +// std::stringstream ss; ss << (original_count - count) << " edges removed for:"; +// Logger::Message(Logger::LOG_WARNING, ss.str(), l->entity); +// } +// +// if (count < 3) { +// Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity); +// return false; +// } +// +// BRepBuilderAPI_MakePolygon w; +// for (int i = 1; i <= polygon.Length(); ++i) { +// w.Add(polygon.Value(i)); +// } +// w.Close(); +// +// result = w.Wire(); + return true; +} + 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->entity); diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index d8760aa233..e720796002 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -1,4 +1,4 @@ -/******************************************************************************** +/******************************************************************************** * * * This file is part of IfcOpenShell. * * * @@ -29,14 +29,17 @@ #include "../../../ifcparse/IfcParse.h" SHAPES(IfcRepresentation); - -SHAPE(IfcExtrudedAreaSolid); // IfcFacetedBrep included // IfcAdvancedBrep included // IfcFacetedBrepWithVoids included // IfcAdvancedBrepWithVoids included SHAPES(IfcManifoldSolidBrep); +SHAPE(IfcExtrudedAreaSolid); SHAPE(IfcConnectedFaceSet); +FACE(IfcFace); + +WIRE(IfcPolyLoop); + CLASS(IfcCartesianPoint,cgal_point_t); From 233aaeaca2de096d4388f1759905e8114a3c9d49 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 31 Jan 2017 19:03:15 -0600 Subject: [PATCH 011/235] Points and wires --- .../kernels/cgal/CgalConversionFunctions.cpp | 19 ++++++++++--------- .../kernels/cgal/CgalEntityMapping.cpp | 10 +++++----- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index f226d7c9e4..53336e0da5 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -28,13 +28,14 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid*, cgal_s } bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_point_t& point) { -// IN_CACHE(IfcCartesianPoint,l,gp_Pnt,point) -// std::vector xyz = l->Coordinates(); -// point = gp_Pnt( -// 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 -// ); -// CACHE(IfcCartesianPoint,l,point) - return true; + std::vector xyz = l->Coordinates(); +// for (const double &coordinate: xyz) std::cout << coordinate << " "; +// std::cout << std::endl; + if (xyz.size() == 3) { + point = new Kernel::Point_3(xyz[0], xyz[1], xyz[2]); + return true; + } else { + point = new Kernel::Point_3(); + return false; + } } diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp index c04005e65d..b093aa2679 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp @@ -390,14 +390,14 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcFace* l, cgal_face_t& face 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 -// TColgp_SequenceOfPnt polygon; + // Parse and store the points in a sequence + cgal_wire_t polygon; for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) { cgal_point_t pnt; IfcGeom::CgalKernel::convert(*it, pnt); -// polygon.Append(pnt); + polygon->push_back(*pnt); } -// + // // A loop should consist of at least three vertices // int original_count = polygon.Length(); // if (original_count < 3) { @@ -425,7 +425,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& // } // w.Close(); // -// result = w.Wire(); + result = polygon; return true; } From f2a45b705704c739dcc182b0d096d7c4241c205e Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 1 Feb 2017 15:57:25 -0600 Subject: [PATCH 012/235] Fixed pointer bug, wires seem okay now --- .../kernels/cgal/CgalConversionFunctions.cpp | 1 + .../kernels/cgal/CgalEntityMapping.cpp | 41 +++++++------------ src/ifcgeom/kernels/cgal/CgalKernel.h | 4 +- 3 files changed, 17 insertions(+), 29 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 53336e0da5..9f80843bb6 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -33,6 +33,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_po // std::cout << std::endl; if (xyz.size() == 3) { point = new Kernel::Point_3(xyz[0], xyz[1], xyz[2]); +// std::cout << *point << std::endl; return true; } else { point = new Kernel::Point_3(); diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp index b093aa2679..08577a7866 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp @@ -236,15 +236,15 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcFace* l, cgal_face_t& face // cgal_wire_t wire; if (!convert_wire(loop, wire)) { -// Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop->entity); + Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop->entity); // delete mf; -// return false; + return false; } -// + // if (!same_sense) { // wire.Reverse(); // } -// +// // wire_senses.Bind(wire.Oriented(TopAbs_FORWARD), same_sense ? TopAbs_FORWARD : TopAbs_REVERSED); // // bool flattened_wire = false; @@ -259,14 +259,6 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcFace* l, cgal_face_t& face // mf = new BRepBuilderAPI_MakeFace(face_surface, wire, false); // } // -// /* BRepBuilderAPI_FaceError er = mf->Error(); -// if (er == BRepBuilderAPI_NotPlanar) { -// ShapeFix_ShapeTolerance FTol; -// FTol.SetTolerance(wire, getValue(GV_PRECISION), TopAbs_WIRE); -// delete mf; -// mf = new BRepBuilderAPI_MakeFace(wire); -// } */ -// // if (mf->IsDone()) { // TopoDS_Face outer_face_bound = mf->Face(); // @@ -391,20 +383,21 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& IfcSchema::IfcCartesianPoint::list::ptr points = l->Polygon(); // Parse and store the points in a sequence - cgal_wire_t polygon; + cgal_wire_t polygon = new std::vector(); for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) { cgal_point_t pnt; IfcGeom::CgalKernel::convert(*it, pnt); +// std::cout << *pnt << std::endl; polygon->push_back(*pnt); } -// // A loop should consist of at least three vertices -// int original_count = polygon.Length(); -// if (original_count < 3) { -// Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity); -// return false; -// } -// + // A loop should consist of at least three vertices + int original_count = polygon->size(); + if (original_count < 3) { + Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity); + return false; + } + // // Remove points that are too close to one another // remove_duplicate_points_from_loop(polygon, true); // @@ -418,13 +411,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& // Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity); // return false; // } -// -// BRepBuilderAPI_MakePolygon w; -// for (int i = 1; i <= polygon.Length(); ++i) { -// w.Add(polygon.Value(i)); -// } -// w.Close(); -// + result = polygon; return true; } diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 5a9fe325a8..377a2687fb 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -40,11 +40,11 @@ if ( it != cache.T.end() ) { e = it->second; return true; } #undef Handle #include -#include +#include typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; -typedef CGAL::Nef_polyhedron_3 *cgal_shape_t; +typedef CGAL::Polyhedron_3 *cgal_shape_t; typedef std::vector *cgal_face_t; typedef std::vector *cgal_wire_t; typedef std::vector *cgal_curve_t; From 5724e1ac348ebbc7fd6dc3cb2c2a92d548d76c87 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 1 Feb 2017 17:53:12 -0600 Subject: [PATCH 013/235] Face from IfcFace --- .../kernels/cgal/CgalConversionFunctions.cpp | 6 +- .../kernels/cgal/CgalEntityMapping.cpp | 262 +++--------------- src/ifcgeom/kernels/cgal/CgalKernel.h | 14 +- 3 files changed, 56 insertions(+), 226 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 9f80843bb6..93947879ea 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -29,14 +29,10 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid*, cgal_s bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_point_t& point) { std::vector xyz = l->Coordinates(); -// for (const double &coordinate: xyz) std::cout << coordinate << " "; -// std::cout << std::endl; if (xyz.size() == 3) { point = new Kernel::Point_3(xyz[0], xyz[1], xyz[2]); -// std::cout << *point << std::endl; return true; } else { - point = new Kernel::Point_3(); - return false; + throw std::runtime_error("Point without 3 coordinates"); } } diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp index 08577a7866..73232096a5 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp @@ -169,213 +169,42 @@ bool IfcGeom::CgalKernel::convert_face(const IfcBaseClass* l, cgal_face_t& r) { 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->is(IfcSchema::Type::IfcFaceOuterBound)) num_outer_bounds ++; + } -// Handle(Geom_Surface) face_surface; -// const bool is_face_surface = l->is(IfcSchema::Type::IfcFaceSurface); -// -// if (is_face_surface) { -// IfcSchema::IfcFaceSurface* fs = (IfcSchema::IfcFaceSurface*) l; -// fs->FaceSurface(); -// // FIXME: Surfaces are interpreted as a TopoDS_Shape -// TopoDS_Shape surface_shape; -// if (!convert_shape(fs->FaceSurface(), surface_shape)) return false; -// -// // FIXME: Assert this obtaines the only face -// TopExp_Explorer exp(surface_shape, TopAbs_FACE); -// if (!exp.More()) return false; -// -// TopoDS_Face surface = TopoDS::Face(exp.Current()); -// face_surface = BRep_Tool::Surface(surface); -// } -// -// const int num_bounds = bounds->size(); -// int num_outer_bounds = 0; -// -// for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) { -// IfcSchema::IfcFaceBound* bound = *it; -// if (bound->is(IfcSchema::Type::IfcFaceOuterBound)) num_outer_bounds ++; -// } -// -// // The number of outer bounds should be one according to the schema. Also Open Cascade -// // expects this, but it is not strictly checked. Regardless, if the number is greater, -// // the face will still be processed as long as there are no holes. A compound of faces -// // is returned in that case. -// if (num_bounds > 1 && num_outer_bounds > 1 && num_bounds != num_outer_bounds) { -// Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l->entity); -// return false; -// } -// -// TopoDS_Compound compound; -// BRep_Builder builder; -// if (num_outer_bounds > 1) { -// builder.MakeCompound(compound); -// } -// -// TopTools_DataMapOfShapeInteger wire_senses; -// -// // The builder is initialized on the heap because of the various different moments -// // of initialization depending on the configuration of surfaces and boundaries. -// BRepBuilderAPI_MakeFace* mf = 0; -// -// bool success = false; -// int processed = 0; -// -// for (int process_interior = 0; process_interior <= 1; ++process_interior) { - for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) { - IfcSchema::IfcFaceBound* bound = *it; - IfcSchema::IfcLoop* loop = bound->Bound(); + if (num_outer_bounds != 1) { + Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l->entity); + return false; + } + + cgal_face_t mf = new CgalFace(); -// bool same_sense = bound->Orientation(); -// const bool is_interior = -// !bound->is(IfcSchema::Type::IfcFaceOuterBound) && -// (num_bounds > 1) && -// (num_outer_bounds < num_bounds); -// -// // The exterior face boundary is processed first -// if (is_interior == !process_interior) continue; -// - cgal_wire_t wire; - if (!convert_wire(loop, wire)) { - Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop->entity); -// delete mf; - return false; - } + for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) { + IfcSchema::IfcFaceBound* bound = *it; + IfcSchema::IfcLoop* loop = bound->Bound(); -// if (!same_sense) { -// wire.Reverse(); -// } -// -// wire_senses.Bind(wire.Oriented(TopAbs_FORWARD), same_sense ? TopAbs_FORWARD : TopAbs_REVERSED); -// -// bool flattened_wire = false; -// -// if (!mf) { -// process_wire: -// -// if (face_surface.IsNull()) { -// mf = new BRepBuilderAPI_MakeFace(wire); -// } else { -// /// @todo check necessity of false here -// mf = new BRepBuilderAPI_MakeFace(face_surface, wire, false); -// } -// -// if (mf->IsDone()) { -// TopoDS_Face outer_face_bound = mf->Face(); -// -// // In case of (non-planar) face surface, p-curves need to be computed. -// // For planar faces, Open Cascade generates p-curves on the fly. -// if (!face_surface.IsNull()) { -// TopExp_Explorer exp(outer_face_bound, TopAbs_EDGE); -// for (; exp.More(); exp.Next()) { -// const TopoDS_Edge& edge = TopoDS::Edge(exp.Current()); -// ShapeFix_Edge fix_edge; -// fix_edge.FixAddPCurve(edge, outer_face_bound, false, getValue(GV_PRECISION)); -// } -// } -// -// if (BRepCheck_Face(outer_face_bound).OrientationOfWires() == BRepCheck_BadOrientationOfSubshape) { -// wire.Reverse(); -// same_sense = !same_sense; -// delete mf; -// if (face_surface.IsNull()) { -// mf = new BRepBuilderAPI_MakeFace(wire); -// } else { -// mf = new BRepBuilderAPI_MakeFace(face_surface, wire); -// } -// ShapeFix_Face fix(mf->Face()); -// fix.FixOrientation(); -// outer_face_bound = fix.Face(); -// } -// -// if (num_outer_bounds > 1) { -// builder.Add(compound, outer_face_bound); -// delete mf; mf = 0; -// } else if (num_bounds > 1) { -// // Reinitialize the builder to the outer face -// // bound in order to add holes more robustly. -// delete mf; -// // TODO: What about the face_surface? -// mf = new BRepBuilderAPI_MakeFace(outer_face_bound); -// } else { -// face = outer_face_bound; -// success = true; -// } -// } else { -// const bool non_planar = mf->Error() == BRepBuilderAPI_NotPlanar; -// delete mf; -// if (!non_planar || flattened_wire || !flatten_wire(wire)) { -// Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary", bound->entity); -// return false; -// } else { -// Logger::Message(Logger::LOG_ERROR, "Flattening face boundary", bound->entity); -// flattened_wire = true; -// goto process_wire; -// } -// } -// -// } else { -// mf->Add(wire); -// } -// processed ++; + const bool is_interior = !bound->is(IfcSchema::Type::IfcFaceOuterBound); + + cgal_wire_t wire; + if (!convert_wire(loop, wire)) { + Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop->entity); + delete mf; + return false; } -// } -// -// if (!success) { -// success = processed == num_bounds; -// if (success) { -// if (num_outer_bounds > 1) { -// face = compound; -// } else { -// success = success && mf->IsDone(); -// if (success) { -// face = mf->Face(); -// } -// -// ShapeFix_Face sfs(TopoDS::Face(face)); -// TopTools_DataMapOfShapeListOfShape wire_map; -// sfs.FixOrientation(wire_map); -// -// TopoDS_Iterator jt(face, false); -// for (; jt.More(); jt.Next()) { -// const TopoDS_Wire& w = TopoDS::Wire(jt.Value()); -// if (wire_map.IsBound(w)) { -// const TopTools_ListOfShape& shapes = wire_map.Find(w); -// TopTools_ListIteratorOfListOfShape it(shapes); -// for (; it.More(); it.Next()) { -// // Apparently the wire got reversed, so register it with opposite orientation in the map -// wire_senses.Bind(it.Value(), wire_senses.Find(w) == TopAbs_FORWARD ? TopAbs_REVERSED : TopAbs_FORWARD); -// } -// } -// } -// -// face = TopoDS::Face(sfs.Face()); -// } -// } -// } -// -// if (success) { -// // If the wires are reversed the face needs to be reversed as well in order -// // to maintain the counter-clock-wise ordering of the bounding wire's vertices. -// if (num_bounds == 1 || true) { -// bool all_reversed = true; -// TopoDS_Iterator jt(face, false); -// for (; jt.More(); jt.Next()) { -// const TopoDS_Wire& w = TopoDS::Wire(jt.Value()); -// if (!wire_senses.IsBound(w.Oriented(TopAbs_FORWARD)) || (w.Orientation() == wire_senses.Find(w.Oriented(TopAbs_FORWARD)))) { -// all_reversed = false; -// } -// } -// -// if (all_reversed) { -// face.Reverse(); -// } -// } -// -// ShapeFix_ShapeTolerance FTol; -// FTol.SetTolerance(face, getValue(GV_PRECISION), TopAbs_FACE); -// } -// -// delete mf; + + if (!is_interior) { + mf->outer = wire; + } else { + mf->inner.push_back(wire); + } + } + + face = mf; return true; } @@ -387,30 +216,29 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) { cgal_point_t pnt; IfcGeom::CgalKernel::convert(*it, pnt); -// std::cout << *pnt << std::endl; polygon->push_back(*pnt); } // A loop should consist of at least three vertices - int original_count = polygon->size(); + std::size_t original_count = polygon->size(); if (original_count < 3) { Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity); return false; } -// // Remove points that are too close to one another + // TODO: Remove repeated points (and points that are too close to one another?) // remove_duplicate_points_from_loop(polygon, true); -// -// int count = polygon.Length(); -// if (original_count - count != 0) { -// std::stringstream ss; ss << (original_count - count) << " edges removed for:"; -// Logger::Message(Logger::LOG_WARNING, ss.str(), l->entity); -// } -// -// if (count < 3) { -// Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity); -// return false; -// } + + 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->entity); + } + + if (count < 3) { + Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity); + return false; + } result = polygon; return true; diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 377a2687fb..dc3cdbd9b7 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -44,12 +44,18 @@ if ( it != cache.T.end() ) { e = it->second; return true; } typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; -typedef CGAL::Polyhedron_3 *cgal_shape_t; -typedef std::vector *cgal_face_t; -typedef std::vector *cgal_wire_t; -typedef std::vector *cgal_curve_t; typedef Kernel::Aff_transformation_3 *cgal_placement_t; typedef Kernel::Point_3 *cgal_point_t; +typedef std::vector *cgal_curve_t; +typedef std::vector *cgal_wire_t; + +struct CgalFace { + cgal_wire_t outer; + std::vector inner; +}; + +typedef CgalFace *cgal_face_t; +typedef CGAL::Polyhedron_3 *cgal_shape_t; namespace IfcGeom { From 1525cf6bfc615571c0907effbdceb00dd04bd87a Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 2 Feb 2017 14:29:26 -0600 Subject: [PATCH 014/235] Polyhedra built with the incremental builder, IfcConvert crashes --- .../kernels/cgal/CgalEntityMapping.cpp | 45 +++++++++--------- src/ifcgeom/kernels/cgal/CgalKernel.h | 47 +++++++++++++++++++ 2 files changed, 69 insertions(+), 23 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp index 73232096a5..4509a8de7e 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp @@ -115,7 +115,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, Conv bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_shape_t& shape) { IfcSchema::IfcFace::list::ptr faces = l->CfsFaces(); -// TopTools_ListOfShape face_list; + std::list face_list; for (IfcSchema::IfcFace::list::it it = faces->begin(); it != faces->end(); ++it) { bool success = false; cgal_face_t face; @@ -128,30 +128,29 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_ Logger::Message(Logger::LOG_WARNING, "Failed to convert face:", (*it)->entity); continue; } - -// if (face_area(face) > getValue(GV_MINIMAL_FACE_AREA)) { -// face_list.Append(face); -// } else { -// Logger::Message(Logger::LOG_WARNING, "Invalid face:", (*it)->entity); -// } + + face_list.push_back(face); } -// -// if (face_list.Extent() == 0) { -// return false; -// } -// -// if (face_list.Extent() > getValue(GV_MAX_FACES_TO_SEW) || !create_solid_from_faces(face_list, shape)) { -// TopoDS_Compound compound; -// BRep_Builder builder; -// builder.MakeCompound(compound); -// -// TopTools_ListIteratorOfListOfShape face_iterator; -// for (face_iterator.Initialize(face_list); face_iterator.More(); face_iterator.Next()) { -// builder.Add(compound, face_iterator.Value()); -// } -// shape = compound; -// } + for (auto const &face : face_list) { + std::cout << "Face" << std::endl; + std::cout << "\touter: "; + for (auto const &point: *face->outer) { + std::cout << "(" << point << ") "; + } std::cout << std::endl; + for (auto const &inner: face->inner) { + std::cout << "\tinner: "; + for (auto const &point: *inner) { + std::cout << "(" << point << ") "; + } std::cout << std::endl; + } + } + + cgal_shape_t polyhedron = new CGAL::Polyhedron_3(); + PolyhedronBuilder builder(&face_list); + polyhedron->delegate(builder); + + shape = polyhedron; return true; } diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index dc3cdbd9b7..b32435793d 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -57,6 +57,53 @@ struct CgalFace { typedef CgalFace *cgal_face_t; typedef CGAL::Polyhedron_3 *cgal_shape_t; +struct PolyhedronBuilder : public CGAL::Modifier_base::HalfedgeDS> { +private: + std::list *face_list; +public: + PolyhedronBuilder(std::list *face_list) { + this->face_list = face_list; + } + + void operator()(CGAL::Polyhedron_3::HalfedgeDS &hds) { + std::map points_map; + std::list> facet_vertices; + CGAL::Polyhedron_incremental_builder_3::HalfedgeDS> builder(hds, true); + + for (auto const &face: *face_list) { + facet_vertices.push_back(std::list()); + for (auto const &point: *face->outer) { + if (points_map.count(point) == 0) { + facet_vertices.back().push_back(points_map.size()); + points_map[point] = points_map.size(); + } else { + facet_vertices.back().push_back(points_map[point]); + } + } + } + + builder.begin_surface(points_map.size(), facet_vertices.size()); + + for (auto const &point: points_map) { + std::cout << "Adding point " << point.first << std::endl; + builder.add_vertex(point.first); + } + + for (auto const &facet: facet_vertices) { + builder.begin_facet(); + std::cout << "Adding facet "; + for (auto const &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 { From 6b47e9ca1d18df4b1cd2c66e488ad91f9730ecdf Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sat, 4 Feb 2017 16:38:57 +0100 Subject: [PATCH 015/235] Add GMP MPFR and CGAL include/libs to cmake and build script --- cmake/CMakeLists.txt | 65 +++++++++++++++++++++++++++++++++++++++++--- nix/build-all.py | 10 ++++++- 2 files changed, 70 insertions(+), 5 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 4084d02f24..63c8712908 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -88,6 +88,12 @@ UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_INCLUDE_DIR) UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_LIBRARY_DIR) UNIFY_ENVVARS_AND_CACHE(PCRE_LIBRARY_DIR) UNIFY_ENVVARS_AND_CACHE(PYTHON_EXECUTABLE) +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) IF(WIN32) UNIFY_ENVVARS_AND_CACHE(THREEDS_MAX_SDK_HOME) ENDIF() @@ -193,6 +199,48 @@ foreach(lib ${OPENCASCADE_LIBRARY_NAMES}) list(APPEND OPENCASCADE_LIBRARIES "${lib_path}") endforeach() +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") +ELSE() + MESSAGE(FATAL_ERROR "Unable to find CGAL library files, aborting") +ENDIF() +foreach(lib ${CGAL_LIBRARY_NAMES}) + string(REPLACE libCGAL "${lib}" lib_path "${libCGAL}") + list(APPEND CGAL_LIBRARIES "${lib_path}") +endforeach() +FIND_LIBRARY(libGMP NAMES gmp 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 "${libGMP}") +list(APPEND CGAL_LIBRARIES "${libMPFR}") + + + + if(MSVC) add_definitions(-DHAVE_NO_DLL) add_debug_variants(OPENCASCADE_LIBRARIES "${OPENCASCADE_LIBRARIES}" d) @@ -384,7 +432,8 @@ ElSE() ENDIF() INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS} - ${ICU_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} + ${ICU_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ${CGAL_INCLUDE_DIR} + ${GMP_INCLUDE_DIR} ${MPFR_INCLUDE_DIR} ) function(files_for_ifc_version IFC_VERSION RESULT_NAME) @@ -517,6 +566,14 @@ if(NOT MSVC) endif() endif() +include(CheckCXXCompilerFlag) +CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) +if(COMPILER_SUPPORTS_CXX11) + add_definitions(-std=c++11) +else() + message(FATAL_ERROR "CGAL kernel requires a compiler with C++11 support") +endif() + set(IFCOPENSHELL_LIBRARIES IfcParse IfcGeom) # IfcParse @@ -548,7 +605,7 @@ set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES}) add_library(IfcGeom ${IFCGEOM_FILES}) set_target_properties(IfcGeom PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS) -TARGET_LINK_LIBRARIES(IfcGeom IfcParse ${OPENCASCADE_LIBRARIES}) +TARGET_LINK_LIBRARIES(IfcGeom IfcParse ${OPENCASCADE_LIBRARIES} ${CGAL_LIBRARIES}) # IfcConvert file(GLOB IFCCONVERT_CPP_FILES ../src/ifcconvert/*.cpp) @@ -559,7 +616,7 @@ if (IFCCONVERT_DOUBLE_PRECISION) set_target_properties(IfcConvert PROPERTIES COMPILE_FLAGS -DIFCCONVERT_DOUBLE_PRECISION) endif() -TARGET_LINK_LIBRARIES(IfcConvert ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES} ${ICU_LIBRARIES}) +TARGET_LINK_LIBRARIES(IfcConvert ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCOLLADA_LIBRARIES} ${ICU_LIBRARIES} ${CGAL_LIBRARIES} ${Boost_LIBRARIES}) if ((NOT WIN32) AND BUILD_SHARED_LIBS) # Only set RPATHs when building shared libraries (i.e. IfcParse and # IfcGeom are dynamically linked). Not necessarily a perfect solution @@ -572,7 +629,7 @@ endif() # file(GLOB H_FILES ../src/ifcgeomserver/*.h) # set(SOURCE_FILES ${CPP_FILES} ${H_FILES}) # ADD_EXECUTABLE(IfcGeomServer ${SOURCE_FILES}) -# TARGET_LINK_LIBRARIES(IfcGeomServer ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${ICU_LIBRARIES}) +# TARGET_LINK_LIBRARIES(IfcGeomServer ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${ICU_LIBRARIES} ${CGAL_LIBRARIES}) # if ((NOT WIN32) AND BUILD_SHARED_LIBS) # SET_INSTALL_RPATHS(IfcGeomServer "${IFCOPENSHELL_LIBARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS};${ICU_LIBRARY_DIR}") # endif() diff --git a/nix/build-all.py b/nix/build-all.py index 9fd36bd27d..277b89f439 100644 --- a/nix/build-all.py +++ b/nix/build-all.py @@ -460,7 +460,7 @@ 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", 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/" % (DEPS_DIR,)], download_url="https://github.com/CGAL/cgal.git", download_name="cgal", download_tool=download_tool_git) +build_dependency(name="cgal", mode="cmake", build_tool_args=["-DBUILD_SHARED_LIBS=Off", "-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/" % (DEPS_DIR,)], download_url="https://github.com/CGAL/cgal.git", download_name="cgal", download_tool=download_tool_git) BUILD_CFG = OLD_BUILD_CFG build_dependency(name="icu-%s" % (ICU_VERSION,), mode="icu", build_tool_args=["--enable-static", "--disable-shared"], download_url="http://download.icu-project.org/files/icu4c/%s/" % (ICU_VERSION,), download_name="icu4c-%s-src.tgz" % (ICU_VERSION_UNDERSCORE,)) @@ -482,6 +482,14 @@ run_cmake("", cmake_args=[ "-DBOOST_ROOT=" "%s/install/boost-%s" % (DEPS_DIR, BOOST_VERSION), "-DOCC_INCLUDE_DIR=" "%s/install/oce-%s/include/oce" % (DEPS_DIR, OCE_VERSION), "-DOCC_LIBRARY_DIR=" "%s/install/oce-%s/lib" % (DEPS_DIR, OCE_VERSION), + + "-DCGAL_INCLUDE_DIR=" "%s/install/cgal/include" % (DEPS_DIR,), + "-DCGAL_LIBRARY_DIR=" "%s/install/cgal/lib" % (DEPS_DIR,), + "-DGMP_INCLUDE_DIR=" "%s/install/gmp-%s/include" % (DEPS_DIR, GMP_VERSION), + "-DGMP_LIBRARY_DIR=" "%s/install/gmp-%s/lib" % (DEPS_DIR, GMP_VERSION), + "-DMPFR_INCLUDE_DIR=" "%s/install/mpfr-%s/include" % (DEPS_DIR, MPFR_VERSION), + "-DMPFR_LIBRARY_DIR=" "%s/install/mpfr-%s/lib" % (DEPS_DIR, MPFR_VERSION), + "-DOPENCOLLADA_INCLUDE_DIR=" "%s/install/OpenCOLLADA/include/opencollada" % (DEPS_DIR,), "-DOPENCOLLADA_LIBRARY_DIR=" "%s/install/OpenCOLLADA/lib/opencollada" % (DEPS_DIR,), "-DICU_INCLUDE_DIR=" "%s/install/icu-%s/include" % (DEPS_DIR, ICU_VERSION), From 6aff3d0f3d1f1fb76ada0505cbc0af0bf2474753 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 6 Feb 2017 16:22:36 -0600 Subject: [PATCH 016/235] Conversion result for breps --- .../kernels/cgal/CgalEntityMapping.cpp | 60 +++++++++---------- src/ifcgeom/kernels/cgal/CgalKernel.h | 8 +-- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp index 4509a8de7e..dea961cf7c 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp @@ -85,29 +85,29 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, Conv cgal_shape_t s; const SurfaceStyle* collective_style = get_style(l); if (convert_shape(l->Outer(),s) ) { -// const SurfaceStyle* indiv_style = get_style(l->Outer()); -// -// IfcSchema::IfcClosedShell::list::ptr voids(new IfcSchema::IfcClosedShell::list); -// if (l->is(IfcSchema::Type::IfcFacetedBrepWithVoids)) { -// voids = l->as()->Voids(); -// } -//#ifdef USE_IFC4 -// if (l->is(IfcSchema::Type::IfcAdvancedBrepWithVoids)) { -// voids = l->as()->Voids(); -// } -//#endif -// -// for (IfcSchema::IfcClosedShell::list::it it = voids->begin(); it != voids->end(); ++it) { + const SurfaceStyle* indiv_style = get_style(l->Outer()); + + IfcSchema::IfcClosedShell::list::ptr voids(new IfcSchema::IfcClosedShell::list); + if (l->is(IfcSchema::Type::IfcFacetedBrepWithVoids)) { + voids = l->as()->Voids(); + } +#ifdef USE_IFC4 + if (l->is(IfcSchema::Type::IfcAdvancedBrepWithVoids)) { + voids = l->as()->Voids(); + } +#endif + + for (IfcSchema::IfcClosedShell::list::it it = voids->begin(); it != voids->end(); ++it) { // TopoDS_Shape s2; // /// @todo No extensive shapefixing since shells should be disjoint. // /// @todo Awaiting generalized boolean ops module with appropriate checking // if (convert_shape(l->Outer(), s2)) { // s = BRepAlgoAPI_Cut(s, s2).Shape(); // } -// } -// -// shape.push_back(ConversionResult(new OpenCascadeShape(s), indiv_style ? indiv_style : collective_style)); -// return true; + } + + shape.push_back(ConversionResult(new CgalShape(s), indiv_style ? indiv_style : collective_style)); + return true; } return false; } @@ -132,19 +132,19 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_ face_list.push_back(face); } - for (auto const &face : face_list) { - std::cout << "Face" << std::endl; - std::cout << "\touter: "; - for (auto const &point: *face->outer) { - std::cout << "(" << point << ") "; - } std::cout << std::endl; - for (auto const &inner: face->inner) { - std::cout << "\tinner: "; - for (auto const &point: *inner) { - std::cout << "(" << point << ") "; - } std::cout << std::endl; - } - } +// for (auto const &face : face_list) { +// std::cout << "Face" << std::endl; +// std::cout << "\touter: "; +// for (auto const &point: *face->outer) { +// std::cout << "(" << point << ") "; +// } std::cout << std::endl; +// for (auto const &inner: face->inner) { +// std::cout << "\tinner: "; +// for (auto const &point: *inner) { +// std::cout << "(" << point << ") "; +// } std::cout << std::endl; +// } +// } cgal_shape_t polyhedron = new CGAL::Polyhedron_3(); PolyhedronBuilder builder(&face_list); diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index b32435793d..b6a042770d 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -85,18 +85,18 @@ public: builder.begin_surface(points_map.size(), facet_vertices.size()); for (auto const &point: points_map) { - std::cout << "Adding point " << point.first << std::endl; +// std::cout << "Adding point " << point.first << std::endl; builder.add_vertex(point.first); } for (auto const &facet: facet_vertices) { builder.begin_facet(); - std::cout << "Adding facet "; +// std::cout << "Adding facet "; for (auto const &vertex: facet) { - std::cout << vertex << " "; +// std::cout << vertex << " "; builder.add_vertex_to_facet(vertex); } - std::cout << std::endl; +// std::cout << std::endl; builder.end_facet(); } From e1702fc0cf12efd43118d434c7d0898287ad6994 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 6 Feb 2017 16:22:54 -0600 Subject: [PATCH 017/235] =?UTF-8?q?Return=20value=20for=20transformation,?= =?UTF-8?q?=20still=20needs=20to=20be=20initialised=20somewhere=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ifcgeom/kernels/cgal/CgalConversionResult.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.h b/src/ifcgeom/kernels/cgal/CgalConversionResult.h index 3fb4bb7e67..92c80dc32a 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.h +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.h @@ -35,7 +35,7 @@ namespace IfcGeom { virtual double Value(int i, int j) const { // Get cell from placement as 4x3 matrix as implemented in OCCT. We'll have to check exact semantics. - throw std::runtime_error("Not implemented"); + return CGAL::to_double(trsf_->cartesian(i, j)); } virtual void Multiply(const ConversionResultPlacement* other) { // Multiply matrix as implemented in OCCT. We'll have to check exact semantics. From bae84b675383655ee10f2afd8dec6c1fa59a3479 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 7 Feb 2017 19:50:51 -0600 Subject: [PATCH 018/235] Directions as CGAL Vector_3, more robust points --- .../kernels/cgal/CgalConversionFunctions.cpp | 15 ++++++++++++++- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + src/ifcgeom/kernels/cgal/CgalKernel.h | 1 + 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 93947879ea..9e66c5def6 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -30,9 +30,22 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid*, cgal_s bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_point_t& point) { std::vector xyz = l->Coordinates(); if (xyz.size() == 3) { - point = new Kernel::Point_3(xyz[0], xyz[1], xyz[2]); + point = new 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); return true; } else { throw std::runtime_error("Point without 3 coordinates"); } } + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcDirection* l, cgal_direction_t& dir) { +// IN_CACHE(IfcDirection,l,cgal_direction_t,dir) + std::vector xyz = l->DirectionRatios(); + dir = new 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; +} + diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index e720796002..d8e39626d2 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -43,3 +43,4 @@ FACE(IfcFace); WIRE(IfcPolyLoop); CLASS(IfcCartesianPoint,cgal_point_t); +CLASS(IfcDirection,cgal_direction_t); diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index b6a042770d..638344c7d8 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -46,6 +46,7 @@ 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 std::vector *cgal_curve_t; typedef std::vector *cgal_wire_t; From 96e9c8ecc160d26138c1bd13a428e8b146b8ced4 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 7 Feb 2017 19:51:16 -0600 Subject: [PATCH 019/235] Skeleton for IfcObjectPlacement and IfcAxis2Placement3D --- .../kernels/cgal/CgalConversionFunctions.cpp | 43 +++++++++++++++++++ src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 3 ++ src/ifcgeom/kernels/cgal/CgalKernel.cpp | 4 +- 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 9e66c5def6..3320c606e0 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -49,3 +49,46 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcDirection* l, cgal_directi 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 = new Kernel::Vector_3(0,0,1);cgal_direction_t refDirection; +// IfcGeom::OpenCascadeKernel::convert(l->Location(),o); +// bool hasRef = l->hasRefDirection(); +// if ( l->hasAxis() ) IfcGeom::OpenCascadeKernel::convert(l->Axis(),axis); +// if ( hasRef ) IfcGeom::OpenCascadeKernel::convert(l->RefDirection(),refDirection); +// gp_Ax3 ax3; +// if ( hasRef ) ax3 = gp_Ax3(o,axis,refDirection); +// else ax3 = gp_Ax3(o,axis); +// +// if (!axis_equal(ax3, (gp_Ax3) gp::XOY(), getValue(GV_PRECISION))) { +// trsf.SetTransformation(ax3, gp::XOY()); +// } +// +// CACHE(IfcAxis2Placement3D,l,trsf) + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_placement_t& trsf) { +// IN_CACHE(IfcObjectPlacement,l,cgal_placement_t,trsf) + if ( ! l->is(IfcSchema::Type::IfcLocalPlacement) ) { + Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l->entity); + return false; + } + IfcSchema::IfcLocalPlacement* current = (IfcSchema::IfcLocalPlacement*)l; + for (;;) { + cgal_placement_t trsf2; + IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement(); + if ( relplacement->is(IfcSchema::Type::IfcAxis2Placement3D) ) { + IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2); + *trsf = *trsf * *trsf2; // TODO: Or should it be the other way around? + } + if ( current->hasPlacementRelTo() ) { + IfcSchema::IfcObjectPlacement* relto = current->PlacementRelTo(); + if ( relto->is(IfcSchema::Type::IfcLocalPlacement) ) + current = (IfcSchema::IfcLocalPlacement*)current->PlacementRelTo(); + else break; + } else break; + } +// CACHE(IfcObjectPlacement,l,trsf) + return true; +} diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index d8e39626d2..a3c68c56ea 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -44,3 +44,6 @@ WIRE(IfcPolyLoop); CLASS(IfcCartesianPoint,cgal_point_t); CLASS(IfcDirection,cgal_direction_t); +//CLASS(IfcAxis2Placement2D,cgal_placement_t); +CLASS(IfcAxis2Placement3D,cgal_placement_t); +CLASS(IfcObjectPlacement,cgal_placement_t); diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index f4f830cbee..73f9bd761e 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -94,7 +94,7 @@ IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representat cgal_placement_t trsf; try { - // convert(product->ObjectPlacement(), trsf); + convert(product->ObjectPlacement(), trsf); } catch (...) {} // Does the IfcElement have any IfcOpenings? @@ -146,7 +146,7 @@ IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_processed_r cgal_placement_t trsf; try { - // convert(product->ObjectPlacement(), trsf); + convert(product->ObjectPlacement(), trsf); } catch (...) {} std::string context_string = ""; From 42b512960b32c39427ed4c395b5688e216625bce Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 7 Feb 2017 20:25:04 -0600 Subject: [PATCH 020/235] Filling in most of the placement code. To check. --- .../kernels/cgal/CgalConversionFunctions.cpp | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 3320c606e0..94f694dcdd 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -51,24 +51,25 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcDirection* l, cgal_directi 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 = new Kernel::Vector_3(0,0,1);cgal_direction_t refDirection; -// IfcGeom::OpenCascadeKernel::convert(l->Location(),o); -// bool hasRef = l->hasRefDirection(); -// if ( l->hasAxis() ) IfcGeom::OpenCascadeKernel::convert(l->Axis(),axis); -// if ( hasRef ) IfcGeom::OpenCascadeKernel::convert(l->RefDirection(),refDirection); -// gp_Ax3 ax3; -// if ( hasRef ) ax3 = gp_Ax3(o,axis,refDirection); -// else ax3 = gp_Ax3(o,axis); -// -// if (!axis_equal(ax3, (gp_Ax3) gp::XOY(), getValue(GV_PRECISION))) { -// trsf.SetTransformation(ax3, gp::XOY()); -// } -// + cgal_point_t o; + cgal_direction_t axis = new Kernel::Vector_3(0,0,1); + cgal_direction_t refDirection = new Kernel::Vector_3(1,0,0); // TODO: Put identity for now. Check? + 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); + + // TODO: From Thomas' email. Should be checked. + trsf = new Kernel::Aff_transformation_3(refDirection->cartesian(0), axis->cartesian(0)*refDirection->cartesian(0), axis->cartesian(0), o->cartesian(0), + refDirection->cartesian(1), axis->cartesian(1)*refDirection->cartesian(1), axis->cartesian(1), o->cartesian(1), + refDirection->cartesian(2), axis->cartesian(2)*refDirection->cartesian(2), axis->cartesian(2), o->cartesian(2)); + // CACHE(IfcAxis2Placement3D,l,trsf) return true; } bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_placement_t& trsf) { + // TODO: These macros don't work for the CGAL types. Need to check why. // IN_CACHE(IfcObjectPlacement,l,cgal_placement_t,trsf) if ( ! l->is(IfcSchema::Type::IfcLocalPlacement) ) { Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l->entity); @@ -80,7 +81,13 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_p IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement(); if ( relplacement->is(IfcSchema::Type::IfcAxis2Placement3D) ) { IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2); - *trsf = *trsf * *trsf2; // TODO: Or should it be the other way around? + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + std::cout << "trsf " << trsf->m(i, j) << std::endl; + } + } +// std::cout << "trsf2" << trsf2 << std::endl; + *trsf = *trsf * *trsf2; // TODO: I think it's fine, but maybe should it be the other way around? } if ( current->hasPlacementRelTo() ) { IfcSchema::IfcObjectPlacement* relto = current->PlacementRelTo(); From 2894b0cb92f45d332ac013f8d68a5136fc4fb541 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 7 Feb 2017 20:37:47 -0600 Subject: [PATCH 021/235] =?UTF-8?q?Nothing=20is=20a=20pointer=20now.=20Ini?= =?UTF-8?q?tialisation=20is=20easier=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kernels/cgal/CgalConversionFunctions.cpp | 30 ++++++++----------- .../kernels/cgal/CgalConversionResult.h | 4 +-- .../kernels/cgal/CgalEntityMapping.cpp | 19 ++++++------ src/ifcgeom/kernels/cgal/CgalKernel.h | 17 +++++------ 4 files changed, 31 insertions(+), 39 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 94f694dcdd..10b2bc49ec 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -30,9 +30,9 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid*, cgal_s bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_point_t& point) { std::vector xyz = l->Coordinates(); if (xyz.size() == 3) { - point = new 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); + 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); return true; } else { throw std::runtime_error("Point without 3 coordinates"); @@ -42,9 +42,9 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_po bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcDirection* l, cgal_direction_t& dir) { // IN_CACHE(IfcDirection,l,cgal_direction_t,dir) std::vector xyz = l->DirectionRatios(); - dir = new Kernel::Vector_3(xyz.size() ? xyz[0] : 0.0f, - xyz.size() > 1 ? xyz[1] : 0.0f, - xyz.size() > 2 ? xyz[2] : 0.0f); + 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; } @@ -52,17 +52,17 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcDirection* l, cgal_directi 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 = new Kernel::Vector_3(0,0,1); - cgal_direction_t refDirection = new Kernel::Vector_3(1,0,0); // TODO: Put identity for now. Check? + cgal_direction_t axis = Kernel::Vector_3(0,0,1); + cgal_direction_t refDirection = Kernel::Vector_3(1,0,0); // TODO: Put identity for now. Check? 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); // TODO: From Thomas' email. Should be checked. - trsf = new Kernel::Aff_transformation_3(refDirection->cartesian(0), axis->cartesian(0)*refDirection->cartesian(0), axis->cartesian(0), o->cartesian(0), - refDirection->cartesian(1), axis->cartesian(1)*refDirection->cartesian(1), axis->cartesian(1), o->cartesian(1), - refDirection->cartesian(2), axis->cartesian(2)*refDirection->cartesian(2), axis->cartesian(2), o->cartesian(2)); + trsf = Kernel::Aff_transformation_3(refDirection.cartesian(0), axis.cartesian(0)*refDirection.cartesian(0), axis.cartesian(0), o.cartesian(0), + refDirection.cartesian(1), axis.cartesian(1)*refDirection.cartesian(1), axis.cartesian(1), o.cartesian(1), + refDirection.cartesian(2), axis.cartesian(2)*refDirection.cartesian(2), axis.cartesian(2), o.cartesian(2)); // CACHE(IfcAxis2Placement3D,l,trsf) return true; @@ -81,13 +81,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_p IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement(); if ( relplacement->is(IfcSchema::Type::IfcAxis2Placement3D) ) { IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2); - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) { - std::cout << "trsf " << trsf->m(i, j) << std::endl; - } - } -// std::cout << "trsf2" << trsf2 << std::endl; - *trsf = *trsf * *trsf2; // TODO: I think it's fine, but maybe should it be the other way around? + trsf = trsf * trsf2; // TODO: I think it's fine, but maybe should it be the other way around? } if ( current->hasPlacementRelTo() ) { IfcSchema::IfcObjectPlacement* relto = current->PlacementRelTo(); diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.h b/src/ifcgeom/kernels/cgal/CgalConversionResult.h index 92c80dc32a..b20c8c8858 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.h +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.h @@ -35,7 +35,7 @@ namespace IfcGeom { virtual double Value(int i, int j) const { // Get cell from placement as 4x3 matrix as implemented in OCCT. We'll have to check exact semantics. - return CGAL::to_double(trsf_->cartesian(i, j)); + return CGAL::to_double(trsf_.cartesian(i, j)); } virtual void Multiply(const ConversionResultPlacement* other) { // Multiply matrix as implemented in OCCT. We'll have to check exact semantics. @@ -74,4 +74,4 @@ namespace IfcGeom { } -#endif \ No newline at end of file +#endif diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp index dea961cf7c..6366590c8d 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp @@ -146,9 +146,9 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_ // } // } - cgal_shape_t polyhedron = new CGAL::Polyhedron_3(); + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); PolyhedronBuilder builder(&face_list); - polyhedron->delegate(builder); + polyhedron.delegate(builder); shape = polyhedron; return true; @@ -181,7 +181,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcFace* l, cgal_face_t& face return false; } - cgal_face_t mf = new CgalFace(); + cgal_face_t mf; for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) { IfcSchema::IfcFaceBound* bound = *it; @@ -192,14 +192,13 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcFace* l, cgal_face_t& face cgal_wire_t wire; if (!convert_wire(loop, wire)) { Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop->entity); - delete mf; return false; } if (!is_interior) { - mf->outer = wire; + mf.outer = wire; } else { - mf->inner.push_back(wire); + mf.inner.push_back(wire); } } @@ -211,15 +210,15 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& IfcSchema::IfcCartesianPoint::list::ptr points = l->Polygon(); // Parse and store the points in a sequence - cgal_wire_t polygon = new std::vector(); + cgal_wire_t polygon = std::vector(); 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); + polygon.push_back(pnt); } // A loop should consist of at least three vertices - std::size_t original_count = polygon->size(); + std::size_t original_count = polygon.size(); if (original_count < 3) { Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity); return false; @@ -228,7 +227,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& // TODO: Remove repeated points (and points that are too close to one another?) // remove_duplicate_points_from_loop(polygon, true); - std::size_t count = polygon->size(); + 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->entity); diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 638344c7d8..48d7aea233 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -44,19 +44,18 @@ if ( it != cache.T.end() ) { e = it->second; return true; } 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 std::vector *cgal_curve_t; -typedef std::vector *cgal_wire_t; +typedef Kernel::Aff_transformation_3 cgal_placement_t; +typedef Kernel::Point_3 cgal_point_t; +typedef Kernel::Vector_3 cgal_direction_t; +typedef std::vector cgal_curve_t; +typedef std::vector cgal_wire_t; -struct CgalFace { +struct cgal_face_t { cgal_wire_t outer; std::vector inner; }; -typedef CgalFace *cgal_face_t; -typedef CGAL::Polyhedron_3 *cgal_shape_t; +typedef CGAL::Polyhedron_3 cgal_shape_t; struct PolyhedronBuilder : public CGAL::Modifier_base::HalfedgeDS> { private: @@ -73,7 +72,7 @@ public: for (auto const &face: *face_list) { facet_vertices.push_back(std::list()); - for (auto const &point: *face->outer) { + for (auto const &point: face.outer) { if (points_map.count(point) == 0) { facet_vertices.back().push_back(points_map.size()); points_map[point] = points_map.size(); From 7051104bc7f564e35da81f134079fa48ac925865 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 8 Feb 2017 16:12:19 -0600 Subject: [PATCH 022/235] Basic code to output triangulation, something goes wrong when getting materials... --- .../kernels/cgal/CgalConversionResult.cpp | 179 +++++++++++++++++- .../kernels/cgal/CgalEntityMapping.cpp | 14 -- src/ifcgeom/kernels/cgal/CgalKernel.h | 16 +- 3 files changed, 189 insertions(+), 20 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index e2da8ecd97..81fd474622 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -2,5 +2,182 @@ #include "CgalConversionResult.h" void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const { - throw std::runtime_error("Not implemented Triangulate()"); + cgal_shape_t s = shape_; + const cgal_placement_t& trsf = dynamic_cast(place)->trsf(); + + // Triangulate the shape and compute the normals + std::map vertex_normals; + boost::associative_property_map> vertex_normals_map(vertex_normals); + std::map face_normals; + boost::associative_property_map> face_normals_map(face_normals); + try { + CGAL::Polygon_mesh_processing::triangulate_faces(s); + CGAL::Polygon_mesh_processing::compute_normals(s, vertex_normals_map, face_normals_map); + } 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, num_vertices = 0; +// TopExp_Explorer exp; + for (auto &face: faces(s)) { + CGAL::Polyhedron_3::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))); + for (int i = 0; i < 3; ++i) t->normals().push_back(CGAL::to_double(face_normals_map[face].cartesian(i))); + t->faces().push_back(num_vertices); + ++num_vertices; + ++current_halfedge; + } while (current_halfedge != face->facet_begin()); + t->material_ids().push_back(surface_style_id); + ++num_faces; + +// 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, int> edgecount; +// std::vector > edges_temp; +// +// const TColgp_Array1OfPnt& nodes = tri->Nodes(); +// const TColgp_Array1OfPnt2d& uvs = tri->UVNodes(); +// std::vector coords; +// BRepGProp_Face prop(face); +// std::map 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()); +// 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() > ALMOST_ZERO) { +// normal = gp_Dir(normal_direction.XYZ() * rotation_matrix); +// } +// t->normals().push_back(static_cast(normal.X())); +// t->normals().push_back(static_cast(normal.Y())); +// t->normals().push_back(static_cast(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); +// +// t->faces().push_back(dict[n1]); +// t->faces().push_back(dict[n2]); +// t->faces().push_back(dict[n3]); +// +// t->material_ids().push_back(surface_style_id); +// +// 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 >::const_iterator jt = edges_temp.begin(); jt != edges_temp.end(); ++jt) { +// if (edgecount[*jt] == 1) { +// // non manifold edge, face boundary +// t->edges().push_back(jt->first); +// t->edges().push_back(jt->second); +// } +// } +// } + } +// +// 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

(p2.X())); +// _verts.push_back(static_cast

(p2.Y())); +// _verts.push_back(static_cast

(p2.Z())); +// _verts.push_back(static_cast

(p3.X())); +// _verts.push_back(static_cast

(p3.Y())); +// _verts.push_back(static_cast

(p3.Z())); +// */ +// +// trsf.Transforms(p); +// +// t->material_ids().push_back(surface_style_id); +// +// t->verts().push_back(static_cast(p.X())); +// t->verts().push_back(static_cast(p.Y())); +// t->verts().push_back(static_cast(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); } diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp index 6366590c8d..996926c978 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp @@ -132,20 +132,6 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_ face_list.push_back(face); } -// for (auto const &face : face_list) { -// std::cout << "Face" << std::endl; -// std::cout << "\touter: "; -// for (auto const &point: *face->outer) { -// std::cout << "(" << point << ") "; -// } std::cout << std::endl; -// for (auto const &inner: face->inner) { -// std::cout << "\tinner: "; -// for (auto const &point: *inner) { -// std::cout << "(" << point << ") "; -// } std::cout << std::endl; -// } -// } - cgal_shape_t polyhedron = CGAL::Polyhedron_3(); PolyhedronBuilder builder(&face_list); polyhedron.delegate(builder); diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 48d7aea233..596fcacf4e 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -39,8 +39,12 @@ if ( it != cache.T.end() ) { e = it->second; return true; } #undef Handle +#include #include #include +#include +#include +#include typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; @@ -56,6 +60,8 @@ struct cgal_face_t { }; typedef CGAL::Polyhedron_3 cgal_shape_t; +typedef boost::graph_traits>::vertex_descriptor cgal_vertex_descriptor_t; +typedef boost::graph_traits>::face_descriptor cgal_face_descriptor_t; struct PolyhedronBuilder : public CGAL::Modifier_base::HalfedgeDS> { private: @@ -70,9 +76,9 @@ public: std::list> facet_vertices; CGAL::Polyhedron_incremental_builder_3::HalfedgeDS> builder(hds, true); - for (auto const &face: *face_list) { + for (auto &face: *face_list) { facet_vertices.push_back(std::list()); - for (auto const &point: face.outer) { + for (auto &point: face.outer) { if (points_map.count(point) == 0) { facet_vertices.back().push_back(points_map.size()); points_map[point] = points_map.size(); @@ -84,15 +90,15 @@ public: builder.begin_surface(points_map.size(), facet_vertices.size()); - for (auto const &point: points_map) { + for (auto &point: points_map) { // std::cout << "Adding point " << point.first << std::endl; builder.add_vertex(point.first); } - for (auto const &facet: facet_vertices) { + for (auto &facet: facet_vertices) { builder.begin_facet(); // std::cout << "Adding facet "; - for (auto const &vertex: facet) { + for (auto &vertex: facet) { // std::cout << vertex << " "; builder.add_vertex_to_facet(vertex); } From 1755752ab75860679dab3f022e43f6e64e1dd4b9 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 8 Feb 2017 16:56:59 -0600 Subject: [PATCH 023/235] IfcAxis2Placement2D --- .../kernels/cgal/CgalConversionFunctions.cpp | 26 ++- .../kernels/cgal/CgalConversionResult.cpp | 151 +----------------- .../kernels/cgal/CgalConversionResult.h | 10 +- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 2 +- 4 files changed, 37 insertions(+), 152 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 10b2bc49ec..1a488a274a 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -49,6 +49,25 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcDirection* l, cgal_directi 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 axis = Kernel::Vector_3(0,0,1); + cgal_direction_t refDirection = Kernel::Vector_3(1,0,0); // TODO: Put identity for now. Check? + IfcGeom::CgalKernel::convert(l->Location(),o); + bool hasRef = l->hasRefDirection(); + if ( hasRef ) IfcGeom::CgalKernel::convert(l->RefDirection(),refDirection); + + // TODO: From Thomas' email. Should be checked. + Kernel::Vector_3 y = CGAL::cross_product(Kernel::Vector_3(0.0, 0.0, 1.0), refDirection); + 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, y.cartesian(2), 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; @@ -60,9 +79,10 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement3D* l, cgal_ if ( hasRef ) IfcGeom::CgalKernel::convert(l->RefDirection(),refDirection); // TODO: From Thomas' email. Should be checked. - trsf = Kernel::Aff_transformation_3(refDirection.cartesian(0), axis.cartesian(0)*refDirection.cartesian(0), axis.cartesian(0), o.cartesian(0), - refDirection.cartesian(1), axis.cartesian(1)*refDirection.cartesian(1), axis.cartesian(1), o.cartesian(1), - refDirection.cartesian(2), axis.cartesian(2)*refDirection.cartesian(2), axis.cartesian(2), o.cartesian(2)); + Kernel::Vector_3 y = CGAL::cross_product(axis, refDirection); + trsf = Kernel::Aff_transformation_3(refDirection.cartesian(0), y.cartesian(0), axis.cartesian(0), o.cartesian(0), + refDirection.cartesian(1), y.cartesian(1), axis.cartesian(1), o.cartesian(1), + refDirection.cartesian(2), y.cartesian(2), axis.cartesian(2), o.cartesian(2)); // CACHE(IfcAxis2Placement3D,l,trsf) return true; diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index 81fd474622..529e692abb 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -5,6 +5,11 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, cgal_shape_t s = shape_; const cgal_placement_t& trsf = dynamic_cast(place)->trsf(); + // Apply transformation + for (auto &vertex: vertices(s)) { + vertex->point() = vertex->point().transform(trsf); + } + // Triangulate the shape and compute the normals std::map vertex_normals; boost::associative_property_map> vertex_normals_map(vertex_normals); @@ -23,7 +28,6 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, // Iterates over the faces of the shape int num_faces = 0, num_vertices = 0; -// TopExp_Explorer exp; for (auto &face: faces(s)) { CGAL::Polyhedron_3::Halfedge_around_facet_const_circulator current_halfedge = face->facet_begin(); do { @@ -32,152 +36,11 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, CGAL::to_double(current_halfedge->vertex()->point().cartesian(1)), CGAL::to_double(current_halfedge->vertex()->point().cartesian(2))); for (int i = 0; i < 3; ++i) t->normals().push_back(CGAL::to_double(face_normals_map[face].cartesian(i))); - t->faces().push_back(num_vertices); +// t->faces().push_back(num_vertices); ++num_vertices; ++current_halfedge; } while (current_halfedge != face->facet_begin()); - t->material_ids().push_back(surface_style_id); +// t->material_ids().push_back(surface_style_id); ++num_faces; - -// 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, int> edgecount; -// std::vector > edges_temp; -// -// const TColgp_Array1OfPnt& nodes = tri->Nodes(); -// const TColgp_Array1OfPnt2d& uvs = tri->UVNodes(); -// std::vector coords; -// BRepGProp_Face prop(face); -// std::map 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()); -// 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() > ALMOST_ZERO) { -// normal = gp_Dir(normal_direction.XYZ() * rotation_matrix); -// } -// t->normals().push_back(static_cast(normal.X())); -// t->normals().push_back(static_cast(normal.Y())); -// t->normals().push_back(static_cast(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); -// -// t->faces().push_back(dict[n1]); -// t->faces().push_back(dict[n2]); -// t->faces().push_back(dict[n3]); -// -// t->material_ids().push_back(surface_style_id); -// -// 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 >::const_iterator jt = edges_temp.begin(); jt != edges_temp.end(); ++jt) { -// if (edgecount[*jt] == 1) { -// // non manifold edge, face boundary -// t->edges().push_back(jt->first); -// t->edges().push_back(jt->second); -// } -// } -// } } -// -// 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

(p2.X())); -// _verts.push_back(static_cast

(p2.Y())); -// _verts.push_back(static_cast

(p2.Z())); -// _verts.push_back(static_cast

(p3.X())); -// _verts.push_back(static_cast

(p3.Y())); -// _verts.push_back(static_cast

(p3.Z())); -// */ -// -// trsf.Transforms(p); -// -// t->material_ids().push_back(surface_style_id); -// -// t->verts().push_back(static_cast(p.X())); -// t->verts().push_back(static_cast(p.Y())); -// t->verts().push_back(static_cast(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); } diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.h b/src/ifcgeom/kernels/cgal/CgalConversionResult.h index b20c8c8858..6a6e6157e8 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.h +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.h @@ -1,4 +1,4 @@ -/******************************************************************************** +/******************************************************************************** * * * This file is part of IfcOpenShell. * * * @@ -34,15 +34,17 @@ namespace IfcGeom { operator const cgal_placement_t& () { return trsf_; } virtual double Value(int i, int j) const { - // Get cell from placement as 4x3 matrix as implemented in OCCT. We'll have to check exact semantics. + // TODO: Check return CGAL::to_double(trsf_.cartesian(i, j)); } virtual void Multiply(const ConversionResultPlacement* other) { - // Multiply matrix as implemented in OCCT. We'll have to check exact semantics. + // TODO: Check + trsf_ = ((CgalPlacement *)other)->trsf_ * trsf_; throw std::runtime_error("Not implemented"); } virtual void PreMultiply(const ConversionResultPlacement* other) { - // PreMultiply matrix as implemented in OCCT. We'll have to check exact semantics. + // TODO: Check + trsf_ = trsf_ * ((CgalPlacement *)other)->trsf_; throw std::runtime_error("Not implemented"); } virtual ConversionResultPlacement* clone() const { diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index a3c68c56ea..ddfab3fc5a 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -44,6 +44,6 @@ WIRE(IfcPolyLoop); CLASS(IfcCartesianPoint,cgal_point_t); CLASS(IfcDirection,cgal_direction_t); -//CLASS(IfcAxis2Placement2D,cgal_placement_t); +CLASS(IfcAxis2Placement2D,cgal_placement_t); CLASS(IfcAxis2Placement3D,cgal_placement_t); CLASS(IfcObjectPlacement,cgal_placement_t); From 44634eb42dbef7ffe41504ae88529d04b691f7d3 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 8 Feb 2017 17:12:56 -0600 Subject: [PATCH 024/235] Remove implemented throws, add faces and materials --- src/ifcgeom/kernels/cgal/CgalConversionResult.cpp | 10 +++++----- src/ifcgeom/kernels/cgal/CgalConversionResult.h | 2 -- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index 529e692abb..7f16e43073 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -6,9 +6,9 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, const cgal_placement_t& trsf = dynamic_cast(place)->trsf(); // Apply transformation - for (auto &vertex: vertices(s)) { - vertex->point() = vertex->point().transform(trsf); - } +// for (auto &vertex: vertices(s)) { +// vertex->point() = vertex->point().transform(trsf); +// } // Triangulate the shape and compute the normals std::map vertex_normals; @@ -36,11 +36,11 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, CGAL::to_double(current_halfedge->vertex()->point().cartesian(1)), CGAL::to_double(current_halfedge->vertex()->point().cartesian(2))); for (int i = 0; i < 3; ++i) t->normals().push_back(CGAL::to_double(face_normals_map[face].cartesian(i))); -// t->faces().push_back(num_vertices); + t->faces().push_back(num_vertices); ++num_vertices; ++current_halfedge; } while (current_halfedge != face->facet_begin()); -// t->material_ids().push_back(surface_style_id); + t->material_ids().push_back(surface_style_id); ++num_faces; } } diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.h b/src/ifcgeom/kernels/cgal/CgalConversionResult.h index 6a6e6157e8..940a598b67 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.h +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.h @@ -40,12 +40,10 @@ namespace IfcGeom { virtual void Multiply(const ConversionResultPlacement* other) { // TODO: Check trsf_ = ((CgalPlacement *)other)->trsf_ * trsf_; - throw std::runtime_error("Not implemented"); } virtual void PreMultiply(const ConversionResultPlacement* other) { // TODO: Check trsf_ = trsf_ * ((CgalPlacement *)other)->trsf_; - throw std::runtime_error("Not implemented"); } virtual ConversionResultPlacement* clone() const { return new CgalPlacement(trsf_); From b463dfe88a3327bba89c31b32800ec2d68742db6 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 9 Feb 2017 14:46:02 -0600 Subject: [PATCH 025/235] Changed --kernel parameter to --opencascade. Was conflicting with positional options for input. --- src/ifcconvert/IfcConvert.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 5b9057a73b..b64e8b508f 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -202,7 +202,8 @@ int main(int argc, char** argv) { "Applies --include or --exclude also to the decomposition and/or containment (IsDecomposedBy, " "HasOpenings, FillsVoid, ContainedInStructure) of the filtered entity, e.g. " "--include --traverse --names \"Level 1\" includes entity with name \"Level 1\" and all of its children.") - ("kernel", "Geometry kernel to use ('opencascade' or 'cgal'). Defaults to 'cgal'."); +// ("kernel", "Geometry kernel to use ('opencascade' or 'cgal'). Defaults to 'cgal'.") + ("opencascade", "Use opencascade kernel rather than cgal."); std::string bounds; boost::program_options::options_description serializer_options("Serialization options"); @@ -286,10 +287,11 @@ int main(int argc, char** argv) { const bool traverse = vmap.count("traverse") != 0; const bool deflection_tolerance_specified = vmap.count("deflection-tolerance") != 0 ; - if (vmap.count("kernel") == 0) { - std::cerr << "Using default CGAL based kernel" << std::endl; - kernel = "cgal"; - } + if (vmap.count("opencascade") == 1) { + kernel = "opencascade"; + } else { + kernel = "cgal"; + } int bounding_width = -1, bounding_height = -1; if (vmap.count("bounds") == 1) { From f4274e4b465406e39c86b91fbbfe987a9d8ce97b Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 13 Feb 2017 11:12:04 -0600 Subject: [PATCH 026/235] Skeleton for IfcExtrudedAreaSolid --- .../kernels/cgal/CgalConversionFunctions.cpp | 80 ++++++++++++++++++- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + 2 files changed, 79 insertions(+), 2 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 1a488a274a..60404f6828 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -23,8 +23,57 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRepresentation* l, Convers return part_succes; } -bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid*, cgal_shape_t&) { - throw std::runtime_error("Not implemented IfcExtrudedAreaSolid"); +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->entity); + return false; + } + + cgal_face_t face; + if ( !convert_face(l->SweptArea(),face) ) 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); + + std::list face_list; + face_list.push_back(face); + + cgal_face_t top_face; + for (auto const &vertex: face.outer) { + top_face.outer.push_back(vertex+dir); + } face_list.push_back(top_face); + + for (std::vector::const_iterator current_vertex = face.outer.begin(); + current_vertex != face.outer.end(); + ++current_vertex) { + std::vector::const_iterator next_vertex = current_vertex; + ++next_vertex; + if (next_vertex == face.outer.end()) { + next_vertex = face.outer.begin(); + } cgal_face_t side_face; + side_face.outer.push_back(*current_vertex); + side_face.outer.push_back(*next_vertex); + side_face.outer.push_back(*next_vertex+dir); + side_face.outer.push_back(*current_vertex+dir); + face_list.push_back(side_face); + } + + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + PolyhedronBuilder builder(&face_list); + polyhedron.delegate(builder); + + shape = polyhedron; + return true; } bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_point_t& point) { @@ -113,3 +162,30 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_p // CACHE(IfcObjectPlacement,l,trsf) 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->entity); + return false; + } + + cgal_placement_t trsf2d; + bool has_position = true; +#ifdef USE_IFC4 + has_position = l->hasPosition(); +#endif + if (has_position) { + IfcGeom::CgalKernel::convert(l->Position(), trsf2d); + } + + 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)); + + return true; +} diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index ddfab3fc5a..b163696066 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -39,6 +39,7 @@ SHAPE(IfcExtrudedAreaSolid); SHAPE(IfcConnectedFaceSet); FACE(IfcFace); +FACE(IfcRectangleProfileDef); WIRE(IfcPolyLoop); From d9d5f17725ba0f848f79560533031a7b9181ce4c Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 13 Feb 2017 11:45:17 -0600 Subject: [PATCH 027/235] Should be working now --- .../kernels/cgal/CgalConversionFunctions.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 60404f6828..6919a9319f 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -48,11 +48,6 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal std::list face_list; face_list.push_back(face); - cgal_face_t top_face; - for (auto const &vertex: face.outer) { - top_face.outer.push_back(vertex+dir); - } face_list.push_back(top_face); - for (std::vector::const_iterator current_vertex = face.outer.begin(); current_vertex != face.outer.end(); ++current_vertex) { @@ -61,13 +56,20 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal if (next_vertex == face.outer.end()) { next_vertex = face.outer.begin(); } cgal_face_t side_face; - side_face.outer.push_back(*current_vertex); side_face.outer.push_back(*next_vertex); - side_face.outer.push_back(*next_vertex+dir); + side_face.outer.push_back(*current_vertex); side_face.outer.push_back(*current_vertex+dir); + side_face.outer.push_back(*next_vertex+dir); face_list.push_back(side_face); } + cgal_face_t top_face; + for (std::vector::const_reverse_iterator vertex = face.outer.rbegin(); + vertex != face.outer.rend(); + ++vertex) { + top_face.outer.push_back(*vertex+dir); + } face_list.push_back(top_face); + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); PolyhedronBuilder builder(&face_list); polyhedron.delegate(builder); From 9d4463b73a0c3d84532ac404c7eb463fcb2035c5 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 13 Feb 2017 15:26:06 -0600 Subject: [PATCH 028/235] Check for NULL placement --- src/ifcgeom/kernels/cgal/CgalConversionResult.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index 7f16e43073..ebb7bb9c9c 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -6,9 +6,9 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, const cgal_placement_t& trsf = dynamic_cast(place)->trsf(); // Apply transformation -// for (auto &vertex: vertices(s)) { -// vertex->point() = vertex->point().transform(trsf); -// } + if (place != NULL) for (auto &vertex: vertices(s)) { + vertex->point() = vertex->point().transform(trsf); + } // Triangulate the shape and compute the normals std::map vertex_normals; From e47d128b180afcd9e8c2a084131020aa5a61af00 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 20 Feb 2017 20:14:49 -0600 Subject: [PATCH 029/235] Brep and swept solid working now --- src/ifcconvert/WavefrontObjSerializer.cpp | 1 + .../kernels/cgal/CgalConversionFunctions.cpp | 10 +++++++ .../kernels/cgal/CgalConversionResult.cpp | 16 +++++++----- .../kernels/cgal/CgalEntityMapping.cpp | 26 +++++++++++++++++++ src/ifcgeom/kernels/cgal/CgalKernel.h | 20 +++++++------- 5 files changed, 55 insertions(+), 18 deletions(-) diff --git a/src/ifcconvert/WavefrontObjSerializer.cpp b/src/ifcconvert/WavefrontObjSerializer.cpp index 54fd609265..52881e858f 100644 --- a/src/ifcconvert/WavefrontObjSerializer.cpp +++ b/src/ifcconvert/WavefrontObjSerializer.cpp @@ -108,6 +108,7 @@ void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement* const bool has_uvs = !mesh.uvs().empty(); const bool has_normals = !mesh.normals().empty(); +// std::cout << mesh.faces().size() << " vertices in face mesh" << std::endl; for ( std::vector::const_iterator it = mesh.faces().begin(); it != mesh.faces().end(); ) { const int material_id = *(material_it++); diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 6919a9319f..4121a7c783 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -70,10 +70,19 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal top_face.outer.push_back(*vertex+dir); } face_list.push_back(top_face); + // Naive creation cgal_shape_t polyhedron = CGAL::Polyhedron_3(); 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 (!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; + shape = polyhedron; return true; } @@ -84,6 +93,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_po 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; } else { throw std::runtime_error("Point without 3 coordinates"); diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index ebb7bb9c9c..59225e53f0 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -4,6 +4,8 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const { cgal_shape_t s = shape_; const cgal_placement_t& trsf = dynamic_cast(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)) { @@ -15,17 +17,15 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, boost::associative_property_map> vertex_normals_map(vertex_normals); std::map face_normals; boost::associative_property_map> face_normals_map(face_normals); - try { - CGAL::Polygon_mesh_processing::triangulate_faces(s); - CGAL::Polygon_mesh_processing::compute_normals(s, vertex_normals_map, face_normals_map); - } catch (...) { - - // TODO: Catch outside - // Logger::Message(Logger::LOG_ERROR,"Failed to triangulate shape:",ifc_file->entityById(_id)->entity); + if (CGAL::Polygon_mesh_processing::triangulate_faces(s)) { +// std::cout << "Triangulated model: " << s.size_of_facets() << " facets and " << s.size_of_vertices() << " vertices" << std::endl; + } else { Logger::Message(Logger::LOG_ERROR, "Failed to triangulate shape"); return; } + CGAL::Polygon_mesh_processing::compute_normals(s, vertex_normals_map, face_normals_map); + // Iterates over the faces of the shape int num_faces = 0, num_vertices = 0; for (auto &face: faces(s)) { @@ -43,4 +43,6 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, t->material_ids().push_back(surface_style_id); ++num_faces; } + +// std::cout << num_faces << " faces" << std::endl; } diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp index 996926c978..802af766c2 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp @@ -129,13 +129,27 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_ continue; } +// std::cout << "Face in ConnectedFaceSet: " << std::endl; +// for (auto &point: face.outer) { +// std::cout << "\tPoint(" << point << ")" << std::endl; +// } + face_list.push_back(face); } + // Naive creation cgal_shape_t polyhedron = CGAL::Polyhedron_3(); 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 (!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; + shape = polyhedron; return true; } @@ -189,6 +203,12 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcFace* l, cgal_face_t& face } face = mf; + +// std::cout << "Face: " << std::endl; +// for (auto &point: face.outer) { +// std::cout << "\tPoint(" << point << ")" << std::endl; +// } + return true; } @@ -225,6 +245,12 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& } result = polygon; + +// std::cout << "PolyLoop: " << std::endl; +// for (auto &point: polygon) { +// std::cout << "\tPoint(" << point << ")" << std::endl; +// } + return true; } diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 596fcacf4e..4e82272375 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -43,6 +43,8 @@ if ( it != cache.T.end() ) { e = it->second; return true; } #include #include #include +#include +#include #include #include @@ -72,27 +74,23 @@ public: } void operator()(CGAL::Polyhedron_3::HalfedgeDS &hds) { - std::map points_map; + std::list points; std::list> facet_vertices; CGAL::Polyhedron_incremental_builder_3::HalfedgeDS> builder(hds, true); for (auto &face: *face_list) { facet_vertices.push_back(std::list()); for (auto &point: face.outer) { - if (points_map.count(point) == 0) { - facet_vertices.back().push_back(points_map.size()); - points_map[point] = points_map.size(); - } else { - facet_vertices.back().push_back(points_map[point]); - } + facet_vertices.back().push_back(points.size()); + points.push_back(point); } } - builder.begin_surface(points_map.size(), facet_vertices.size()); + builder.begin_surface(points.size(), facet_vertices.size()); - for (auto &point: points_map) { -// std::cout << "Adding point " << point.first << std::endl; - builder.add_vertex(point.first); + for (auto &point: points) { +// std::cout << "Adding point " << point << std::endl; + builder.add_vertex(point); } for (auto &facet: facet_vertices) { From c0732f5197fdb08d55adfeb23a05dfb7b1d93b3a Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 21 Feb 2017 15:37:38 -0600 Subject: [PATCH 030/235] =?UTF-8?q?Trying=20to=20find=20out=20why=20placem?= =?UTF-8?q?ents=20don=E2=80=99t=20arrive=20at=20Triangulate()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ifcgeom/IfcGeomIterator.h | 7 ++++ .../kernels/cgal/CgalConversionFunctions.cpp | 34 +++++++++++++++++++ .../kernels/cgal/CgalConversionResult.h | 5 +-- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 7 ++++ 4 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/ifcgeom/IfcGeomIterator.h b/src/ifcgeom/IfcGeomIterator.h index 2d2c8fe312..8a1de806e5 100644 --- a/src/ifcgeom/IfcGeomIterator.h +++ b/src/ifcgeom/IfcGeomIterator.h @@ -702,6 +702,13 @@ namespace IfcGeom { try { next_shape_model = create_shape_model_for_next_entity(); + +// std::cout << "trsf" << std::endl; +// for (int i = 0; i < 3; ++i) { +// for (int j = 0; j < 4; ++j) { +// std::cout << next_shape_model->transformation().matrix().data() << " "; +// } std::cout << std::endl; +// } } catch (...) {} if (next_shape_model) { diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 4121a7c783..80f7457811 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -139,12 +139,22 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement3D* l, cgal_ if ( l->hasAxis() ) IfcGeom::CgalKernel::convert(l->Axis(),axis); if ( hasRef ) IfcGeom::CgalKernel::convert(l->RefDirection(),refDirection); +// std::cout << "Ref direction: " << refDirection << std::endl; +// std::cout << "Axis: " << axis << std::endl; +// std::cout << "Origin: " << o << std::endl; + // TODO: From Thomas' email. Should be checked. Kernel::Vector_3 y = CGAL::cross_product(axis, refDirection); trsf = Kernel::Aff_transformation_3(refDirection.cartesian(0), y.cartesian(0), axis.cartesian(0), o.cartesian(0), refDirection.cartesian(1), y.cartesian(1), axis.cartesian(1), o.cartesian(1), refDirection.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; } @@ -156,13 +166,37 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_p Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l->entity); 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->is(IfcSchema::Type::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 = trsf * trsf2; // TODO: I think it's fine, but maybe should it be the other way around? + +// 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(); diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.h b/src/ifcgeom/kernels/cgal/CgalConversionResult.h index 940a598b67..b02e6e5c95 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.h +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.h @@ -35,7 +35,8 @@ namespace IfcGeom { virtual double Value(int i, int j) const { // TODO: Check - return CGAL::to_double(trsf_.cartesian(i, j)); +// std::cout << "Getting CgalPlacement with i = " << i << " and j = " << j << std::endl; + return CGAL::to_double(trsf_.cartesian(i-1, j-1)); } virtual void Multiply(const ConversionResultPlacement* other) { // TODO: Check @@ -51,7 +52,7 @@ namespace IfcGeom { private: cgal_placement_t trsf_; }; - + class CgalShape : public ConversionResultShape { public: CgalShape(const cgal_shape_t& shape) diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index 73f9bd761e..7d346c93fc 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -96,6 +96,13 @@ IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representat try { convert(product->ObjectPlacement(), trsf); } catch (...) {} + + std::cout << "trsf" << 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; + } // Does the IfcElement have any IfcOpenings? // Note that openings for IfcOpeningElements are not processed From 64eb7079960ab8ac6ad98bb6f59cca319cae2e82 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 21 Feb 2017 18:40:27 -0600 Subject: [PATCH 031/235] Fixed issue with transformations? --- src/ifcgeom/IfcGeomIterator.h | 3 +- .../kernels/cgal/CgalEntityMapping.cpp | 2 +- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 33 ++++++++++++++----- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/ifcgeom/IfcGeomIterator.h b/src/ifcgeom/IfcGeomIterator.h index 8a1de806e5..f85c056ae6 100644 --- a/src/ifcgeom/IfcGeomIterator.h +++ b/src/ifcgeom/IfcGeomIterator.h @@ -704,9 +704,10 @@ namespace IfcGeom { next_shape_model = create_shape_model_for_next_entity(); // std::cout << "trsf" << std::endl; +// IfcGeom::CgalPlacement *trsf = next_shape_model->transformation().data(); // for (int i = 0; i < 3; ++i) { // for (int j = 0; j < 4; ++j) { -// std::cout << next_shape_model->transformation().matrix().data() << " "; +// std::cout << << " "; // } std::cout << std::endl; // } } catch (...) {} diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp index 802af766c2..d7c576a4e7 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp @@ -67,7 +67,7 @@ bool IfcGeom::CgalKernel::convert_shape(const IfcBaseClass* l, cgal_shape_t& r) } if ( processed && success ) { - const double precision = getValue(GV_PRECISION); +// const double precision = getValue(GV_PRECISION); // apply_tolerance(r, precision); #ifndef NO_CACHE cache.Shape[id] = r; diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index 7d346c93fc..e67be1c390 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -97,12 +97,12 @@ IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representat convert(product->ObjectPlacement(), trsf); } catch (...) {} - std::cout << "trsf" << 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; - } +// std::cout << "trsf" << 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; +// } // Does the IfcElement have any IfcOpenings? // Note that openings for IfcOpeningElements are not processed @@ -114,9 +114,24 @@ IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representat if (!settings.get(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && openings && openings->size()) { Logger::Message(Logger::LOG_ERROR, "Not implemented opening subtractions"); } - - shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), shapes); - + + if (settings.get(IteratorSettings::USE_WORLD_COORDS)) { + // TODO: OpenCascade code uses opened_shapes. Check why. + for ( IfcGeom::ConversionResults::iterator it = shapes.begin(); it != shapes.end(); ++ it ) { + it->prepend(new CgalPlacement(trsf)); + } + trsf = Kernel::Aff_transformation_3(); + shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), shapes); + } else if (settings.get(IteratorSettings::USE_WORLD_COORDS)) { + for ( IfcGeom::ConversionResults::iterator it = shapes.begin(); it != shapes.end(); ++ it ) { + it->prepend(new CgalPlacement(trsf)); + } + trsf = Kernel::Aff_transformation_3(); + shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), shapes); + } else { + shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), shapes); + } + std::string context_string = ""; if (representation->hasRepresentationIdentifier()) { context_string = representation->RepresentationIdentifier(); From b893f5a3f08f065de6f889c71dc5a1dfd8a693e4 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 22 Feb 2017 18:15:27 -0600 Subject: [PATCH 032/235] Take into account extrusion height --- src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 80f7457811..063b4d8abf 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -44,6 +44,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal cgal_direction_t dir; convert(l->ExtrudedDirection(),dir); +// std::cout << "Direction: " << dir << std::endl; std::list face_list; face_list.push_back(face); @@ -58,8 +59,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal } 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+dir); - side_face.outer.push_back(*next_vertex+dir); + side_face.outer.push_back(*current_vertex+height*dir); + side_face.outer.push_back(*next_vertex+height*dir); face_list.push_back(side_face); } @@ -67,7 +68,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal for (std::vector::const_reverse_iterator vertex = face.outer.rbegin(); vertex != face.outer.rend(); ++vertex) { - top_face.outer.push_back(*vertex+dir); + top_face.outer.push_back(*vertex+height*dir); } face_list.push_back(top_face); // Naive creation From 57fae25de8287d2f89178c57633696cb2609f3cb Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 1 Mar 2017 17:48:19 -0600 Subject: [PATCH 033/235] Putting functions into files per geometric type --- .../kernels/cgal/CgalConversionFunctions.cpp | 92 ---------- .../kernels/cgal/CgalEntityMapping.cpp | 161 ------------------ src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp | 74 ++++++++ .../kernels/cgal/CgalIfcGeomShapes.cpp | 140 +++++++++++++++ src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp | 43 +++++ 5 files changed, 257 insertions(+), 253 deletions(-) create mode 100644 src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp create mode 100644 src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp create mode 100644 src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 063b4d8abf..38f9e0d457 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -23,71 +23,6 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRepresentation* l, Convers return part_succes; } -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->entity); - return false; - } - - cgal_face_t face; - if ( !convert_face(l->SweptArea(),face) ) 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); -// std::cout << "Direction: " << dir << std::endl; - - std::list face_list; - face_list.push_back(face); - - for (std::vector::const_iterator current_vertex = face.outer.begin(); - current_vertex != face.outer.end(); - ++current_vertex) { - std::vector::const_iterator next_vertex = current_vertex; - ++next_vertex; - if (next_vertex == face.outer.end()) { - next_vertex = 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::const_reverse_iterator vertex = face.outer.rbegin(); - vertex != face.outer.rend(); - ++vertex) { - top_face.outer.push_back(*vertex+height*dir); - } face_list.push_back(top_face); - - // Naive creation - cgal_shape_t polyhedron = CGAL::Polyhedron_3(); - 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 (!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; - - shape = polyhedron; - return true; -} - bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_point_t& point) { std::vector xyz = l->Coordinates(); if (xyz.size() == 3) { @@ -209,30 +144,3 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_p // CACHE(IfcObjectPlacement,l,trsf) 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->entity); - return false; - } - - cgal_placement_t trsf2d; - bool has_position = true; -#ifdef USE_IFC4 - has_position = l->hasPosition(); -#endif - if (has_position) { - IfcGeom::CgalKernel::convert(l->Position(), trsf2d); - } - - 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)); - - return true; -} diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp index d7c576a4e7..26d5f819c1 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp @@ -81,79 +81,6 @@ bool IfcGeom::CgalKernel::convert_shape(const IfcBaseClass* l, cgal_shape_t& r) return success; } -bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, ConversionResults& shape) { - cgal_shape_t s; - const SurfaceStyle* collective_style = get_style(l); - if (convert_shape(l->Outer(),s) ) { - const SurfaceStyle* indiv_style = get_style(l->Outer()); - - IfcSchema::IfcClosedShell::list::ptr voids(new IfcSchema::IfcClosedShell::list); - if (l->is(IfcSchema::Type::IfcFacetedBrepWithVoids)) { - voids = l->as()->Voids(); - } -#ifdef USE_IFC4 - if (l->is(IfcSchema::Type::IfcAdvancedBrepWithVoids)) { - voids = l->as()->Voids(); - } -#endif - - for (IfcSchema::IfcClosedShell::list::it it = voids->begin(); it != voids->end(); ++it) { -// TopoDS_Shape s2; -// /// @todo No extensive shapefixing since shells should be disjoint. -// /// @todo Awaiting generalized boolean ops module with appropriate checking -// if (convert_shape(l->Outer(), s2)) { -// s = BRepAlgoAPI_Cut(s, s2).Shape(); -// } - } - - shape.push_back(ConversionResult(new CgalShape(s), indiv_style ? indiv_style : collective_style)); - return true; - } - return false; -} - -bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_shape_t& shape) { - IfcSchema::IfcFace::list::ptr faces = l->CfsFaces(); - - std::list 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)->entity); - continue; - } - -// std::cout << "Face in ConnectedFaceSet: " << std::endl; -// for (auto &point: face.outer) { -// std::cout << "\tPoint(" << point << ")" << std::endl; -// } - - face_list.push_back(face); - } - - // Naive creation - cgal_shape_t polyhedron = CGAL::Polyhedron_3(); - 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 (!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; - - shape = polyhedron; - return true; -} - 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->entity); @@ -166,94 +93,6 @@ bool IfcGeom::CgalKernel::convert_face(const IfcBaseClass* l, cgal_face_t& r) { return false; } -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->is(IfcSchema::Type::IfcFaceOuterBound)) num_outer_bounds ++; - } - - if (num_outer_bounds != 1) { - Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l->entity); - 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->is(IfcSchema::Type::IfcFaceOuterBound); - - cgal_wire_t wire; - if (!convert_wire(loop, wire)) { - Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop->entity); - 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::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(); - 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->entity); - return false; - } - - // TODO: Remove repeated points (and points that are too close to one another?) -// remove_duplicate_points_from_loop(polygon, true); - - 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->entity); - } - - if (count < 3) { - Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity); - 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_curve(const IfcBaseClass* l, cgal_curve_t& r) { #include "CgalEntityMappingCurve.h" Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp new file mode 100644 index 0000000000..6cd88a434b --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp @@ -0,0 +1,74 @@ +#include "CgalKernel.h" + +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->entity); + return false; + } + + cgal_placement_t trsf2d; + bool has_position = true; +#ifdef USE_IFC4 + has_position = l->hasPosition(); +#endif + if (has_position) { + IfcGeom::CgalKernel::convert(l->Position(), trsf2d); + } + + 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)); + + 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->is(IfcSchema::Type::IfcFaceOuterBound)) num_outer_bounds ++; + } + + if (num_outer_bounds != 1) { + Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l->entity); + 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->is(IfcSchema::Type::IfcFaceOuterBound); + + cgal_wire_t wire; + if (!convert_wire(loop, wire)) { + Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop->entity); + 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; +} diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp new file mode 100644 index 0000000000..b8efaf7f18 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -0,0 +1,140 @@ +#include "CgalKernel.h" +#include "CgalConversionResult.h" + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, ConversionResults& shape) { + cgal_shape_t s; + const SurfaceStyle* collective_style = get_style(l); + if (convert_shape(l->Outer(),s) ) { + const SurfaceStyle* indiv_style = get_style(l->Outer()); + + IfcSchema::IfcClosedShell::list::ptr voids(new IfcSchema::IfcClosedShell::list); + if (l->is(IfcSchema::Type::IfcFacetedBrepWithVoids)) { + voids = l->as()->Voids(); + } +#ifdef USE_IFC4 + if (l->is(IfcSchema::Type::IfcAdvancedBrepWithVoids)) { + voids = l->as()->Voids(); + } +#endif + + for (IfcSchema::IfcClosedShell::list::it it = voids->begin(); it != voids->end(); ++it) { + // TopoDS_Shape s2; + // /// @todo No extensive shapefixing since shells should be disjoint. + // /// @todo Awaiting generalized boolean ops module with appropriate checking + // if (convert_shape(l->Outer(), s2)) { + // s = BRepAlgoAPI_Cut(s, s2).Shape(); + // } + } + + shape.push_back(ConversionResult(new CgalShape(s), indiv_style ? indiv_style : collective_style)); + return true; + } + return false; +} + +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->entity); + return false; + } + + cgal_face_t face; + if ( !convert_face(l->SweptArea(),face) ) 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); + // std::cout << "Direction: " << dir << std::endl; + + std::list face_list; + face_list.push_back(face); + + for (std::vector::const_iterator current_vertex = face.outer.begin(); + current_vertex != face.outer.end(); + ++current_vertex) { + std::vector::const_iterator next_vertex = current_vertex; + ++next_vertex; + if (next_vertex == face.outer.end()) { + next_vertex = 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::const_reverse_iterator vertex = face.outer.rbegin(); + vertex != face.outer.rend(); + ++vertex) { + top_face.outer.push_back(*vertex+height*dir); + } face_list.push_back(top_face); + + // Naive creation + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + 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 (!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; + + shape = polyhedron; + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_shape_t& shape) { + IfcSchema::IfcFace::list::ptr faces = l->CfsFaces(); + + std::list 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)->entity); + continue; + } + + // std::cout << "Face in ConnectedFaceSet: " << std::endl; + // for (auto &point: face.outer) { + // std::cout << "\tPoint(" << point << ")" << std::endl; + // } + + face_list.push_back(face); + } + + // Naive creation + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + 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 (!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; + + shape = polyhedron; + return true; +} diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp new file mode 100644 index 0000000000..56e43432c3 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp @@ -0,0 +1,43 @@ +#include "CgalKernel.h" + +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(); + 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->entity); + return false; + } + + // TODO: Remove repeated points (and points that are too close to one another?) + // remove_duplicate_points_from_loop(polygon, true); + + 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->entity); + } + + if (count < 3) { + Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity); + return false; + } + + result = polygon; + + // std::cout << "PolyLoop: " << std::endl; + // for (auto &point: polygon) { + // std::cout << "\tPoint(" << point << ")" << std::endl; + // } + + return true; +} From 2cb53a860dfc91f4fdc68d7b0fda5f34125a14a5 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 2 Mar 2017 15:09:05 -0600 Subject: [PATCH 034/235] Entities for basic CSG --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 2 + .../kernels/cgal/CgalIfcGeomShapes.cpp | 78 +++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index b163696066..520c21dfd4 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -37,6 +37,8 @@ SHAPES(IfcManifoldSolidBrep); SHAPE(IfcExtrudedAreaSolid); SHAPE(IfcConnectedFaceSet); +SHAPE(IfcCsgSolid); +SHAPE(IfcBlock); FACE(IfcFace); FACE(IfcRectangleProfileDef); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index b8efaf7f18..78b9b33c80 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -138,3 +138,81 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_ shape = polyhedron; 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 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)); + + // Naive creation + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + 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 (!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; + + cgal_placement_t trsf; + IfcGeom::CgalKernel::convert(l->Position(),trsf); + + // IfcCsgPrimitive3D.Position has unit scale factor + for (auto &vertex: vertices(polyhedron)) { + vertex->point() = vertex->point().transform(trsf); + } + + shape = polyhedron; + return true; +} From c9633273a6f89206364a7d76ffbea65e10ca56ae Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 2 Mar 2017 17:11:58 -0600 Subject: [PATCH 035/235] Several more classes, needs testing --- .../kernels/cgal/CgalConversionFunctions.cpp | 5 ++ src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 3 ++ src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp | 10 ++++ .../kernels/cgal/CgalIfcGeomShapes.cpp | 52 +++++++++++++++++++ src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp | 20 ++++++- src/ifcgeom/kernels/cgal/CgalKernel.h | 2 + 6 files changed, 91 insertions(+), 1 deletion(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 38f9e0d457..b096b3408e 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -144,3 +144,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_p // CACHE(IfcObjectPlacement,l,trsf) return true; } + +bool IfcGeom::CgalKernel::convert_wire_to_face(const cgal_wire_t& wire, cgal_face_t& face) { + face.outer = wire; + return true; +} diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 520c21dfd4..54efeb04ba 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -34,16 +34,19 @@ SHAPES(IfcRepresentation); // IfcFacetedBrepWithVoids included // IfcAdvancedBrepWithVoids included SHAPES(IfcManifoldSolidBrep); +SHAPES(IfcMappedItem); SHAPE(IfcExtrudedAreaSolid); SHAPE(IfcConnectedFaceSet); SHAPE(IfcCsgSolid); SHAPE(IfcBlock); +FACE(IfcArbitraryClosedProfileDef); FACE(IfcFace); FACE(IfcRectangleProfileDef); WIRE(IfcPolyLoop); +WIRE(IfcPolyline); CLASS(IfcCartesianPoint,cgal_point_t); CLASS(IfcDirection,cgal_direction_t); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp index 6cd88a434b..7c4e64337f 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp @@ -1,5 +1,15 @@ #include "CgalKernel.h" +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::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); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 78b9b33c80..37c344e483 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -32,6 +32,58 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, Conv return false; } +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcMappedItem* l, ConversionResults& shapes) { + cgal_placement_t gtrsf; + IfcSchema::IfcCartesianTransformationOperator* transform = l->MappingTarget(); + if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3DnonUniform) ) { + Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); +// IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3DnonUniform*)transform,gtrsf); + } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2DnonUniform) ) { + Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); + return false; + } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3D) ) { + cgal_placement_t trsf; + Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); +// IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,trsf); + gtrsf = trsf; + } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2D) ) { + cgal_placement_t trsf_2d; + Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); +// IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator2D*)transform,trsf_2d); + gtrsf = (cgal_placement_t) trsf_2d; + } + IfcSchema::IfcRepresentationMap* map = l->MappingSource(); + IfcSchema::IfcAxis2Placement* placement = map->MappingOrigin(); + cgal_placement_t trsf; + if (placement->is(IfcSchema::Type::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; + + 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::IfcExtrudedAreaSolid *l, cgal_shape_t &shape) { const double height = l->Depth() * getValue(GV_LENGTH_UNIT); if (height < getValue(GV_PRECISION)) { diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp index 56e43432c3..c6d8820c65 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp @@ -18,7 +18,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& return false; } - // TODO: Remove repeated points (and points that are too close to one another?) + // TODO: Remove repeated points and points that are too close to one another // remove_duplicate_points_from_loop(polygon, true); std::size_t count = polygon.size(); @@ -41,3 +41,21 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& 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(); + 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); + } + + // TODO: Remove points that are too close to one another + // remove_duplicate_points_from_loop(polygon, false); + + result = polygon; + return true; +} diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 4e82272375..94021ae750 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -130,6 +130,8 @@ namespace IfcGeom { 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); // bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, ConversionResults& cut_shapes); From 6297ff74f169bac61fc462720bf003552bbff0cb Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 2 Mar 2017 18:11:11 -0600 Subject: [PATCH 036/235] Boolean ops using Nef polyhedra (untested) --- .../kernels/cgal/CgalConversionFunctions.cpp | 7 +- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 2 + .../kernels/cgal/CgalIfcGeomShapes.cpp | 238 ++++++++++++++++++ src/ifcgeom/kernels/cgal/CgalKernel.h | 1 + 4 files changed, 246 insertions(+), 2 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index b096b3408e..9573fdaa7a 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -25,14 +25,17 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRepresentation* l, Convers bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_point_t& point) { std::vector xyz = l->Coordinates(); - if (xyz.size() == 3) { + if (xyz.size() < 4) { 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; } else { - throw std::runtime_error("Point without 3 coordinates"); + std::cout << "Point("; + for (auto &coordinate: xyz) std::cout << coordinate << " "; + std::cout << ")"; + throw std::runtime_error("Could not parse point"); } } diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 54efeb04ba..12c8224e20 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -40,6 +40,8 @@ SHAPE(IfcExtrudedAreaSolid); SHAPE(IfcConnectedFaceSet); SHAPE(IfcCsgSolid); SHAPE(IfcBlock); +SHAPE(IfcBooleanResult); +SHAPE(IfcSphere); FACE(IfcArbitraryClosedProfileDef); FACE(IfcFace); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 37c344e483..d16264bc0f 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -268,3 +268,241 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBlock* l, cgal_shape_t& sh shape = polyhedron; 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->is(IfcSchema::Type::IfcHalfSpaceSolid); + + if ( shape_type(operand1) == ST_SHAPELIST ) { + std::cout << "ST_SHAPELIST" << std::endl; +// 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; + } +// TopoDS_Solid temp_solid; +// s1 = ensure_fit_for_subtraction(s1, temp_solid); + } else { + Logger::Message(Logger::LOG_ERROR, "s1: Invalid representation item for boolean operation", operand1->entity); + return false; + } + +// const double first_operand_volume = shape_volume(s1); +// if ( first_operand_volume <= ALMOST_ZERO ) +// Logger::Message(Logger::LOG_WARNING,"Empty solid for:",l->FirstOperand()->entity); + + bool shape2_processed = false; + if ( shape_type(operand2) == ST_SHAPELIST ) { + std::cout << "ST_SHAPELIST" << std::endl; +// 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); + if (shape2_processed && !is_halfspace) { +// TopoDS_Solid temp_solid; +// s2 = ensure_fit_for_subtraction(s2, temp_solid); + } + } else { + Logger::Message(Logger::LOG_ERROR, "s2: Invalid representation item for boolean operation", operand2->entity); + } + + if (!shape2_processed) { +// shape = s1; + Logger::Message(Logger::LOG_ERROR,"Failed to convert SecondOperand of:",l->entity); +// return true; + } + +// if (!is_halfspace) { +// const double second_operand_volume = shape_volume(s2); +// if ( second_operand_volume <= ALMOST_ZERO ) +// Logger::Message(Logger::LOG_WARNING,"Empty solid for:",operand2->entity); +// } + + const IfcSchema::IfcBooleanOperator::IfcBooleanOperator op = l->Operator(); + + CGAL::Nef_polyhedron_3 nef1(s1); + CGAL::Nef_polyhedron_3 nef2(s2); + + if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) { + + CGAL::Nef_polyhedron_3 nef_result = nef1-nef2; + cgal_shape_t result; + nef_result.convert_to_polyhedron(result); + shape = result; + return true; + + } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) { + + CGAL::Nef_polyhedron_3 nef_result = nef1+nef2; + cgal_shape_t result; + nef_result.convert_to_polyhedron(result); + shape = result; + return true; + + } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) { + + CGAL::Nef_polyhedron_3 nef_result = nef1*nef2; + cgal_shape_t result; + nef_result.convert_to_polyhedron(result); + shape = result; + return true; + + } + + 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 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 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]); + + // TODO: Refine icosahedron to create icosphere + + // Naive creation + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + 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 (!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; + + cgal_placement_t trsf; + IfcGeom::CgalKernel::convert(l->Position(),trsf); + + for (auto &vertex: vertices(polyhedron)) { + vertex->point() = Kernel::Point_3(vertex->point().x()*r, + vertex->point().y()*r, + vertex->point().z()*r).transform(trsf); + } + + return true; +} diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 94021ae750..748fd4fbb3 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -47,6 +47,7 @@ if ( it != cache.T.end() ) { e = it->second; return true; } #include #include #include +#include typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; From 82cd4056b7a825891a4239c07d05e9d59eefd2be Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 2 Mar 2017 18:22:34 -0600 Subject: [PATCH 037/235] IfcRectangularPyramid --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + .../kernels/cgal/CgalIfcGeomShapes.cpp | 60 ++++++++++++++++++- 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 12c8224e20..20d363e13b 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -42,6 +42,7 @@ SHAPE(IfcCsgSolid); SHAPE(IfcBlock); SHAPE(IfcBooleanResult); SHAPE(IfcSphere); +SHAPE(IfcRectangularPyramid); FACE(IfcArbitraryClosedProfileDef); FACE(IfcFace); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index d16264bc0f..ae969a8e13 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -260,7 +260,6 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBlock* l, cgal_shape_t& sh cgal_placement_t trsf; IfcGeom::CgalKernel::convert(l->Position(),trsf); - // IfcCsgPrimitive3D.Position has unit scale factor for (auto &vertex: vertices(polyhedron)) { vertex->point() = vertex->point().transform(trsf); } @@ -506,3 +505,62 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& s 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 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)); + + // Naive creation + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + 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 (!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; + + cgal_placement_t trsf; + IfcGeom::CgalKernel::convert(l->Position(),trsf); + + for (auto &vertex: vertices(polyhedron)) { + vertex->point() = vertex->point().transform(trsf); + } + + shape = polyhedron; + return true; +} From bece7053a001af99686db6bc249dd78915e8d545 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 2 Mar 2017 18:39:18 -0600 Subject: [PATCH 038/235] IfcRightCircularCylinder --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + .../kernels/cgal/CgalIfcGeomShapes.cpp | 58 +++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 20d363e13b..0f66367e23 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -43,6 +43,7 @@ SHAPE(IfcBlock); SHAPE(IfcBooleanResult); SHAPE(IfcSphere); SHAPE(IfcRectangularPyramid); +SHAPE(IfcRightCircularCylinder); FACE(IfcArbitraryClosedProfileDef); FACE(IfcFace); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index ae969a8e13..8b28f4abbb 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -564,3 +564,61 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangularPyramid* l, cga shape = polyhedron; 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 face_list; + + const int segments = 10; + + // Base + face_list.push_back(cgal_face_t()); + for (int current_segment = 0; current_segment < segments; ++current_segment) { + double current_angle = current_segment*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*3.141592653589793/((double)segments); + int next_segment = (current_segment+1)%segments; + double next_angle = next_segment*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*3.141592653589793/((double)segments); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), h)); + } + + // Naive creation + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + 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 (!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; + + cgal_placement_t trsf; + IfcGeom::CgalKernel::convert(l->Position(),trsf); + + for (auto &vertex: vertices(polyhedron)) { + vertex->point() = vertex->point().transform(trsf); + } + + shape = polyhedron; + return true; +} From 302e7b2db86dacdf5fa7b74580f15cd5bdfd59e0 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 2 Mar 2017 18:42:10 -0600 Subject: [PATCH 039/235] IfcRightCircularCone --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + .../kernels/cgal/CgalIfcGeomShapes.cpp | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 0f66367e23..afbb9db9f5 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -44,6 +44,7 @@ SHAPE(IfcBooleanResult); SHAPE(IfcSphere); SHAPE(IfcRectangularPyramid); SHAPE(IfcRightCircularCylinder); +SHAPE(IfcRightCircularCone); FACE(IfcArbitraryClosedProfileDef); FACE(IfcFace); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 8b28f4abbb..71dd71432b 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -622,3 +622,53 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, shape = polyhedron; 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 face_list; + + const int segments = 10; + + // Base + face_list.push_back(cgal_face_t()); + for (int current_segment = 0; current_segment < segments; ++current_segment) { + double current_angle = current_segment*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*3.141592653589793/((double)segments); + int next_segment = (current_segment+1)%segments; + double next_angle = next_segment*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)); + } + + // Naive creation + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + 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 (!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; + + cgal_placement_t trsf; + IfcGeom::CgalKernel::convert(l->Position(),trsf); + + for (auto &vertex: vertices(polyhedron)) { + vertex->point() = vertex->point().transform(trsf); + } + + shape = polyhedron; + return true; +} From 596c4f8b7750b4bb37822fcc3da9869a9473525f Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 3 Mar 2017 09:58:17 -0600 Subject: [PATCH 040/235] Adding some validation code --- .../kernels/cgal/CgalIfcGeomShapes.cpp | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 71dd71432b..b0e710c084 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -142,7 +142,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } + } CGAL_postcondition(polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; shape = polyhedron; @@ -254,7 +254,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBlock* l, cgal_shape_t& sh CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } + } CGAL_postcondition(polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; cgal_placement_t trsf; @@ -278,7 +278,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha bool is_halfspace = operand2->is(IfcSchema::Type::IfcHalfSpaceSolid); if ( shape_type(operand1) == ST_SHAPELIST ) { - std::cout << "ST_SHAPELIST" << std::endl; + Logger::Message(Logger::LOG_ERROR, "s1: ST_SHAPELIST Unsupported", operand1->entity); // if (!(convert_shapes(operand1, items1) && flatten_shape_list(items1, s1, true))) { return false; // } @@ -299,7 +299,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha bool shape2_processed = false; if ( shape_type(operand2) == ST_SHAPELIST ) { - std::cout << "ST_SHAPELIST" << std::endl; + Logger::Message(Logger::LOG_ERROR, "s2: ST_SHAPELIST Unsupported", operand1->entity); // 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); @@ -325,8 +325,19 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha const IfcSchema::IfcBooleanOperator::IfcBooleanOperator op = l->Operator(); + CGAL_precondition(s1.is_valid() && s1.is_closed()); CGAL::Nef_polyhedron_3 nef1(s1); + if (!nef1.is_simple()) { + Logger::Message(Logger::LOG_ERROR, "s1: Not simple Nef?", operand1->entity); + return false; + } + + CGAL_precondition(s2.is_valid() && s2.is_closed()); CGAL::Nef_polyhedron_3 nef2(s2); + if (!nef2.is_simple()) { + Logger::Message(Logger::LOG_ERROR, "s2: Not simple Nef?", operand2->entity); + return false; + } if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) { @@ -491,7 +502,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& s CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } + } CGAL_postcondition(polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; cgal_placement_t trsf; @@ -551,7 +562,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangularPyramid* l, cga CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } + } CGAL_postcondition(polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; cgal_placement_t trsf; @@ -609,7 +620,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } + } CGAL_postcondition(polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; cgal_placement_t trsf; @@ -659,7 +670,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCone* l, cgal CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } + } CGAL_postcondition(polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; cgal_placement_t trsf; From 7145b1ae85d7f56a45f74a3c9cfdade0007a0d3c Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 3 Mar 2017 12:58:52 -0600 Subject: [PATCH 041/235] Some debugging code, checking transformations --- .../kernels/cgal/CgalConversionFunctions.cpp | 6 +-- .../kernels/cgal/CgalIfcGeomShapes.cpp | 52 ++++++++++++++++--- 2 files changed, 47 insertions(+), 11 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 9573fdaa7a..d0d6be43bc 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -53,7 +53,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement2D* l, cgal_ // 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); // TODO: Put identity for now. Check? + 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); @@ -62,7 +62,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement2D* l, cgal_ Kernel::Vector_3 y = CGAL::cross_product(Kernel::Vector_3(0.0, 0.0, 1.0), refDirection); 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, y.cartesian(2), 1.0, 0.0); + 0.0, 0.0, 1.0, 0.0); // CACHE(IfcAxis2Placement3D,l,trsf) return true; @@ -72,7 +72,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement3D* l, cgal_ // 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); // TODO: Put identity for now. Check? + 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); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index b0e710c084..87acdd4394 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -142,7 +142,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } CGAL_postcondition(polyhedron.is_closed()); + } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; shape = polyhedron; @@ -254,7 +254,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBlock* l, cgal_shape_t& sh CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } CGAL_postcondition(polyhedron.is_closed()); + } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; cgal_placement_t trsf; @@ -339,27 +339,63 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha return false; } + std::ofstream f1; + f1.open("/Users/ken/Desktop/s1.off"); + f1 << s1 << std::endl; + f1.close(); + std::ofstream f2; + f2.open("/Users/ken/Desktop/s2.off"); + f2 << s2 << std::endl; + f2.close(); + if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) { + std::cout << "Difference" << std::endl; CGAL::Nef_polyhedron_3 nef_result = nef1-nef2; + if (!nef_result.is_simple()) { + std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; + return false; + } cgal_shape_t result; nef_result.convert_to_polyhedron(result); + std::ofstream fresult; + fresult.open("/Users/ken/Desktop/result.off"); + fresult << result << std::endl; + fresult.close(); shape = result; return true; } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) { + std::cout << "Union" << std::endl; CGAL::Nef_polyhedron_3 nef_result = nef1+nef2; + if (!nef_result.is_simple()) { + std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; + return false; + } cgal_shape_t result; nef_result.convert_to_polyhedron(result); + std::ofstream fresult; + fresult.open("/Users/ken/Desktop/result.off"); + fresult << result << std::endl; + fresult.close(); shape = result; return true; } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) { + std::cout << "Intersection" << std::endl; CGAL::Nef_polyhedron_3 nef_result = nef1*nef2; + if (!nef_result.is_simple()) { + std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; + return false; + } cgal_shape_t result; nef_result.convert_to_polyhedron(result); + std::ofstream fresult; + fresult.open("/Users/ken/Desktop/result.off"); + fresult << result << std::endl; + fresult.close(); shape = result; return true; @@ -502,7 +538,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& s CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } CGAL_postcondition(polyhedron.is_closed()); + } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; cgal_placement_t trsf; @@ -562,7 +598,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangularPyramid* l, cga CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } CGAL_postcondition(polyhedron.is_closed()); + } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; cgal_placement_t trsf; @@ -582,7 +618,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, std::list face_list; - const int segments = 10; + const int segments = 25; // Base face_list.push_back(cgal_face_t()); @@ -620,7 +656,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } CGAL_postcondition(polyhedron.is_closed()); + } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; cgal_placement_t trsf; @@ -640,7 +676,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCone* l, cgal std::list face_list; - const int segments = 10; + const int segments = 25; // Base face_list.push_back(cgal_face_t()); @@ -670,7 +706,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCone* l, cgal CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } CGAL_postcondition(polyhedron.is_closed()); + } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; cgal_placement_t trsf; From c59ae03cb3beee36d6ef3d2a288349384234dbd7 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 3 Mar 2017 13:12:05 -0600 Subject: [PATCH 042/235] Fixed bug in cylinders/cones --- src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 87acdd4394..7b0b5d173a 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -623,15 +623,15 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, // Base face_list.push_back(cgal_face_t()); for (int current_segment = 0; current_segment < segments; ++current_segment) { - double current_angle = current_segment*3.141592653589793/((double)segments); + 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*3.141592653589793/((double)segments); + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); int next_segment = (current_segment+1)%segments; - double next_angle = next_segment*3.141592653589793/((double)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)); @@ -642,7 +642,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, // Top face_list.push_back(cgal_face_t()); for (int current_segment = segments-1; current_segment >= 0; --current_segment) { - double current_angle = current_segment*3.141592653589793/((double)segments); + 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)); } @@ -681,15 +681,15 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCone* l, cgal // Base face_list.push_back(cgal_face_t()); for (int current_segment = 0; current_segment < segments; ++current_segment) { - double current_angle = current_segment*3.141592653589793/((double)segments); + 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*3.141592653589793/((double)segments); + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); int next_segment = (current_segment+1)%segments; - double next_angle = next_segment*3.141592653589793/((double)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)); From efb8bce25aa6a95e07a3e3bb00aa33123056c34f Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 3 Mar 2017 13:20:47 -0600 Subject: [PATCH 043/235] =?UTF-8?q?Didn=E2=80=99t=20save=20sphere=20output?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 7b0b5d173a..ec1c1d4170 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -550,6 +550,12 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& s vertex->point().z()*r).transform(trsf); } +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/sphere.off"); +// fresult << polyhedron << std::endl; +// fresult.close(); + + shape = polyhedron; return true; } From bbe0b74f83a760db650f01d5064bc54f24f18fbe Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 3 Mar 2017 13:56:08 -0600 Subject: [PATCH 044/235] Boolean ops working? --- .../kernels/cgal/CgalIfcGeomShapes.cpp | 97 ++++++++++++++----- 1 file changed, 74 insertions(+), 23 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index ec1c1d4170..95fe301e15 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -339,18 +339,18 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha return false; } - std::ofstream f1; - f1.open("/Users/ken/Desktop/s1.off"); - f1 << s1 << std::endl; - f1.close(); - std::ofstream f2; - f2.open("/Users/ken/Desktop/s2.off"); - f2 << s2 << std::endl; - f2.close(); +// std::ofstream f1; +// f1.open("/Users/ken/Desktop/s1.off"); +// f1 << s1 << std::endl; +// f1.close(); +// std::ofstream f2; +// f2.open("/Users/ken/Desktop/s2.off"); +// f2 << s2 << std::endl; +// f2.close(); if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) { - std::cout << "Difference" << std::endl; +// std::cout << "Difference" << std::endl; CGAL::Nef_polyhedron_3 nef_result = nef1-nef2; if (!nef_result.is_simple()) { std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; @@ -358,16 +358,16 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha } cgal_shape_t result; nef_result.convert_to_polyhedron(result); - std::ofstream fresult; - fresult.open("/Users/ken/Desktop/result.off"); - fresult << result << std::endl; - fresult.close(); +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/result.off"); +// fresult << result << std::endl; +// fresult.close(); shape = result; return true; } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) { - std::cout << "Union" << std::endl; +// std::cout << "Union" << std::endl; CGAL::Nef_polyhedron_3 nef_result = nef1+nef2; if (!nef_result.is_simple()) { std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; @@ -375,16 +375,16 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha } cgal_shape_t result; nef_result.convert_to_polyhedron(result); - std::ofstream fresult; - fresult.open("/Users/ken/Desktop/result.off"); - fresult << result << std::endl; - fresult.close(); +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/result.off"); +// fresult << result << std::endl; +// fresult.close(); shape = result; return true; } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) { - std::cout << "Intersection" << std::endl; +// std::cout << "Intersection" << std::endl; CGAL::Nef_polyhedron_3 nef_result = nef1*nef2; if (!nef_result.is_simple()) { std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; @@ -392,10 +392,10 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha } cgal_shape_t result; nef_result.convert_to_polyhedron(result); - std::ofstream fresult; - fresult.open("/Users/ken/Desktop/result.off"); - fresult << result << std::endl; - fresult.close(); +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/result.off"); +// fresult << result << std::endl; +// fresult.close(); shape = result; return true; @@ -527,12 +527,63 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& s face_list.back().outer.push_back(icosahedron_vertices[1]); // TODO: Refine icosahedron to create icosphere + const unsigned int refinements = 3; + for (unsigned int current_refinement = 0; current_refinement < refinements; ++current_refinement) { + std::list 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; + } // Naive creation cgal_shape_t polyhedron = CGAL::Polyhedron_3(); PolyhedronBuilder builder(&face_list); polyhedron.delegate(builder); +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/sphere.off"); +// fresult << polyhedron << std::endl; +// fresult.close(); + // 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); From b9828b029c917019bce4524d697c08edf5690db0 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 3 Mar 2017 15:25:45 -0600 Subject: [PATCH 045/235] Right way to output more than one object --- .../kernels/cgal/CgalConversionResult.cpp | 42 +++++++++++++------ .../kernels/cgal/CgalIfcGeomShapes.cpp | 7 ++-- 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index 59225e53f0..cb25f900ef 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -12,6 +12,11 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, vertex->point() = vertex->point().transform(trsf); } +// std::ofstream fbefore; +// fbefore.open("/Users/ken/Desktop/before.off"); +// fbefore << s << std::endl; +// fbefore.close(); + // Triangulate the shape and compute the normals std::map vertex_normals; boost::associative_property_map> vertex_normals_map(vertex_normals); @@ -23,26 +28,37 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, Logger::Message(Logger::LOG_ERROR, "Failed to triangulate shape"); return; } + +// std::ofstream fafter; +// fafter.open("/Users/ken/Desktop/after.off"); +// fafter << s << std::endl; +// fafter.close(); CGAL::Polygon_mesh_processing::compute_normals(s, vertex_normals_map, face_normals_map); - - // Iterates over the faces of the shape - int num_faces = 0, num_vertices = 0; + std::map::Vertex_const_handle, int> vertices_map; + std::size_t initial_size = t->verts().size()/3; + for (auto &vertex: vertices(s)) { + if (vertices_map.count(vertex) == 0) { + vertices_map[vertex] = (int)(vertices_map.size()+initial_size); + t->addVertex(surface_style_id, + CGAL::to_double(vertex->point().cartesian(0)), + CGAL::to_double(vertex->point().cartesian(1)), + CGAL::to_double(vertex->point().cartesian(2))); +// std::cout << "Size: " << t->verts().size() << std::endl; + for (int i = 0; i < 3; ++i) t->normals().push_back(CGAL::to_double(vertex_normals_map[vertex].cartesian(i))); + } + } + for (auto &face: faces(s)) { + if (!face->is_triangle()) { + std::cout << "Warning: non-triangular face!" << std::endl; + continue; + } CGAL::Polyhedron_3::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))); - for (int i = 0; i < 3; ++i) t->normals().push_back(CGAL::to_double(face_normals_map[face].cartesian(i))); - t->faces().push_back(num_vertices); - ++num_vertices; + t->faces().push_back(vertices_map[current_halfedge->vertex()]); ++current_halfedge; } while (current_halfedge != face->facet_begin()); t->material_ids().push_back(surface_style_id); - ++num_faces; } - -// std::cout << num_faces << " faces" << std::endl; } diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 95fe301e15..e163bea2b8 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -526,8 +526,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& s face_list.back().outer.push_back(icosahedron_vertices[8]); face_list.back().outer.push_back(icosahedron_vertices[1]); - // TODO: Refine icosahedron to create icosphere - const unsigned int refinements = 3; + const unsigned int refinements = 2; for (unsigned int current_refinement = 0; current_refinement < refinements; ++current_refinement) { std::list refined_face_list; for (auto &face: face_list) { @@ -675,7 +674,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, std::list face_list; - const int segments = 25; + const int segments = 12; // Base face_list.push_back(cgal_face_t()); @@ -733,7 +732,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCone* l, cgal std::list face_list; - const int segments = 25; + const int segments = 12; // Base face_list.push_back(cgal_face_t()); From 64bc8e9d4fcf9554e4111a7ffa1512e8659ddaa6 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 6 Mar 2017 10:52:57 -0600 Subject: [PATCH 046/235] Circular profiles, added missing transformation for rectangles --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp | 41 +++++++++++++++++-- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index afbb9db9f5..e35dad0f01 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -47,6 +47,7 @@ SHAPE(IfcRightCircularCylinder); SHAPE(IfcRightCircularCone); FACE(IfcArbitraryClosedProfileDef); +FACE(IfcCircleProfileDef); FACE(IfcFace); FACE(IfcRectangleProfileDef); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp index 7c4e64337f..05de331234 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp @@ -24,9 +24,6 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleProfileDef* l, cg #ifdef USE_IFC4 has_position = l->hasPosition(); #endif - if (has_position) { - IfcGeom::CgalKernel::convert(l->Position(), trsf2d); - } face = cgal_face_t(); face.outer.push_back(Kernel::Point_3(-x, -y, 0.0)); @@ -34,6 +31,44 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleProfileDef* l, cg 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::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->entity); + 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; } From 1bcc369c7a66425b17f7e340e3bdfdc8228f4711 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 6 Mar 2017 11:12:06 -0600 Subject: [PATCH 047/235] Rounded rectangles --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp | 51 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index e35dad0f01..d2b1deeb90 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -50,6 +50,7 @@ FACE(IfcArbitraryClosedProfileDef); FACE(IfcCircleProfileDef); FACE(IfcFace); FACE(IfcRectangleProfileDef); +FACE(IfcRoundedRectangleProfileDef); WIRE(IfcPolyLoop); WIRE(IfcPolyline); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp index 05de331234..fad3b6affa 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp @@ -41,6 +41,57 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleProfileDef* l, cg return true; } +// TODO: Untested +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->entity); + 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(); + + 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::IfcCircleProfileDef* l, cgal_face_t& face) { const double r = l->Radius() * getValue(GV_LENGTH_UNIT); if ( r == 0.0f ) { From 584b2e5584eaecf6144b0e5031ad279c0dabec4c Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 6 Mar 2017 11:18:51 -0600 Subject: [PATCH 048/235] IfcTrapeziumProfileDef --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index d2b1deeb90..2528bb3622 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -51,6 +51,7 @@ FACE(IfcCircleProfileDef); FACE(IfcFace); FACE(IfcRectangleProfileDef); FACE(IfcRoundedRectangleProfileDef); +FACE(IfcTrapeziumProfileDef) WIRE(IfcPolyLoop); WIRE(IfcPolyline); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp index fad3b6affa..4b8c369820 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp @@ -92,6 +92,39 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRoundedRectangleProfileDef 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->entity); + 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 ) { From 1d3732aa62bf67ee9d1845b178b136fd215a09f1 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 6 Mar 2017 11:23:37 -0600 Subject: [PATCH 049/235] IfcEllipseProfileDef --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 3 +- src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp | 33 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 2528bb3622..65cdb41309 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -51,7 +51,8 @@ FACE(IfcCircleProfileDef); FACE(IfcFace); FACE(IfcRectangleProfileDef); FACE(IfcRoundedRectangleProfileDef); -FACE(IfcTrapeziumProfileDef) +FACE(IfcTrapeziumProfileDef); +FACE(IfcEllipseProfileDef); WIRE(IfcPolyLoop); WIRE(IfcPolyline); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp index 4b8c369820..294b9d8105 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp @@ -156,6 +156,39 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCircleProfileDef* l, cgal_ 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->entity); + 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(); From 033a2e748262fc011e90e18ea34f2368f41b06a0 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 6 Mar 2017 11:28:57 -0600 Subject: [PATCH 050/235] IfcFaceBasedSurfaceModel --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 65cdb41309..635da2cfd1 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -35,6 +35,7 @@ SHAPES(IfcRepresentation); // IfcAdvancedBrepWithVoids included SHAPES(IfcManifoldSolidBrep); SHAPES(IfcMappedItem); +SHAPES(IfcFaceBasedSurfaceModel); SHAPE(IfcExtrudedAreaSolid); SHAPE(IfcConnectedFaceSet); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index e163bea2b8..66578c5763 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -84,6 +84,21 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcMappedItem* l, ConversionR 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(new CgalShape(s), shell_style ? shell_style : collective_style)); + part_success |= true; + } + } + return part_success; +} + 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)) { From 484cea968e40a441480dfb8f533231fa3180e3ad Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 6 Mar 2017 11:41:58 -0600 Subject: [PATCH 051/235] IfcTriangulatedFaceSet --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + .../kernels/cgal/CgalIfcGeomShapes.cpp | 62 +++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 635da2cfd1..072594ce65 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -46,6 +46,7 @@ SHAPE(IfcSphere); SHAPE(IfcRectangularPyramid); SHAPE(IfcRightCircularCylinder); SHAPE(IfcRightCircularCone); +SHAPE(IfcTriangulatedFaceSet); FACE(IfcArbitraryClosedProfileDef); FACE(IfcCircleProfileDef); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 66578c5763..10f7bde015 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -790,3 +790,65 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCone* l, cgal shape = polyhedron; return true; } + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, cgal_shape_t& shape) { + IfcSchema::IfcCartesianPointList3D* point_list = l->Coordinates(); + const std::vector< std::vector > coordinates = point_list->CoordList(); + std::vector points; + points.reserve(coordinates.size()); + for (std::vector< std::vector >::const_iterator it = coordinates.begin(); it != coordinates.end(); ++it) { + const std::vector& coords = *it; + if (coords.size() != 3) { + Logger::Message(Logger::LOG_ERROR, "Invalid dimensions encountered on Coordinates", l->entity); + 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 > indices = l->CoordIndex(); + + std::list face_list; + + for(std::vector< std::vector >::const_iterator it = indices.begin(); it != indices.end(); ++ it) { + const std::vector& tri = *it; + if (tri.size() != 3) { + Logger::Message(Logger::LOG_ERROR, "Invalid dimensions encountered on CoordIndex", l->entity); + 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->entity); + 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); + } + + // Naive creation + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + 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 (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { + CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); + } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); + // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; + + shape = polyhedron; + return true; +} From ca19d447cce742c648fbe082dddb637b803d9756 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 6 Mar 2017 15:03:57 -0600 Subject: [PATCH 052/235] Zero-radius rounded rectangles --- src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp index 294b9d8105..4d208bd4cc 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp @@ -60,26 +60,29 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRoundedRectangleProfileDef const int segments = 3; - 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)); + 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)); } - 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)); + 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) { From 4f5ecee81e59d6eb567c521d453905c0f78e7462 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 6 Mar 2017 16:03:29 -0600 Subject: [PATCH 053/235] Removing duplicate points, IfcCartesianTransformationOperator3D with problems --- .../kernels/cgal/CgalConversionFunctions.cpp | 41 +++++++++++++++++++ src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + .../kernels/cgal/CgalIfcGeomShapes.cpp | 23 ++++++++++- src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp | 8 ++-- src/ifcgeom/kernels/cgal/CgalKernel.h | 2 + 5 files changed, 69 insertions(+), 6 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index d0d6be43bc..6866dea9e9 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -152,3 +152,44 @@ bool IfcGeom::CgalKernel::convert_wire_to_face(const cgal_wire_t& wire, cgal_fac face.outer = wire; 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(); + } + + 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)); + +// CACHE(IfcCartesianTransformationOperator3D,l,trsf) + return true; +} + +void IfcGeom::CgalKernel::remove_duplicate_points_from_loop(cgal_wire_t& polygon, bool closed, double tol) { + if (tol <= 0.) tol = getValue(GV_PRECISION); + tol *= tol; + + for (int i = 0; i < polygon.size(); ++i) { + for (int j = i+1; j < polygon.size(); ++j) { + if (CGAL::squared_distance(polygon[i], polygon[j]) < tol) { + polygon.erase(polygon.begin()+j); + --j; + } + } if (closed) { + if (CGAL::squared_distance(polygon.front(), polygon.back()) < tol) { + polygon.erase(polygon.begin()+polygon.size()-1); + } + } + } +} diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 072594ce65..78ab93c02e 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -64,3 +64,4 @@ CLASS(IfcDirection,cgal_direction_t); CLASS(IfcAxis2Placement2D,cgal_placement_t); CLASS(IfcAxis2Placement3D,cgal_placement_t); CLASS(IfcObjectPlacement,cgal_placement_t); +CLASS(IfcCartesianTransformationOperator3D,cgal_placement_t); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 10f7bde015..0bdd75128f 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -43,8 +43,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcMappedItem* l, ConversionR return false; } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3D) ) { cgal_placement_t trsf; - Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); -// IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,trsf); + IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,trsf); gtrsf = trsf; } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2D) ) { cgal_placement_t trsf_2d; @@ -108,6 +107,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal cgal_face_t face; if ( !convert_face(l->SweptArea(),face) ) return false; +// std::cout << "Face vertices: " << face.outer.size() << std::endl; cgal_placement_t trsf; bool has_position = true; @@ -125,6 +125,17 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal std::list face_list; face_list.push_back(face); +// if (true) { +// cgal_shape_t polyhedron = CGAL::Polyhedron_3(); +// PolyhedronBuilder builder(&face_list); +// polyhedron.delegate(builder); +// +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/profile.off"); +// fresult << polyhedron << std::endl; +// fresult.close(); +// } + for (std::vector::const_iterator current_vertex = face.outer.begin(); current_vertex != face.outer.end(); ++current_vertex) { @@ -155,6 +166,14 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal // 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()) { + std::cout << "Invalid polyhedron!" << std::endl; + std::ofstream fresult; + fresult.open("/Users/ken/Desktop/invalid.off"); + fresult << polyhedron << std::endl; + fresult.close(); + } + if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp index c6d8820c65..b605eac93a 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp @@ -18,8 +18,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& return false; } - // TODO: Remove repeated points and points that are too close to one another - // remove_duplicate_points_from_loop(polygon, true); + // Remove points that are too close to one another + remove_duplicate_points_from_loop(polygon, true); std::size_t count = polygon.size(); if (original_count - count != 0) { @@ -53,8 +53,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyline* l, cgal_wire_t& polygon.push_back(pnt); } - // TODO: Remove points that are too close to one another - // remove_duplicate_points_from_loop(polygon, false); + // Remove points that are too close to one another + remove_duplicate_points_from_loop(polygon, false); result = polygon; return true; diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 748fd4fbb3..30d0a33792 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -133,6 +133,8 @@ namespace IfcGeom { 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 closed, double tol = -1.); // bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, ConversionResults& cut_shapes); From 27b5fd0fc50cf45bff5f60a07abf2530ad013aea Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 6 Mar 2017 17:29:20 -0600 Subject: [PATCH 054/235] Debug code --- src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 6866dea9e9..040b09bd59 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -167,11 +167,18 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOpe 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)); +// 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; } From 64e385c3614e293303ca4eb5c7679e23ec043b37 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 6 Mar 2017 17:45:55 -0600 Subject: [PATCH 055/235] Skeleton for IfcEdgeLoop and IfcOrientedEdge --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 2 ++ src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 78ab93c02e..1d50cdff5c 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -56,6 +56,8 @@ FACE(IfcRoundedRectangleProfileDef); FACE(IfcTrapeziumProfileDef); FACE(IfcEllipseProfileDef); +WIRE(IfcEdgeLoop); +WIRE(IfcOrientedEdge); WIRE(IfcPolyLoop); WIRE(IfcPolyline); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp index b605eac93a..07adccfe8c 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp @@ -59,3 +59,29 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyline* l, cgal_wire_t& 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? +// 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; + } +} From b299c2747387c6e48f67174cf8c704f65c905586 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 6 Mar 2017 19:28:12 -0600 Subject: [PATCH 056/235] Switched to Nef_polyhedron_3. Some problems... --- .../kernels/cgal/CgalConversionResult.cpp | 13 ++-- .../kernels/cgal/CgalIfcGeomShapes.cpp | 64 +++++++++---------- src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp | 2 +- src/ifcgeom/kernels/cgal/CgalKernel.h | 2 +- 4 files changed, 40 insertions(+), 41 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index cb25f900ef..beffd368cb 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -7,8 +7,11 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, // std::cout << "Model: " << s.size_of_facets() << " facets and " << s.size_of_vertices() << " vertices" << std::endl; // std::cout << "Valid: " << s.is_valid() << std::endl; + CGAL::Polyhedron_3 polyhedron; + s.convert_to_polyhedron(polyhedron); + // Apply transformation - if (place != NULL) for (auto &vertex: vertices(s)) { + if (place != NULL) for (auto &vertex: vertices(polyhedron)) { vertex->point() = vertex->point().transform(trsf); } @@ -22,7 +25,7 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, boost::associative_property_map> vertex_normals_map(vertex_normals); std::map face_normals; boost::associative_property_map> face_normals_map(face_normals); - if (CGAL::Polygon_mesh_processing::triangulate_faces(s)) { + if (CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron)) { // std::cout << "Triangulated model: " << s.size_of_facets() << " facets and " << s.size_of_vertices() << " vertices" << std::endl; } else { Logger::Message(Logger::LOG_ERROR, "Failed to triangulate shape"); @@ -34,10 +37,10 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, // fafter << s << std::endl; // fafter.close(); - CGAL::Polygon_mesh_processing::compute_normals(s, vertex_normals_map, face_normals_map); + CGAL::Polygon_mesh_processing::compute_normals(polyhedron, vertex_normals_map, face_normals_map); std::map::Vertex_const_handle, int> vertices_map; std::size_t initial_size = t->verts().size()/3; - for (auto &vertex: vertices(s)) { + for (auto &vertex: vertices(polyhedron)) { if (vertices_map.count(vertex) == 0) { vertices_map[vertex] = (int)(vertices_map.size()+initial_size); t->addVertex(surface_style_id, @@ -49,7 +52,7 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, } } - for (auto &face: faces(s)) { + for (auto &face: faces(polyhedron)) { if (!face->is_triangle()) { std::cout << "Warning: non-triangular face!" << std::endl; continue; diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 0bdd75128f..6a5d2bf88a 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -159,7 +159,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal } face_list.push_back(top_face); // Naive creation - cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + CGAL::Polyhedron_3 polyhedron = CGAL::Polyhedron_3(); PolyhedronBuilder builder(&face_list); polyhedron.delegate(builder); @@ -179,7 +179,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; - shape = polyhedron; + shape = CGAL::Nef_polyhedron_3(polyhedron); return true; } @@ -209,7 +209,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_ } // Naive creation - cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + CGAL::Polyhedron_3 polyhedron = CGAL::Polyhedron_3(); PolyhedronBuilder builder(&face_list); polyhedron.delegate(builder); @@ -221,7 +221,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_ } // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; - shape = polyhedron; + shape = CGAL::Nef_polyhedron_3(polyhedron); return true; } @@ -279,7 +279,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBlock* l, cgal_shape_t& sh face_list.back().outer.push_back(Kernel::Point_3(dx, 0, dz)); // Naive creation - cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + CGAL::Polyhedron_3 polyhedron = CGAL::Polyhedron_3(); PolyhedronBuilder builder(&face_list); polyhedron.delegate(builder); @@ -298,7 +298,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBlock* l, cgal_shape_t& sh vertex->point() = vertex->point().transform(trsf); } - shape = polyhedron; + shape = CGAL::Nef_polyhedron_3(polyhedron); return true; } @@ -359,16 +359,12 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha const IfcSchema::IfcBooleanOperator::IfcBooleanOperator op = l->Operator(); - CGAL_precondition(s1.is_valid() && s1.is_closed()); - CGAL::Nef_polyhedron_3 nef1(s1); - if (!nef1.is_simple()) { + if (!s1.is_simple()) { Logger::Message(Logger::LOG_ERROR, "s1: Not simple Nef?", operand1->entity); return false; } - CGAL_precondition(s2.is_valid() && s2.is_closed()); - CGAL::Nef_polyhedron_3 nef2(s2); - if (!nef2.is_simple()) { + if (!s2.is_simple()) { Logger::Message(Logger::LOG_ERROR, "s2: Not simple Nef?", operand2->entity); return false; } @@ -385,52 +381,52 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) { // std::cout << "Difference" << std::endl; - CGAL::Nef_polyhedron_3 nef_result = nef1-nef2; + CGAL::Nef_polyhedron_3 nef_result = s1-s2; if (!nef_result.is_simple()) { std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; return false; } - cgal_shape_t result; - nef_result.convert_to_polyhedron(result); +// cgal_shape_t result; +// nef_result.convert_to_polyhedron(result); // std::ofstream fresult; // fresult.open("/Users/ken/Desktop/result.off"); // fresult << result << std::endl; // fresult.close(); - shape = result; + shape = nef_result; return true; } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) { // std::cout << "Union" << std::endl; - CGAL::Nef_polyhedron_3 nef_result = nef1+nef2; + CGAL::Nef_polyhedron_3 nef_result = s1+s2; if (!nef_result.is_simple()) { std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; return false; } - cgal_shape_t result; - nef_result.convert_to_polyhedron(result); +// cgal_shape_t result; +// nef_result.convert_to_polyhedron(result); // std::ofstream fresult; // fresult.open("/Users/ken/Desktop/result.off"); // fresult << result << std::endl; // fresult.close(); - shape = result; + shape = nef_result; return true; } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) { // std::cout << "Intersection" << std::endl; - CGAL::Nef_polyhedron_3 nef_result = nef1*nef2; + CGAL::Nef_polyhedron_3 nef_result = s1*s2; if (!nef_result.is_simple()) { std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; return false; } - cgal_shape_t result; - nef_result.convert_to_polyhedron(result); +// cgal_shape_t result; +// nef_result.convert_to_polyhedron(result); // std::ofstream fresult; // fresult.open("/Users/ken/Desktop/result.off"); // fresult << result << std::endl; // fresult.close(); - shape = result; + shape = nef_result; return true; } @@ -608,7 +604,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& s } // Naive creation - cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + CGAL::Polyhedron_3 polyhedron = CGAL::Polyhedron_3(); PolyhedronBuilder builder(&face_list); polyhedron.delegate(builder); @@ -639,7 +635,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& s // fresult << polyhedron << std::endl; // fresult.close(); - shape = polyhedron; + shape = CGAL::Nef_polyhedron_3(polyhedron); return true; } @@ -679,7 +675,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangularPyramid* l, cga face_list.back().outer.push_back(Kernel::Point_3(0.5*dx, 0.5*dy, dz)); // Naive creation - cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + CGAL::Polyhedron_3 polyhedron = CGAL::Polyhedron_3(); PolyhedronBuilder builder(&face_list); polyhedron.delegate(builder); @@ -698,7 +694,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangularPyramid* l, cga vertex->point() = vertex->point().transform(trsf); } - shape = polyhedron; + shape = CGAL::Nef_polyhedron_3(polyhedron); return true; } @@ -737,7 +733,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, } // Naive creation - cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + CGAL::Polyhedron_3 polyhedron = CGAL::Polyhedron_3(); PolyhedronBuilder builder(&face_list); polyhedron.delegate(builder); @@ -756,7 +752,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, vertex->point() = vertex->point().transform(trsf); } - shape = polyhedron; + shape = CGAL::Nef_polyhedron_3(polyhedron); return true; } @@ -787,7 +783,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCone* l, cgal } // Naive creation - cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + CGAL::Polyhedron_3 polyhedron = CGAL::Polyhedron_3(); PolyhedronBuilder builder(&face_list); polyhedron.delegate(builder); @@ -806,7 +802,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCone* l, cgal vertex->point() = vertex->point().transform(trsf); } - shape = polyhedron; + shape = CGAL::Nef_polyhedron_3(polyhedron); return true; } @@ -856,7 +852,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, cg } // Naive creation - cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + CGAL::Polyhedron_3 polyhedron = CGAL::Polyhedron_3(); PolyhedronBuilder builder(&face_list); polyhedron.delegate(builder); @@ -868,6 +864,6 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, cg } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; - shape = polyhedron; + shape = CGAL::Nef_polyhedron_3(polyhedron); return true; } diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp index 07adccfe8c..220b854930 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp @@ -66,7 +66,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcEdgeLoop* l, cgal_wire_t& 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? + // TODO: What to do here? Add some points only? // mw.Add(TopoDS::Edge(TopoDS_Iterator(w).Value())); return false; } diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 30d0a33792..ada2fdd91c 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -62,7 +62,7 @@ struct cgal_face_t { std::vector inner; }; -typedef CGAL::Polyhedron_3 cgal_shape_t; +typedef CGAL::Nef_polyhedron_3 cgal_shape_t; typedef boost::graph_traits>::vertex_descriptor cgal_vertex_descriptor_t; typedef boost::graph_traits>::face_descriptor cgal_face_descriptor_t; From 1fb76a9749acfb4eb28381c0c016cdfc988e4bfd Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 7 Mar 2017 12:50:06 -0600 Subject: [PATCH 057/235] Switched to normals per vertex per face --- .../kernels/cgal/CgalConversionResult.cpp | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index beffd368cb..171b7ee2e8 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -38,19 +38,6 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, // fafter.close(); CGAL::Polygon_mesh_processing::compute_normals(polyhedron, vertex_normals_map, face_normals_map); - std::map::Vertex_const_handle, int> vertices_map; - std::size_t initial_size = t->verts().size()/3; - for (auto &vertex: vertices(polyhedron)) { - if (vertices_map.count(vertex) == 0) { - vertices_map[vertex] = (int)(vertices_map.size()+initial_size); - t->addVertex(surface_style_id, - CGAL::to_double(vertex->point().cartesian(0)), - CGAL::to_double(vertex->point().cartesian(1)), - CGAL::to_double(vertex->point().cartesian(2))); -// std::cout << "Size: " << t->verts().size() << std::endl; - for (int i = 0; i < 3; ++i) t->normals().push_back(CGAL::to_double(vertex_normals_map[vertex].cartesian(i))); - } - } for (auto &face: faces(polyhedron)) { if (!face->is_triangle()) { @@ -59,7 +46,12 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, } CGAL::Polyhedron_3::Halfedge_around_facet_const_circulator current_halfedge = face->facet_begin(); do { - t->faces().push_back(vertices_map[current_halfedge->vertex()]); + t->faces().push_back((int)t->verts().size()/3); + 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))); + for (int i = 0; i < 3; ++i) t->normals().push_back(CGAL::to_double(face_normals_map[face].cartesian(i))); ++current_halfedge; } while (current_halfedge != face->facet_begin()); t->material_ids().push_back(surface_style_id); From 29021d8b0638fb1d517a11caed04906f9efc68cb Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 7 Mar 2017 13:04:22 -0600 Subject: [PATCH 058/235] Hollow circles --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp | 39 +++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 1d50cdff5c..f9f1b43252 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -49,6 +49,7 @@ SHAPE(IfcRightCircularCone); SHAPE(IfcTriangulatedFaceSet); FACE(IfcArbitraryClosedProfileDef); +FACE(IfcCircleHollowProfileDef); FACE(IfcCircleProfileDef); FACE(IfcFace); FACE(IfcRectangleProfileDef); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp index 4d208bd4cc..f49fcc8cf2 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp @@ -159,6 +159,45 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCircleProfileDef* l, cgal_ 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->entity); + 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); + } + } + + 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); From 31d4de228abc4136409845a3b0f63482e79771a4 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 7 Mar 2017 13:18:49 -0600 Subject: [PATCH 059/235] Extrusions with holes (Nef) --- .../kernels/cgal/CgalIfcGeomShapes.cpp | 76 ++++++++++++++++--- 1 file changed, 67 insertions(+), 9 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 6a5d2bf88a..f028fec103 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -105,8 +105,9 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal return false; } - cgal_face_t face; - if ( !convert_face(l->SweptArea(),face) ) 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; @@ -123,7 +124,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal // std::cout << "Direction: " << dir << std::endl; std::list face_list; - face_list.push_back(face); + face_list.push_back(bottom_face); // if (true) { // cgal_shape_t polyhedron = CGAL::Polyhedron_3(); @@ -136,13 +137,13 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal // fresult.close(); // } - for (std::vector::const_iterator current_vertex = face.outer.begin(); - current_vertex != face.outer.end(); + for (std::vector::const_iterator current_vertex = bottom_face.outer.begin(); + current_vertex != bottom_face.outer.end(); ++current_vertex) { std::vector::const_iterator next_vertex = current_vertex; ++next_vertex; - if (next_vertex == face.outer.end()) { - next_vertex = face.outer.begin(); + 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); @@ -152,8 +153,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal } cgal_face_t top_face; - for (std::vector::const_reverse_iterator vertex = face.outer.rbegin(); - vertex != face.outer.rend(); + for (std::vector::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); @@ -180,6 +181,63 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; shape = CGAL::Nef_polyhedron_3(polyhedron); + + // 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; + face_list.push_back(hole_bottom_face); + + for (std::vector::const_iterator current_vertex = inner.begin(); + current_vertex != inner.end(); + ++current_vertex) { + std::vector::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::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); + + // Naive creation + CGAL::Polyhedron_3 hole_polyhedron = CGAL::Polyhedron_3(); + PolyhedronBuilder builder(&face_list); + hole_polyhedron.delegate(builder); + + // Stitch edges + // std::cout << "Before: " << hole_polyhedron.size_of_vertices() << " vertices and " << hole_polyhedron.size_of_facets() << " facets" << std::endl; + CGAL::Polygon_mesh_processing::stitch_borders(hole_polyhedron); + if (!hole_polyhedron.is_valid()) { + std::cout << "Invalid hole polyhedron!" << std::endl; + std::ofstream fresult; + fresult.open("/Users/ken/Desktop/invalid.off"); + fresult << hole_polyhedron << std::endl; + fresult.close(); + } + + if (!CGAL::Polygon_mesh_processing::is_outward_oriented(hole_polyhedron)) { + CGAL::Polygon_mesh_processing::reverse_face_orientations(hole_polyhedron); + } CGAL_postcondition(hole_polyhedron.is_valid() && hole_polyhedron.is_closed()); + // std::cout << "After: " << hole_polyhedron.size_of_vertices() << " vertices and " << hole_polyhedron.size_of_facets() << " facets" << std::endl; + + shape -= CGAL::Nef_polyhedron_3(hole_polyhedron); + } + return true; } From 66048610e239232237983ede202bbc92bbbb4001 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 7 Mar 2017 13:41:04 -0600 Subject: [PATCH 060/235] Rounded rectangles work now, def must be before rectangles --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 2 +- src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index f9f1b43252..52ca33352d 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -52,8 +52,8 @@ FACE(IfcArbitraryClosedProfileDef); FACE(IfcCircleHollowProfileDef); FACE(IfcCircleProfileDef); FACE(IfcFace); -FACE(IfcRectangleProfileDef); FACE(IfcRoundedRectangleProfileDef); +FACE(IfcRectangleProfileDef); FACE(IfcTrapeziumProfileDef); FACE(IfcEllipseProfileDef); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp index f49fcc8cf2..c5e861b587 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp @@ -43,6 +43,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleProfileDef* l, cg // TODO: Untested bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRoundedRectangleProfileDef* l, cgal_face_t& face) { + std::cout << "IfcRoundedRectangleProfileDef" << std::endl; + 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); @@ -73,14 +75,17 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRoundedRectangleProfileDef 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); + } + 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); + } + 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); + } + 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)); } } From 27d8e860245f9b3a725ca7bbad464337e35361f8 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 7 Mar 2017 13:52:29 -0600 Subject: [PATCH 061/235] Hollow rectangle profiles, all tested now --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp | 101 +++++++++++++++++- 2 files changed, 99 insertions(+), 3 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 52ca33352d..b85f741966 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -53,6 +53,7 @@ FACE(IfcCircleHollowProfileDef); FACE(IfcCircleProfileDef); FACE(IfcFace); FACE(IfcRoundedRectangleProfileDef); +FACE(IfcRectangleHollowProfileDef); FACE(IfcRectangleProfileDef); FACE(IfcTrapeziumProfileDef); FACE(IfcEllipseProfileDef); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp index c5e861b587..9e8fe9fecf 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp @@ -41,10 +41,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleProfileDef* l, cg return true; } -// TODO: Untested bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRoundedRectangleProfileDef* l, cgal_face_t& face) { - std::cout << "IfcRoundedRectangleProfileDef" << std::endl; - 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); @@ -100,6 +97,100 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRoundedRectangleProfileDef 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->entity); + 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); @@ -197,6 +288,10 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCircleHollowProfileDef* l, 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); + } } } From 3f94d4af37da312cd1972459655dd31bd59663d6 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 7 Mar 2017 14:30:48 -0600 Subject: [PATCH 062/235] Skeleton for planes+halfspaces. Might be wrong. --- .../kernels/cgal/CgalConversionFunctions.cpp | 12 ++++++++++++ src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 2 ++ src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp | 18 ++++++++++++++++++ src/ifcgeom/kernels/cgal/CgalKernel.h | 1 + 4 files changed, 33 insertions(+) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 040b09bd59..50c0cb892d 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -49,6 +49,18 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcDirection* l, cgal_directi 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); + IfcGeom::CgalKernel::convert(l->Location(),o); + if ( l->hasAxis() ) IfcGeom::CgalKernel::convert(l->Axis(),axis); + plane = Kernel::Plane_3(o, axis); +// 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; diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index b85f741966..77c654e604 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -47,6 +47,7 @@ SHAPE(IfcRectangularPyramid); SHAPE(IfcRightCircularCylinder); SHAPE(IfcRightCircularCone); SHAPE(IfcTriangulatedFaceSet); +SHAPE(IfcHalfSpaceSolid); FACE(IfcArbitraryClosedProfileDef); FACE(IfcCircleHollowProfileDef); @@ -65,6 +66,7 @@ WIRE(IfcPolyline); CLASS(IfcCartesianPoint,cgal_point_t); CLASS(IfcDirection,cgal_direction_t); +CLASS(IfcPlane,cgal_plane_t); CLASS(IfcAxis2Placement2D,cgal_placement_t); CLASS(IfcAxis2Placement3D,cgal_placement_t); CLASS(IfcObjectPlacement,cgal_placement_t); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index f028fec103..8882d9e961 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -925,3 +925,21 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, cg shape = CGAL::Nef_polyhedron_3(polyhedron); return true; } + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, cgal_shape_t& shape) { + IfcSchema::IfcSurface* surface = l->BaseSurface(); + if ( ! surface->is(IfcSchema::Type::IfcPlane) ) { + Logger::Message(Logger::LOG_ERROR, "Unsupported BaseSurface:", surface->entity); + return false; + } + cgal_plane_t pln; + IfcGeom::CgalKernel::convert((IfcSchema::IfcPlane*)surface,pln); + + // TODO: This might be the other way around? + 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(); + + shape = CGAL::Nef_polyhedron_3(pln); + return true; +} diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index ada2fdd91c..7a27ae854e 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -54,6 +54,7 @@ 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::Plane_3 cgal_plane_t; typedef std::vector cgal_curve_t; typedef std::vector cgal_wire_t; From a3df0556aa7083dc70415054dd59fd8ded21d2e0 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 7 Mar 2017 19:39:59 -0600 Subject: [PATCH 063/235] Composite curves --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + .../kernels/cgal/CgalIfcGeomShapes.cpp | 5 +- src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp | 90 +++++++++++++++++++ 3 files changed, 94 insertions(+), 2 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 77c654e604..a6e8430528 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -63,6 +63,7 @@ WIRE(IfcEdgeLoop); WIRE(IfcOrientedEdge); WIRE(IfcPolyLoop); WIRE(IfcPolyline); +WIRE(IfcCompositeCurve); CLASS(IfcCartesianPoint,cgal_point_t); CLASS(IfcDirection,cgal_direction_t); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 8882d9e961..07df06545f 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -127,7 +127,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal face_list.push_back(bottom_face); // if (true) { -// cgal_shape_t polyhedron = CGAL::Polyhedron_3(); +// CGAL::Polyhedron_3 polyhedron; // PolyhedronBuilder builder(&face_list); // polyhedron.delegate(builder); // @@ -166,12 +166,13 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal // Stitch edges // std::cout << "Before: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; + CGAL::Polyhedron_3 old_polyhedron(polyhedron); CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!polyhedron.is_valid()) { std::cout << "Invalid polyhedron!" << std::endl; std::ofstream fresult; fresult.open("/Users/ken/Desktop/invalid.off"); - fresult << polyhedron << std::endl; + fresult << old_polyhedron << std::endl; fresult.close(); } diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp index 220b854930..72ac78fa2d 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp @@ -85,3 +85,93 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcOrientedEdge* l, cgal_wire return false; } } + +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->entity); + + // 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->entity); + 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::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, false); + + wire = w; + return true; +} From cb7ed51fc6c3f6c3460778b785d5db769a8de0ea Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 7 Mar 2017 20:00:32 -0600 Subject: [PATCH 064/235] IfcCartesianTransformationOperator3DnonUniform (untested) --- .../kernels/cgal/CgalConversionFunctions.cpp | 30 +++++++++++++++++++ src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + .../kernels/cgal/CgalIfcGeomShapes.cpp | 13 +++++++- 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 50c0cb892d..c931af40bf 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -185,6 +185,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOpe 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) << " "; @@ -195,6 +196,35 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOpe 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 << trsf.cartesian(i, j) << " "; +// } std::cout << std::endl; +// } + +// CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gtrsf) + return true; +} + void IfcGeom::CgalKernel::remove_duplicate_points_from_loop(cgal_wire_t& polygon, bool closed, double tol) { if (tol <= 0.) tol = getValue(GV_PRECISION); tol *= tol; diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index a6e8430528..a98d162c87 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -72,3 +72,4 @@ CLASS(IfcAxis2Placement2D,cgal_placement_t); CLASS(IfcAxis2Placement3D,cgal_placement_t); CLASS(IfcObjectPlacement,cgal_placement_t); CLASS(IfcCartesianTransformationOperator3D,cgal_placement_t); +CLASS(IfcCartesianTransformationOperator3DnonUniform,cgal_placement_t); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 07df06545f..e419996de2 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -36,8 +36,9 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcMappedItem* l, ConversionR cgal_placement_t gtrsf; IfcSchema::IfcCartesianTransformationOperator* transform = l->MappingTarget(); if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3DnonUniform) ) { + IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3DnonUniform*)transform,gtrsf); Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); -// IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3DnonUniform*)transform,gtrsf); + return false; } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2DnonUniform) ) { Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); return false; @@ -45,6 +46,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcMappedItem* l, ConversionR cgal_placement_t trsf; IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,trsf); gtrsf = trsf; +// Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); +// return false; } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2D) ) { cgal_placement_t trsf_2d; Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); @@ -61,9 +64,17 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcMappedItem* l, ConversionR 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(); From 0d36693780e4dd531f09f507dff672ad8560441e Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 8 Mar 2017 19:38:25 -0600 Subject: [PATCH 065/235] C profiles --- .../kernels/cgal/CgalConversionFunctions.cpp | 2 +- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp | 92 +++++++++++++++++++ 3 files changed, 94 insertions(+), 1 deletion(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index c931af40bf..eb6561c890 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -217,7 +217,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOpe // for (int i = 0; i < 3; ++i) { // for (int j = 0; j < 4; ++j) { -// std::cout << trsf.cartesian(i, j) << " "; +// std::cout << gtrsf.cartesian(i, j) << " "; // } std::cout << std::endl; // } diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index a98d162c87..a4102d7d11 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -58,6 +58,7 @@ FACE(IfcRectangleHollowProfileDef); FACE(IfcRectangleProfileDef); FACE(IfcTrapeziumProfileDef); FACE(IfcEllipseProfileDef); +FACE(IfcCShapeProfileDef); WIRE(IfcEdgeLoop); WIRE(IfcOrientedEdge); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp index 9e8fe9fecf..6463169512 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp @@ -376,3 +376,95 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcFace* l, cgal_face_t& face 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->entity); + 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; +} From e922212357af518503880f92cfec7c9b36b1bea5 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 8 Mar 2017 19:55:17 -0600 Subject: [PATCH 066/235] L profiles --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp | 109 ++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index a4102d7d11..fb54c938c5 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -59,6 +59,7 @@ FACE(IfcRectangleProfileDef); FACE(IfcTrapeziumProfileDef); FACE(IfcEllipseProfileDef); FACE(IfcCShapeProfileDef); +FACE(IfcLShapeProfileDef); WIRE(IfcEdgeLoop); WIRE(IfcOrientedEdge); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp index 6463169512..68a27bef3b 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp @@ -468,3 +468,112 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCShapeProfileDef* l, cgal_ 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->entity); + 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->entity); + 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; + +// double coords[12] = {-x,-y, x,-y, x,-y+d-dy1, xx, xy, -x+d-dx1,y, -x,y}; +// int fillets[3] = {2,3,4}; +// double radii[3] = {f2,f1,f2}; +// return profile_helper(6,coords,doFillet ? 3 : 0,fillets,radii,trsf2d,face); +} From 15e4e1952ffa522b0676fa0d0aa5da22d15149a4 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Wed, 8 Mar 2017 20:11:45 -0600 Subject: [PATCH 067/235] I profiles (untested) --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp | 88 +++++++++++++++++-- 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index fb54c938c5..379d855231 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -59,6 +59,7 @@ FACE(IfcRectangleProfileDef); FACE(IfcTrapeziumProfileDef); FACE(IfcEllipseProfileDef); FACE(IfcCShapeProfileDef); +FACE(IfcIShapeProfileDef); FACE(IfcLShapeProfileDef); WIRE(IfcEdgeLoop); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp index 68a27bef3b..69e50cde35 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp @@ -571,9 +571,87 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcLShapeProfileDef* l, cgal_ } return true; - -// double coords[12] = {-x,-y, x,-y, x,-y+d-dy1, xx, xy, -x+d-dx1,y, -x,y}; -// int fillets[3] = {2,3,4}; -// double radii[3] = {f2,f1,f2}; -// return profile_helper(6,coords,doFillet ? 3 : 0,fillets,radii,trsf2d,face); +} + +// 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->is(IfcSchema::Type::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->entity); + 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; } From 619b4fbed53bdfe09b974f2df871379c043afe96 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 9 Mar 2017 12:14:00 +0100 Subject: [PATCH 068/235] Fix CGAL library linking on windows, conditional IfcTriangulatedFaceSet based on schema --- cmake/CMakeLists.txt | 22 +++++++++++++------ src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 2 ++ .../kernels/cgal/CgalIfcGeomShapes.cpp | 2 ++ 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 63c8712908..604bb3781b 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -220,15 +220,23 @@ 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() - MESSAGE(FATAL_ERROR "Unable to find CGAL library files, aborting") + FILE(GLOB CGAL_LIBRARIES ${CGAL_LIBRARY_DIR}/CGAL*.lib) + LIST(LENGTH CGAL_LIBRARY_NAMES num_cgal_library_names) + LIST(LENGTH CGAL_LIBRARIES num_cgal_libraries) + LINK_DIRECTORIES("${CGAL_LIBRARY_DIR}") + if(NOT "${num_cgal_library_names}" STREQUAL "${num_cgal_library_names}") + MESSAGE(FATAL_ERROR "Unable to find CGAL library files, aborting") + endif() + MESSAGE(STATUS "CGAL library files found") ENDIF() -foreach(lib ${CGAL_LIBRARY_NAMES}) - string(REPLACE libCGAL "${lib}" lib_path "${libCGAL}") - list(APPEND CGAL_LIBRARIES "${lib_path}") -endforeach() -FIND_LIBRARY(libGMP NAMES gmp PATHS ${GMP_LIBRARY_DIR} NO_DEFAULT_PATH) -FIND_LIBRARY(libMPFR NAMES mpfr PATHS ${MPFR_LIBRARY_DIR} NO_DEFAULT_PATH) +# TODO: Remove hardcoded version numbers for windows +FIND_LIBRARY(libGMP NAMES gmp "libgmp-10" PATHS ${GMP_LIBRARY_DIR} NO_DEFAULT_PATH) +FIND_LIBRARY(libMPFR NAMES mpfr "libmpfr-4" PATHS ${MPFR_LIBRARY_DIR} NO_DEFAULT_PATH) IF(NOT libGMP) MESSAGE(FATAL_ERROR "Unable to find GMP library files, aborting") ENDIF() diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 379d855231..371a2b7769 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -46,7 +46,9 @@ SHAPE(IfcSphere); SHAPE(IfcRectangularPyramid); SHAPE(IfcRightCircularCylinder); SHAPE(IfcRightCircularCone); +#ifdef USE_IFC4 SHAPE(IfcTriangulatedFaceSet); +#endif SHAPE(IfcHalfSpaceSolid); FACE(IfcArbitraryClosedProfileDef); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index e419996de2..ce8f1fa17f 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -876,6 +876,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCone* l, cgal 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 > coordinates = point_list->CoordList(); @@ -937,6 +938,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, cg shape = CGAL::Nef_polyhedron_3(polyhedron); return true; } +#endif bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, cgal_shape_t& shape) { IfcSchema::IfcSurface* surface = l->BaseSurface(); From 0596827b9d0c9271f1a56a6fe2c6f987089107ff Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 9 Mar 2017 15:04:54 +0100 Subject: [PATCH 069/235] Fix null pointer access in tesselation of opencascade shape --- src/ifcgeom/kernels/opencascade/OpenCascadeShape.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeShape.cpp b/src/ifcgeom/kernels/opencascade/OpenCascadeShape.cpp index fcc94b52e3..da31ee08b9 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeShape.cpp +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeShape.cpp @@ -11,7 +11,10 @@ void IfcGeom::OpenCascadeShape::Triangulate(const IfcGeom::IteratorSettings& settings, const IfcGeom::ConversionResultPlacement* place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const { const TopoDS_Shape& s = shape_; - const gp_GTrsf& trsf = dynamic_cast(place)->trsf(); + gp_GTrsf trsf; + if (place) { + trsf = dynamic_cast(place)->trsf(); + } // Triangulate the shape try { From 7bcd0d0a8dd6dc161358ff175b828614eab908eb Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 9 Mar 2017 15:35:29 +0100 Subject: [PATCH 070/235] Apply transformation to IfcExtrudedAreaSolid --- src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index ce8f1fa17f..3eba31aa9c 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -191,6 +191,10 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; + + for (auto &vertex : vertices(polyhedron)) { + vertex->point() = vertex->point().transform(trsf); + } shape = CGAL::Nef_polyhedron_3(polyhedron); @@ -241,6 +245,10 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal fresult << hole_polyhedron << std::endl; fresult.close(); } + + for (auto &vertex : vertices(hole_polyhedron)) { + vertex->point() = vertex->point().transform(trsf); + } if (!CGAL::Polygon_mesh_processing::is_outward_oriented(hole_polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(hole_polyhedron); From 0fbadc2985f2409762131d79fc41ef251a0cdadc Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 9 Mar 2017 16:29:14 -0600 Subject: [PATCH 071/235] T profiles --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp | 139 ++++++++++++++++++ 2 files changed, 140 insertions(+) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 371a2b7769..99387cec0d 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -63,6 +63,7 @@ FACE(IfcEllipseProfileDef); FACE(IfcCShapeProfileDef); FACE(IfcIShapeProfileDef); FACE(IfcLShapeProfileDef); +FACE(IfcTShapeProfileDef); WIRE(IfcEdgeLoop); WIRE(IfcOrientedEdge); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp index 69e50cde35..5d50e810da 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp @@ -655,3 +655,142 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcIShapeProfileDef* l, cgal_ 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->entity); + 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->entity); + 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; +} From 3e918180d235b5fcee981453841866c15844d64e Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 9 Mar 2017 16:46:09 -0600 Subject: [PATCH 072/235] U profiles --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp | 85 +++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 99387cec0d..eca2679c2c 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -64,6 +64,7 @@ FACE(IfcCShapeProfileDef); FACE(IfcIShapeProfileDef); FACE(IfcLShapeProfileDef); FACE(IfcTShapeProfileDef); +FACE(IfcUShapeProfileDef); WIRE(IfcEdgeLoop); WIRE(IfcOrientedEdge); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp index 5d50e810da..169f8fd8f6 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp @@ -794,3 +794,88 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTShapeProfileDef* l, cgal_ 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->entity); + 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; +} From 3972727f9d6896c20d0e2a613cd762054e932ffe Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 9 Mar 2017 16:55:33 -0600 Subject: [PATCH 073/235] Z profiles --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp | 77 +++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index eca2679c2c..c2f0825b72 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -65,6 +65,7 @@ FACE(IfcIShapeProfileDef); FACE(IfcLShapeProfileDef); FACE(IfcTShapeProfileDef); FACE(IfcUShapeProfileDef); +FACE(IfcZShapeProfileDef); WIRE(IfcEdgeLoop); WIRE(IfcOrientedEdge); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp index 169f8fd8f6..0040b65cc3 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp @@ -879,3 +879,80 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcUShapeProfileDef* l, cgal_ 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->entity); + 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; +} From 06c10dc4da93abf24991a181317f7675736db985 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 9 Mar 2017 17:04:37 -0600 Subject: [PATCH 074/235] Correct plane creation? --- src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index eb6561c890..30e441be04 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -54,9 +54,15 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPlane* pln, cgal_plane_t& IfcSchema::IfcAxis2Placement3D* l = pln->Position(); cgal_point_t o; cgal_direction_t axis = Kernel::Vector_3(0,0,1); + cgal_direction_t refDirection; IfcGeom::CgalKernel::convert(l->Location(),o); + bool hasRef = l->hasRefDirection(); if ( l->hasAxis() ) IfcGeom::CgalKernel::convert(l->Axis(),axis); - plane = Kernel::Plane_3(o, axis); + if ( hasRef ) IfcGeom::CgalKernel::convert(l->RefDirection(),refDirection); + cgal_plane_t ax3; + if ( hasRef ) ax3 = Kernel::Plane_3(o,o+axis,o+refDirection); + else ax3 = Kernel::Plane_3(o,axis); + plane = ax3; // CACHE(IfcPlane,pln,plane) return true; } From 287fb9f0ed115ab515a84b48c9de64f0182d9fbe Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 9 Mar 2017 18:42:54 -0600 Subject: [PATCH 075/235] Convert openings and subtract them --- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 101 ++++++++++++++++++++---- src/ifcgeom/kernels/cgal/CgalKernel.h | 2 +- 2 files changed, 87 insertions(+), 16 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index e67be1c390..f111d9bc93 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -111,25 +111,24 @@ IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representat const std::string product_type = IfcSchema::Type::ToString(product->type()); ElementSettings element_settings(settings, getValue(GV_LENGTH_UNIT), product_type); - if (!settings.get(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && openings && openings->size()) { - Logger::Message(Logger::LOG_ERROR, "Not implemented opening subtractions"); - } - - if (settings.get(IteratorSettings::USE_WORLD_COORDS)) { - // TODO: OpenCascade code uses opened_shapes. Check why. + if (!settings.get(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && openings && openings->size()) { + IfcGeom::ConversionResults opened_shapes; + convert_openings(product,openings,shapes,trsf,opened_shapes); + if (settings.get(IteratorSettings::USE_WORLD_COORDS)) { + for ( IfcGeom::ConversionResults::iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) { + it->prepend(new CgalPlacement(trsf)); + } + trsf = cgal_placement_t(); + } + shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), opened_shapes); + } else if (settings.get(IteratorSettings::USE_WORLD_COORDS)) { for ( IfcGeom::ConversionResults::iterator it = shapes.begin(); it != shapes.end(); ++ it ) { it->prepend(new CgalPlacement(trsf)); } - trsf = Kernel::Aff_transformation_3(); - shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), shapes); - } else if (settings.get(IteratorSettings::USE_WORLD_COORDS)) { - for ( IfcGeom::ConversionResults::iterator it = shapes.begin(); it != shapes.end(); ++ it ) { - it->prepend(new CgalPlacement(trsf)); - } - trsf = Kernel::Aff_transformation_3(); - shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), shapes); + trsf = cgal_placement_t(); + shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), shapes); } else { - shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), shapes); + shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), shapes); } std::string context_string = ""; @@ -191,3 +190,75 @@ IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_processed_r brep->geometry_pointer() ); } + +bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, + const IfcGeom::ConversionResults& entity_shapes, const cgal_placement_t& entity_trsf, IfcGeom::ConversionResults& cut_shapes) { + + std::list opening_shapelist; + + for ( IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++ it ) { + IfcSchema::IfcRelVoidsElement* v = *it; + IfcSchema::IfcFeatureElementSubtraction* fes = v->RelatedOpeningElement(); + if ( fes->is(IfcSchema::Type::IfcOpeningElement) ) { + if (!fes->hasRepresentation()) continue; + + // Convert the IfcRepresentation of the IfcOpeningElement + 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 = opening_trsf * entity_trsf.inverse(); + + 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_shape_t opening_shape(((CgalShape*)opening_shapes[i].Shape())->shape()); + if (opening_shapes[i].Placement()) { + cgal_placement_t gtrsf = *(CgalPlacement*)opening_shapes[i].Placement(); + gtrsf = gtrsf * opening_trsf; + opening_shape.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(); + entity_shape.transform(entity_shape_gtrsf); + } + + cgal_shape_t brep_cut_result(entity_shape); + + for (auto &opening: opening_shapelist) { + brep_cut_result -= opening; + } + + if (brep_cut_result.is_valid()) { + cut_shapes.push_back(IfcGeom::ConversionResult(new CgalShape(brep_cut_result), &it3->Style())); + } else { + // Apparently processing the boolean operation failed or resulted in an invalid result + // in which case the original shape without the subtractions is returned instead + // we try convert the openings in the original way, one by one. + Logger::Message(Logger::LOG_WARNING, "Subtracting combined openings compound failed:", entity->entity); + return false; + } + + } + return true; +} diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 7a27ae854e..e6658f547f 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -137,7 +137,7 @@ namespace IfcGeom { void remove_duplicate_points_from_loop(cgal_wire_t& polygon, bool closed, double tol = -1.); - // bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, ConversionResults& cut_shapes); + 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); void purge_cache() { // Rather hack-ish, but a stopgap solution to keep memory under control From b5e79b2558be6b5382c670d62c185f2e4abde5b2 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 10 Mar 2017 17:44:19 -0600 Subject: [PATCH 076/235] Debug code --- .../kernels/cgal/CgalIfcGeomShapes.cpp | 4 --- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 25 +++++++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 3eba31aa9c..788db838aa 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -37,8 +37,6 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcMappedItem* l, ConversionR IfcSchema::IfcCartesianTransformationOperator* transform = l->MappingTarget(); if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3DnonUniform) ) { IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3DnonUniform*)transform,gtrsf); - Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); - return false; } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2DnonUniform) ) { Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); return false; @@ -46,8 +44,6 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcMappedItem* l, ConversionR cgal_placement_t trsf; IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,trsf); gtrsf = trsf; -// Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); -// return false; } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2D) ) { cgal_placement_t trsf_2d; Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index f111d9bc93..16c58bbd5b 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -213,6 +213,13 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* entity, // Move the opening into the coordinate system of the IfcProduct opening_trsf = opening_trsf * entity_trsf.inverse(); +// std::cout << "opening_trsf" << std::endl; +// for (int i = 0; i < 3; ++i) { +// for (int j = 0; j < 4; ++j) { +// std::cout << opening_trsf.cartesian(i, j) << " "; +// } std::cout << std::endl; +// } + IfcSchema::IfcProductRepresentation* prodrep = fes->Representation(); IfcSchema::IfcRepresentation::list::ptr reps = prodrep->Representations(); @@ -246,7 +253,25 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* entity, cgal_shape_t brep_cut_result(entity_shape); for (auto &opening: opening_shapelist) { + + CGAL::Polyhedron_3 polyhedron; + brep_cut_result.convert_to_polyhedron(polyhedron); + std::ofstream fresult; + fresult.open("/Users/ken/Desktop/before.off"); + fresult << polyhedron << std::endl; + fresult.close(); + + opening.convert_to_polyhedron(polyhedron); + fresult.open("/Users/ken/Desktop/opening.off"); + fresult << polyhedron << std::endl; + fresult.close(); + brep_cut_result -= opening; + + brep_cut_result.convert_to_polyhedron(polyhedron); + fresult.open("/Users/ken/Desktop/after.off"); + fresult << polyhedron << std::endl; + fresult.close(); } if (brep_cut_result.is_valid()) { From ac7099ab39803f6e6f53d55dbd844ff0cda86b59 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 10 Mar 2017 18:21:15 -0600 Subject: [PATCH 077/235] Fixed bug with opening placements --- .../kernels/cgal/CgalIfcGeomShapes.cpp | 24 +++++++++++--- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 33 +++++++++++++++---- 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 788db838aa..e06163c425 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -235,11 +235,12 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal // std::cout << "Before: " << hole_polyhedron.size_of_vertices() << " vertices and " << hole_polyhedron.size_of_facets() << " facets" << std::endl; CGAL::Polygon_mesh_processing::stitch_borders(hole_polyhedron); if (!hole_polyhedron.is_valid()) { - std::cout << "Invalid hole polyhedron!" << std::endl; - std::ofstream fresult; - fresult.open("/Users/ken/Desktop/invalid.off"); - fresult << hole_polyhedron << std::endl; - fresult.close(); +// std::cout << "Invalid hole polyhedron!" << std::endl; +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/invalid.off"); +// fresult << hole_polyhedron << std::endl; +// fresult.close(); + return false; } for (auto &vertex : vertices(hole_polyhedron)) { @@ -254,6 +255,19 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal shape -= CGAL::Nef_polyhedron_3(hole_polyhedron); } +// std::cout << "trsf" << 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; +// } + +// shape.convert_to_polyhedron(polyhedron); +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/extrusion.off"); +// fresult << polyhedron << std::endl; +// fresult.close(); + return true; } diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index 16c58bbd5b..bc13ea6fb0 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -210,10 +210,24 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* entity, } catch (...) {} } +// std::cout << "entity_trsf" << std::endl; +// for (int i = 0; i < 3; ++i) { +// for (int j = 0; j < 4; ++j) { +// std::cout << entity_trsf.cartesian(i, j) << " "; +// } std::cout << std::endl; +// } +// +// std::cout << "opening_trsf before" << std::endl; +// for (int i = 0; i < 3; ++i) { +// for (int j = 0; j < 4; ++j) { +// std::cout << opening_trsf.cartesian(i, j) << " "; +// } std::cout << std::endl; +// } + // Move the opening into the coordinate system of the IfcProduct opening_trsf = opening_trsf * entity_trsf.inverse(); -// std::cout << "opening_trsf" << std::endl; +// std::cout << "opening_trsf after" << std::endl; // for (int i = 0; i < 3; ++i) { // for (int j = 0; j < 4; ++j) { // std::cout << opening_trsf.cartesian(i, j) << " "; @@ -230,12 +244,19 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* entity, } 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 = gtrsf * opening_trsf; cgal_shape_t opening_shape(((CgalShape*)opening_shapes[i].Shape())->shape()); - if (opening_shapes[i].Placement()) { - cgal_placement_t gtrsf = *(CgalPlacement*)opening_shapes[i].Placement(); - gtrsf = gtrsf * opening_trsf; - opening_shape.transform(gtrsf); - } opening_shapelist.push_back(opening_shape); + opening_shape.transform(gtrsf); + opening_shapelist.push_back(opening_shape); + +// std::cout << "gtrsf" << 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; +// } } } From d02918070d601811f730663f400048bc11ffe203 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 10 Mar 2017 18:26:15 -0600 Subject: [PATCH 078/235] Remove debug code --- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 34 +++++++++++++------------ 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index bc13ea6fb0..10e616c318 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -245,7 +245,9 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* entity, 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(); + if (opening_shapes[i].Placement()) { + gtrsf = *(CgalPlacement*)opening_shapes[i].Placement(); + } gtrsf = gtrsf * opening_trsf; cgal_shape_t opening_shape(((CgalShape*)opening_shapes[i].Shape())->shape()); opening_shape.transform(gtrsf); @@ -275,24 +277,24 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* entity, for (auto &opening: opening_shapelist) { - CGAL::Polyhedron_3 polyhedron; - brep_cut_result.convert_to_polyhedron(polyhedron); - std::ofstream fresult; - fresult.open("/Users/ken/Desktop/before.off"); - fresult << polyhedron << std::endl; - fresult.close(); - - opening.convert_to_polyhedron(polyhedron); - fresult.open("/Users/ken/Desktop/opening.off"); - fresult << polyhedron << std::endl; - fresult.close(); +// CGAL::Polyhedron_3 polyhedron; +// brep_cut_result.convert_to_polyhedron(polyhedron); +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/before.off"); +// fresult << polyhedron << std::endl; +// fresult.close(); +// +// opening.convert_to_polyhedron(polyhedron); +// fresult.open("/Users/ken/Desktop/opening.off"); +// fresult << polyhedron << std::endl; +// fresult.close(); brep_cut_result -= opening; - brep_cut_result.convert_to_polyhedron(polyhedron); - fresult.open("/Users/ken/Desktop/after.off"); - fresult << polyhedron << std::endl; - fresult.close(); +// brep_cut_result.convert_to_polyhedron(polyhedron); +// fresult.open("/Users/ken/Desktop/after.off"); +// fresult << polyhedron << std::endl; +// fresult.close(); } if (brep_cut_result.is_valid()) { From 54331062c3fd560fc92ad76fbb330b0578db90a8 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 13 Mar 2017 19:08:23 -0600 Subject: [PATCH 079/235] Basic curve types --- .../kernels/cgal/CgalConversionFunctions.cpp | 9 +++ src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 5 ++ .../kernels/cgal/CgalIfcGeomCurves.cpp | 75 +++++++++++++++++++ src/ifcgeom/kernels/cgal/CgalKernel.h | 1 + 4 files changed, 90 insertions(+) create mode 100644 src/ifcgeom/kernels/cgal/CgalIfcGeomCurves.cpp diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 30e441be04..f290b24061 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -49,6 +49,15 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcDirection* l, cgal_directi 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(); diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index c2f0825b72..21dbc8cbb6 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -73,8 +73,13 @@ WIRE(IfcPolyLoop); WIRE(IfcPolyline); WIRE(IfcCompositeCurve); +CURVE(IfcCircle); +CURVE(IfcEllipse); +CURVE(IfcLine); + CLASS(IfcCartesianPoint,cgal_point_t); CLASS(IfcDirection,cgal_direction_t); +CLASS(IfcVector,cgal_vector_t); CLASS(IfcPlane,cgal_plane_t); CLASS(IfcAxis2Placement2D,cgal_placement_t); CLASS(IfcAxis2Placement3D,cgal_placement_t); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomCurves.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomCurves.cpp new file mode 100644 index 0000000000..536bc74b66 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomCurves.cpp @@ -0,0 +1,75 @@ +#include "CgalKernel.h" + +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->entity); + return false; + } + cgal_placement_t trsf; + IfcSchema::IfcAxis2Placement* placement = l->Position(); + if (placement->is(IfcSchema::Type::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->entity); + return false; + } + cgal_placement_t trsf; + IfcSchema::IfcAxis2Placement* placement = l->Position(); + if (placement->is(IfcSchema::Type::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; +} diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index e6658f547f..f63404d129 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -54,6 +54,7 @@ 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 cgal_curve_t; typedef std::vector cgal_wire_t; From 7d16b725a33d2ffd938a7c2772d930d9ef44ec17 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 13 Mar 2017 19:08:50 -0600 Subject: [PATCH 080/235] IfcTrimmedCurve. Needs projection to closest point in curve? --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp | 158 ++++++++++++++++++ 2 files changed, 159 insertions(+) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 21dbc8cbb6..80a6cae20a 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -72,6 +72,7 @@ WIRE(IfcOrientedEdge); WIRE(IfcPolyLoop); WIRE(IfcPolyline); WIRE(IfcCompositeCurve); +WIRE(IfcTrimmedCurve); CURVE(IfcCircle); CURVE(IfcEllipse); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp index 72ac78fa2d..c6832de476 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp @@ -175,3 +175,161 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCompositeCurve* l, cgal_wi wire = w; return true; } + +// TODO: Project points to closest point in curve? +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTrimmedCurve* l, cgal_wire_t& wire) { + IfcSchema::IfcCurve* basis_curve = l->BasisCurve(); + bool isConic = basis_curve->is(IfcSchema::Type::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->is(IfcSchema::Type::IfcCartesianPoint) ) { + IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[sense_agreement] ); + has_pnts[sense_agreement] = true; + } else if ( i->is(IfcSchema::Type::IfcParameterValue) ) { + const double value = *((IfcSchema::IfcParameterValue*)i); + flts[sense_agreement] = value * parameterFactor; + has_flts[sense_agreement] = true; + } + } + for ( IfcEntityList::it it = trims2->begin(); it != trims2->end(); it ++ ) { + IfcUtil::IfcBaseClass* i = *it; + if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) { + IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[1-sense_agreement] ); + has_pnts[1-sense_agreement] = true; + } else if ( i->is(IfcSchema::Type::IfcParameterValue) ) { + const double value = *((IfcSchema::IfcParameterValue*)i); + flts[1-sense_agreement] = value * parameterFactor; + has_flts[1-sense_agreement] = true; + } + } + trim_cartesian &= has_pnts[0] && has_pnts[1]; + bool trim_cartesian_failed = !trim_cartesian; + if ( trim_cartesian ) { + if ( 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->entity); + return false; + } + if (l->SenseAgreement()) { + bool found = false; + int loops_to_go = 2; + std::vector::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::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->is(IfcSchema::Type::IfcLine) ) { + IfcSchema::IfcLine* line = static_cast(basis_curve); + const double magnitude = line->Dir()->Magnitude(); + flts[0] *= magnitude; flts[1] *= magnitude; + } + if ( basis_curve->is(IfcSchema::Type::IfcEllipse) ) { + IfcSchema::IfcEllipse* ellipse = static_cast(basis_curve); + double x = ellipse->SemiAxis1() * getValue(GV_LENGTH_UNIT); + double y = ellipse->SemiAxis2() * getValue(GV_LENGTH_UNIT); + const bool rotated = y > x; + if (rotated) { + flts[0] -= M_PI / 2.; + flts[1] -= M_PI / 2.; + } + } + if ( isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],M_PI*2.),0.) ) { + for (auto &point: curve) w.push_back(point); + } else { + if (l->SenseAgreement()) { + bool found = false; + int loops_to_go = 2; + std::vector::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::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()); + } + } + } 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; +} From 81cb7f379ea1ecfea634a10d30acdc98cf9d9e4d Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 13 Mar 2017 19:26:54 -0600 Subject: [PATCH 081/235] Ignore output files in /test/ --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index f7b2047913..69f95db0c8 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,9 @@ __pycache__ # Visual Studio Code files .vscode +# Mac metadata .DS_Store +# Conversion results +/test/input/*.obj +/test/input/*.mtl +/test/input/*.tmp \ No newline at end of file From 38cbdbc0f422bfbb9934b2efa3032a6ad7c86e09 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 13 Mar 2017 20:22:19 -0600 Subject: [PATCH 082/235] Correct way to create trimmed parametric curves? --- src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp | 66 +++++-------------- 1 file changed, 16 insertions(+), 50 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp index c6832de476..674ba921d6 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp @@ -176,7 +176,6 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCompositeCurve* l, cgal_wi return true; } -// TODO: Project points to closest point in curve? bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTrimmedCurve* l, cgal_wire_t& wire) { IfcSchema::IfcCurve* basis_curve = l->BasisCurve(); bool isConic = basis_curve->is(IfcSchema::Type::IfcConic); @@ -217,6 +216,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTrimmedCurve* l, cgal_wire 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->entity); return false; @@ -272,58 +272,24 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTrimmedCurve* l, cgal_wire const double magnitude = line->Dir()->Magnitude(); flts[0] *= magnitude; flts[1] *= magnitude; } - if ( basis_curve->is(IfcSchema::Type::IfcEllipse) ) { - IfcSchema::IfcEllipse* ellipse = static_cast(basis_curve); - double x = ellipse->SemiAxis1() * getValue(GV_LENGTH_UNIT); - double y = ellipse->SemiAxis2() * getValue(GV_LENGTH_UNIT); - const bool rotated = y > x; - if (rotated) { - flts[0] -= M_PI / 2.; - flts[1] -= M_PI / 2.; - } - } if ( isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],M_PI*2.),0.) ) { for (auto &point: curve) w.push_back(point); } else { - if (l->SenseAgreement()) { - bool found = false; - int loops_to_go = 2; - std::vector::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::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()); + const int segments_of_full_curve = 12; + double segment_angle = 2.0*3.141592653589793/segments_of_full_curve; + if ( basis_curve->is(IfcSchema::Type::IfcEllipse) ) { + IfcSchema::IfcEllipse* ellipse = static_cast(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->is(IfcSchema::Type::IfcCircle) ) { + IfcSchema::IfcCircle* circle = static_cast(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]) ) { From d2aef0fcbd1cbd13db725fa1c527435776ec3a0d Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 13 Mar 2017 22:32:12 -0600 Subject: [PATCH 083/235] 2D Cartesian transformations (untested) --- .../kernels/cgal/CgalConversionFunctions.cpp | 48 +++++++++++++++++++ src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 4 +- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index f290b24061..61477a3c78 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -180,6 +180,54 @@ bool IfcGeom::CgalKernel::convert_wire_to_face(const cgal_wire_t& wire, cgal_fac 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& gtrsf) { +// IN_CACHE(IfcCartesianTransformationOperator2DnonUniform,l,cgal_placement_t,gtrsf) + + 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); + + 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; diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 80a6cae20a..e0ecad5298 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -85,5 +85,7 @@ CLASS(IfcPlane,cgal_plane_t); CLASS(IfcAxis2Placement2D,cgal_placement_t); CLASS(IfcAxis2Placement3D,cgal_placement_t); CLASS(IfcObjectPlacement,cgal_placement_t); -CLASS(IfcCartesianTransformationOperator3D,cgal_placement_t); +CLASS(IfcCartesianTransformationOperator2DnonUniform,cgal_placement_t); CLASS(IfcCartesianTransformationOperator3DnonUniform,cgal_placement_t); +CLASS(IfcCartesianTransformationOperator2D,cgal_placement_t); +CLASS(IfcCartesianTransformationOperator3D,cgal_placement_t); From 98ce04ed6480283c8fbd9507d97e40b0ecb63ccc Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 16 Mar 2017 18:44:25 -0600 Subject: [PATCH 084/235] Fix logic of transformations --- .../kernels/cgal/CgalConversionFunctions.cpp | 68 +++++++++++++------ .../kernels/cgal/CgalIfcGeomShapes.cpp | 2 +- 2 files changed, 47 insertions(+), 23 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 61477a3c78..7e9c48046e 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -25,18 +25,11 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRepresentation* l, Convers bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_point_t& point) { std::vector xyz = l->Coordinates(); - if (xyz.size() < 4) { - 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; - } else { - std::cout << "Point("; - for (auto &coordinate: xyz) std::cout << coordinate << " "; - std::cout << ")"; - throw std::runtime_error("Could not parse point"); - } + 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) { @@ -63,15 +56,46 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPlane* pln, cgal_plane_t& IfcSchema::IfcAxis2Placement3D* l = pln->Position(); cgal_point_t o; cgal_direction_t axis = Kernel::Vector_3(0,0,1); - cgal_direction_t refDirection; + 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+axis,o+refDirection); + 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; } @@ -79,14 +103,13 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPlane* pln, cgal_plane_t& 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 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 ( hasRef ) IfcGeom::CgalKernel::convert(l->RefDirection(),refDirection); + cgal_direction_t y = Kernel::Vector_3(-refDirection.y(), refDirection.x(), 0.0); - // TODO: From Thomas' email. Should be checked. - Kernel::Vector_3 y = CGAL::cross_product(Kernel::Vector_3(0.0, 0.0, 1.0), refDirection); + // 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); @@ -104,16 +127,17 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement3D* l, cgal_ 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); // std::cout << "Ref direction: " << refDirection << std::endl; // std::cout << "Axis: " << axis << std::endl; // std::cout << "Origin: " << o << std::endl; - // TODO: From Thomas' email. Should be checked. - Kernel::Vector_3 y = CGAL::cross_product(axis, refDirection); - trsf = Kernel::Aff_transformation_3(refDirection.cartesian(0), y.cartesian(0), axis.cartesian(0), o.cartesian(0), - refDirection.cartesian(1), y.cartesian(1), axis.cartesian(1), o.cartesian(1), - refDirection.cartesian(2), y.cartesian(2), axis.cartesian(2), o.cartesian(2)); + // 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) { diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index e06163c425..dfe4782294 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -967,7 +967,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, cgal_sh cgal_plane_t pln; IfcGeom::CgalKernel::convert((IfcSchema::IfcPlane*)surface,pln); - // TODO: This might be the other way around? + // TODO: This might be the other way around 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(); From 30e88210b28bc2343bbb8c8d1f0e2a27d376ed3a Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 16 Mar 2017 19:20:41 -0600 Subject: [PATCH 085/235] Simplified code by moving Nef creation outside --- .../kernels/cgal/CgalConversionFunctions.cpp | 25 ++ .../kernels/cgal/CgalIfcGeomShapes.cpp | 224 ++---------------- src/ifcgeom/kernels/cgal/CgalKernel.h | 4 +- 3 files changed, 44 insertions(+), 209 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 7e9c48046e..b44429d144 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -329,3 +329,28 @@ void IfcGeom::CgalKernel::remove_duplicate_points_from_loop(cgal_wire_t& polygon } } } + +CGAL::Nef_polyhedron_3 IfcGeom::CgalKernel::create_nef_polyhedron(std::list &face_list) { + + // Naive creation + CGAL::Polyhedron_3 polyhedron = CGAL::Polyhedron_3(); + 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()) { + std::cout << "Invalid polyhedron!" << std::endl; + std::ofstream fresult; + fresult.open("/Users/ken/Desktop/invalid.off"); + fresult << old_polyhedron << std::endl; + fresult.close(); + } + 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 CGAL::Nef_polyhedron_3(polyhedron); +} diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index dfe4782294..7ac1ec8677 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -133,17 +133,6 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal std::list face_list; face_list.push_back(bottom_face); -// if (true) { -// CGAL::Polyhedron_3 polyhedron; -// PolyhedronBuilder builder(&face_list); -// polyhedron.delegate(builder); -// -// std::ofstream fresult; -// fresult.open("/Users/ken/Desktop/profile.off"); -// fresult << polyhedron << std::endl; -// fresult.close(); -// } - for (std::vector::const_iterator current_vertex = bottom_face.outer.begin(); current_vertex != bottom_face.outer.end(); ++current_vertex) { @@ -166,33 +155,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal top_face.outer.push_back(*vertex+height*dir); } face_list.push_back(top_face); - // Naive creation - CGAL::Polyhedron_3 polyhedron = CGAL::Polyhedron_3(); - 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::Polyhedron_3 old_polyhedron(polyhedron); - CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); - if (!polyhedron.is_valid()) { - std::cout << "Invalid polyhedron!" << std::endl; - std::ofstream fresult; - fresult.open("/Users/ken/Desktop/invalid.off"); - fresult << old_polyhedron << std::endl; - fresult.close(); - } - - if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { - CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); - // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; - - for (auto &vertex : vertices(polyhedron)) { - vertex->point() = vertex->point().transform(trsf); - } - - shape = CGAL::Nef_polyhedron_3(polyhedron); + shape = create_nef_polyhedron(face_list); // Inner // TODO: Would be faster to triangulate top/bottom face template rather than use Nef polyhedra for subtraction @@ -226,48 +189,10 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal hole_top_face.outer.push_back(*vertex+height*dir); } face_list.push_back(hole_top_face); - // Naive creation - CGAL::Polyhedron_3 hole_polyhedron = CGAL::Polyhedron_3(); - PolyhedronBuilder builder(&face_list); - hole_polyhedron.delegate(builder); - - // Stitch edges - // std::cout << "Before: " << hole_polyhedron.size_of_vertices() << " vertices and " << hole_polyhedron.size_of_facets() << " facets" << std::endl; - CGAL::Polygon_mesh_processing::stitch_borders(hole_polyhedron); - if (!hole_polyhedron.is_valid()) { -// std::cout << "Invalid hole polyhedron!" << std::endl; -// std::ofstream fresult; -// fresult.open("/Users/ken/Desktop/invalid.off"); -// fresult << hole_polyhedron << std::endl; -// fresult.close(); - return false; - } - - for (auto &vertex : vertices(hole_polyhedron)) { - vertex->point() = vertex->point().transform(trsf); - } - - if (!CGAL::Polygon_mesh_processing::is_outward_oriented(hole_polyhedron)) { - CGAL::Polygon_mesh_processing::reverse_face_orientations(hole_polyhedron); - } CGAL_postcondition(hole_polyhedron.is_valid() && hole_polyhedron.is_closed()); - // std::cout << "After: " << hole_polyhedron.size_of_vertices() << " vertices and " << hole_polyhedron.size_of_facets() << " facets" << std::endl; - - shape -= CGAL::Nef_polyhedron_3(hole_polyhedron); + shape -= create_nef_polyhedron(face_list); } -// std::cout << "trsf" << 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; -// } - -// shape.convert_to_polyhedron(polyhedron); -// std::ofstream fresult; -// fresult.open("/Users/ken/Desktop/extrusion.off"); -// fresult << polyhedron << std::endl; -// fresult.close(); - + shape.transform(trsf); return true; } @@ -296,20 +221,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_ face_list.push_back(face); } - // Naive creation - CGAL::Polyhedron_3 polyhedron = CGAL::Polyhedron_3(); - 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 (!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; - - shape = CGAL::Nef_polyhedron_3(polyhedron); + shape = create_nef_polyhedron(face_list); return true; } @@ -366,27 +278,12 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBlock* l, cgal_shape_t& sh face_list.back().outer.push_back(Kernel::Point_3(dx, dy, dz)); face_list.back().outer.push_back(Kernel::Point_3(dx, 0, dz)); - // Naive creation - CGAL::Polyhedron_3 polyhedron = CGAL::Polyhedron_3(); - 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 (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { - CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); - // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; - cgal_placement_t trsf; IfcGeom::CgalKernel::convert(l->Position(),trsf); - for (auto &vertex: vertices(polyhedron)) { - vertex->point() = vertex->point().transform(trsf); - } - - shape = CGAL::Nef_polyhedron_3(polyhedron); + shape = create_nef_polyhedron(face_list); + shape.transform(trsf); + return true; } @@ -691,39 +588,11 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& s } face_list = refined_face_list; } - // Naive creation - CGAL::Polyhedron_3 polyhedron = CGAL::Polyhedron_3(); - PolyhedronBuilder builder(&face_list); - polyhedron.delegate(builder); - -// std::ofstream fresult; -// fresult.open("/Users/ken/Desktop/sphere.off"); -// fresult << polyhedron << std::endl; -// fresult.close(); - - // 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 (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { - CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); - // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; - cgal_placement_t trsf; IfcGeom::CgalKernel::convert(l->Position(),trsf); - for (auto &vertex: vertices(polyhedron)) { - vertex->point() = Kernel::Point_3(vertex->point().x()*r, - vertex->point().y()*r, - vertex->point().z()*r).transform(trsf); - } - -// std::ofstream fresult; -// fresult.open("/Users/ken/Desktop/sphere.off"); -// fresult << polyhedron << std::endl; -// fresult.close(); - - shape = CGAL::Nef_polyhedron_3(polyhedron); + shape = create_nef_polyhedron(face_list); + shape.transform(trsf); return true; } @@ -762,27 +631,11 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangularPyramid* l, cga 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)); - // Naive creation - CGAL::Polyhedron_3 polyhedron = CGAL::Polyhedron_3(); - 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 (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { - CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); - // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; - cgal_placement_t trsf; IfcGeom::CgalKernel::convert(l->Position(),trsf); - for (auto &vertex: vertices(polyhedron)) { - vertex->point() = vertex->point().transform(trsf); - } - - shape = CGAL::Nef_polyhedron_3(polyhedron); + shape = create_nef_polyhedron(face_list); + shape.transform(trsf); return true; } @@ -820,27 +673,11 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, face_list.back().outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), h)); } - // Naive creation - CGAL::Polyhedron_3 polyhedron = CGAL::Polyhedron_3(); - 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 (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { - CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); - // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; - cgal_placement_t trsf; IfcGeom::CgalKernel::convert(l->Position(),trsf); - for (auto &vertex: vertices(polyhedron)) { - vertex->point() = vertex->point().transform(trsf); - } - - shape = CGAL::Nef_polyhedron_3(polyhedron); + shape = create_nef_polyhedron(face_list); + shape.transform(trsf); return true; } @@ -870,27 +707,11 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCone* l, cgal face_list.back().outer.push_back(Kernel::Point_3(0, 0, h)); } - // Naive creation - CGAL::Polyhedron_3 polyhedron = CGAL::Polyhedron_3(); - 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 (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { - CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); - // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; - cgal_placement_t trsf; IfcGeom::CgalKernel::convert(l->Position(),trsf); - for (auto &vertex: vertices(polyhedron)) { - vertex->point() = vertex->point().transform(trsf); - } - - shape = CGAL::Nef_polyhedron_3(polyhedron); + shape = create_nef_polyhedron(face_list); + shape.transform(trsf); return true; } @@ -940,20 +761,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, cg face_list.back().outer.push_back(c); } - // Naive creation - CGAL::Polyhedron_3 polyhedron = CGAL::Polyhedron_3(); - 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 (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { - CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); - // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; - - shape = CGAL::Nef_polyhedron_3(polyhedron); + shape = create_nef_polyhedron(face_list); return true; } #endif diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index f63404d129..71071f5d92 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -138,7 +138,9 @@ namespace IfcGeom { void remove_duplicate_points_from_loop(cgal_wire_t& polygon, bool closed, double tol = -1.); - 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); + 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::Nef_polyhedron_3 create_nef_polyhedron(std::list &face_list); void purge_cache() { // Rather hack-ish, but a stopgap solution to keep memory under control From 0ffa633a6da9822387286ebe820d678c27d129d3 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 16 Mar 2017 19:30:39 -0600 Subject: [PATCH 086/235] Better validation --- .../kernels/cgal/CgalConversionFunctions.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index b44429d144..b42d90bcdf 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -341,11 +341,20 @@ CGAL::Nef_polyhedron_3 IfcGeom::CgalKernel::create_nef_polyhedron(std::l // 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()) { - std::cout << "Invalid polyhedron!" << std::endl; + std::cout << "Polyhedron not valid!" << std::endl; std::ofstream fresult; fresult.open("/Users/ken/Desktop/invalid.off"); - fresult << old_polyhedron << std::endl; + fresult << polyhedron << std::endl; fresult.close(); + return CGAL::Nef_polyhedron_3(); + } if (!polyhedron.is_closed()) { + std::cout << "Polyhedron not closed" << std::endl; + std::ofstream fresult; + fresult.open("/Users/ken/Desktop/open.off"); + fresult << polyhedron << std::endl; + fresult.close(); + // TODO: Nef constructor doesn't support open meshes + return CGAL::Nef_polyhedron_3(polyhedron); } if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); From 2bbe80fd280f4dc8138f79973dbb10b5df8adefc Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 17 Mar 2017 16:12:24 -0600 Subject: [PATCH 087/235] Problems with extended kernel experiment, but this should be incorporated in any case --- .../kernels/cgal/CgalIfcGeomShapes.cpp | 116 ++++++++++-------- 1 file changed, 67 insertions(+), 49 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 7ac1ec8677..6a6248f8ba 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -302,11 +302,9 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha return false; // } } else if ( shape_type(operand1) == ST_SHAPE ) { - if ( ! convert_shape(operand1, s1) ) { + if (!convert_shape(operand1, s1) ) { return false; } -// TopoDS_Solid temp_solid; -// s1 = ensure_fit_for_subtraction(s1, temp_solid); } else { Logger::Message(Logger::LOG_ERROR, "s1: Invalid representation item for boolean operation", operand1->entity); return false; @@ -322,18 +320,14 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha // 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); - if (shape2_processed && !is_halfspace) { -// TopoDS_Solid temp_solid; -// s2 = ensure_fit_for_subtraction(s2, temp_solid); - } } else { Logger::Message(Logger::LOG_ERROR, "s2: Invalid representation item for boolean operation", operand2->entity); } if (!shape2_processed) { -// shape = s1; + shape = s1; Logger::Message(Logger::LOG_ERROR,"Failed to convert SecondOperand of:",l->entity); -// return true; + return true; } // if (!is_halfspace) { @@ -347,76 +341,100 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha if (!s1.is_simple()) { Logger::Message(Logger::LOG_ERROR, "s1: Not simple Nef?", operand1->entity); return false; + } else { + std::ofstream f1; + CGAL::Polyhedron_3 p1; + s1.convert_to_Polyhedron(p1); + f1.open("/Users/ken/Desktop/s1.off"); + f1 << p1 << std::endl; + f1.close(); } if (!s2.is_simple()) { Logger::Message(Logger::LOG_ERROR, "s2: Not simple Nef?", operand2->entity); return false; + } else if (is_halfspace) { + // std::cout << "s2: halfspace" << std::endl; + IfcSchema::IfcHalfSpaceSolid *hss = static_cast(operand2); + IfcSchema::IfcSurface* surface = hss->BaseSurface(); + if (surface->is(IfcSchema::Type::IfcPlane) ) { + cgal_plane_t plane; + IfcGeom::CgalKernel::convert((IfcSchema::IfcPlane *)surface, plane); + 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 p2; + s2.convert_to_Polyhedron(p2); + f2.open("/Users/ken/Desktop/s2.off"); + f2 << p2 << std::endl; + f2.close(); } -// std::ofstream f1; -// f1.open("/Users/ken/Desktop/s1.off"); -// f1 << s1 << std::endl; -// f1.close(); -// std::ofstream f2; -// f2.open("/Users/ken/Desktop/s2.off"); -// f2 << s2 << std::endl; -// f2.close(); - if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) { -// std::cout << "Difference" << std::endl; + std::cout << "Difference" << std::endl; CGAL::Nef_polyhedron_3 nef_result = s1-s2; if (!nef_result.is_simple()) { std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; return false; - } -// cgal_shape_t result; -// nef_result.convert_to_polyhedron(result); -// std::ofstream fresult; -// fresult.open("/Users/ken/Desktop/result.off"); -// fresult << result << std::endl; -// fresult.close(); - shape = nef_result; + } else { + CGAL::Polyhedron_3 result; + nef_result.convert_to_polyhedron(result); + std::ofstream fresult; + fresult.open("/Users/ken/Desktop/result.off"); + fresult << result << std::endl; + fresult.close(); + } shape = nef_result; return true; } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) { -// std::cout << "Union" << std::endl; + std::cout << "Union" << std::endl; CGAL::Nef_polyhedron_3 nef_result = s1+s2; if (!nef_result.is_simple()) { std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; return false; - } -// cgal_shape_t result; -// nef_result.convert_to_polyhedron(result); -// std::ofstream fresult; -// fresult.open("/Users/ken/Desktop/result.off"); -// fresult << result << std::endl; -// fresult.close(); - shape = nef_result; + } else { + CGAL::Polyhedron_3 result; + nef_result.convert_to_polyhedron(result); + std::ofstream fresult; + fresult.open("/Users/ken/Desktop/result.off"); + fresult << result << std::endl; + fresult.close(); + } shape = nef_result; return true; } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) { -// std::cout << "Intersection" << std::endl; + std::cout << "Intersection" << std::endl; CGAL::Nef_polyhedron_3 nef_result = s1*s2; if (!nef_result.is_simple()) { std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; return false; - } -// cgal_shape_t result; -// nef_result.convert_to_polyhedron(result); -// std::ofstream fresult; -// fresult.open("/Users/ken/Desktop/result.off"); -// fresult << result << std::endl; -// fresult.close(); - shape = nef_result; + } else { + CGAL::Polyhedron_3 result; + nef_result.convert_to_polyhedron(result); + std::ofstream fresult; + fresult.open("/Users/ken/Desktop/result.off"); + fresult << result << std::endl; + fresult.close(); + } shape = nef_result; return true; - - } - - return false; + } return false; } bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& shape) { From 95e6c14f396ae9310b5b2b88e501a6edc423163d Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 17 Mar 2017 19:24:51 -0600 Subject: [PATCH 088/235] Hack to solve issues with IfcHalfSpaceSolid. Not ideal. --- .../kernels/cgal/CgalConversionFunctions.cpp | 20 +-- .../kernels/cgal/CgalIfcGeomShapes.cpp | 114 ++++++++++-------- 2 files changed, 72 insertions(+), 62 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index b42d90bcdf..3291059fb5 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -341,18 +341,18 @@ CGAL::Nef_polyhedron_3 IfcGeom::CgalKernel::create_nef_polyhedron(std::l // 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()) { - std::cout << "Polyhedron not valid!" << std::endl; - std::ofstream fresult; - fresult.open("/Users/ken/Desktop/invalid.off"); - fresult << polyhedron << std::endl; - fresult.close(); + std::cout << "create_nef_polyhedron: Polyhedron not valid!" << std::endl; +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/invalid.off"); +// fresult << polyhedron << std::endl; +// fresult.close(); return CGAL::Nef_polyhedron_3(); } if (!polyhedron.is_closed()) { - std::cout << "Polyhedron not closed" << std::endl; - std::ofstream fresult; - fresult.open("/Users/ken/Desktop/open.off"); - fresult << polyhedron << std::endl; - fresult.close(); + std::cout << "create_nef_polyhedron: Polyhedron not closed" << std::endl; +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/open.off"); +// fresult << polyhedron << std::endl; +// fresult.close(); // TODO: Nef constructor doesn't support open meshes return CGAL::Nef_polyhedron_3(polyhedron); } diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 6a6248f8ba..15e5054dc4 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -342,14 +342,16 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha Logger::Message(Logger::LOG_ERROR, "s1: Not simple Nef?", operand1->entity); return false; } else { - std::ofstream f1; - CGAL::Polyhedron_3 p1; - s1.convert_to_Polyhedron(p1); - f1.open("/Users/ken/Desktop/s1.off"); - f1 << p1 << std::endl; - f1.close(); +// std::ofstream f1; +// CGAL::Polyhedron_3 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_simple()) { Logger::Message(Logger::LOG_ERROR, "s2: Not simple Nef?", operand2->entity); return false; @@ -358,80 +360,86 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha IfcSchema::IfcHalfSpaceSolid *hss = static_cast(operand2); IfcSchema::IfcSurface* surface = hss->BaseSurface(); if (surface->is(IfcSchema::Type::IfcPlane) ) { - cgal_plane_t plane; + is_plane = true; IfcGeom::CgalKernel::convert((IfcSchema::IfcPlane *)surface, plane); - 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(); + 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 p2; - s2.convert_to_Polyhedron(p2); - f2.open("/Users/ken/Desktop/s2.off"); - f2 << p2 << std::endl; - f2.close(); +// std::ofstream f2; +// CGAL::Polyhedron_3 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 nef_result = s1-s2; +// std::cout << "Difference" << std::endl; + CGAL::Nef_polyhedron_3 nef_result = s1; + if (is_halfspace) { + if (is_plane) nef_result = nef_result.intersection(plane, CGAL::Nef_polyhedron_3::Intersection_mode::CLOSED_HALFSPACE); + } else { + nef_result -= s2; + } if (!nef_result.is_simple()) { std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; return false; } else { - CGAL::Polyhedron_3 result; - nef_result.convert_to_polyhedron(result); - std::ofstream fresult; - fresult.open("/Users/ken/Desktop/result.off"); - fresult << result << std::endl; - fresult.close(); +// CGAL::Polyhedron_3 result; +// nef_result.convert_to_polyhedron(result); +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/result.off"); +// fresult << result << std::endl; +// fresult.close(); } shape = nef_result; return true; } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) { - std::cout << "Union" << std::endl; +// std::cout << "Union" << std::endl; CGAL::Nef_polyhedron_3 nef_result = s1+s2; if (!nef_result.is_simple()) { std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; return false; } else { - CGAL::Polyhedron_3 result; - nef_result.convert_to_polyhedron(result); - std::ofstream fresult; - fresult.open("/Users/ken/Desktop/result.off"); - fresult << result << std::endl; - fresult.close(); +// CGAL::Polyhedron_3 result; +// nef_result.convert_to_polyhedron(result); +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/result.off"); +// fresult << result << std::endl; +// fresult.close(); } shape = nef_result; return true; } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) { - std::cout << "Intersection" << std::endl; +// std::cout << "Intersection" << std::endl; CGAL::Nef_polyhedron_3 nef_result = s1*s2; if (!nef_result.is_simple()) { std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; return false; } else { - CGAL::Polyhedron_3 result; - nef_result.convert_to_polyhedron(result); - std::ofstream fresult; - fresult.open("/Users/ken/Desktop/result.off"); - fresult << result << std::endl; - fresult.close(); +// CGAL::Polyhedron_3 result; +// nef_result.convert_to_polyhedron(result); +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/result.off"); +// fresult << result << std::endl; +// fresult.close(); } shape = nef_result; return true; } return false; @@ -793,11 +801,13 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, cgal_sh cgal_plane_t pln; IfcGeom::CgalKernel::convert((IfcSchema::IfcPlane*)surface,pln); - // TODO: This might be the other way around - if (!l->AgreementFlag()) pln = pln.opposite(); + // 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(); - shape = CGAL::Nef_polyhedron_3(pln); + shape = CGAL::Nef_polyhedron_3(); + // TODO: We return an empty Nef polyhedron for now and handle halfspace differences in IfcBooleanResult. The other option would be to switch to an extended kernel. +// shape = CGAL::Nef_polyhedron_3(pln); return true; } From cf9605f1089098775bfa5eb1b691aecdd95a74c0 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 20 Mar 2017 15:56:31 -0600 Subject: [PATCH 089/235] Missing Shapes, support for voids --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 6 ++- .../kernels/cgal/CgalIfcGeomShapes.cpp | 52 ++++++++++++++++--- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index e0ecad5298..e438b3ace1 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -28,14 +28,16 @@ #include "../../../ifcparse/IfcUtil.h" #include "../../../ifcparse/IfcParse.h" +SHAPES(IfcShellBasedSurfaceModel); +SHAPES(IfcFaceBasedSurfaceModel); SHAPES(IfcRepresentation); +SHAPES(IfcMappedItem); // IfcFacetedBrep included // IfcAdvancedBrep included // IfcFacetedBrepWithVoids included // IfcAdvancedBrepWithVoids included SHAPES(IfcManifoldSolidBrep); -SHAPES(IfcMappedItem); -SHAPES(IfcFaceBasedSurfaceModel); +SHAPES(IfcGeometricSet); SHAPE(IfcExtrudedAreaSolid); SHAPE(IfcConnectedFaceSet); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 15e5054dc4..7e912c8b5b 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -1,6 +1,46 @@ #include "CgalKernel.h" #include "CgalConversionResult.h" +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->is(IfcSchema::Type::IfcPoint)) { + style = get_style((IfcSchema::IfcPoint*) element); + } else if (element->is(IfcSchema::Type::IfcCurve)) { + style = get_style((IfcSchema::IfcCurve*) element); + } else if (element->is(IfcSchema::Type::IfcSurface)) { + style = get_style((IfcSchema::IfcSurface*) element); + } + shapes.push_back(ConversionResult(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)->is(IfcSchema::Type::IfcRepresentationItem)) { + shell_style = get_style((IfcSchema::IfcRepresentationItem*)*it); + } + if (convert_shape(*it,s)) { + shapes.push_back(ConversionResult(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); @@ -18,12 +58,12 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, Conv #endif for (IfcSchema::IfcClosedShell::list::it it = voids->begin(); it != voids->end(); ++it) { - // TopoDS_Shape s2; - // /// @todo No extensive shapefixing since shells should be disjoint. - // /// @todo Awaiting generalized boolean ops module with appropriate checking - // if (convert_shape(l->Outer(), s2)) { - // s = BRepAlgoAPI_Cut(s, s2).Shape(); - // } + cgal_shape_t s2; + /// @todo No extensive shapefixing since shells should be disjoint. + /// @todo Awaiting generalized boolean ops module with appropriate checking + if (convert_shape(l->Outer(), s2)) { + s -= s2; + } } shape.push_back(ConversionResult(new CgalShape(s), indiv_style ? indiv_style : collective_style)); From cf6bd5a6291b3d11b7e81158eed46873e7746cb6 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 20 Mar 2017 16:31:06 -0600 Subject: [PATCH 090/235] Enabled missing Cartesian transformations --- src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 7e912c8b5b..39c505386a 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -78,17 +78,11 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcMappedItem* l, ConversionR if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3DnonUniform) ) { IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3DnonUniform*)transform,gtrsf); } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2DnonUniform) ) { - Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); - return false; + IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator2DnonUniform*)transform,gtrsf); } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3D) ) { - cgal_placement_t trsf; - IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,trsf); - gtrsf = trsf; + IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,gtrsf); } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2D) ) { - cgal_placement_t trsf_2d; - Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); -// IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator2D*)transform,trsf_2d); - gtrsf = (cgal_placement_t) trsf_2d; + IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator2D*)transform,gtrsf); } IfcSchema::IfcRepresentationMap* map = l->MappingSource(); IfcSchema::IfcAxis2Placement* placement = map->MappingOrigin(); From 8090bb4c0070650b8d5a30313392b0b448846656 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 20 Mar 2017 16:35:14 -0600 Subject: [PATCH 091/235] Shapes with styles in separate file --- .../kernels/cgal/CgalConversionFunctions.cpp | 21 --- .../kernels/cgal/CgalIfcGeomShapes.cpp | 139 --------------- .../cgal/CgalIfcGeomShapesWithStyles.cpp | 160 ++++++++++++++++++ 3 files changed, 160 insertions(+), 160 deletions(-) create mode 100644 src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 3291059fb5..a7a52b34ad 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -1,27 +1,6 @@ #include "../../../ifcparse/IfcParse.h" #include "CgalKernel.h" -#include "CgalConversionResult.h" - -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(new CgalShape(s), get_style(representation_item))); - part_succes |= true; - } - } - } - } - return part_succes; -} bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_point_t& point) { std::vector xyz = l->Coordinates(); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 39c505386a..80a5da0066 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -1,143 +1,4 @@ #include "CgalKernel.h" -#include "CgalConversionResult.h" - -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->is(IfcSchema::Type::IfcPoint)) { - style = get_style((IfcSchema::IfcPoint*) element); - } else if (element->is(IfcSchema::Type::IfcCurve)) { - style = get_style((IfcSchema::IfcCurve*) element); - } else if (element->is(IfcSchema::Type::IfcSurface)) { - style = get_style((IfcSchema::IfcSurface*) element); - } - shapes.push_back(ConversionResult(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)->is(IfcSchema::Type::IfcRepresentationItem)) { - shell_style = get_style((IfcSchema::IfcRepresentationItem*)*it); - } - if (convert_shape(*it,s)) { - shapes.push_back(ConversionResult(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); - if (convert_shape(l->Outer(),s) ) { - const SurfaceStyle* indiv_style = get_style(l->Outer()); - - IfcSchema::IfcClosedShell::list::ptr voids(new IfcSchema::IfcClosedShell::list); - if (l->is(IfcSchema::Type::IfcFacetedBrepWithVoids)) { - voids = l->as()->Voids(); - } -#ifdef USE_IFC4 - if (l->is(IfcSchema::Type::IfcAdvancedBrepWithVoids)) { - voids = l->as()->Voids(); - } -#endif - - for (IfcSchema::IfcClosedShell::list::it it = voids->begin(); it != voids->end(); ++it) { - cgal_shape_t s2; - /// @todo No extensive shapefixing since shells should be disjoint. - /// @todo Awaiting generalized boolean ops module with appropriate checking - if (convert_shape(l->Outer(), s2)) { - s -= s2; - } - } - - shape.push_back(ConversionResult(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->is(IfcSchema::Type::IfcCartesianTransformationOperator3DnonUniform) ) { - IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3DnonUniform*)transform,gtrsf); - } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2DnonUniform) ) { - IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator2DnonUniform*)transform,gtrsf); - } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3D) ) { - IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,gtrsf); - } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2D) ) { - IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator2D*)transform,gtrsf); - } - IfcSchema::IfcRepresentationMap* map = l->MappingSource(); - IfcSchema::IfcAxis2Placement* placement = map->MappingOrigin(); - cgal_placement_t trsf; - if (placement->is(IfcSchema::Type::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(new CgalShape(s), shell_style ? shell_style : collective_style)); - part_success |= true; - } - } - return part_success; -} bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal_shape_t &shape) { const double height = l->Depth() * getValue(GV_LENGTH_UNIT); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp new file mode 100644 index 0000000000..4898625956 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp @@ -0,0 +1,160 @@ +#include "CgalKernel.h" +#include "CgalConversionResult.h" + +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(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->is(IfcSchema::Type::IfcPoint)) { + style = get_style((IfcSchema::IfcPoint*) element); + } else if (element->is(IfcSchema::Type::IfcCurve)) { + style = get_style((IfcSchema::IfcCurve*) element); + } else if (element->is(IfcSchema::Type::IfcSurface)) { + style = get_style((IfcSchema::IfcSurface*) element); + } + shapes.push_back(ConversionResult(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)->is(IfcSchema::Type::IfcRepresentationItem)) { + shell_style = get_style((IfcSchema::IfcRepresentationItem*)*it); + } + if (convert_shape(*it,s)) { + shapes.push_back(ConversionResult(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); + if (convert_shape(l->Outer(),s) ) { + const SurfaceStyle* indiv_style = get_style(l->Outer()); + + IfcSchema::IfcClosedShell::list::ptr voids(new IfcSchema::IfcClosedShell::list); + if (l->is(IfcSchema::Type::IfcFacetedBrepWithVoids)) { + voids = l->as()->Voids(); + } +#ifdef USE_IFC4 + if (l->is(IfcSchema::Type::IfcAdvancedBrepWithVoids)) { + voids = l->as()->Voids(); + } +#endif + + for (IfcSchema::IfcClosedShell::list::it it = voids->begin(); it != voids->end(); ++it) { + cgal_shape_t s2; + /// @todo No extensive shapefixing since shells should be disjoint. + /// @todo Awaiting generalized boolean ops module with appropriate checking + if (convert_shape(l->Outer(), s2)) { + s -= s2; + } + } + + shape.push_back(ConversionResult(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->is(IfcSchema::Type::IfcCartesianTransformationOperator3DnonUniform) ) { + IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3DnonUniform*)transform,gtrsf); + } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2DnonUniform) ) { + IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator2DnonUniform*)transform,gtrsf); + } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3D) ) { + IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,gtrsf); + } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2D) ) { + IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator2D*)transform,gtrsf); + } + IfcSchema::IfcRepresentationMap* map = l->MappingSource(); + IfcSchema::IfcAxis2Placement* placement = map->MappingOrigin(); + cgal_placement_t trsf; + if (placement->is(IfcSchema::Type::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(new CgalShape(s), shell_style ? shell_style : collective_style)); + part_success |= true; + } + } + return part_success; +} From 62ca6f6a7d2e79a03f9033b79b8d04fbc0425caf Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 20 Mar 2017 16:45:27 -0600 Subject: [PATCH 092/235] Checked shapes with styles. Found bug? --- src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp index 4898625956..2bfd8caaac 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp @@ -79,8 +79,9 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, Conv for (IfcSchema::IfcClosedShell::list::it it = voids->begin(); it != voids->end(); ++it) { cgal_shape_t s2; - /// @todo No extensive shapefixing since shells should be disjoint. - /// @todo Awaiting generalized boolean ops module with appropriate checking + // TODO: This looks weird. Aren't we removing the outer shell again and again? + // Maybe it should be + // if (convert_shape(*it, s2)) { if (convert_shape(l->Outer(), s2)) { s -= s2; } From 71d7bbd6bab33de8a533b39b67fee2a91b757917 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 20 Mar 2017 20:06:48 -0600 Subject: [PATCH 093/235] =?UTF-8?q?Ordering=20things=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kernels/cgal/CgalConversionFunctions.cpp | 286 ------------------ .../kernels/cgal/CgalIfcGeomPrimitives.cpp | 285 +++++++++++++++++ 2 files changed, 285 insertions(+), 286 deletions(-) create mode 100644 src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index a7a52b34ad..818ee56f47 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -1,296 +1,10 @@ -#include "../../../ifcparse/IfcParse.h" - #include "CgalKernel.h" -bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_point_t& point) { - std::vector 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 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); - - // 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); - -// std::cout << "Ref direction: " << refDirection << std::endl; -// std::cout << "Axis: " << axis << 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::IfcObjectPlacement* l, cgal_placement_t& trsf) { - // TODO: These macros don't work for the CGAL types. Need to check why. -// IN_CACHE(IfcObjectPlacement,l,cgal_placement_t,trsf) - if ( ! l->is(IfcSchema::Type::IfcLocalPlacement) ) { - Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l->entity); - 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->is(IfcSchema::Type::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 = trsf * trsf2; // TODO: I think it's fine, but maybe should it be the other way around? - -// 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->is(IfcSchema::Type::IfcLocalPlacement) ) - current = (IfcSchema::IfcLocalPlacement*)current->PlacementRelTo(); - else break; - } else break; - } -// CACHE(IfcObjectPlacement,l,trsf) - return true; -} - bool IfcGeom::CgalKernel::convert_wire_to_face(const cgal_wire_t& wire, cgal_face_t& face) { face.outer = wire; 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& gtrsf) { -// IN_CACHE(IfcCartesianTransformationOperator2DnonUniform,l,cgal_placement_t,gtrsf) - - 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); - - 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; -} - void IfcGeom::CgalKernel::remove_duplicate_points_from_loop(cgal_wire_t& polygon, bool closed, double tol) { if (tol <= 0.) tol = getValue(GV_PRECISION); tol *= tol; diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp new file mode 100644 index 0000000000..2a878e40fe --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp @@ -0,0 +1,285 @@ +#include "CgalKernel.h" + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_point_t& point) { + std::vector 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 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); + + // 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); + + // std::cout << "Ref direction: " << refDirection << std::endl; + // std::cout << "Axis: " << axis << 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::IfcObjectPlacement* l, cgal_placement_t& trsf) { + // TODO: These macros don't work for the CGAL types. Need to check why. + // IN_CACHE(IfcObjectPlacement,l,cgal_placement_t,trsf) + if ( ! l->is(IfcSchema::Type::IfcLocalPlacement) ) { + Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l->entity); + 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->is(IfcSchema::Type::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 = trsf * trsf2; // TODO: I think it's fine, but maybe should it be the other way around? + + // 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->is(IfcSchema::Type::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& gtrsf) { + // IN_CACHE(IfcCartesianTransformationOperator2DnonUniform,l,cgal_placement_t,gtrsf) + + 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); + + 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; +} From 4061f93560ab90d93db17d5ec49c339490bb7277 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 20 Mar 2017 20:57:17 -0600 Subject: [PATCH 094/235] Export non-simple Nef too --- .../kernels/cgal/CgalConversionFunctions.cpp | 16 +++++++-- .../kernels/cgal/CgalConversionResult.cpp | 34 +++++++++++++++++-- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 818ee56f47..6d69e9c384 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -41,13 +41,23 @@ CGAL::Nef_polyhedron_3 IfcGeom::CgalKernel::create_nef_polyhedron(std::l // fresult.close(); return CGAL::Nef_polyhedron_3(); } if (!polyhedron.is_closed()) { - std::cout << "create_nef_polyhedron: Polyhedron not closed" << std::endl; // std::ofstream fresult; // fresult.open("/Users/ken/Desktop/open.off"); // fresult << polyhedron << std::endl; // fresult.close(); - // TODO: Nef constructor doesn't support open meshes - return CGAL::Nef_polyhedron_3(polyhedron); + CGAL::Nef_polyhedron_3 mesh; + unsigned int current_face = 0; + for (auto &face: faces(polyhedron)) { + ++current_face; +// if (current_face%10 == 0) std::cout << current_face << "/" << polyhedron.size_of_facets() << std::endl; + std::list points_in_face; + CGAL::Polyhedron_3::Halfedge_around_facet_const_circulator current_halfedge = face->facet_begin(); + do { + points_in_face.push_back(current_halfedge->vertex()->point()); + ++current_halfedge; + } while (current_halfedge != face->facet_begin()); + mesh += CGAL::Nef_polyhedron_3(points_in_face.begin(), points_in_face.end()); + } return mesh; } if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index 171b7ee2e8..93abf453b4 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -4,11 +4,39 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const { cgal_shape_t s = shape_; const cgal_placement_t& trsf = dynamic_cast(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; + + std::cout << "Nef Model: " << s.number_of_facets() << " facets and " << s.number_of_vertices() << " vertices" << std::endl; + std::cout << "Simple: " << s.is_simple() << std::endl; CGAL::Polyhedron_3 polyhedron; - s.convert_to_polyhedron(polyhedron); + if (s.is_simple()) s.convert_to_polyhedron(polyhedron); + else { + std::list face_list; + face_list.push_back(cgal_face_t()); + std::set::Halffacet_const_handle> visited_halffacets; + for (CGAL::Nef_polyhedron_3::Halffacet_const_iterator current_halffacet = s.halffacets_begin(); + current_halffacet != s.halffacets_end(); + ++current_halffacet) { + if (visited_halffacets.count(current_halffacet->twin())) continue; + for (CGAL::Nef_polyhedron_3::Halffacet_cycle_const_iterator current_halffacet_cycle = current_halffacet->facet_cycles_begin(); + current_halffacet_cycle != current_halffacet->facet_cycles_end(); + ++current_halffacet_cycle) { + if (current_halffacet_cycle.is_shalfloop()) continue; + CGAL::Nef_polyhedron_3::SHalfedge_const_handle first_shalfedge = current_halffacet_cycle; + CGAL::Nef_polyhedron_3::SHalfedge_const_handle current_shalfedge = first_shalfedge; + if (!face_list.back().outer.empty()) face_list.push_back(cgal_face_t()); + do { + face_list.back().outer.push_back(current_shalfedge->source()->center_vertex()->point()); + current_shalfedge = current_shalfedge->next(); + } while (current_shalfedge != first_shalfedge); + } + } if (face_list.back().outer.empty()) face_list.pop_back(); + PolyhedronBuilder builder(&face_list); + polyhedron.delegate(builder); + } + + std::cout << "Polyhedron Model: " << polyhedron.size_of_facets() << " facets and " << polyhedron.size_of_vertices() << " vertices" << std::endl; + std::cout << "Valid: " << polyhedron.is_valid() << std::endl; // Apply transformation if (place != NULL) for (auto &vertex: vertices(polyhedron)) { From 12967790ba52ca4f0f0591b78c861fd73469d6f6 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 23 Mar 2017 19:49:15 -0600 Subject: [PATCH 095/235] Switched back to Polyhedron_3 for shapes. Should be checked. --- .../kernels/cgal/CgalConversionFunctions.cpp | 46 ++++++--------- .../kernels/cgal/CgalConversionResult.cpp | 41 ++----------- .../kernels/cgal/CgalIfcGeomPrimitives.cpp | 1 - .../kernels/cgal/CgalIfcGeomShapes.cpp | 58 +++++++++---------- .../cgal/CgalIfcGeomShapesWithStyles.cpp | 5 +- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 9 ++- src/ifcgeom/kernels/cgal/CgalKernel.h | 3 +- 7 files changed, 63 insertions(+), 100 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 6d69e9c384..6a7b805150 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -23,7 +23,7 @@ void IfcGeom::CgalKernel::remove_duplicate_points_from_loop(cgal_wire_t& polygon } } -CGAL::Nef_polyhedron_3 IfcGeom::CgalKernel::create_nef_polyhedron(std::list &face_list) { +CGAL::Polyhedron_3 IfcGeom::CgalKernel::create_polyhedron(std::list &face_list) { // Naive creation CGAL::Polyhedron_3 polyhedron = CGAL::Polyhedron_3(); @@ -34,35 +34,25 @@ CGAL::Nef_polyhedron_3 IfcGeom::CgalKernel::create_nef_polyhedron(std::l // 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()) { - std::cout << "create_nef_polyhedron: Polyhedron not valid!" << std::endl; -// std::ofstream fresult; -// fresult.open("/Users/ken/Desktop/invalid.off"); -// fresult << polyhedron << std::endl; -// fresult.close(); - return CGAL::Nef_polyhedron_3(); - } if (!polyhedron.is_closed()) { -// std::ofstream fresult; -// fresult.open("/Users/ken/Desktop/open.off"); -// fresult << polyhedron << std::endl; -// fresult.close(); - CGAL::Nef_polyhedron_3 mesh; - unsigned int current_face = 0; - for (auto &face: faces(polyhedron)) { - ++current_face; -// if (current_face%10 == 0) std::cout << current_face << "/" << polyhedron.size_of_facets() << std::endl; - std::list points_in_face; - CGAL::Polyhedron_3::Halfedge_around_facet_const_circulator current_halfedge = face->facet_begin(); - do { - points_in_face.push_back(current_halfedge->vertex()->point()); - ++current_halfedge; - } while (current_halfedge != face->facet_begin()); - mesh += CGAL::Nef_polyhedron_3(points_in_face.begin(), points_in_face.end()); - } return mesh; - } - if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { - CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); + std::cout << "create_polyhedron: Polyhedron not valid!" << std::endl; + // std::ofstream fresult; + // fresult.open("/Users/ken/Desktop/invalid.off"); + // fresult << polyhedron << std::endl; + // fresult.close(); + return CGAL::Polyhedron_3(); + } 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::Nef_polyhedron_3 IfcGeom::CgalKernel::create_nef_polyhedron(std::list &face_list) { + CGAL::Polyhedron_3 polyhedron = create_polyhedron(face_list); return CGAL::Nef_polyhedron_3(polyhedron); } diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index 93abf453b4..ba6e1fa5b2 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -5,41 +5,8 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, cgal_shape_t s = shape_; const cgal_placement_t& trsf = dynamic_cast(place)->trsf(); - std::cout << "Nef Model: " << s.number_of_facets() << " facets and " << s.number_of_vertices() << " vertices" << std::endl; - std::cout << "Simple: " << s.is_simple() << std::endl; - - CGAL::Polyhedron_3 polyhedron; - if (s.is_simple()) s.convert_to_polyhedron(polyhedron); - else { - std::list face_list; - face_list.push_back(cgal_face_t()); - std::set::Halffacet_const_handle> visited_halffacets; - for (CGAL::Nef_polyhedron_3::Halffacet_const_iterator current_halffacet = s.halffacets_begin(); - current_halffacet != s.halffacets_end(); - ++current_halffacet) { - if (visited_halffacets.count(current_halffacet->twin())) continue; - for (CGAL::Nef_polyhedron_3::Halffacet_cycle_const_iterator current_halffacet_cycle = current_halffacet->facet_cycles_begin(); - current_halffacet_cycle != current_halffacet->facet_cycles_end(); - ++current_halffacet_cycle) { - if (current_halffacet_cycle.is_shalfloop()) continue; - CGAL::Nef_polyhedron_3::SHalfedge_const_handle first_shalfedge = current_halffacet_cycle; - CGAL::Nef_polyhedron_3::SHalfedge_const_handle current_shalfedge = first_shalfedge; - if (!face_list.back().outer.empty()) face_list.push_back(cgal_face_t()); - do { - face_list.back().outer.push_back(current_shalfedge->source()->center_vertex()->point()); - current_shalfedge = current_shalfedge->next(); - } while (current_shalfedge != first_shalfedge); - } - } if (face_list.back().outer.empty()) face_list.pop_back(); - PolyhedronBuilder builder(&face_list); - polyhedron.delegate(builder); - } - - std::cout << "Polyhedron Model: " << polyhedron.size_of_facets() << " facets and " << polyhedron.size_of_vertices() << " vertices" << std::endl; - std::cout << "Valid: " << polyhedron.is_valid() << std::endl; - // Apply transformation - if (place != NULL) for (auto &vertex: vertices(polyhedron)) { + if (place != NULL) for (auto &vertex: vertices(s)) { vertex->point() = vertex->point().transform(trsf); } @@ -53,7 +20,7 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, boost::associative_property_map> vertex_normals_map(vertex_normals); std::map face_normals; boost::associative_property_map> face_normals_map(face_normals); - if (CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron)) { + if (CGAL::Polygon_mesh_processing::triangulate_faces(s)) { // std::cout << "Triangulated model: " << s.size_of_facets() << " facets and " << s.size_of_vertices() << " vertices" << std::endl; } else { Logger::Message(Logger::LOG_ERROR, "Failed to triangulate shape"); @@ -65,9 +32,9 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, // fafter << s << std::endl; // fafter.close(); - CGAL::Polygon_mesh_processing::compute_normals(polyhedron, vertex_normals_map, face_normals_map); + CGAL::Polygon_mesh_processing::compute_normals(s, vertex_normals_map, face_normals_map); - for (auto &face: faces(polyhedron)) { + for (auto &face: faces(s)) { if (!face->is_triangle()) { std::cout << "Warning: non-triangular face!" << std::endl; continue; diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp index 2a878e40fe..446f877394 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp @@ -127,7 +127,6 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement3D* l, cgal_ } bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_placement_t& trsf) { - // TODO: These macros don't work for the CGAL types. Need to check why. // IN_CACHE(IfcObjectPlacement,l,cgal_placement_t,trsf) if ( ! l->is(IfcSchema::Type::IfcLocalPlacement) ) { Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l->entity); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 80a5da0066..a275b071bf 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -50,7 +50,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal top_face.outer.push_back(*vertex+height*dir); } face_list.push_back(top_face); - shape = create_nef_polyhedron(face_list); + CGAL::Nef_polyhedron_3 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 @@ -84,10 +84,11 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal hole_top_face.outer.push_back(*vertex+height*dir); } face_list.push_back(hole_top_face); - shape -= create_nef_polyhedron(face_list); + nef_shape -= create_nef_polyhedron(face_list); } - shape.transform(trsf); + nef_shape.transform(trsf); + nef_shape.convert_to_polyhedron(shape); return true; } @@ -116,7 +117,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_ face_list.push_back(face); } - shape = create_nef_polyhedron(face_list); + shape = create_polyhedron(face_list); return true; } @@ -176,9 +177,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBlock* l, cgal_shape_t& sh cgal_placement_t trsf; IfcGeom::CgalKernel::convert(l->Position(),trsf); - shape = create_nef_polyhedron(face_list); - shape.transform(trsf); - + shape = create_polyhedron(face_list); + for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf); return true; } @@ -233,8 +233,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha const IfcSchema::IfcBooleanOperator::IfcBooleanOperator op = l->Operator(); - if (!s1.is_simple()) { - Logger::Message(Logger::LOG_ERROR, "s1: Not simple Nef?", operand1->entity); + if (!s1.is_valid()) { + Logger::Message(Logger::LOG_ERROR, "s1: Not valid?", operand1->entity); return false; } else { // std::ofstream f1; @@ -247,8 +247,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha bool is_plane = false; cgal_plane_t plane; - if (!s2.is_simple()) { - Logger::Message(Logger::LOG_ERROR, "s2: Not simple Nef?", operand2->entity); + if (!s2.is_valid()) { + Logger::Message(Logger::LOG_ERROR, "s2: Not valid?", operand2->entity); return false; } else if (is_halfspace) { // std::cout << "s2: halfspace" << std::endl; @@ -285,11 +285,11 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) { // std::cout << "Difference" << std::endl; - CGAL::Nef_polyhedron_3 nef_result = s1; + CGAL::Nef_polyhedron_3 nef_result(s1); if (is_halfspace) { if (is_plane) nef_result = nef_result.intersection(plane, CGAL::Nef_polyhedron_3::Intersection_mode::CLOSED_HALFSPACE); } else { - nef_result -= s2; + nef_result -= CGAL::Nef_polyhedron_3(s2); } if (!nef_result.is_simple()) { std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; @@ -301,13 +301,13 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha // fresult.open("/Users/ken/Desktop/result.off"); // fresult << result << std::endl; // fresult.close(); - } shape = nef_result; + } nef_result.convert_to_polyhedron(shape); return true; } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) { // std::cout << "Union" << std::endl; - CGAL::Nef_polyhedron_3 nef_result = s1+s2; + CGAL::Nef_polyhedron_3 nef_result = CGAL::Nef_polyhedron_3(s1)+CGAL::Nef_polyhedron_3(s2); if (!nef_result.is_simple()) { std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; return false; @@ -318,13 +318,13 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha // fresult.open("/Users/ken/Desktop/result.off"); // fresult << result << std::endl; // fresult.close(); - } shape = nef_result; + } nef_result.convert_to_polyhedron(shape); return true; } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) { // std::cout << "Intersection" << std::endl; - CGAL::Nef_polyhedron_3 nef_result = s1*s2; + CGAL::Nef_polyhedron_3 nef_result = CGAL::Nef_polyhedron_3(s1)*CGAL::Nef_polyhedron_3(s2); if (!nef_result.is_simple()) { std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; return false; @@ -335,7 +335,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha // fresult.open("/Users/ken/Desktop/result.off"); // fresult << result << std::endl; // fresult.close(); - } shape = nef_result; + } nef_result.convert_to_polyhedron(shape); return true; } return false; } @@ -512,8 +512,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& s cgal_placement_t trsf; IfcGeom::CgalKernel::convert(l->Position(),trsf); - shape = create_nef_polyhedron(face_list); - shape.transform(trsf); + shape = create_polyhedron(face_list); + for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf); return true; } @@ -555,8 +555,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangularPyramid* l, cga cgal_placement_t trsf; IfcGeom::CgalKernel::convert(l->Position(),trsf); - shape = create_nef_polyhedron(face_list); - shape.transform(trsf); + shape = create_polyhedron(face_list); + for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf); return true; } @@ -597,8 +597,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, cgal_placement_t trsf; IfcGeom::CgalKernel::convert(l->Position(),trsf); - shape = create_nef_polyhedron(face_list); - shape.transform(trsf); + shape = create_polyhedron(face_list); + for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf); return true; } @@ -631,8 +631,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCone* l, cgal cgal_placement_t trsf; IfcGeom::CgalKernel::convert(l->Position(),trsf); - shape = create_nef_polyhedron(face_list); - shape.transform(trsf); + shape = create_polyhedron(face_list); + for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf); return true; } @@ -682,7 +682,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, cg face_list.back().outer.push_back(c); } - shape = create_nef_polyhedron(face_list); + shape = create_polyhedron(face_list); return true; } #endif @@ -701,8 +701,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, cgal_sh // const gp_Pnt pnt = pln.Location().Translated( l->AgreementFlag() ? -pln.Axis().Direction() : pln.Axis().Direction()); // shape = BRepPrimAPI_MakeHalfSpace(BRepBuilderAPI_MakeFace(pln),pnt).Solid(); - shape = CGAL::Nef_polyhedron_3(); - // TODO: We return an empty Nef polyhedron for now and handle halfspace differences in IfcBooleanResult. The other option would be to switch to an extended kernel. + shape = CGAL::Polyhedron_3(); + // TODO: We need to do something for now. Find a better solution later (abstract shape class?) // shape = CGAL::Nef_polyhedron_3(pln); return true; } diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp index 2bfd8caaac..a2a804f0aa 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp @@ -63,6 +63,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, ConversionResults& shape) { cgal_shape_t s; + CGAL::Nef_polyhedron_3 nef_s(s); const SurfaceStyle* collective_style = get_style(l); if (convert_shape(l->Outer(),s) ) { const SurfaceStyle* indiv_style = get_style(l->Outer()); @@ -79,14 +80,16 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, Conv for (IfcSchema::IfcClosedShell::list::it it = voids->begin(); it != voids->end(); ++it) { cgal_shape_t s2; + CGAL::Nef_polyhedron_3 nef_s2(s2); // TODO: This looks weird. Aren't we removing the outer shell again and again? // Maybe it should be // if (convert_shape(*it, s2)) { if (convert_shape(l->Outer(), s2)) { - s -= s2; + nef_s -= nef_s2; } } + nef_s.convert_to_polyhedron(s); shape.push_back(ConversionResult(new CgalShape(s), indiv_style ? indiv_style : collective_style)); return true; } diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index 10e616c318..2e69487603 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -250,7 +250,7 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* entity, } gtrsf = gtrsf * opening_trsf; cgal_shape_t opening_shape(((CgalShape*)opening_shapes[i].Shape())->shape()); - opening_shape.transform(gtrsf); + for (auto &vertex: vertices(opening_shape)) vertex->point() = vertex->point().transform(gtrsf); opening_shapelist.push_back(opening_shape); // std::cout << "gtrsf" << std::endl; @@ -270,10 +270,11 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* entity, cgal_shape_t entity_shape(entity_shape_unlocated); if (it3->Placement()) { const cgal_placement_t& entity_shape_gtrsf = *(CgalPlacement*)it3->Placement(); - entity_shape.transform(entity_shape_gtrsf); + for (auto &vertex: vertices(entity_shape)) vertex->point() = vertex->point().transform(entity_shape_gtrsf); } cgal_shape_t brep_cut_result(entity_shape); + CGAL::Nef_polyhedron_3 nef_brep_cut_result(brep_cut_result); for (auto &opening: opening_shapelist) { @@ -289,7 +290,8 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* entity, // fresult << polyhedron << std::endl; // fresult.close(); - brep_cut_result -= opening; + CGAL::Nef_polyhedron_3 nef_opening(opening); + nef_brep_cut_result -= nef_opening; // brep_cut_result.convert_to_polyhedron(polyhedron); // fresult.open("/Users/ken/Desktop/after.off"); @@ -298,6 +300,7 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* entity, } if (brep_cut_result.is_valid()) { + nef_brep_cut_result.convert_to_Polyhedron(brep_cut_result); cut_shapes.push_back(IfcGeom::ConversionResult(new CgalShape(brep_cut_result), &it3->Style())); } else { // Apparently processing the boolean operation failed or resulted in an invalid result diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 71071f5d92..baaf48914c 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -64,7 +64,7 @@ struct cgal_face_t { std::vector inner; }; -typedef CGAL::Nef_polyhedron_3 cgal_shape_t; +typedef CGAL::Polyhedron_3 cgal_shape_t; typedef boost::graph_traits>::vertex_descriptor cgal_vertex_descriptor_t; typedef boost::graph_traits>::face_descriptor cgal_face_descriptor_t; @@ -140,6 +140,7 @@ namespace IfcGeom { 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 create_polyhedron(std::list &face_list); CGAL::Nef_polyhedron_3 create_nef_polyhedron(std::list &face_list); void purge_cache() { From dd206a2a52ae2a86a05c2936f849f6b2d4fdea26 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 23 Mar 2017 20:20:43 -0600 Subject: [PATCH 096/235] A few more simple IFC classes to fill in things --- .../kernels/cgal/CgalConversionFunctions.cpp | 2 +- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 63 ++++++++++++++----- src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp | 15 +++++ .../kernels/cgal/CgalIfcGeomPrimitives.cpp | 16 +++++ .../kernels/cgal/CgalIfcGeomShapes.cpp | 10 ++- src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp | 28 +++++++++ 6 files changed, 114 insertions(+), 20 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 6a7b805150..8b465db32a 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -26,7 +26,7 @@ void IfcGeom::CgalKernel::remove_duplicate_points_from_loop(cgal_wire_t& polygon CGAL::Polyhedron_3 IfcGeom::CgalKernel::create_polyhedron(std::list &face_list) { // Naive creation - CGAL::Polyhedron_3 polyhedron = CGAL::Polyhedron_3(); + CGAL::Polyhedron_3 polyhedron; PolyhedronBuilder builder(&face_list); polyhedron.delegate(builder); diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index e438b3ace1..37967d966b 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -39,55 +39,84 @@ SHAPES(IfcMappedItem); 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(IfcCsgSolid); -SHAPE(IfcBlock); SHAPE(IfcBooleanResult); -SHAPE(IfcSphere); +//SHAPE(IfcPolygonalBoundedHalfSpace); +SHAPE(IfcHalfSpaceSolid); +//SHAPE(IfcSurfaceOfLinearExtrusion); +//SHAPE(IfcSurfaceOfRevolution); +SHAPE(IfcBlock); SHAPE(IfcRectangularPyramid); SHAPE(IfcRightCircularCylinder); SHAPE(IfcRightCircularCone); -#ifdef USE_IFC4 -SHAPE(IfcTriangulatedFaceSet); -#endif -SHAPE(IfcHalfSpaceSolid); +SHAPE(IfcSphere); +SHAPE(IfcCsgSolid); +//SHAPE(IfcCurveBoundedPlane); +//SHAPE(IfcRectangularTrimmedSurface); +//SHAPE(IfcSurfaceCurveSweptAreaSolid); +//SHAPE(IfcSweptDiskSolid); +FACE(IfcArbitraryProfileDefWithVoids); FACE(IfcArbitraryClosedProfileDef); -FACE(IfcCircleHollowProfileDef); -FACE(IfcCircleProfileDef); -FACE(IfcFace); FACE(IfcRoundedRectangleProfileDef); FACE(IfcRectangleHollowProfileDef); FACE(IfcRectangleProfileDef); -FACE(IfcTrapeziumProfileDef); -FACE(IfcEllipseProfileDef); +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(IfcEdgeLoop); +//WIRE(IfcEdgeCurve); +//WIRE(IfcSubedge); WIRE(IfcOrientedEdge); -WIRE(IfcPolyLoop); +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(IfcVector,cgal_vector_t); -CLASS(IfcPlane,cgal_plane_t); CLASS(IfcAxis2Placement2D,cgal_placement_t); CLASS(IfcAxis2Placement3D,cgal_placement_t); -CLASS(IfcObjectPlacement,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); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp index 0040b65cc3..09729e2467 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp @@ -10,6 +10,21 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcArbitraryClosedProfileDef* 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); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp index 446f877394..d4cda51f6c 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp @@ -126,6 +126,22 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement3D* l, cgal_ 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); + + // 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->is(IfcSchema::Type::IfcLocalPlacement) ) { diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index a275b071bf..c29b9ad36f 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -50,6 +50,12 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal top_face.outer.push_back(*vertex+height*dir); } face_list.push_back(top_face); + if (bottom_face.inner.empty()) { + shape = create_polyhedron(face_list); + for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf); + return true; + } + CGAL::Nef_polyhedron_3 nef_shape = create_nef_polyhedron(face_list); // Inner @@ -701,8 +707,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, cgal_sh // 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(); - // TODO: We need to do something for now. Find a better solution later (abstract shape class?) -// shape = CGAL::Nef_polyhedron_3(pln); return true; } diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp index 674ba921d6..ee874bc140 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp @@ -86,6 +86,34 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcOrientedEdge* l, cgal_wire } } +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcEdge* l, cgal_wire_t& result) { + if (!l->EdgeStart()->is(IfcSchema::Type::IfcVertexPoint) || !l->EdgeEnd()->is(IfcSchema::Type::IfcVertexPoint)) { + Logger::Message(Logger::LOG_ERROR, "Only IfcVertexPoints are supported for EdgeStart and -End", l->entity); + return false; + } + + IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) l->EdgeStart())->VertexGeometry(); + IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) l->EdgeEnd())->VertexGeometry(); + if (!pnt1->is(IfcSchema::Type::IfcCartesianPoint) || !pnt2->is(IfcSchema::Type::IfcCartesianPoint)) { + Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l->entity); + 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->entity); From f8f4db72ec9f8d017635711acae4f22db47f96ba Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 23 Mar 2017 20:25:54 -0600 Subject: [PATCH 097/235] IfcDerivedProfileDef --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 2 +- src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 37967d966b..3dc4b9c95e 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -84,7 +84,7 @@ FACE(IfcCircleProfileDef); FACE(IfcEllipseProfileDef); //FACE(IfcCenterLineProfileDef); //FACE(IfcCompositeProfileDef); -//FACE(IfcDerivedProfileDef); +FACE(IfcDerivedProfileDef); // IfcFaceSurface included // IfcAdvancedFace included in case of IFC4 FACE(IfcFace); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp index 09729e2467..e1a4383dc4 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp @@ -971,3 +971,18 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcZShapeProfileDef* l, cgal_ 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; + } +} From 583c3348027788ddd83362ca90c5eb9e02c6fbdd Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 23 Mar 2017 20:31:41 -0600 Subject: [PATCH 098/235] Removed sphere radius at some point --- src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index c29b9ad36f..4ad278c939 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -519,7 +519,12 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& s IfcGeom::CgalKernel::convert(l->Position(),trsf); shape = create_polyhedron(face_list); - for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf); + 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; } From ed9676ed38e3cd008d6c1e503bf556a53ded4e8c Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 30 Mar 2017 19:04:39 -0600 Subject: [PATCH 099/235] Squashed some bugs --- .../kernels/cgal/CgalConversionFunctions.cpp | 20 ++++++++++++++ .../kernels/cgal/CgalIfcGeomPrimitives.cpp | 27 ++++++++++++++++--- .../cgal/CgalIfcGeomShapesWithStyles.cpp | 7 +++-- src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp | 6 ++--- src/ifcgeom/kernels/cgal/CgalKernel.h | 4 ++- 5 files changed, 53 insertions(+), 11 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 8b465db32a..b34ca73bc8 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -51,8 +51,28 @@ CGAL::Polyhedron_3 IfcGeom::CgalKernel::create_polyhedron(std::list IfcGeom::CgalKernel::create_polyhedron(CGAL::Nef_polyhedron_3 &nef_polyhedron) { + if (nef_polyhedron.is_simple()) { + CGAL::Polyhedron_3 polyhedron; + nef_polyhedron.convert_to_polyhedron(polyhedron); + return polyhedron; + } else { + std::cout << "Nef polyhedron not simple: cannot create polyhedron!" << std::endl; + return CGAL::Polyhedron_3(); + } +} CGAL::Nef_polyhedron_3 IfcGeom::CgalKernel::create_nef_polyhedron(std::list &face_list) { CGAL::Polyhedron_3 polyhedron = create_polyhedron(face_list); return CGAL::Nef_polyhedron_3(polyhedron); } + +CGAL::Nef_polyhedron_3 IfcGeom::CgalKernel::create_nef_polyhedron(CGAL::Polyhedron_3 &polyhedron) { + if (polyhedron.is_valid()) { + CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron); + return CGAL::Nef_polyhedron_3(polyhedron); + } else { + std::cout << "Polyhedron not valid: cannot create Nef polyhedron!" << std::endl; + return CGAL::Nef_polyhedron_3(); + } +} diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp index d4cda51f6c..62c155b5ba 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp @@ -86,6 +86,14 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement2D* l, cgal_ 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), @@ -107,9 +115,16 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement3D* l, cgal_ Kernel::Vector_3 y = CGAL::cross_product(axis, refDirection); Kernel::Vector_3 x = CGAL::cross_product(y, axis); - // std::cout << "Ref direction: " << refDirection << std::endl; - // std::cout << "Axis: " << axis << std::endl; - // std::cout << "Origin: " << o << std::endl; + 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), @@ -133,6 +148,12 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis1Placement* l, cgal_pl 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), diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp index a2a804f0aa..c28d6ee8e2 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp @@ -63,9 +63,9 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, ConversionResults& shape) { cgal_shape_t s; - CGAL::Nef_polyhedron_3 nef_s(s); const SurfaceStyle* collective_style = get_style(l); if (convert_shape(l->Outer(),s) ) { + CGAL::Nef_polyhedron_3 nef_s = create_nef_polyhedron(s); const SurfaceStyle* indiv_style = get_style(l->Outer()); IfcSchema::IfcClosedShell::list::ptr voids(new IfcSchema::IfcClosedShell::list); @@ -80,16 +80,15 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, Conv for (IfcSchema::IfcClosedShell::list::it it = voids->begin(); it != voids->end(); ++it) { cgal_shape_t s2; - CGAL::Nef_polyhedron_3 nef_s2(s2); // TODO: This looks weird. Aren't we removing the outer shell again and again? // Maybe it should be // if (convert_shape(*it, s2)) { if (convert_shape(l->Outer(), s2)) { - nef_s -= nef_s2; + nef_s -= CGAL::Nef_polyhedron_3(s2); } } - nef_s.convert_to_polyhedron(s); + s = create_polyhedron(nef_s); shape.push_back(ConversionResult(new CgalShape(s), indiv_style ? indiv_style : collective_style)); return true; } diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp index ee874bc140..c845cba55a 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp @@ -19,7 +19,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& } // Remove points that are too close to one another - remove_duplicate_points_from_loop(polygon, true); + remove_duplicate_points_from_loop(polygon); std::size_t count = polygon.size(); if (original_count - count != 0) { @@ -54,7 +54,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyline* l, cgal_wire_t& } // Remove points that are too close to one another - remove_duplicate_points_from_loop(polygon, false); + remove_duplicate_points_from_loop(polygon); result = polygon; return true; @@ -198,7 +198,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCompositeCurve* l, cgal_wi } } - remove_duplicate_points_from_loop(w, false); + remove_duplicate_points_from_loop(w); wire = w; return true; diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index baaf48914c..266b7a8294 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -136,12 +136,14 @@ namespace IfcGeom { 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 closed, double tol = -1.); + 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 create_polyhedron(std::list &face_list); + CGAL::Polyhedron_3 create_polyhedron(CGAL::Nef_polyhedron_3 &nef_polyhedron); CGAL::Nef_polyhedron_3 create_nef_polyhedron(std::list &face_list); + CGAL::Nef_polyhedron_3 create_nef_polyhedron(CGAL::Polyhedron_3 &polyhedron); void purge_cache() { // Rather hack-ish, but a stopgap solution to keep memory under control From 71ad7dd4bc6feb2db3a550cd7ba17c1302c73d5e Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 30 Mar 2017 19:06:47 -0600 Subject: [PATCH 100/235] Forgot one line --- src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index b34ca73bc8..2b5110f859 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -5,7 +5,7 @@ bool IfcGeom::CgalKernel::convert_wire_to_face(const cgal_wire_t& wire, cgal_fac return true; } -void IfcGeom::CgalKernel::remove_duplicate_points_from_loop(cgal_wire_t& polygon, bool closed, double tol) { +void IfcGeom::CgalKernel::remove_duplicate_points_from_loop(cgal_wire_t& polygon) { if (tol <= 0.) tol = getValue(GV_PRECISION); tol *= tol; From c1887f3f1fbe7c7227e2f2eaa75ff32bedb57f00 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 30 Mar 2017 19:16:11 -0600 Subject: [PATCH 101/235] And the rest --- .../kernels/cgal/CgalConversionFunctions.cpp | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 2b5110f859..69003d9aa1 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -6,20 +6,12 @@ bool IfcGeom::CgalKernel::convert_wire_to_face(const cgal_wire_t& wire, cgal_fac } void IfcGeom::CgalKernel::remove_duplicate_points_from_loop(cgal_wire_t& polygon) { - if (tol <= 0.) tol = getValue(GV_PRECISION); - tol *= tol; - + std::set points; for (int i = 0; i < polygon.size(); ++i) { - for (int j = i+1; j < polygon.size(); ++j) { - if (CGAL::squared_distance(polygon[i], polygon[j]) < tol) { - polygon.erase(polygon.begin()+j); - --j; - } - } if (closed) { - if (CGAL::squared_distance(polygon.front(), polygon.back()) < tol) { - polygon.erase(polygon.begin()+polygon.size()-1); - } - } + if (points.count(polygon[i])) { + polygon.erase(polygon.begin()+i); + --i; + } else points.insert(polygon[i]); } } From 4a340027bf475dc7c81aae10b2da5fa6f8ea2aad Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 30 Mar 2017 20:12:23 -0600 Subject: [PATCH 102/235] IfcExtrudedAreaSolidTapered (with problems?) --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 2 +- .../kernels/cgal/CgalIfcGeomShapes.cpp | 127 +++++++++++++++++- 2 files changed, 126 insertions(+), 3 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 3dc4b9c95e..22f52e6f2d 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -44,7 +44,7 @@ SHAPES(IfcGeometricSet); //SHAPE(IfcAdvancedBrep); //SHAPE(IfcBSplineSurfaceWithKnots); SHAPE(IfcTriangulatedFaceSet); -//SHAPE(IfcExtrudedAreaSolidTapered); +SHAPE(IfcExtrudedAreaSolidTapered); #endif //SHAPE(IfcPlane); SHAPE(IfcExtrudedAreaSolid); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 4ad278c939..227d45825c 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -52,7 +52,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal if (bottom_face.inner.empty()) { shape = create_polyhedron(face_list); - for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf); + if (has_position) for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf); return true; } @@ -66,6 +66,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal 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::const_iterator current_vertex = inner.begin(); @@ -93,11 +94,133 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal nef_shape -= create_nef_polyhedron(face_list); } - nef_shape.transform(trsf); + if (has_position) { + // IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D + // and therefore has a unit scale factor + nef_shape.transform(trsf); + } + nef_shape.convert_to_polyhedron(shape); return true; } +#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->entity); + 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 face_list; + face_list.push_back(face1); + face_list.push_back(face2); + + std::vector::const_iterator current_face1_vertex = face1.outer.begin(); + std::vector::const_iterator current_face2_vertex = face2.outer.begin(); + while (current_face1_vertex != face1.outer.end() && + current_face2_vertex != face2.outer.end()) { + std::vector::const_iterator next_face1_vertex = current_face1_vertex; + std::vector::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; + } + + 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; + } + + CGAL::Nef_polyhedron_3 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::iterator inner_face1 = face1.inner.begin(); + std::vector::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); + face_list.push_back(hole_face2); + + 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::const_iterator next_face1_vertex = current_face1_vertex; + std::vector::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; + } + + nef_shape -= create_nef_polyhedron(face_list); + + ++inner_face1; + ++inner_face2; + } + + if (has_position) { + // IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D + // and therefore has a unit scale factor + nef_shape.transform(trsf); + } + + nef_shape.convert_to_polyhedron(shape); + return true; +} +#endif + bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_shape_t& shape) { IfcSchema::IfcFace::list::ptr faces = l->CfsFaces(); From c9267d7ace8584bca4997ad2bb1db8d38413d6cf Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 30 Mar 2017 21:11:05 -0600 Subject: [PATCH 103/235] Fixed orientation bug in tapered extrusions --- .../kernels/cgal/CgalIfcGeomShapes.cpp | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 227d45825c..e3264e78ec 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -136,7 +136,6 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* // Outer std::list face_list; face_list.push_back(face1); - face_list.push_back(face2); std::vector::const_iterator current_face1_vertex = face1.outer.begin(); std::vector::const_iterator current_face2_vertex = face2.outer.begin(); @@ -158,12 +157,27 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* ++current_face2_vertex; } + cgal_face_t top_face; + for (std::vector::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 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 nef_shape = create_nef_polyhedron(face_list); // Inner @@ -182,7 +196,6 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* cgal_face_t hole_face2; hole_face2.outer = *inner_face2; remove_duplicate_points_from_loop(hole_face2.outer); - face_list.push_back(hole_face2); current_face1_vertex = hole_face1.outer.begin(); current_face2_vertex = hole_face2.outer.begin(); @@ -204,6 +217,21 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* ++current_face2_vertex; } + cgal_face_t top_hole_face; + for (std::vector::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 inner_polyhedron; +// PolyhedronBuilder builder(&face_list); +// inner_polyhedron.delegate(builder); +// f2.open("/Users/ken/Desktop/inner.off"); +// f2 << inner_polyhedron << std::endl; +// f2.close(); + nef_shape -= create_nef_polyhedron(face_list); ++inner_face1; From 009f50abe1b3e6705316bfe5cdc451326773226f Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 5 Apr 2017 15:57:21 +0200 Subject: [PATCH 104/235] Fix compilation on MSVC --- src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp index c845cba55a..08a947efd6 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp @@ -1,3 +1,7 @@ +// For MSVC to have M_PI +#define _USE_MATH_DEFINES +#include + #include "CgalKernel.h" bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& result) { From 91e5b337d371c2f1bbf31f7ce5907b6b5f4c4b5b Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 5 Apr 2017 16:06:07 +0200 Subject: [PATCH 105/235] Reverse matrix multiplication order --- src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp | 2 +- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp index 62c155b5ba..34f5b6c10c 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp @@ -192,7 +192,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_p // } std::cout << std::endl; // } - trsf = trsf * trsf2; // TODO: I think it's fine, but maybe should it be the other way around? + trsf = trsf2 * trsf; // std::cout << "trsf (after multiplication)" << std::endl; // for (int i = 0; i < 3; ++i) { diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index 2e69487603..9c9512ceac 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -225,7 +225,7 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* entity, // } // Move the opening into the coordinate system of the IfcProduct - opening_trsf = opening_trsf * entity_trsf.inverse(); + opening_trsf = entity_trsf.inverse() * opening_trsf; // std::cout << "opening_trsf after" << std::endl; // for (int i = 0; i < 3; ++i) { @@ -248,7 +248,7 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* entity, if (opening_shapes[i].Placement()) { gtrsf = *(CgalPlacement*)opening_shapes[i].Placement(); } - gtrsf = gtrsf * opening_trsf; + 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); From 7189219aa4692316e921bc5ae707673b167beeac Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 6 Apr 2017 14:44:57 +0200 Subject: [PATCH 106/235] Attempt to fix travis build w/ CGAL --- .travis.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7fe6cc4b3c..fc3360ddf8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,6 +31,8 @@ install: - sudo apt-get install -y liboce-ocaf-lite-dev - sudo apt-get install -y libpcre3-dev + + - sudo apt-get install -y libcgal-dev libmpfr-dev libgmp-dev script: - pwd @@ -51,8 +53,8 @@ script: - cd cmake - mkdir build-ifc2x3 build-ifc4 - cd build-ifc2x3 - - cmake -DCOLLADA_SUPPORT=True -DOPENCOLLADA_INCLUDE_DIR=/usr/local/include/opencollada -DOPENCOLLADA_LIBRARY_DIR=/usr/local/lib/opencollada -DPCRE_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu -DUSE_IFC4=False -DBUILD_IFCPYTHON=True -DUNICODE_SUPPORT=True -DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu .. + - cmake -DCOLLADA_SUPPORT=True -DOPENCOLLADA_INCLUDE_DIR=/usr/local/include/opencollada -DOPENCOLLADA_LIBRARY_DIR=/usr/local/lib/opencollada -DPCRE_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu -DUSE_IFC4=False -DBUILD_IFCPYTHON=True -DUNICODE_SUPPORT=True -DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu -DGMP_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu/ -DMPFR_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu/ .. - make -j IfcConvert - cd ../build-ifc4 - - cmake -DCOLLADA_SUPPORT=True -DOPENCOLLADA_INCLUDE_DIR=/usr/local/include/opencollada -DOPENCOLLADA_LIBRARY_DIR=/usr/local/lib/opencollada -DPCRE_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu -DUSE_IFC4=True -DBUILD_IFCPYTHON=True -DUNICODE_SUPPORT=True -DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu .. + - cmake -DCOLLADA_SUPPORT=True -DOPENCOLLADA_INCLUDE_DIR=/usr/local/include/opencollada -DOPENCOLLADA_LIBRARY_DIR=/usr/local/lib/opencollada -DPCRE_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu -DUSE_IFC4=True -DBUILD_IFCPYTHON=True -DUNICODE_SUPPORT=True -DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu -DGMP_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu/ -DMPFR_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu/ .. - make -j IfcConvert From 7b7f9b4852e713bde06ff27d3f8ae96f4650cfe3 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 6 Apr 2017 14:57:10 +0200 Subject: [PATCH 107/235] Attempt to fix travis build w/ CGAL --- .travis.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index fc3360ddf8..a289378efa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,11 +15,11 @@ install: - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 90 - sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 90 - - sudo apt-get install -y libboost1.55-dev - - sudo apt-get install -y libboost-regex1.55-dev - - sudo apt-get install -y libboost-system1.55-dev - - sudo apt-get install -y libboost-thread1.55-dev - - sudo apt-get install -y libboost-program-options1.55-dev + - sudo apt-get install -y libboost-dev + - sudo apt-get install -y libboost-regex-dev + - sudo apt-get install -y libboost-system-dev + - sudo apt-get install -y libboost-thread-dev + - sudo apt-get install -y libboost-program-options-dev - sudo apt-get install -y cmake - sudo apt-get install -y libicu-dev - sudo apt-get install -y python-all-dev From 8d9acfa677564f750558c135d711dc4e671d1e28 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 6 Apr 2017 15:23:45 +0200 Subject: [PATCH 108/235] Attempt to fix travis build w/ CGAL --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a289378efa..51aa99a546 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: cpp compiler: gcc os: linux -dist: trusty +dist: xenial sudo: required From 248c73c2ab945b06924bf9fddc7e0c44faa1e82e Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 10 Apr 2017 18:53:28 -0500 Subject: [PATCH 109/235] Catch failures to convert Nef to Polyhedron_3 --- .../kernels/cgal/CgalIfcGeomShapes.cpp | 46 +++++++++++++++---- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 12 ++++- 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index e3264e78ec..7b64a21321 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -100,8 +100,14 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal nef_shape.transform(trsf); } - nef_shape.convert_to_polyhedron(shape); - return true; + try { + nef_shape.convert_to_polyhedron(shape); + return true; + } catch (...) { + std::cout << "IfcExtrudedAreaSolid: cannot convert Nef to polyhedron!" << std::endl; + return false; + } + } #ifdef USE_IFC4 @@ -244,8 +250,13 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* nef_shape.transform(trsf); } - nef_shape.convert_to_polyhedron(shape); - return true; + try { + nef_shape.convert_to_polyhedron(shape); + return true; + } catch (...) { + std::cout << "IfcExtrudedAreaSolidTapered: cannot convert Nef to polyhedron!" << std::endl; + return false; + } } #endif @@ -458,8 +469,13 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha // fresult.open("/Users/ken/Desktop/result.off"); // fresult << result << std::endl; // fresult.close(); - } nef_result.convert_to_polyhedron(shape); - return true; + } 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) { @@ -475,8 +491,13 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha // fresult.open("/Users/ken/Desktop/result.off"); // fresult << result << std::endl; // fresult.close(); - } nef_result.convert_to_polyhedron(shape); - return true; + } 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) { @@ -492,8 +513,13 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha // fresult.open("/Users/ken/Desktop/result.off"); // fresult << result << std::endl; // fresult.close(); - } nef_result.convert_to_polyhedron(shape); - return true; + } try { + nef_result.convert_to_polyhedron(shape); + return true; + } catch (...) { + std::cout << "IfcBooleanResult: cannot convert Nef to polyhedron!" << std::endl; + return false; + } } return false; } diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index 9c9512ceac..d13dab80ec 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -300,8 +300,16 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* entity, } if (brep_cut_result.is_valid()) { - nef_brep_cut_result.convert_to_Polyhedron(brep_cut_result); - cut_shapes.push_back(IfcGeom::ConversionResult(new CgalShape(brep_cut_result), &it3->Style())); + try { + nef_brep_cut_result.convert_to_polyhedron(brep_cut_result); + cut_shapes.push_back(IfcGeom::ConversionResult(new CgalShape(brep_cut_result), &it3->Style())); + } catch (...) { + // Apparently processing the boolean operation failed or resulted in an invalid result + // in which case the original shape without the subtractions is returned instead + // we try convert the openings in the original way, one by one. + Logger::Message(Logger::LOG_WARNING, "Subtracting combined openings compound failed:", entity->entity); + return false; + } } else { // Apparently processing the boolean operation failed or resulted in an invalid result // in which case the original shape without the subtractions is returned instead From 26bd03e4073b52b570ab77f13c58c96206df287c Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 10 Apr 2017 18:53:52 -0500 Subject: [PATCH 110/235] Ditto --- src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 69003d9aa1..c01c6e8576 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -45,9 +45,14 @@ CGAL::Polyhedron_3 IfcGeom::CgalKernel::create_polyhedron(std::list IfcGeom::CgalKernel::create_polyhedron(CGAL::Nef_polyhedron_3 &nef_polyhedron) { if (nef_polyhedron.is_simple()) { - CGAL::Polyhedron_3 polyhedron; - nef_polyhedron.convert_to_polyhedron(polyhedron); - return polyhedron; + try { + CGAL::Polyhedron_3 polyhedron; + nef_polyhedron.convert_to_polyhedron(polyhedron); + return polyhedron; + } catch (...) { + std::cout << "Conversion from Nef to polyhedron failed!" << std::endl; + return CGAL::Polyhedron_3(); + } } else { std::cout << "Nef polyhedron not simple: cannot create polyhedron!" << std::endl; return CGAL::Polyhedron_3(); From 9f2a617ad740995195711737da5e51826ae82124 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 10 Apr 2017 18:54:30 -0500 Subject: [PATCH 111/235] Catch a few nasty cases in triangulation, more efficient to only compute face normals --- .../kernels/cgal/CgalConversionResult.cpp | 39 +++++++++++++++---- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index ba6e1fa5b2..8aa38cbee1 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -10,29 +10,52 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, vertex->point() = vertex->point().transform(trsf); } + if (!s.is_valid() || !s.is_closed()) { + Logger::Message(Logger::LOG_ERROR, "Invalid Polyhedron_3 in object (before triangulation)"); + std::ofstream ferror; + ferror.open("/Users/ken/Desktop/error.off"); + ferror << s << std::endl; + ferror.close(); + return; + } + // std::ofstream fbefore; // fbefore.open("/Users/ken/Desktop/before.off"); // fbefore << s << std::endl; // fbefore.close(); // Triangulate the shape and compute the normals - std::map vertex_normals; - boost::associative_property_map> vertex_normals_map(vertex_normals); +// std::map vertex_normals; +// boost::associative_property_map> vertex_normals_map(vertex_normals); std::map face_normals; boost::associative_property_map> face_normals_map(face_normals); - if (CGAL::Polygon_mesh_processing::triangulate_faces(s)) { -// std::cout << "Triangulated model: " << s.size_of_facets() << " facets and " << s.size_of_vertices() << " vertices" << std::endl; - } else { - Logger::Message(Logger::LOG_ERROR, "Failed to triangulate shape"); + cgal_shape_t s_copy(s); + if (!CGAL::Polygon_mesh_processing::triangulate_faces(s) ) { + Logger::Message(Logger::LOG_ERROR, "Triangulation failed"); + std::ofstream ferror; + ferror.open("/Users/ken/Desktop/error.off"); + ferror << s << std::endl; + ferror.close(); return; } + // std::cout << "Triangulated model: " << s.size_of_facets() << " facets and " << s.size_of_vertices() << " vertices" << std::endl; // std::ofstream fafter; // fafter.open("/Users/ken/Desktop/after.off"); // fafter << s << std::endl; // fafter.close(); - - CGAL::Polygon_mesh_processing::compute_normals(s, vertex_normals_map, face_normals_map); + + if (!s.is_valid() || !s.is_closed()) { + Logger::Message(Logger::LOG_ERROR, "Invalid Polyhedron_3 in object (after triangulation)"); + std::ofstream ferror; + ferror.open("/Users/ken/Desktop/error.off"); + ferror << s_copy << std::endl; + ferror.close(); + 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); for (auto &face: faces(s)) { if (!face->is_triangle()) { From 164e67a50bc3deaee567a30aa2dc1853299fe71b Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 21 Apr 2017 15:43:19 +0200 Subject: [PATCH 112/235] Catching some more CGAL errors, allow non-closed meshes, start of new code to triangulate faces --- .../kernels/cgal/CgalConversionFunctions.cpp | 52 ++++++++++++++++--- .../kernels/cgal/CgalConversionResult.cpp | 16 ++++-- .../kernels/cgal/CgalIfcGeomShapes.cpp | 34 +++++++++--- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 34 ++++++++++-- src/ifcgeom/kernels/cgal/CgalKernel.h | 1 + 5 files changed, 117 insertions(+), 20 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index c01c6e8576..c3645d77b8 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -26,7 +26,7 @@ CGAL::Polyhedron_3 IfcGeom::CgalKernel::create_polyhedron(std::list IfcGeom::CgalKernel::create_polyhedron(CGAL::Nef_poly nef_polyhedron.convert_to_polyhedron(polyhedron); return polyhedron; } catch (...) { - std::cout << "Conversion from Nef to polyhedron failed!" << std::endl; + Logger::Message(Logger::LOG_ERROR, "Conversion from Nef to polyhedron failed!"); return CGAL::Polyhedron_3(); } } else { - std::cout << "Nef polyhedron not simple: cannot create polyhedron!" << std::endl; + Logger::Message(Logger::LOG_ERROR, "Nef polyhedron not simple: cannot create polyhedron!"); return CGAL::Polyhedron_3(); } } CGAL::Nef_polyhedron_3 IfcGeom::CgalKernel::create_nef_polyhedron(std::list &face_list) { CGAL::Polyhedron_3 polyhedron = create_polyhedron(face_list); - return CGAL::Nef_polyhedron_3(polyhedron); + CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron); + CGAL::Nef_polyhedron_3 nef_polyhedron; + try { + nef_polyhedron = CGAL::Nef_polyhedron_3(polyhedron); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Conversion to Nef polyhedron failed!"); + return nef_polyhedron; + } return nef_polyhedron; } CGAL::Nef_polyhedron_3 IfcGeom::CgalKernel::create_nef_polyhedron(CGAL::Polyhedron_3 &polyhedron) { if (polyhedron.is_valid()) { CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron); - return CGAL::Nef_polyhedron_3(polyhedron); + CGAL::Nef_polyhedron_3 nef_polyhedron; + try { + nef_polyhedron = CGAL::Nef_polyhedron_3(polyhedron); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Conversion to Nef polyhedron failed!"); + return nef_polyhedron; + } return nef_polyhedron; } else { - std::cout << "Polyhedron not valid: cannot create Nef polyhedron!" << std::endl; + Logger::Message(Logger::LOG_ERROR, "Polyhedron not valid: cannot create Nef polyhedron!"); return CGAL::Nef_polyhedron_3(); } } + +CGAL::Polyhedron_3 IfcGeom::CgalKernel::triangulate_faces(CGAL::Polyhedron_3 &polyhedron) { + std::list face_list; + + for (CGAL::Polyhedron_3::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::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 points_in_polygon; + + } + } + + return create_polyhedron(face_list); +} diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index 8aa38cbee1..98a4272fee 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -10,7 +10,7 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, vertex->point() = vertex->point().transform(trsf); } - if (!s.is_valid() || !s.is_closed()) { + if (!s.is_valid()) { Logger::Message(Logger::LOG_ERROR, "Invalid Polyhedron_3 in object (before triangulation)"); std::ofstream ferror; ferror.open("/Users/ken/Desktop/error.off"); @@ -30,7 +30,17 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, std::map face_normals; boost::associative_property_map> face_normals_map(face_normals); cgal_shape_t s_copy(s); - if (!CGAL::Polygon_mesh_processing::triangulate_faces(s) ) { + bool success = false; + try { + success = CGAL::Polygon_mesh_processing::triangulate_faces(s); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Triangulation crashed"); + std::ofstream ferror; + ferror.open("/Users/ken/Desktop/error.off"); + ferror << s << std::endl; + ferror.close(); + return; + } if (!success) { Logger::Message(Logger::LOG_ERROR, "Triangulation failed"); std::ofstream ferror; ferror.open("/Users/ken/Desktop/error.off"); @@ -45,7 +55,7 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, // fafter << s << std::endl; // fafter.close(); - if (!s.is_valid() || !s.is_closed()) { + if (!s.is_valid()) { Logger::Message(Logger::LOG_ERROR, "Invalid Polyhedron_3 in object (after triangulation)"); std::ofstream ferror; ferror.open("/Users/ken/Desktop/error.off"); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 7b64a21321..f6af7fc884 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -91,7 +91,12 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal hole_top_face.outer.push_back(*vertex+height*dir); } face_list.push_back(hole_top_face); - nef_shape -= create_nef_polyhedron(face_list); + try { + nef_shape -= create_nef_polyhedron(face_list); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "IfcExtrudedAreaSolid: cannot subtract opening for:", l->entity); + return false; + } } if (has_position) { @@ -104,7 +109,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal nef_shape.convert_to_polyhedron(shape); return true; } catch (...) { - std::cout << "IfcExtrudedAreaSolid: cannot convert Nef to polyhedron!" << std::endl; + Logger::Message(Logger::LOG_ERROR, "IfcExtrudedAreaSolid: cannot convert Nef to polyhedron for:", l->entity); return false; } @@ -238,7 +243,12 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* // f2 << inner_polyhedron << std::endl; // f2.close(); - nef_shape -= create_nef_polyhedron(face_list); + try { + nef_shape -= create_nef_polyhedron(face_list); + } catch (...) { + std::cout << "IfcExtrudedAreaSolidTapered: cannot subtract opening for:" << std::endl; + return false; + } ++inner_face1; ++inner_face2; @@ -453,14 +463,24 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) { // std::cout << "Difference" << std::endl; - CGAL::Nef_polyhedron_3 nef_result(s1); - if (is_halfspace) { + CGAL::Nef_polyhedron_3 nef_result; + try { + nef_result = CGAL::Nef_polyhedron_3(s1); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "s1: cannot convert to Nef?", operand1->entity); + return false; + } if (is_halfspace) { if (is_plane) nef_result = nef_result.intersection(plane, CGAL::Nef_polyhedron_3::Intersection_mode::CLOSED_HALFSPACE); } else { - nef_result -= CGAL::Nef_polyhedron_3(s2); + CGAL::Nef_polyhedron_3 nef_s2; + try { + nef_s2 = CGAL::Nef_polyhedron_3(s2); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "s2: cannot convert to Nef?", operand2->entity); + } nef_result -= nef_s2; } if (!nef_result.is_simple()) { - std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; + Logger::Message(Logger::LOG_ERROR, "s2: not simple?", operand2->entity); return false; } else { // CGAL::Polyhedron_3 result; diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index d13dab80ec..280db29647 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -290,8 +290,26 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* entity, // fresult << polyhedron << std::endl; // fresult.close(); - CGAL::Nef_polyhedron_3 nef_opening(opening); - nef_brep_cut_result -= nef_opening; + CGAL::Nef_polyhedron_3 nef_opening; + try { + nef_opening = CGAL::Nef_polyhedron_3(opening); + } catch (...) { + Logger::Message(Logger::LOG_WARNING, "Subtracting combined openings compound failed (Nef conversion):", entity->entity); + std::ofstream ferror; + ferror.open("/Users/ken/Desktop/error.off"); + ferror << entity_shape << std::endl; + ferror.close(); + return false; + } try { + nef_brep_cut_result -= nef_opening; + } catch (...) { + Logger::Message(Logger::LOG_WARNING, "Subtracting combined openings compound failed (subtraction):", entity->entity); + std::ofstream ferror; + ferror.open("/Users/ken/Desktop/error.off"); + ferror << entity_shape << std::endl; + ferror.close(); + return false; + } // brep_cut_result.convert_to_polyhedron(polyhedron); // fresult.open("/Users/ken/Desktop/after.off"); @@ -307,14 +325,22 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* entity, // Apparently processing the boolean operation failed or resulted in an invalid result // in which case the original shape without the subtractions is returned instead // we try convert the openings in the original way, one by one. - Logger::Message(Logger::LOG_WARNING, "Subtracting combined openings compound failed:", entity->entity); + Logger::Message(Logger::LOG_WARNING, "Subtracting combined openings compound failed (conversion):", entity->entity); + std::ofstream ferror; + ferror.open("/Users/ken/Desktop/error.off"); + ferror << entity_shape << std::endl; + ferror.close(); return false; } } else { // Apparently processing the boolean operation failed or resulted in an invalid result // in which case the original shape without the subtractions is returned instead // we try convert the openings in the original way, one by one. - Logger::Message(Logger::LOG_WARNING, "Subtracting combined openings compound failed:", entity->entity); + Logger::Message(Logger::LOG_WARNING, "Subtracting combined openings compound failed (invalid):", entity->entity); + std::ofstream ferror; + ferror.open("/Users/ken/Desktop/error.off"); + ferror << entity_shape << std::endl; + ferror.close(); return false; } diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 266b7a8294..a445ec275c 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -140,6 +140,7 @@ namespace IfcGeom { 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 triangulate_faces(CGAL::Polyhedron_3 &polyhedron); CGAL::Polyhedron_3 create_polyhedron(std::list &face_list); CGAL::Polyhedron_3 create_polyhedron(CGAL::Nef_polyhedron_3 &nef_polyhedron); CGAL::Nef_polyhedron_3 create_nef_polyhedron(std::list &face_list); From 85a36738d2357fd77429da8fe522736a17958c5e Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 25 Apr 2017 13:42:38 +0200 Subject: [PATCH 113/235] Comment out triangulation code --- .../kernels/cgal/CgalConversionFunctions.cpp | 52 +++++++++---------- src/ifcgeom/kernels/cgal/CgalKernel.h | 2 +- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index c3645d77b8..026b491b88 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -87,29 +87,29 @@ CGAL::Nef_polyhedron_3 IfcGeom::CgalKernel::create_nef_polyhedron(CGAL:: } } -CGAL::Polyhedron_3 IfcGeom::CgalKernel::triangulate_faces(CGAL::Polyhedron_3 &polyhedron) { - std::list face_list; - - for (CGAL::Polyhedron_3::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::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 points_in_polygon; - - } - } - - return create_polyhedron(face_list); -} +//CGAL::Polyhedron_3 IfcGeom::CgalKernel::triangulate_faces(CGAL::Polyhedron_3 &polyhedron) { +// std::list face_list; +// +// for (CGAL::Polyhedron_3::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::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 points_in_polygon; +// +// } +// } +// +// return create_polyhedron(face_list); +//} diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index a445ec275c..ed3ba02b69 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -140,7 +140,7 @@ namespace IfcGeom { 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 triangulate_faces(CGAL::Polyhedron_3 &polyhedron); +// CGAL::Polyhedron_3 triangulate_faces(CGAL::Polyhedron_3 &polyhedron); CGAL::Polyhedron_3 create_polyhedron(std::list &face_list); CGAL::Polyhedron_3 create_polyhedron(CGAL::Nef_polyhedron_3 &nef_polyhedron); CGAL::Nef_polyhedron_3 create_nef_polyhedron(std::list &face_list); From 02244400abbc2269cb1ffc0c867aaf8e6490f027 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 25 Apr 2017 13:43:55 +0200 Subject: [PATCH 114/235] Remove old debug code --- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 52 ------------------------- 1 file changed, 52 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index 280db29647..a35d21b9ae 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -96,13 +96,6 @@ IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representat try { convert(product->ObjectPlacement(), trsf); } catch (...) {} - -// std::cout << "trsf" << 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; -// } // Does the IfcElement have any IfcOpenings? // Note that openings for IfcOpeningElements are not processed @@ -210,30 +203,9 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* entity, } catch (...) {} } -// std::cout << "entity_trsf" << std::endl; -// for (int i = 0; i < 3; ++i) { -// for (int j = 0; j < 4; ++j) { -// std::cout << entity_trsf.cartesian(i, j) << " "; -// } std::cout << std::endl; -// } -// -// std::cout << "opening_trsf before" << std::endl; -// for (int i = 0; i < 3; ++i) { -// for (int j = 0; j < 4; ++j) { -// std::cout << opening_trsf.cartesian(i, j) << " "; -// } std::cout << std::endl; -// } - // Move the opening into the coordinate system of the IfcProduct opening_trsf = entity_trsf.inverse() * opening_trsf; -// std::cout << "opening_trsf after" << std::endl; -// for (int i = 0; i < 3; ++i) { -// for (int j = 0; j < 4; ++j) { -// std::cout << opening_trsf.cartesian(i, j) << " "; -// } std::cout << std::endl; -// } - IfcSchema::IfcProductRepresentation* prodrep = fes->Representation(); IfcSchema::IfcRepresentation::list::ptr reps = prodrep->Representations(); @@ -252,13 +224,6 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* entity, 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); - -// std::cout << "gtrsf" << 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; -// } } } @@ -278,18 +243,6 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* entity, for (auto &opening: opening_shapelist) { -// CGAL::Polyhedron_3 polyhedron; -// brep_cut_result.convert_to_polyhedron(polyhedron); -// std::ofstream fresult; -// fresult.open("/Users/ken/Desktop/before.off"); -// fresult << polyhedron << std::endl; -// fresult.close(); -// -// opening.convert_to_polyhedron(polyhedron); -// fresult.open("/Users/ken/Desktop/opening.off"); -// fresult << polyhedron << std::endl; -// fresult.close(); - CGAL::Nef_polyhedron_3 nef_opening; try { nef_opening = CGAL::Nef_polyhedron_3(opening); @@ -310,11 +263,6 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* entity, ferror.close(); return false; } - -// brep_cut_result.convert_to_polyhedron(polyhedron); -// fresult.open("/Users/ken/Desktop/after.off"); -// fresult << polyhedron << std::endl; -// fresult.close(); } if (brep_cut_result.is_valid()) { From b732759388dc8c2d01753ec9e9c73080a57d05dd Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 25 Apr 2017 13:44:34 +0200 Subject: [PATCH 115/235] Comprehensive validation code for opening subtractions --- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 203 +++++++++++++++++++----- 1 file changed, 163 insertions(+), 40 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index a35d21b9ae..5a9ebd4f0f 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -238,60 +238,183 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* entity, for (auto &vertex: vertices(entity_shape)) vertex->point() = vertex->point().transform(entity_shape_gtrsf); } - cgal_shape_t brep_cut_result(entity_shape); - CGAL::Nef_polyhedron_3 nef_brep_cut_result(brep_cut_result); + cgal_shape_t original_entity_shape(entity_shape); + if (!entity_shape.is_valid()) { + Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Invalid entity:", entity->entity); + std::ofstream fentity; + fentity.open("/Users/ken/Desktop/entity.off"); + fentity << original_entity_shape << std::endl; + fentity.close(); + 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 entity:", entity->entity); + std::ofstream fentity; + fentity.open("/Users/ken/Desktop/entity.off"); + fentity << original_entity_shape << std::endl; + fentity.close(); + return false; + } bool success = false; + try { + success = CGAL::Polygon_mesh_processing::triangulate_faces(entity_shape); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Triangulation of entity crashed:", entity->entity); + std::ofstream fentity; + fentity.open("/Users/ken/Desktop/entity.off"); + fentity << original_entity_shape << std::endl; + fentity.close(); + return false; + } if (!success) { + Logger::Message(Logger::LOG_ERROR, "Triangulation of entity failed:", entity->entity); + std::ofstream fentity; + fentity.open("/Users/ken/Desktop/entity.off"); + fentity << original_entity_shape << std::endl; + fentity.close(); + return false; + } if (CGAL::Polygon_mesh_processing::does_self_intersect(entity_shape)) { + Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Self-intersecting entity:", entity->entity); + std::ofstream fentity; + fentity.open("/Users/ken/Desktop/entity.off"); + fentity << original_entity_shape << std::endl; + fentity.close(); + return false; + } CGAL::Nef_polyhedron_3 nef_brep_cut_result; + try { + nef_brep_cut_result = CGAL::Nef_polyhedron_3(entity_shape); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Could not convert entity to Nef:", entity->entity); + std::ofstream fentity; + fentity.open("/Users/ken/Desktop/entity.off"); + fentity << original_entity_shape << std::endl; + fentity.close(); + 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 entity from Nef:", entity->entity); + std::ofstream fentity; + fentity.open("/Users/ken/Desktop/entity.off"); + fentity << original_entity_shape << std::endl; + fentity.close(); +// return false; + } for (auto &opening: opening_shapelist) { - CGAL::Nef_polyhedron_3 nef_opening; + cgal_shape_t original_opening_shape(opening); + if (!opening.is_valid()) { + Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Invalid opening in entity:", entity->entity); + std::ofstream fentity; + fentity.open("/Users/ken/Desktop/entity.off"); + fentity << original_entity_shape << std::endl; + fentity.close(); + std::ofstream fopening; + fopening.open("/Users/ken/Desktop/opening.off"); + fopening << original_opening_shape << std::endl; + fopening.close(); + return false; + } if (!opening.is_closed()) { + Logger::Message(Logger::LOG_ERROR, "Subtraction of opening makes no sense. Not closed opening in entity:", entity->entity); + std::ofstream fentity; + fentity.open("/Users/ken/Desktop/entity.off"); + fentity << original_entity_shape << std::endl; + fentity.close(); + std::ofstream fopening; + fopening.open("/Users/ken/Desktop/opening.off"); + fopening << original_opening_shape << std::endl; + fopening.close(); + return false; + } success = false; + try { + success = CGAL::Polygon_mesh_processing::triangulate_faces(opening); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Triangulation of opening of entity crashed:", entity->entity); + std::ofstream fentity; + fentity.open("/Users/ken/Desktop/entity.off"); + fentity << original_entity_shape << std::endl; + fentity.close(); + std::ofstream fopening; + fopening.open("/Users/ken/Desktop/opening.off"); + fopening << original_opening_shape << std::endl; + fopening.close(); + return false; + } if (!success) { + Logger::Message(Logger::LOG_ERROR, "Triangulation of opening of entity failed:", entity->entity); + std::ofstream fentity; + fentity.open("/Users/ken/Desktop/entity.off"); + fentity << original_entity_shape << std::endl; + fentity.close(); + std::ofstream fopening; + fopening.open("/Users/ken/Desktop/opening.off"); + fopening << original_opening_shape << std::endl; + fopening.close(); + 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 entity:", entity->entity); + std::ofstream fentity; + fentity.open("/Users/ken/Desktop/entity.off"); + fentity << original_entity_shape << std::endl; + fentity.close(); + std::ofstream fopening; + fopening.open("/Users/ken/Desktop/opening.off"); + fopening << original_opening_shape << std::endl; + fopening.close(); + return false; + } CGAL::Nef_polyhedron_3 nef_opening; try { nef_opening = CGAL::Nef_polyhedron_3(opening); } catch (...) { - Logger::Message(Logger::LOG_WARNING, "Subtracting combined openings compound failed (Nef conversion):", entity->entity); - std::ofstream ferror; - ferror.open("/Users/ken/Desktop/error.off"); - ferror << entity_shape << std::endl; - ferror.close(); + Logger::Message(Logger::LOG_ERROR, "Could not convert opening of entity to Nef:", entity->entity); + std::ofstream fentity; + fentity.open("/Users/ken/Desktop/entity.off"); + fentity << original_entity_shape << std::endl; + fentity.close(); + std::ofstream fopening; + fopening.open("/Users/ken/Desktop/opening.off"); + fopening << original_opening_shape << std::endl; + fopening.close(); 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 entity from Nef:", entity->entity); + std::ofstream fentity; + fentity.open("/Users/ken/Desktop/entity.off"); + fentity << original_entity_shape << std::endl; + fentity.close(); + std::ofstream fopening; + fopening.open("/Users/ken/Desktop/opening.off"); + fopening << original_opening_shape << std::endl; + fopening.close(); +// return false; } try { nef_brep_cut_result -= nef_opening; } catch (...) { - Logger::Message(Logger::LOG_WARNING, "Subtracting combined openings compound failed (subtraction):", entity->entity); - std::ofstream ferror; - ferror.open("/Users/ken/Desktop/error.off"); - ferror << entity_shape << std::endl; - ferror.close(); + Logger::Message(Logger::LOG_ERROR, "Could not subtract Nef opening of entity:", entity->entity); + std::ofstream fentity; + fentity.open("/Users/ken/Desktop/entity.off"); + fentity << original_entity_shape << std::endl; + fentity.close(); + std::ofstream fopening; + fopening.open("/Users/ken/Desktop/opening.off"); + fopening << original_opening_shape << std::endl; + fopening.close(); return false; } } - if (brep_cut_result.is_valid()) { - try { - nef_brep_cut_result.convert_to_polyhedron(brep_cut_result); - cut_shapes.push_back(IfcGeom::ConversionResult(new CgalShape(brep_cut_result), &it3->Style())); - } catch (...) { - // Apparently processing the boolean operation failed or resulted in an invalid result - // in which case the original shape without the subtractions is returned instead - // we try convert the openings in the original way, one by one. - Logger::Message(Logger::LOG_WARNING, "Subtracting combined openings compound failed (conversion):", entity->entity); - std::ofstream ferror; - ferror.open("/Users/ken/Desktop/error.off"); - ferror << entity_shape << std::endl; - ferror.close(); - return false; - } - } else { - // Apparently processing the boolean operation failed or resulted in an invalid result - // in which case the original shape without the subtractions is returned instead - // we try convert the openings in the original way, one by one. - Logger::Message(Logger::LOG_WARNING, "Subtracting combined openings compound failed (invalid):", entity->entity); - std::ofstream ferror; - ferror.open("/Users/ken/Desktop/error.off"); - ferror << entity_shape << std::endl; - ferror.close(); + try { + nef_brep_cut_result.convert_to_polyhedron(entity_shape); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Could not convert entity with openings from Nef:", entity->entity); + std::ofstream fentity; + fentity.open("/Users/ken/Desktop/entity.off"); + fentity << original_entity_shape << std::endl; + fentity.close(); return false; - } + } cut_shapes.push_back(IfcGeom::ConversionResult(new CgalShape(entity_shape), &it3->Style())); - } - return true; + } return true; } From 8b539d2b93f5f9713ef2d0b3fbe28b262db3833a Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 25 Apr 2017 13:44:57 +0200 Subject: [PATCH 116/235] Requirement for self-intersection tests --- src/ifcgeom/kernels/cgal/CgalKernel.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index ed3ba02b69..c9c2c46495 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -47,6 +47,7 @@ if ( it != cache.T.end() ) { e = it->second; return true; } #include #include #include +#include #include typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; From 42f23a786f9d988e9c9826582419be4f7a0d6e30 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Tue, 25 Apr 2017 13:45:18 +0200 Subject: [PATCH 117/235] Output all errors as separate files --- .../kernels/cgal/CgalConversionResult.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index 98a4272fee..f2ecb1a66b 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -10,10 +10,19 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, vertex->point() = vertex->point().transform(trsf); } + std::string error_file_path; + for (unsigned int error_number = 1; error_number < 1000; ++error_number) { + error_file_path = std::string("/Users/ken/Desktop/error/error"); + error_file_path += std::to_string(error_number); + error_file_path += ".off"; + std::ifstream file_path_test(error_file_path); + if (!file_path_test.good()) break; + } + if (!s.is_valid()) { Logger::Message(Logger::LOG_ERROR, "Invalid Polyhedron_3 in object (before triangulation)"); std::ofstream ferror; - ferror.open("/Users/ken/Desktop/error.off"); + ferror.open(error_file_path); ferror << s << std::endl; ferror.close(); return; @@ -36,14 +45,14 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, } catch (...) { Logger::Message(Logger::LOG_ERROR, "Triangulation crashed"); std::ofstream ferror; - ferror.open("/Users/ken/Desktop/error.off"); + ferror.open(error_file_path); ferror << s << std::endl; ferror.close(); return; } if (!success) { Logger::Message(Logger::LOG_ERROR, "Triangulation failed"); std::ofstream ferror; - ferror.open("/Users/ken/Desktop/error.off"); + ferror.open(error_file_path); ferror << s << std::endl; ferror.close(); return; @@ -58,7 +67,7 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, if (!s.is_valid()) { Logger::Message(Logger::LOG_ERROR, "Invalid Polyhedron_3 in object (after triangulation)"); std::ofstream ferror; - ferror.open("/Users/ken/Desktop/error.off"); + ferror.open(error_file_path); ferror << s_copy << std::endl; ferror.close(); return; From 9ae55ab303ec366a255be214434282cfe5b5140a Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Tue, 6 Jun 2017 17:12:46 +0200 Subject: [PATCH 118/235] Small fixes to transformations --- src/ifcgeom/kernels/cgal/CgalConversionResult.h | 10 +++------- src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp | 3 +-- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.h b/src/ifcgeom/kernels/cgal/CgalConversionResult.h index b02e6e5c95..5ed715a50f 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.h +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.h @@ -34,17 +34,13 @@ namespace IfcGeom { operator const cgal_placement_t& () { return trsf_; } virtual double Value(int i, int j) const { - // TODO: Check -// std::cout << "Getting CgalPlacement with i = " << i << " and j = " << j << std::endl; - return CGAL::to_double(trsf_.cartesian(i-1, j-1)); + return CGAL::to_double(trsf_.cartesian(i-1, j-1)); } virtual void Multiply(const ConversionResultPlacement* other) { - // TODO: Check - trsf_ = ((CgalPlacement *)other)->trsf_ * trsf_; + trsf_ = trsf_ * ((CgalPlacement *)other)->trsf_; } virtual void PreMultiply(const ConversionResultPlacement* other) { - // TODO: Check - trsf_ = trsf_ * ((CgalPlacement *)other)->trsf_; + trsf_ = ((CgalPlacement *)other)->trsf_ * trsf_; } virtual ConversionResultPlacement* clone() const { return new CgalPlacement(trsf_); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp index 34f5b6c10c..f91617f8f3 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp @@ -236,10 +236,9 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOpe return true; } -bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOperator2DnonUniform* l, cgal_placement_t& gtrsf) { +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOperator2DnonUniform* l, cgal_placement_t& trsf) { // IN_CACHE(IfcCartesianTransformationOperator2DnonUniform,l,cgal_placement_t,gtrsf) - cgal_placement_t trsf; cgal_point_t origin; cgal_direction_t axis1 (1.,0.,0.); cgal_direction_t axis2 (0.,1.,0.); From 6737b5445791bfdcc6f512e7e76a34462c433f57 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Mon, 9 Jan 2017 17:09:19 +0100 Subject: [PATCH 119/235] Add GMP MPFR CGAL to build script --- nix/build-all.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/nix/build-all.py b/nix/build-all.py index 1061994f75..956f8e7827 100644 --- a/nix/build-all.py +++ b/nix/build-all.py @@ -73,6 +73,8 @@ LIBXML_VERSION="2.9.3" CMAKE_VERSION="3.4.1" ICU_VERSION="56.1" SWIG_VERSION="3.0.12" +GMP_VERSION="6.1.2" +MPFR_VERSION="3.1.5" # binaries cp="cp" @@ -212,7 +214,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,)) @@ -644,6 +646,11 @@ if "icu" in targets: download_name="icu4c-{ICU_VERSION_UNDERSCORE}-src.tgz".format(**locals()) ) +if "cgal" in targets: + build_dependency(name="gmp-%s" % (GMP_VERSION,), mode="autoconf", build_tool_args=[], 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=["--with-gmp=%s/install/gmp-%s" % (DEPS_DIR, GMP_VERSION)], download_url="http://www.mpfr.org/mpfr-current/", download_name="mpfr-%s.tar.bz2" % (MPFR_VERSION,)) + build_dependency(name="cgal-master", 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)], download_url="https://github.com/CGAL/cgal.git", download_name="cgal", download_tool=download_tool_git) + cecho("Building IfcOpenShell:", GREEN) IFCOS_DIR=os.path.join(DEPS_DIR, "build", "ifcopenshell") From cf2dd2aa8deb14006e81924c8e7103868d33398f Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 16 Jan 2019 14:04:05 +0100 Subject: [PATCH 120/235] Add GMP MPFR CGAL to build script --- nix/build-all.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/nix/build-all.py b/nix/build-all.py index 956f8e7827..906eedbed8 100644 --- a/nix/build-all.py +++ b/nix/build-all.py @@ -282,10 +282,14 @@ OPENCOLLADA_COMMIT="v1.6.63" 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.mkdir(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: @@ -647,9 +651,15 @@ if "icu" in targets: ) if "cgal" in targets: - build_dependency(name="gmp-%s" % (GMP_VERSION,), mode="autoconf", build_tool_args=[], 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=["--with-gmp=%s/install/gmp-%s" % (DEPS_DIR, GMP_VERSION)], download_url="http://www.mpfr.org/mpfr-current/", download_name="mpfr-%s.tar.bz2" % (MPFR_VERSION,)) - build_dependency(name="cgal-master", 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)], download_url="https://github.com/CGAL/cgal.git", download_name="cgal", download_tool=download_tool_git) + 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-current/", 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", 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/" % (DEPS_DIR,)], download_url="https://github.com/CGAL/cgal.git", download_name="cgal", download_tool=download_tool_git) + BUILD_CFG = OLD_BUILD_CFG cecho("Building IfcOpenShell:", GREEN) From a0dfdc78ef30a95f7cc3d53f1ffbe90c11f14ce5 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 16 Jan 2019 14:06:17 +0100 Subject: [PATCH 121/235] Add cgal to IfcGeom deps --- nix/build-all.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/build-all.py b/nix/build-all.py index 906eedbed8..c06cb21abd 100644 --- a/nix/build-all.py +++ b/nix/build-all.py @@ -184,7 +184,7 @@ cecho(""" - How many compiler processes may be run in parallel. dependency_tree = { 'IfcParse': ('icu', 'boost', 'libxml2'), - 'IfcGeom': ('IfcParse', 'occ'), + 'IfcGeom': ('IfcParse', 'occ', 'cgal'), 'IfcConvert': ('IfcGeom', 'OpenCOLLADA'), 'OpenCOLLADA': ('libxml2', 'pcre'), 'IfcGeomServer': ('IfcGeom',), From 208f6d4d7481f6025d77d17518ff4d2e140c3480 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 16 Jan 2019 14:18:36 +0100 Subject: [PATCH 122/235] Small fixes to build script --- nix/build-all.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nix/build-all.py b/nix/build-all.py index c06cb21abd..0118d2df6b 100644 --- a/nix/build-all.py +++ b/nix/build-all.py @@ -196,6 +196,7 @@ dependency_tree = { 'python': (), 'swig': (), 'occ': (), + 'cgal': (), 'pcre': () } @@ -285,7 +286,7 @@ def run_autoconf(arg1, configure_args, cwd): 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.mkdir(install_dir) + 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 From 116b80cf91504877a4a6ffe3bc88e10bfe1dba96 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 16 Jan 2019 14:41:34 +0100 Subject: [PATCH 123/235] Fix MPFR download location --- nix/build-all.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/build-all.py b/nix/build-all.py index 0118d2df6b..b7c10d50a6 100644 --- a/nix/build-all.py +++ b/nix/build-all.py @@ -653,7 +653,7 @@ if "icu" in targets: 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-current/", download_name="mpfr-%s.tar.bz2" % (MPFR_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": From 0072e1f24757da9da9a3284c4cc7df4ba1b929be Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 16 Jan 2019 14:44:43 +0100 Subject: [PATCH 124/235] CMake CGAL version of IfcGeom --- cmake/CMakeLists.txt | 50 +++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index b4513c41e4..a1464e56e7 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -536,7 +536,7 @@ if(NOT Boost_VERSION LESS 105800) add_definitions(-DBOOST_OPTIONAL_USE_OLD_DEFINITION_OF_NONE) endif() -set(IFCOPENSHELL_LIBRARIES IfcParse IfcGeom_ifc2x3 IfcGeom_ifc4 IfcGeom IfcGeom_ifc2x3 IfcGeom_ifc4 IfcGeom Serializers_ifc2x3 Serializers_ifc4 Serializers Serializers_ifc2x3 Serializers_ifc4 Serializers) +set(IFCOPENSHELL_LIBRARIES IfcParse IfcGeom IfcGeom IfcGeom_CGAL Serializers Serializers) # IfcParse file(GLOB IFCPARSE_H_FILES ../src/ifcparse/*.h) @@ -554,29 +554,51 @@ ENDIF() if (BUILD_IFCGEOM) -# IfcGeom +### OCCT + +# IfcGeom, schema dependent, OCCT file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/*.h) file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/*.cpp) set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES}) -add_library(IfcGeom_ifc2x3 ${IFCGEOM_FILES}) -add_library(IfcGeom_ifc4 ${IFCGEOM_FILES}) - -set_target_properties(IfcGeom_ifc2x3 PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc2x3") -# TODO: Detect based on IfcSchema -set_target_properties(IfcGeom_ifc4 PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc4 -DUSE_IFC4") - -TARGET_LINK_LIBRARIES(IfcGeom_ifc2x3 IfcParse ${OPENCASCADE_LIBRARIES}) -TARGET_LINK_LIBRARIES(IfcGeom_ifc4 IfcParse ${OPENCASCADE_LIBRARIES}) - -# IfcGeom (schema agnostic) +# IfcGeom, schema agnostic, OCCT 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}) +foreach(schema 2x3 4) +add_library(IfcGeom_ifc${schema} ${IFCGEOM_FILES}) +set_target_properties(IfcGeom_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema} -DUSE_IFC${schema}") +TARGET_LINK_LIBRARIES(IfcGeom_ifc${schema} IfcParse ${OPENCASCADE_LIBRARIES}) +list(APPEND IfcGeom_libraries IfcGeom_ifc${schema}) +endforeach() + add_library(IfcGeom ${SCHEMA_AGNOSTIC_FILES}) set_target_properties(IfcGeom PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS) -TARGET_LINK_LIBRARIES(IfcGeom IfcGeom_ifc2x3 IfcGeom_ifc4) +TARGET_LINK_LIBRARIES(IfcGeom ${IfcGeom_libraries}) + +### CGAL + +# IfcGeom, schema dependent, OCCT +file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/kernels/cgal/*.h) +file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/kernels/cgal/*.cpp) +set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES}) + +# IfcGeom, schema agnostic, OCCT +file(GLOB SCHEMA_AGNOSTIC_H_FILES ../src/ifcgeom_schema_agnostic_cgal/*.h) +file(GLOB SCHEMA_AGNOSTIC_CPP_FILES ../src/ifcgeom_schema_agnostic_cgal/*.cpp) +set(SCHEMA_AGNOSTIC_FILES ${SCHEMA_AGNOSTIC_H_FILES} ${SCHEMA_AGNOSTIC_CPP_FILES}) + +foreach(schema 2x3 4) +add_library(IfcGeom_ifc${schema} ${IFCGEOM_FILES}) +set_target_properties(IfcGeom_CGAL_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema} -DUSE_IFC${schema}") +TARGET_LINK_LIBRARIES(IfcGeom_CGAL_ifc${schema} IfcParse ${OPENCASCADE_LIBRARIES}) +list(APPEND IfcGeom_CGAL_libraries IfcGeom_CGAL_ifc${schema}) +endforeach() + +add_library(IfcGeom_CGAL ${SCHEMA_AGNOSTIC_FILES}) +set_target_properties(IfcGeom_CGAL PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS) +TARGET_LINK_LIBRARIES(IfcGeom_CGAL ${IfcGeom_CGAL_libraries}) endif(BUILD_IFCGEOM) From ad24b6be0fec00c5a32f24eae271f097049ce2a3 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 18 Jan 2019 11:23:19 +0100 Subject: [PATCH 125/235] Isolate (most of the) geometry processing code into separate opencascade kernel --- cmake/CMakeLists.txt | 31 +-- src/ifcconvert/IfcConvert.cpp | 8 +- src/ifcgeom/IfcGeom.h | 36 +-- src/ifcgeom/IfcGeomFunctions.cpp | 190 +++++++------- src/ifcgeom/IfcGeomIteratorImplementation.h | 18 +- src/ifcgeom/IfcGeomShapes.cpp | 27 +- src/ifcgeom/IfcGeomTree.h | 4 +- src/ifcgeom/IfcRegister.cpp | 6 +- src/ifcgeom/IfcRegisterGeomHeader.h | 2 +- src/ifcgeom/IfcRepresentationShapeItem.h | 55 ---- src/ifcgeom/OpenCascadeConversionResult.h | 104 ++++++++ src/ifcgeom/OpenCascadeShape.cpp | 202 +++++++++++++++ src/ifcgeom/kernels/cgal/todo.cpp | 0 src/ifcgeom/kernels/cgal/todo.h | 0 .../ConversionResult.h | 93 +++++++ .../IfcGeomElement.h | 41 ++- src/ifcgeom_schema_agnostic/IfcGeomIterator.h | 2 +- .../IfcGeomIteratorSettings.h | 1 + .../IfcGeomRenderStyles.h | 2 +- .../IfcGeomRepresentation.cpp | 42 +-- .../IfcGeomRepresentation.h | 240 +++--------------- .../IteratorImplementation.h | 6 +- src/ifcgeom_schema_agnostic/Kernel.h | 10 +- src/ifcgeom_schema_agnostic/Serialization.h | 2 +- .../ifc_geom_api.h | 0 src/ifcgeom_schema_agnostic_cgal/todo.cpp | 0 src/ifcgeom_schema_agnostic_cgal/todo.h | 0 src/ifcgeomserver/IfcGeomServer.cpp | 10 +- src/ifcwrap/IfcGeomWrapper.i | 4 +- src/serializers/ColladaSerializer.h | 2 +- src/serializers/GeometrySerializer.h | 4 +- src/serializers/IgesSerializer.h | 4 +- .../OpenCascadeBasedSerializer.cpp | 5 +- src/serializers/OpenCascadeBasedSerializer.h | 6 +- src/serializers/StepSerializer.h | 4 +- src/serializers/SvgSerializer.cpp | 4 +- src/serializers/SvgSerializer.h | 2 +- src/serializers/WavefrontObjSerializer.h | 2 +- 38 files changed, 678 insertions(+), 491 deletions(-) delete mode 100644 src/ifcgeom/IfcRepresentationShapeItem.h create mode 100644 src/ifcgeom/OpenCascadeConversionResult.h create mode 100644 src/ifcgeom/OpenCascadeShape.cpp create mode 100644 src/ifcgeom/kernels/cgal/todo.cpp create mode 100644 src/ifcgeom/kernels/cgal/todo.h create mode 100644 src/ifcgeom_schema_agnostic/ConversionResult.h rename src/{ifcgeom => ifcgeom_schema_agnostic}/IfcGeomElement.h (85%) rename src/{ifcgeom => ifcgeom_schema_agnostic}/IfcGeomIteratorSettings.h (99%) rename src/{ifcgeom => ifcgeom_schema_agnostic}/IfcGeomRepresentation.cpp (84%) rename src/{ifcgeom => ifcgeom_schema_agnostic}/IfcGeomRepresentation.h (50%) rename src/{ifcgeom => ifcgeom_schema_agnostic}/ifc_geom_api.h (100%) create mode 100644 src/ifcgeom_schema_agnostic_cgal/todo.cpp create mode 100644 src/ifcgeom_schema_agnostic_cgal/todo.h diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index a1464e56e7..10c7b93912 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -536,7 +536,7 @@ if(NOT Boost_VERSION LESS 105800) add_definitions(-DBOOST_OPTIONAL_USE_OLD_DEFINITION_OF_NONE) endif() -set(IFCOPENSHELL_LIBRARIES IfcParse IfcGeom IfcGeom IfcGeom_CGAL Serializers Serializers) +set(IFCOPENSHELL_LIBRARIES IfcParse IfcGeom Serializers) # IfcParse file(GLOB IFCPARSE_H_FILES ../src/ifcparse/*.h) @@ -561,11 +561,6 @@ file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/*.h) file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/*.cpp) set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES}) -# IfcGeom, schema agnostic, OCCT -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}) - foreach(schema 2x3 4) add_library(IfcGeom_ifc${schema} ${IFCGEOM_FILES}) set_target_properties(IfcGeom_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema} -DUSE_IFC${schema}") @@ -573,32 +568,28 @@ TARGET_LINK_LIBRARIES(IfcGeom_ifc${schema} IfcParse ${OPENCASCADE_LIBRARIES}) list(APPEND IfcGeom_libraries IfcGeom_ifc${schema}) endforeach() -add_library(IfcGeom ${SCHEMA_AGNOSTIC_FILES}) -set_target_properties(IfcGeom PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS) -TARGET_LINK_LIBRARIES(IfcGeom ${IfcGeom_libraries}) - ### CGAL -# IfcGeom, schema dependent, OCCT +# IfcGeom, schema dependent, CGAL file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/kernels/cgal/*.h) file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/kernels/cgal/*.cpp) set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES}) -# IfcGeom, schema agnostic, OCCT -file(GLOB SCHEMA_AGNOSTIC_H_FILES ../src/ifcgeom_schema_agnostic_cgal/*.h) -file(GLOB SCHEMA_AGNOSTIC_CPP_FILES ../src/ifcgeom_schema_agnostic_cgal/*.cpp) -set(SCHEMA_AGNOSTIC_FILES ${SCHEMA_AGNOSTIC_H_FILES} ${SCHEMA_AGNOSTIC_CPP_FILES}) - foreach(schema 2x3 4) -add_library(IfcGeom_ifc${schema} ${IFCGEOM_FILES}) +add_library(IfcGeom_CGAL_ifc${schema} ${IFCGEOM_FILES}) set_target_properties(IfcGeom_CGAL_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema} -DUSE_IFC${schema}") TARGET_LINK_LIBRARIES(IfcGeom_CGAL_ifc${schema} IfcParse ${OPENCASCADE_LIBRARIES}) list(APPEND IfcGeom_CGAL_libraries IfcGeom_CGAL_ifc${schema}) endforeach() -add_library(IfcGeom_CGAL ${SCHEMA_AGNOSTIC_FILES}) -set_target_properties(IfcGeom_CGAL PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS) -TARGET_LINK_LIBRARIES(IfcGeom_CGAL ${IfcGeom_CGAL_libraries}) +# IfcGeom, schema and kernel agnostic +file(GLOB SCHEMA_AGNOSTIC_H_FILES ../src/ifcgeom_schema_agnostic/*.h) +file(GLOB SCHEMA_AGNOSTIC_CPP_FILES ../src/ifcgeom_schema_agnostic/*.cpp) +set(SCHEMA_AGNOSTIC_FILES ${SCHEMA_AGNOSTIC_H_FILES} ${SCHEMA_AGNOSTIC_CPP_FILES}) + +add_library(IfcGeom ${SCHEMA_AGNOSTIC_FILES}) +set_target_properties(IfcGeom PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS) +TARGET_LINK_LIBRARIES(IfcGeom ${IfcGeom_libraries}) endif(BUILD_IFCGEOM) diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 910d17ad18..2e7ac79e7a 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -711,7 +711,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 @@ -729,7 +729,7 @@ int main(int argc, char** argv) } else { - serializer->write(static_cast*>(geom_object)); + serializer->write(static_cast*>(geom_object)); } if (!no_progress) { @@ -1152,7 +1152,7 @@ void fix_quantities(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool std if (num_created) { has_more = context_iterator.next(); } - IfcGeom::BRepElement* geom_object = nullptr; + IfcGeom::NativeElement* geom_object = nullptr; if (has_more) { geom_object = context_iterator.get_native(); } @@ -1205,7 +1205,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(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); } diff --git a/src/ifcgeom/IfcGeom.h b/src/ifcgeom/IfcGeom.h index c6e3c7692d..f4466798bd 100644 --- a/src/ifcgeom/IfcGeom.h +++ b/src/ifcgeom/IfcGeom.h @@ -52,14 +52,15 @@ inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance=ALMO #include "../ifcparse/IfcParse.h" #include "../ifcparse/IfcBaseClass.h" -#include "../ifcgeom/IfcGeomElement.h" -#include "../ifcgeom/IfcGeomRepresentation.h" -#include "../ifcgeom/IfcRepresentationShapeItem.h" +#include "../ifcgeom_schema_agnostic/IfcGeomElement.h" +#include "../ifcgeom_schema_agnostic/IfcGeomRepresentation.h" +#include "../ifcgeom_schema_agnostic/ConversionResult.h" #include "../ifcgeom/IfcGeomShapeType.h" #include "../ifcgeom_schema_agnostic/Kernel.h" +#include "OpenCascadeConversionResult.h" -#include "ifc_geom_api.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 @@ -258,21 +259,21 @@ 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 gp_Trsf& entity_trsf, ConversionResults& cut_shapes); + bool convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, ConversionResults& cut_shapes); void assert_closed_wire(TopoDS_Wire& wire); bool convert_layerset(const IfcSchema::IfcProduct*, std::vector&, std::vector&, std::vector&); - bool apply_layerset(const IfcRepresentationShapeItems&, const std::vector&, const std::vector&, IfcRepresentationShapeItems&); - bool apply_folded_layerset(const IfcRepresentationShapeItems&, const std::vector< std::vector >&, const std::vector&, IfcRepresentationShapeItems&); - bool fold_layers(const IfcSchema::IfcWall*, const IfcRepresentationShapeItems&, const std::vector&, const std::vector&, std::vector< std::vector >&); + bool apply_layerset(const ConversionResults&, const std::vector&, const std::vector&, ConversionResults&); + bool apply_folded_layerset(const ConversionResults&, const std::vector< std::vector >&, const std::vector&, ConversionResults&); + bool fold_layers(const IfcSchema::IfcWall*, const ConversionResults&, const std::vector&, const std::vector&, std::vector< std::vector >&); 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&); @@ -326,6 +327,7 @@ 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&); @@ -338,12 +340,12 @@ public: std::pair initializeUnits(IfcSchema::IfcUnitAssignment*); template - IfcGeom::BRepElement* create_brep_for_representation_and_product( + IfcGeom::NativeElement* create_brep_for_representation_and_product( const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*); template - IfcGeom::BRepElement* create_brep_for_processed_representation( - const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::BRepElement*); + IfcGeom::NativeElement* create_brep_for_processed_representation( + const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::NativeElement*); const IfcSchema::IfcMaterial* get_single_material_association(const IfcSchema::IfcProduct*); IfcSchema::IfcRepresentation* representation_mapped_to(const IfcSchema::IfcRepresentation* representation); @@ -416,15 +418,15 @@ public: virtual void setValue(GeomValue var, double value); virtual double getValue(GeomValue var) const; - virtual IfcGeom::BRepElement* convert( + virtual IfcGeom::NativeElement* convert( const IteratorSettings& settings, IfcUtil::IfcBaseClass* representation, IfcUtil::IfcBaseClass* product) { return create_brep_for_representation_and_product(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"); diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/IfcGeomFunctions.cpp index fff22622f9..2dd9f4129b 100644 --- a/src/ifcgeom/IfcGeomFunctions.cpp +++ b/src/ifcgeom/IfcGeomFunctions.cpp @@ -507,13 +507,13 @@ const TopoDS_Shape& IfcGeom::Kernel::ensure_fit_for_subtraction(const TopoDS_Sha } bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, - const IfcGeom::IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::IfcRepresentationShapeItems& cut_shapes) { + const IfcGeom::ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::ConversionResults& cut_shapes) { // TODO: Refactor convert_openings() convert_openings_fast() and convert(IfcBooleanResult) to use // the same code base and conform to the same checks and logging messages. // Iterate over IfcOpeningElements - IfcGeom::IfcRepresentationShapeItems opening_shapes; + IfcGeom::ConversionResults opening_shapes; unsigned int last_size = 0; for ( IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++ it ) { IfcSchema::IfcRelVoidsElement* v = *it; @@ -545,30 +545,26 @@ bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, cons const unsigned int current_size = (const unsigned int) opening_shapes.size(); for ( unsigned int i = last_size; i < current_size; ++ i ) { - opening_shapes[i].prepend(opening_trsf); + OpenCascadePlacement p((gp_GTrsf)opening_trsf); + opening_shapes[i].prepend(&p); } last_size = current_size; } } // Iterate over the shapes of the IfcProduct - for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) { + for ( IfcGeom::ConversionResults::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) { TopoDS_Shape entity_shape_solid; - const TopoDS_Shape& entity_shape_unlocated = ensure_fit_for_subtraction(it3->Shape(),entity_shape_solid); - const gp_GTrsf& entity_shape_gtrsf = it3->Placement(); - if ( entity_shape_gtrsf.Form() == gp_Other ) { - Logger::Message(Logger::LOG_WARNING, "Applying non uniform transformation to:", entity); - } + const TopoDS_Shape& entity_shape_unlocated = ensure_fit_for_subtraction(*(OpenCascadeShape*) it3->Shape(), entity_shape_solid); + const OpenCascadePlacement* entity_shape_gtrsf = (OpenCascadePlacement*) it3->Placement(); + TopoDS_Shape entity_shape = apply_transformation(entity_shape_unlocated, entity_shape_gtrsf); // Iterate over the shapes of the IfcOpeningElements - for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it4 = opening_shapes.begin(); it4 != opening_shapes.end(); ++ it4 ) { + for ( IfcGeom::ConversionResults::const_iterator it4 = opening_shapes.begin(); it4 != opening_shapes.end(); ++ it4 ) { TopoDS_Shape opening_shape_solid; - const TopoDS_Shape& opening_shape_unlocated = ensure_fit_for_subtraction(it4->Shape(),opening_shape_solid); - const gp_GTrsf& opening_shape_gtrsf = it4->Placement(); - if ( opening_shape_gtrsf.Form() == gp_Other ) { - Logger::Message(Logger::LOG_WARNING,"Applying non uniform transformation to opening of:",entity); - } + const TopoDS_Shape& opening_shape_unlocated = ensure_fit_for_subtraction(*(OpenCascadeShape*) it4->Shape(),opening_shape_solid); + const OpenCascadePlacement* opening_shape_gtrsf = (OpenCascadePlacement*)it4->Placement(); TopoDS_Shape opening_shape = apply_transformation(opening_shape_unlocated, opening_shape_gtrsf); double opening_volume; @@ -673,7 +669,7 @@ bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, cons } } - cut_shapes.push_back(IfcGeom::IfcRepresentationShapeItem(it3->ItemId(), it3->Placement(), entity_shape, &it3->Style())); + cut_shapes.push_back(IfcGeom::ConversionResult(it3->ItemId(), it3->Placement()->clone(), new OpenCascadeShape(entity_shape), &it3->Style())); } return true; @@ -681,7 +677,7 @@ bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, cons #if OCC_VERSION_HEX < 0x60900 bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, - const IfcGeom::IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::IfcRepresentationShapeItems& cut_shapes) { + const IfcGeom::ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::ConversionResults& cut_shapes) { // Create a compound of all opening shapes in order to speed up the boolean operations TopoDS_Compound opening_compound; @@ -712,7 +708,7 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, IfcSchema::IfcProductRepresentation* prodrep = fes->Representation(); IfcSchema::IfcRepresentation::list::ptr reps = prodrep->Representations(); - IfcGeom::IfcRepresentationShapeItems opening_shapes; + IfcGeom::ConversionResults opening_shapes; for ( IfcSchema::IfcRepresentation::list::it it2 = reps->begin(); it2 != reps->end(); ++ it2 ) { convert_shapes(*it2,opening_shapes); @@ -729,7 +725,7 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, } // Iterate over the shapes of the IfcProduct - for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) { + for ( IfcGeom::ConversionResults::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) { TopoDS_Shape entity_shape_solid; const TopoDS_Shape& entity_shape_unlocated = ensure_fit_for_subtraction(it3->Shape(),entity_shape_solid); const gp_GTrsf& entity_shape_gtrsf = it3->Placement(); @@ -747,7 +743,7 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, BRepCheck_Analyzer analyser(brep_cut_result); is_valid = analyser.IsValid() != 0; if ( is_valid ) { - cut_shapes.push_back(IfcGeom::IfcRepresentationShapeItem(it3->ItemId(), brep_cut_result, &it3->Style())); + cut_shapes.push_back(IfcGeom::ConversionResult(it3->ItemId(), brep_cut_result, &it3->Style())); } } if ( !is_valid ) { @@ -772,7 +768,7 @@ namespace { } bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, - const IfcGeom::IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::IfcRepresentationShapeItems& cut_shapes) { + const IfcGeom::ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::ConversionResults& cut_shapes) { std::vector< std::pair > opening_vector; @@ -800,7 +796,7 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, IfcSchema::IfcProductRepresentation* prodrep = fes->Representation(); IfcSchema::IfcRepresentation::list::ptr reps = prodrep->Representations(); - IfcGeom::IfcRepresentationShapeItems opening_shapes; + IfcGeom::ConversionResults opening_shapes; for (IfcSchema::IfcRepresentation::list::it it2 = reps->begin(); it2 != reps->end(); ++it2) { convert_shapes(*it2, opening_shapes); @@ -808,9 +804,12 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, for (unsigned int i = 0; i < opening_shapes.size(); ++i) { TopoDS_Shape opening_shape_solid; - const TopoDS_Shape& opening_shape_unlocated = ensure_fit_for_subtraction(opening_shapes[i].Shape(), opening_shape_solid); + const TopoDS_Shape& opening_shape_unlocated = ensure_fit_for_subtraction(*(OpenCascadeShape*)opening_shapes[i].Shape(), opening_shape_solid); - gp_GTrsf gtrsf = opening_shapes[i].Placement(); + gp_GTrsf gtrsf; + if (opening_shapes[i].Placement()) { + gtrsf = ((OpenCascadePlacement*)opening_shapes[i].Placement())->trsf(); + } gtrsf.PreMultiply(opening_trsf); TopoDS_Shape opening_shape = apply_transformation(opening_shape_unlocated, gtrsf); opening_vector.push_back(std::make_pair(min_edge_length(opening_shape), opening_shape)); @@ -822,13 +821,10 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, std::sort(opening_vector.begin(), opening_vector.end(), opening_sorter()); // Iterate over the shapes of the IfcProduct - for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) { + for ( IfcGeom::ConversionResults::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) { TopoDS_Shape entity_shape_solid; - const TopoDS_Shape& entity_shape_unlocated = ensure_fit_for_subtraction(it3->Shape(),entity_shape_solid); - const gp_GTrsf& entity_shape_gtrsf = it3->Placement(); - if (entity_shape_gtrsf.Form() == gp_Other) { - Logger::Message(Logger::LOG_WARNING, "Applying non uniform transformation to:", entity); - } + const TopoDS_Shape& entity_shape_unlocated = ensure_fit_for_subtraction(*(OpenCascadeShape*) it3->Shape(),entity_shape_solid); + const OpenCascadePlacement* entity_shape_gtrsf = (OpenCascadePlacement*)it3->Placement(); TopoDS_Shape entity_shape = apply_transformation(entity_shape_unlocated, entity_shape_gtrsf); TopoDS_Shape result = entity_shape; @@ -859,7 +855,7 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, } } - cut_shapes.push_back(IfcGeom::IfcRepresentationShapeItem(it3->ItemId(), result, &it3->Style())); + cut_shapes.push_back(IfcGeom::ConversionResult(it3->ItemId(), new OpenCascadeShape(result), &it3->Style())); } return true; } @@ -1263,22 +1259,22 @@ bool IfcGeom::Kernel::fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& sha return true; } -bool IfcGeom::Kernel::flatten_shape_list(const IfcGeom::IfcRepresentationShapeItems& shapes, TopoDS_Shape& result, bool fuse) { +bool IfcGeom::Kernel::flatten_shape_list(const IfcGeom::ConversionResults& shapes, TopoDS_Shape& result, bool fuse) { TopoDS_Compound compound; BRep_Builder builder; builder.MakeCompound(compound); result = TopoDS_Shape(); - for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) { + for ( IfcGeom::ConversionResults::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) { TopoDS_Shape merged; - const TopoDS_Shape& s = it->Shape(); + const TopoDS_Shape& s = *(OpenCascadeShape*)it->Shape(); if (fuse) { ensure_fit_for_subtraction(s, merged); } else { merged = s; } - const gp_GTrsf& trsf = it->Placement(); + const OpenCascadePlacement* trsf = (const OpenCascadePlacement*) it->Placement(); const TopoDS_Shape moved_shape = apply_transformation(merged, trsf); if (shapes.size() == 1) { @@ -1463,7 +1459,7 @@ const IfcSchema::IfcMaterial* IfcGeom::Kernel::get_single_material_association(c } template -IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_representation_and_product( +IfcGeom::NativeElement* IfcGeom::Kernel::create_brep_for_representation_and_product( const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product) { std::stringstream representation_id_builder; @@ -1471,7 +1467,7 @@ IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_representation_and representation_id_builder << representation->data().id(); IfcGeom::Representation::BRep* shape; - IfcGeom::IfcRepresentationShapeItems shapes, shapes2; + IfcGeom::ConversionResults shapes, shapes2; if ( !convert_shapes(representation, shapes) ) { return 0; @@ -1526,7 +1522,7 @@ IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_representation_and const IfcSchema::IfcMaterial* single_material = get_single_material_association(product); if (single_material) { const IfcGeom::SurfaceStyle* s = get_style(single_material); - for (IfcGeom::IfcRepresentationShapeItems::iterator it = shapes.begin(); it != shapes.end(); ++it) { + for (IfcGeom::ConversionResults::iterator it = shapes.begin(); it != shapes.end(); ++it) { if (!it->hasStyle() && s) { it->setStyle(s); material_style_applied = true; @@ -1534,7 +1530,7 @@ IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_representation_and } } else { bool some_items_without_style = false; - for (IfcGeom::IfcRepresentationShapeItems::iterator it = shapes.begin(); it != shapes.end(); ++it) { + for (IfcGeom::ConversionResults::iterator it = shapes.begin(); it != shapes.end(); ++it) { if (!it->hasStyle()) { some_items_without_style = true; break; @@ -1584,7 +1580,7 @@ IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_representation_and representation_id_builder << "-" << (*it)->data().id(); } - IfcGeom::IfcRepresentationShapeItems opened_shapes; + IfcGeom::ConversionResults opened_shapes; bool caught_error = false; try { #if OCC_VERSION_HEX < 0x60900 @@ -1617,16 +1613,18 @@ IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_representation_and } if (settings.get(IteratorSettings::USE_WORLD_COORDS)) { - for ( IfcGeom::IfcRepresentationShapeItems::iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) { - it->prepend(trsf); + for ( IfcGeom::ConversionResults::iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) { + OpenCascadePlacement p(trsf); + it->prepend(&p); } trsf = gp_Trsf(); 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::IfcRepresentationShapeItems::iterator it = shapes.begin(); it != shapes.end(); ++ it ) { - it->prepend(trsf); + for ( IfcGeom::ConversionResults::iterator it = shapes.begin(); it != shapes.end(); ++ it ) { + OpenCascadePlacement p(trsf); + it->prepend(&p); } trsf = gp_Trsf(); representation_id_builder << "-world-coords"; @@ -1642,14 +1640,14 @@ IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_representation_and context_string = representation->ContextOfItems()->ContextType(); } - auto elem = new BRepElement( + auto elem = new NativeElement( product->data().id(), parent_id, name, product_type, guid, context_string, - trsf, + new OpenCascadePlacement(trsf), boost::shared_ptr(shape), product ); @@ -1703,7 +1701,7 @@ IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_representation_and int genus = q2->as()->CountValue(); for (auto& part : elem->geometry()) { if (part.ItemId() == item_id) { - if (surface_genus(part.Shape()) != genus) { + if (surface_genus(*(OpenCascadeShape*)part.Shape()) != genus) { all_succeeded = false; } } @@ -1792,9 +1790,9 @@ IfcSchema::IfcProduct::list::ptr IfcGeom::Kernel::products_represented_by(const } template -IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_processed_representation( +IfcGeom::NativeElement* IfcGeom::Kernel::create_brep_for_processed_representation( const IteratorSettings& /*settings*/, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, - IfcGeom::BRepElement* brep) + IfcGeom::NativeElement* brep) { int parent_id = -1; try { @@ -1827,32 +1825,32 @@ IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_processed_represen const std::string product_type = product->declaration().name(); - return new BRepElement( + return new NativeElement( product->data().id(), parent_id, name, product_type, guid, context_string, - trsf, + new OpenCascadePlacement(trsf), brep->geometry_pointer(), product ); } -template IFC_GEOM_API IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_representation_and_product( +template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::Kernel::create_brep_for_representation_and_product( const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); -template IFC_GEOM_API IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_representation_and_product( +template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::Kernel::create_brep_for_representation_and_product( const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); -template IFC_GEOM_API IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_representation_and_product( +template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::Kernel::create_brep_for_representation_and_product( const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); -template IFC_GEOM_API IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_processed_representation( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::BRepElement* brep); -template IFC_GEOM_API IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_processed_representation( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::BRepElement* brep); -template IFC_GEOM_API IfcGeom::BRepElement* IfcGeom::Kernel::create_brep_for_processed_representation( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::BRepElement* brep); +template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::Kernel::create_brep_for_processed_representation( + const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); +template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::Kernel::create_brep_for_processed_representation( + const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); +template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::Kernel::create_brep_for_processed_representation( + const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); std::pair IfcGeom::Kernel::initializeUnits(IfcSchema::IfcUnitAssignment* unit_assignment) { // Set default units, set length to meters, angles to undefined @@ -1952,7 +1950,7 @@ bool IfcGeom::Kernel::convert_layerset(const IfcSchema::IfcProduct* product, std return false; } - IfcRepresentationShapeItems axis_items; + ConversionResults axis_items; { Kernel temp = *this; temp.setValue(GV_DIMENSIONALITY, -1.); @@ -2144,7 +2142,7 @@ bool IfcGeom::Kernel::find_wall_end_points(const IfcSchema::IfcWall* wall, gp_Pn return false; } - IfcRepresentationShapeItems items; + ConversionResults items; { Kernel temp = *this; temp.setValue(GV_DIMENSIONALITY, -1.); @@ -2152,8 +2150,8 @@ bool IfcGeom::Kernel::find_wall_end_points(const IfcSchema::IfcWall* wall, gp_Pn } TopoDS_Vertex a, b; - for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) { - TopExp_Explorer exp(it->Shape(), TopAbs_VERTEX); + for (ConversionResults::const_iterator it = items.begin(); it != items.end(); ++it) { + TopExp_Explorer exp(*(OpenCascadeShape*)it->Shape(), TopAbs_VERTEX); for (; exp.More(); exp.Next()) { b = TopoDS::Vertex(exp.Current()); if (a.IsNull()) { @@ -2172,7 +2170,7 @@ bool IfcGeom::Kernel::find_wall_end_points(const IfcSchema::IfcWall* wall, gp_Pn return true; } -bool IfcGeom::Kernel::fold_layers(const IfcSchema::IfcWall* wall, const IfcRepresentationShapeItems& items, const std::vector& surfaces, const std::vector& thicknesses, std::vector< std::vector >& result) { +bool IfcGeom::Kernel::fold_layers(const IfcSchema::IfcWall* wall, const ConversionResults& items, const std::vector& surfaces, const std::vector& thicknesses, std::vector< std::vector >& result) { bool folds_made = false; IfcSchema::IfcRelConnectsPathElements::list::ptr connections(new IfcSchema::IfcRelConnectsPathElements::list); @@ -2321,7 +2319,7 @@ bool IfcGeom::Kernel::fold_layers(const IfcSchema::IfcWall* wall, const IfcRepre continue; } - IfcRepresentationShapeItems axis_items; + ConversionResults axis_items; { Kernel temp = *this; temp.setValue(GV_DIMENSIONALITY, -1.); @@ -2605,7 +2603,7 @@ namespace { #endif } -bool IfcGeom::Kernel::apply_folded_layerset(const IfcRepresentationShapeItems& items, const std::vector< std::vector >& surfaces, const std::vector& styles, IfcRepresentationShapeItems& result) { +bool IfcGeom::Kernel::apply_folded_layerset(const ConversionResults& items, const std::vector< std::vector >& surfaces, const std::vector& styles, ConversionResults& result) { Bnd_Box bb; TopoDS_Shape input; flatten_shape_list(items, input, false); @@ -2681,11 +2679,11 @@ bool IfcGeom::Kernel::apply_folded_layerset(const IfcRepresentationShapeItems& i } else if (shells.Extent() == 1) { - for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) { + for (ConversionResults::const_iterator it = items.begin(); it != items.end(); ++it) { TopoDS_Shape a,b; - if (split_solid_by_shell(it->Shape(), shells.First(), a, b)) { - result.push_back(IfcRepresentationShapeItem(it->ItemId(), it->Placement(), b, styles[0] ? styles[0] : &it->Style())); - result.push_back(IfcRepresentationShapeItem(it->ItemId(), it->Placement(), a, styles[1] ? styles[1] : &it->Style())); + if (split_solid_by_shell(*(OpenCascadeShape*)it->Shape(), shells.First(), a, b)) { + result.push_back(ConversionResult(it->ItemId(), it->Placement()->clone(), new OpenCascadeShape(b), styles[0] ? styles[0] : &it->Style())); + result.push_back(ConversionResult(it->ItemId(), it->Placement()->clone(), new OpenCascadeShape(a), styles[1] ? styles[1] : &it->Style())); } else { continue; } @@ -2695,16 +2693,16 @@ bool IfcGeom::Kernel::apply_folded_layerset(const IfcRepresentationShapeItems& i } else { - for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) { + for (ConversionResults::const_iterator it = items.begin(); it != items.end(); ++it) { - const TopoDS_Shape& s = it->Shape(); + const TopoDS_Shape& s = *(OpenCascadeShape*)it->Shape(); TopoDS_Solid sld; ensure_fit_for_subtraction(s, sld); std::vector slices; - if (split(*this, it->Shape(), shells, getValue(GV_PRECISION), slices) && slices.size() == styles.size()) { + if (split(*this, *(OpenCascadeShape*)it->Shape(), shells, getValue(GV_PRECISION), slices) && slices.size() == styles.size()) { for (size_t i = 0; i < slices.size(); ++i) { - result.push_back(IfcRepresentationShapeItem(it->ItemId(), it->Placement(), slices[i], styles[i] ? styles[i] : &it->Style())); + result.push_back(ConversionResult(it->ItemId(), it->Placement()->clone(), new OpenCascadeShape(slices[i]), styles[i] ? styles[i] : &it->Style())); } } else { return false; @@ -2717,18 +2715,18 @@ bool IfcGeom::Kernel::apply_folded_layerset(const IfcRepresentationShapeItems& i } -bool IfcGeom::Kernel::apply_layerset(const IfcRepresentationShapeItems& items, const std::vector& surfaces, const std::vector& styles, IfcRepresentationShapeItems& result) { +bool IfcGeom::Kernel::apply_layerset(const ConversionResults& items, const std::vector& surfaces, const std::vector& styles, ConversionResults& result) { if (surfaces.size() < 3) { return false; } else if (surfaces.size() == 3) { - for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) { + for (ConversionResults::const_iterator it = items.begin(); it != items.end(); ++it) { TopoDS_Shape a,b; - if (split_solid_by_surface(it->Shape(), surfaces[1], a, b)) { - result.push_back(IfcRepresentationShapeItem(it->ItemId(), it->Placement(), b, styles[0] ? styles[0] : &it->Style())); - result.push_back(IfcRepresentationShapeItem(it->ItemId(), it->Placement(), a, styles[1] ? styles[1] : &it->Style())); + if (split_solid_by_surface(*(OpenCascadeShape*)it->Shape(), surfaces[1], a, b)) { + result.push_back(ConversionResult(it->ItemId(), it->Placement()->clone(), new OpenCascadeShape(b), styles[0] ? styles[0] : &it->Style())); + result.push_back(ConversionResult(it->ItemId(), it->Placement()->clone(), new OpenCascadeShape(a), styles[1] ? styles[1] : &it->Style())); } else { continue; } @@ -2742,7 +2740,7 @@ bool IfcGeom::Kernel::apply_layerset(const IfcRepresentationShapeItems& items, c // Determine whether sequence of surfaces is consistent with surface normal, so that // layer operations are applied in the correct order. This seems to be always the case. Bnd_Box bb; - for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) { + for (ConversionResults::const_iterator it = items.begin(); it != items.end(); ++it) { BRepBndLib::Add(it->Shape(), bb); } @@ -2767,9 +2765,9 @@ bool IfcGeom::Kernel::apply_layerset(const IfcRepresentationShapeItems& items, c mass.ChangeCoord() += n1.XYZ(); */ - for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) { + for (ConversionResults::const_iterator it = items.begin(); it != items.end(); ++it) { - const TopoDS_Shape& s = it->Shape(); + const TopoDS_Shape& s = *(OpenCascadeShape*)it->Shape(); TopoDS_Solid sld; ensure_fit_for_subtraction(s, sld); @@ -2786,9 +2784,9 @@ bool IfcGeom::Kernel::apply_layerset(const IfcRepresentationShapeItems& items, c } std::vector slices; - if (split(*this, it->Shape(), operands, getValue(GV_PRECISION), slices) && slices.size() == styles.size()) { + if (split(*this, *(OpenCascadeShape*)it->Shape(), operands, getValue(GV_PRECISION), slices) && slices.size() == styles.size()) { for (size_t i = 0; i < slices.size(); ++i) { - result.push_back(IfcRepresentationShapeItem(it->ItemId(), it->Placement(), slices[i], styles[i] ? styles[i] : &it->Style())); + result.push_back(ConversionResult(it->ItemId(), it->Placement()->clone(), new OpenCascadeShape(slices[i]), styles[i] ? styles[i] : &it->Style())); } } else { return false; @@ -3201,28 +3199,32 @@ bool IfcGeom::Kernel::triangulate_wire(const TopoDS_Wire& wire, TopTools_ListOfS return true; } -TopoDS_Shape IfcGeom::Kernel::apply_transformation(const TopoDS_Shape& s, const gp_Trsf& t) { - if (t.Form() == gp_Identity) { +TopoDS_Shape IfcGeom::Kernel::apply_transformation(const TopoDS_Shape& s, const OpenCascadePlacement* t) { + if (t == nullptr) { return s; } else { - /// @todo set to 1. and exactly 1. or use epsilon? - if (t.ScaleFactor() != 1.) { - return BRepBuilderAPI_Transform(s, t, true); - } else { - return s.Moved(t); - } + return apply_transformation(s, t->trsf()); } } TopoDS_Shape IfcGeom::Kernel::apply_transformation(const TopoDS_Shape& s, const gp_GTrsf& t) { if (t.Form() == gp_Other) { + Logger::Message(Logger::LOG_WARNING, "Applying non uniform transformation"); return BRepBuilderAPI_GTransform(s, t, true); } else { - return apply_transformation(s, t.Trsf()); } } +TopoDS_Shape IfcGeom::Kernel::apply_transformation(const TopoDS_Shape& s, const gp_Trsf& t) { + /// @todo set to 1. and exactly 1. or use epsilon? + if (t.ScaleFactor() != 1.) { + return BRepBuilderAPI_Transform(s, t, true); + } else { + return s.Moved(t); + } +} + namespace { /* diff --git a/src/ifcgeom/IfcGeomIteratorImplementation.h b/src/ifcgeom/IfcGeomIteratorImplementation.h index b32668a5e8..b430a79edd 100644 --- a/src/ifcgeom/IfcGeomIteratorImplementation.h +++ b/src/ifcgeom/IfcGeomIteratorImplementation.h @@ -76,10 +76,10 @@ #include "../ifcparse/IfcFile.h" #include "../ifcgeom/IfcGeom.h" -#include "../ifcgeom/IfcGeomElement.h" +#include "../ifcgeom_schema_agnostic/IfcGeomElement.h" #include "../ifcgeom_schema_agnostic/IfcGeomMaterial.h" -#include "../ifcgeom/IfcGeomIteratorSettings.h" -#include "../ifcgeom/IfcRepresentationShapeItem.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" @@ -112,7 +112,7 @@ namespace IfcGeom { // The object is fetched beforehand to be sure that get() returns a valid element TriangulationElement* current_triangulation; - BRepElement* current_shape_model; + NativeElement* current_shape_model; SerializedElement* current_serialization; // A container and iterator for IfcBuildingElements for the current IfcRepresentation referenced by *representation_iterator @@ -403,7 +403,7 @@ namespace IfcGeom { return associated_single_materials.size() == 1; } - BRepElement* create_shape_model_for_next_entity() { + NativeElement* create_shape_model_for_next_entity() { for (;;) { IfcSchema::IfcRepresentation* representation; @@ -474,7 +474,7 @@ namespace IfcGeom { IfcSchema::IfcProduct* product = *ifcproduct_iterator; Logger::SetProduct(product); - BRepElement* element; + NativeElement* element; if (ifcproduct_iterator == ifcproducts->begin() || !geometry_reuse_ok_for_current_representation_) { element = kernel.create_brep_for_representation_and_product(settings, representation, product); } else { @@ -588,7 +588,7 @@ namespace IfcGeom { } /// Gets the native (Open Cascade) representation of the current geometrical entity. - BRepElement* get_native() + NativeElement* get_native() { // TODO: Test settings and throw return current_shape_model; @@ -646,12 +646,12 @@ namespace IfcGeom { ElementSettings element_settings(settings, unit_magnitude, instance_type); - Element* ifc_object = new Element(element_settings, id, parent_id, product_name, instance_type, product_guid, "", trsf, ifc_product); + Element* ifc_object = new Element(element_settings, id, parent_id, product_name, instance_type, product_guid, "", new OpenCascadePlacement(trsf), ifc_product); return ifc_object; } IfcUtil::IfcBaseClass* create() { - IfcGeom::BRepElement* next_shape_model = 0; + IfcGeom::NativeElement* next_shape_model = 0; IfcGeom::SerializedElement* next_serialization = 0; IfcGeom::TriangulationElement* next_triangulation = 0; diff --git a/src/ifcgeom/IfcGeomShapes.cpp b/src/ifcgeom/IfcGeomShapes.cpp index e72af56d93..1ace031e56 100644 --- a/src/ifcgeom/IfcGeomShapes.cpp +++ b/src/ifcgeom/IfcGeomShapes.cpp @@ -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; @@ -478,7 +478,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, Ifc bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape& shape) { TopoDS_Shape s1, s2; - IfcRepresentationShapeItems items1, items2; + ConversionResults items1, items2; TopoDS_Wire boundary_wire; IfcSchema::IfcBooleanOperand* operand1 = l->FirstOperand(); IfcSchema::IfcBooleanOperand* operand2 = l->SecondOperand(); @@ -664,7 +664,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()) ) { @@ -699,7 +699,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 @@ -711,7 +712,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() ) { @@ -722,7 +723,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; } } @@ -731,7 +732,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; @@ -749,7 +750,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; diff --git a/src/ifcgeom/IfcGeomTree.h b/src/ifcgeom/IfcGeomTree.h index d2acf71c33..e369acc5d3 100644 --- a/src/ifcgeom/IfcGeomTree.h +++ b/src/ifcgeom/IfcGeomTree.h @@ -21,7 +21,7 @@ #define IFCGEOMTREE_H #include "../ifcparse/IfcFile.h" -#include "../ifcgeom/IfcGeomElement.h" +#include "../ifcgeom_schema_agnostic/IfcGeomElement.h" #include "../ifcgeom_schema_agnostic/IfcGeomIterator.h" #include "../ifcgeom_schema_agnostic/Kernel.h" @@ -267,7 +267,7 @@ namespace IfcGeom { if (it.initialize()) { do { - IfcGeom::BRepElement* elem = (IfcGeom::BRepElement*)it.get(); + IfcGeom::NativeElement* elem = (IfcGeom::NativeElement*)it.get(); add((IfcUtil::IfcBaseEntity*)f.instance_by_id(elem->id()), elem->geometry().as_compound()); } while (it.next()); } diff --git a/src/ifcgeom/IfcRegister.cpp b/src/ifcgeom/IfcRegister.cpp index 08773b09e6..b0574c2008 100644 --- a/src/ifcgeom/IfcRegister.cpp +++ b/src/ifcgeom/IfcRegister.cpp @@ -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()))); + r.push_back(IfcGeom::ConversionResult(l->data().id(), new OpenCascadeShape(shp), get_style(l->as()))); 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" diff --git a/src/ifcgeom/IfcRegisterGeomHeader.h b/src/ifcgeom/IfcRegisterGeomHeader.h index 9969d5e2db..51286f3693 100644 --- a/src/ifcgeom/IfcRegisterGeomHeader.h +++ b/src/ifcgeom/IfcRegisterGeomHeader.h @@ -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) diff --git a/src/ifcgeom/IfcRepresentationShapeItem.h b/src/ifcgeom/IfcRepresentationShapeItem.h deleted file mode 100644 index 58a77c4c5b..0000000000 --- a/src/ifcgeom/IfcRepresentationShapeItem.h +++ /dev/null @@ -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 . * - * * - ********************************************************************************/ - -#ifndef IFCSHAPELIST_H -#define IFCSHAPELIST_H - -#include -#include - -#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* style) { this->style = style; } - int ItemId() const { return id; } - }; - typedef std::vector IfcRepresentationShapeItems; -} -#endif diff --git a/src/ifcgeom/OpenCascadeConversionResult.h b/src/ifcgeom/OpenCascadeConversionResult.h new file mode 100644 index 0000000000..8254510245 --- /dev/null +++ b/src/ifcgeom/OpenCascadeConversionResult.h @@ -0,0 +1,104 @@ +/******************************************************************************** +* * +* 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 . * +* * +********************************************************************************/ + +#ifndef IFCGEOMOPENCASCADEREPRESENTATION_H +#define IFCGEOMOPENCASCADEREPRESENTATION_H + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#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_)); + } + 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* t, int surface_style_id) const; + + virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation* 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 \ No newline at end of file diff --git a/src/ifcgeom/OpenCascadeShape.cpp b/src/ifcgeom/OpenCascadeShape.cpp new file mode 100644 index 0000000000..bf9e705674 --- /dev/null +++ b/src/ifcgeom/OpenCascadeShape.cpp @@ -0,0 +1,202 @@ +#include "OpenCascadeConversionResult.h" + +#include "../ifcparse/IfcLogger.h" +#include "../ifcgeom_schema_agnostic/IfcGeomRepresentation.h" + +#include "IfcGeom.h" + +#include + +#include + +template +void triangulate_helper(const TopoDS_Shape& s, const IfcGeom::IteratorSettings& settings, const IfcGeom::ConversionResultPlacement* place, IfcGeom::Representation::Triangulation* t, int surface_style_id) { + + gp_GTrsf trsf; + if (place) { + trsf = dynamic_cast(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, int> edgecount; + std::vector > edges_temp; + + const TColgp_Array1OfPnt& nodes = tri->Nodes(); + const TColgp_Array1OfPnt2d& uvs = tri->UVNodes(); + std::vector coords; + BRepGProp_Face prop(face); + std::map 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 >::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

(p2.X())); + // _verts.push_back(static_cast

(p2.Y())); + // _verts.push_back(static_cast

(p2.Z())); + // _verts.push_back(static_cast

(p3.X())); + // _verts.push_back(static_cast

(p3.Y())); + // _verts.push_back(static_cast

(p3.Z())); + + trsf.Transforms(p); + + t->material_ids().push_back(surface_style_id); + + t->verts().push_back(static_cast(p.X())); + t->verts().push_back(static_cast(p.Y())); + t->verts().push_back(static_cast(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* 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* t, int surface_style_id) const { + triangulate_helper(shape_, settings, place, t, surface_style_id); +} + +int IfcGeom::OpenCascadeShape::surface_genus() const { + return IfcGeom::Kernel::surface_genus(shape_); +} \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/todo.cpp b/src/ifcgeom/kernels/cgal/todo.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/ifcgeom/kernels/cgal/todo.h b/src/ifcgeom/kernels/cgal/todo.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/ifcgeom_schema_agnostic/ConversionResult.h b/src/ifcgeom_schema_agnostic/ConversionResult.h new file mode 100644 index 0000000000..2f2b9d9796 --- /dev/null +++ b/src/ifcgeom_schema_agnostic/ConversionResult.h @@ -0,0 +1,93 @@ +/******************************************************************************** + * * + * 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 . * + * * + ********************************************************************************/ + +#ifndef IFCSHAPELIST_H +#define IFCSHAPELIST_H + +#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h" +#include "../ifcgeom_schema_agnostic/IfcGeomIteratorSettings.h" + +namespace IfcGeom { + + namespace Representation { + template + class IFC_GEOM_API Triangulation; + } + + class IFC_GEOM_API ConversionResultPlacement { + public: + virtual void Multiply(const ConversionResultPlacement*) = 0; + virtual void PreMultiply(const ConversionResultPlacement*) = 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* t, int surface_style_id) const = 0; + virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement* place, IfcGeom::Representation::Triangulation* 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->clone()), shape(shape->clone()), style(style) {} + ConversionResult(int id, const ConversionResultPlacement* placement, const ConversionResultShape* shape) + : id(id), placement(placement->clone()), 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* style) { this->style = style; } + int ItemId() const { return id; } + }; + + typedef std::vector ConversionResults; +} +#endif diff --git a/src/ifcgeom/IfcGeomElement.h b/src/ifcgeom_schema_agnostic/IfcGeomElement.h similarity index 85% rename from src/ifcgeom/IfcGeomElement.h rename to src/ifcgeom_schema_agnostic/IfcGeomElement.h index 26ecd7341b..fa6e00a107 100644 --- a/src/ifcgeom/IfcGeomElement.h +++ b/src/ifcgeom_schema_agnostic/IfcGeomElement.h @@ -25,8 +25,8 @@ #include "../ifcparse/IfcGlobalId.h" -#include "../ifcgeom/IfcGeomRepresentation.h" -#include "../ifcgeom/IfcGeomIteratorSettings.h" +#include "../ifcgeom_schema_agnostic/IfcGeomRepresentation.h" +#include "../ifcgeom_schema_agnostic/IfcGeomIteratorSettings.h" #include "ifc_geom_api.h" namespace IfcGeom { @@ -36,7 +36,7 @@ namespace IfcGeom { private: std::vector

_data; public: - Matrix(const ElementSettings& settings, const gp_Trsf& trsf) { + Matrix(const ElementSettings& settings, const 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 @@ -44,7 +44,7 @@ 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 trsf_value = trsf->Value(j,i); const double matrix_value = i == 4 && settings.get(IteratorSettings::CONVERT_BACK_UNITS) ? trsf_value / settings.unit_magnitude() : trsf_value; @@ -59,23 +59,23 @@ namespace IfcGeom { class Transformation { private: ElementSettings settings_; - gp_Trsf trsf_; + ConversionResultPlacement* trsf_; Matrix

matrix_; public: - Transformation(const ElementSettings& settings, const gp_Trsf& trsf) + Transformation(const ElementSettings& settings, const ConversionResultPlacement* trsf) : settings_(settings) - , trsf_(trsf) + , trsf_(trsf->clone()) , matrix_(settings, trsf) {} - const gp_Trsf& data() const { return trsf_; } + const ConversionResultPlacement* data() const { return trsf_; } const Matrix

& 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())); } }; @@ -129,7 +129,7 @@ namespace IfcGeom { void SetParents(std::vector*> 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 ConversionResultPlacement* trsf, IfcUtil::IfcBaseEntity* product) : _id(id), _parent_id(parent_id), _name(name), _type(type), _guid(guid), _context(context), _transformation(settings, trsf) , product_(product) { @@ -159,28 +159,25 @@ namespace IfcGeom { }; template - class BRepElement : public Element { + class NativeElement : public Element { private: boost::shared_ptr _geometry; public: const boost::shared_ptr& 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& geometry, + NativeElement(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, + const std::string& context, const ConversionResultPlacement* trsf, const boost::shared_ptr& geometry, IfcUtil::IfcBaseEntity* product) : Element(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 @@ -190,7 +187,7 @@ namespace IfcGeom { public: const Representation::Triangulation

& geometry() const { return *_geometry; } const boost::shared_ptr< Representation::Triangulation

>& geometry_pointer() const { return _geometry; } - TriangulationElement(const BRepElement& shape_model) + TriangulationElement(const NativeElement& shape_model) : Element(shape_model) , _geometry(boost::shared_ptr >(new Representation::Triangulation

(shape_model.geometry()))) {} @@ -209,7 +206,7 @@ namespace IfcGeom { Representation::Serialization* _geometry; public: const Representation::Serialization& geometry() const { return *_geometry; } - SerializedElement(const BRepElement& shape_model) + SerializedElement(const NativeElement& shape_model) : Element(shape_model) , _geometry(new Representation::Serialization(shape_model.geometry())) {} diff --git a/src/ifcgeom_schema_agnostic/IfcGeomIterator.h b/src/ifcgeom_schema_agnostic/IfcGeomIterator.h index 4658d37780..babff4709f 100644 --- a/src/ifcgeom_schema_agnostic/IfcGeomIterator.h +++ b/src/ifcgeom_schema_agnostic/IfcGeomIterator.h @@ -119,7 +119,7 @@ namespace IfcGeom { Element* get() { return implementation_->get(); } - BRepElement* get_native() { return implementation_->get_native(); } + NativeElement* get_native() { return implementation_->get_native(); } const Element* get_object(int id) { return implementation_->get_object(id); } diff --git a/src/ifcgeom/IfcGeomIteratorSettings.h b/src/ifcgeom_schema_agnostic/IfcGeomIteratorSettings.h similarity index 99% rename from src/ifcgeom/IfcGeomIteratorSettings.h rename to src/ifcgeom_schema_agnostic/IfcGeomIteratorSettings.h index 7928d296ec..662d475e1e 100644 --- a/src/ifcgeom/IfcGeomIteratorSettings.h +++ b/src/ifcgeom_schema_agnostic/IfcGeomIteratorSettings.h @@ -23,6 +23,7 @@ #include "ifc_geom_api.h" #include "../ifcparse/IfcException.h" #include "../ifcparse/IfcBaseClass.h" +#include "../ifcparse/IfcLogger.h" namespace IfcGeom { diff --git a/src/ifcgeom_schema_agnostic/IfcGeomRenderStyles.h b/src/ifcgeom_schema_agnostic/IfcGeomRenderStyles.h index 804e1caa12..ec0b5ed265 100644 --- a/src/ifcgeom_schema_agnostic/IfcGeomRenderStyles.h +++ b/src/ifcgeom_schema_agnostic/IfcGeomRenderStyles.h @@ -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 #include diff --git a/src/ifcgeom/IfcGeomRepresentation.cpp b/src/ifcgeom_schema_agnostic/IfcGeomRepresentation.cpp similarity index 84% rename from src/ifcgeom/IfcGeomRepresentation.cpp rename to src/ifcgeom_schema_agnostic/IfcGeomRepresentation.cpp index 4a6158601a..011fd96a4d 100644 --- a/src/ifcgeom/IfcGeomRepresentation.cpp +++ b/src/ifcgeom_schema_agnostic/IfcGeomRepresentation.cpp @@ -26,16 +26,16 @@ #include #include -#include "../ifcgeom/IfcGeom.h" - #include "IfcGeomRepresentation.h" +#include "../ifcgeom/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) { + 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 +57,7 @@ IfcGeom::Representation::Serialization::Serialization(const BRep& brep) brep_data_ = sstream.str(); } -// todo copied from kernel +// @todo copied from kernel #include #include @@ -86,9 +86,13 @@ TopoDS_Compound IfcGeom::Representation::BRep::as_compound() const { TopoDS_Compound compound; BRep_Builder builder; builder.MakeCompound(compound); - for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = begin(); it != end(); ++it) { - 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 (settings().get(IteratorSettings::CONVERT_BACK_UNITS)) { gp_Trsf scale; @@ -166,7 +170,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 +194,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 +211,10 @@ bool IfcGeom::Representation::BRep::calculate_volume(double& volume) const { try { volume = 0.; - for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = begin(); it != end(); ++it) { - if (Kernel::is_manifold(it->Shape())) { + for (IfcGeom::ConversionResults::const_iterator it = begin(); it != end(); ++it) { + if (Kernel::is_manifold(*(OpenCascadeShape*)it->Shape())) { GProp_GProps prop; - BRepGProp::VolumeProperties(it->Shape(), prop); + BRepGProp::VolumeProperties(*(OpenCascadeShape*)it->Shape(), prop); volume += prop.Mass(); } else { return false; @@ -224,15 +228,19 @@ 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())) { + if (Kernel::is_manifold(*(OpenCascadeShape*)it->Shape())) { x /= 2.; y /= 2.; z /= 2.; diff --git a/src/ifcgeom/IfcGeomRepresentation.h b/src/ifcgeom_schema_agnostic/IfcGeomRepresentation.h similarity index 50% rename from src/ifcgeom/IfcGeomRepresentation.h rename to src/ifcgeom_schema_agnostic/IfcGeomRepresentation.h index 7f1eb8f9e5..f67b130b43 100644 --- a/src/ifcgeom/IfcGeomRepresentation.h +++ b/src/ifcgeom_schema_agnostic/IfcGeomRepresentation.h @@ -35,12 +35,14 @@ #include #include -#include "../ifcgeom/IfcGeomIteratorSettings.h" +#include "../ifcgeom_schema_agnostic/IfcGeomIteratorSettings.h" #include "../ifcgeom_schema_agnostic/IfcGeomMaterial.h" -#include "../ifcgeom/IfcRepresentationShapeItem.h" +#include "../ifcgeom_schema_agnostic/ConversionResult.h" #include +#include + namespace IfcGeom { namespace Representation { @@ -61,25 +63,25 @@ namespace IfcGeom { class IFC_GEOM_API BRep : public Representation { private: std::string id_; - const IfcGeom::IfcRepresentationShapeItems shapes_; + const IfcGeom::ConversionResults shapes_; BRep(const BRep& other); BRep& operator=(const BRep& other); public: - BRep(const ElementSettings& settings, const std::string& id, const IfcGeom::IfcRepresentationShapeItems& shapes) + BRep(const ElementSettings& settings, const std::string& id, const IfcGeom::ConversionResults& 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_; } + 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_; } TopoDS_Compound as_compound() 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; + bool calculate_projected_surface_area(const ConversionResultPlacement* ax, double& along_x, double& along_y, double& along_z) const; }; class IFC_GEOM_API Serialization : public Representation { @@ -133,7 +135,7 @@ namespace IfcGeom { : Representation(shape_model.settings()) , id_(shape_model.id()) { - for ( IfcGeom::IfcRepresentationShapeItems::const_iterator iit = shape_model.begin(); iit != shape_model.end(); ++ iit ) { + for ( IfcGeom::ConversionResults::const_iterator iit = shape_model.begin(); iit != shape_model.end(); ++ iit ) { int surface_style_id = -1; if (iit->hasStyle()) { @@ -158,192 +160,7 @@ namespace IfcGeom { } } - 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,int> edgecount; - std::vector > edges_temp; - - const TColgp_Array1OfPnt& nodes = tri->Nodes(); - const TColgp_Array1OfPnt2d& uvs = tri->UVNodes(); - std::vector coords; - BRepGProp_Face prop(face); - std::map 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

(normal.X())); - _normals.push_back(static_cast

(normal.Y())); - _normals.push_back(static_cast

(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 >::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

(p2.X())); - _verts.push_back(static_cast

(p2.Y())); - _verts.push_back(static_cast

(p2.Z())); - _verts.push_back(static_cast

(p3.X())); - _verts.push_back(static_cast

(p3.Y())); - _verts.push_back(static_cast

(p3.Z())); - */ - - trsf.Transforms(p); - - _material_ids.push_back(surface_style_id); - - _verts.push_back(static_cast

(p.X())); - _verts.push_back(static_cast

(p.Y())); - _verts.push_back(static_cast

(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); + iit->Shape()->Triangulate(settings(), iit->Placement(), this, surface_style_id); } } virtual ~Triangulation() {} @@ -378,13 +195,14 @@ namespace IfcGeom { return uvs; } - private: + public: + // Welds vertices that belong to different faces - int addVertex(int material_index, const gp_XYZ& p) { + int addVertex(int material_index, P X, P Y, P Z) { const bool convert = settings().get(IteratorSettings::CONVERT_BACK_UNITS); - const P X = static_cast

(convert ? (p.X() / settings().unit_magnitude()) : p.X()); - const P Y = static_cast

(convert ? (p.Y() / settings().unit_magnitude()) : p.Y()); - const P Z = static_cast

(convert ? (p.Z() / settings().unit_magnitude()) : p.Z()); + X = static_cast

(convert ? (X / settings().unit_magnitude()) : X); + Y = static_cast

(convert ? (Y / settings().unit_magnitude()) : Y); + Z = static_cast

(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))); @@ -398,12 +216,34 @@ namespace IfcGeom { _verts.push_back(Z); return i; } + inline void addEdge(int n1, int n2, std::map,int>& edgecount, std::vector >& 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&); diff --git a/src/ifcgeom_schema_agnostic/IteratorImplementation.h b/src/ifcgeom_schema_agnostic/IteratorImplementation.h index 69ddbb618f..5417584c20 100644 --- a/src/ifcgeom_schema_agnostic/IteratorImplementation.h +++ b/src/ifcgeom_schema_agnostic/IteratorImplementation.h @@ -3,7 +3,7 @@ #include "../ifcgeom_schema_agnostic/IfcGeomFilter.h" #include "../ifcparse/IfcFile.h" -#include "../ifcgeom/IfcGeomIteratorSettings.h" +#include "../ifcgeom_schema_agnostic/IfcGeomIteratorSettings.h" #include @@ -20,7 +20,7 @@ namespace IfcGeom { class Element; template - class BRepElement; + class NativeElement; } typedef boost::function3*, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector&> iterator_float_float_fn; @@ -71,7 +71,7 @@ namespace IfcGeom { virtual IfcParse::IfcFile* file() const = 0; virtual IfcUtil::IfcBaseClass* next() = 0; virtual Element* get() = 0; - virtual BRepElement* get_native() = 0; + virtual NativeElement* get_native() = 0; virtual const Element* get_object(int id) = 0; virtual IfcUtil::IfcBaseClass* create() = 0; }; diff --git a/src/ifcgeom_schema_agnostic/Kernel.h b/src/ifcgeom_schema_agnostic/Kernel.h index c924f8af6a..5f1fdac66c 100644 --- a/src/ifcgeom_schema_agnostic/Kernel.h +++ b/src/ifcgeom_schema_agnostic/Kernel.h @@ -2,8 +2,8 @@ #define ITERATOR_KERNEL_H #include "../ifcparse/IfcFile.h" -#include "../ifcgeom/IfcGeomIteratorSettings.h" -#include "../ifcgeom/IfcRepresentationShapeItem.h" +#include "../ifcgeom_schema_agnostic/IfcGeomIteratorSettings.h" +#include "../ifcgeom_schema_agnostic/ConversionResult.h" #include "../ifcparse/Ifc2x3.h" #include "../ifcparse/Ifc4.h" @@ -15,7 +15,7 @@ namespace IfcGeom { template - class BRepElement; + class NativeElement; class Kernel { private: @@ -64,14 +64,14 @@ namespace IfcGeom { return implementation_->getValue(var); } - virtual BRepElement* convert( + virtual NativeElement* 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); } diff --git a/src/ifcgeom_schema_agnostic/Serialization.h b/src/ifcgeom_schema_agnostic/Serialization.h index be3d79bd3f..e7adf5f057 100644 --- a/src/ifcgeom_schema_agnostic/Serialization.h +++ b/src/ifcgeom_schema_agnostic/Serialization.h @@ -1,4 +1,4 @@ -#include "../ifcgeom/ifc_geom_api.h" +#include "../ifcgeom_schema_agnostic/ifc_geom_api.h" #include "../ifcparse/IfcBaseClass.h" #include diff --git a/src/ifcgeom/ifc_geom_api.h b/src/ifcgeom_schema_agnostic/ifc_geom_api.h similarity index 100% rename from src/ifcgeom/ifc_geom_api.h rename to src/ifcgeom_schema_agnostic/ifc_geom_api.h diff --git a/src/ifcgeom_schema_agnostic_cgal/todo.cpp b/src/ifcgeom_schema_agnostic_cgal/todo.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/ifcgeom_schema_agnostic_cgal/todo.h b/src/ifcgeom_schema_agnostic_cgal/todo.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/ifcgeomserver/IfcGeomServer.cpp b/src/ifcgeomserver/IfcGeomServer.cpp index ed340a7a48..7a2cc9ee90 100644 --- a/src/ifcgeomserver/IfcGeomServer.cpp +++ b/src/ifcgeomserver/IfcGeomServer.cpp @@ -39,7 +39,7 @@ #endif #include "../ifcgeom_schema_agnostic/IfcGeomIterator.h" -#include "../ifcgeom/IfcGeomElement.h" +#include "../ifcgeom_schema_agnostic/IfcGeomElement.h" #include "../ifcparse/IfcFile.h" #include "../ifcparse/IfcLogger.h" @@ -404,9 +404,9 @@ static const std::string WALKABLE_SURFACE_AREA = "WALKABLE_SURFACE_AREA"; class QuantityWriter_v0 : public EntityExtension { private: - const IfcGeom::BRepElement* elem_; + const IfcGeom::NativeElement* elem_; public: - QuantityWriter_v0(const IfcGeom::BRepElement* elem) : + QuantityWriter_v0(const IfcGeom::NativeElement* elem) : elem_(elem) { put_json(TOTAL_SURFACE_AREA, 0.); @@ -419,9 +419,9 @@ public: class QuantityWriter_v1 : public EntityExtension { private: - const IfcGeom::BRepElement* elem_; + const IfcGeom::NativeElement* elem_; public: - QuantityWriter_v1(const IfcGeom::BRepElement* elem) : + QuantityWriter_v1(const IfcGeom::NativeElement* elem) : elem_(elem) { double a, b, c; diff --git a/src/ifcwrap/IfcGeomWrapper.i b/src/ifcwrap/IfcGeomWrapper.i index ce359b1708..80a67a6745 100644 --- a/src/ifcwrap/IfcGeomWrapper.i +++ b/src/ifcwrap/IfcGeomWrapper.i @@ -369,7 +369,7 @@ struct ShapeRTTI : public boost::static_visitor } } - IfcGeom::BRepElement* brep = kernel.convert(settings, ifc_representation, product); + IfcGeom::NativeElement* brep = kernel.convert(settings, ifc_representation, product); if (!brep) { throw IfcParse::IfcException("Failed to process shape"); } @@ -387,7 +387,7 @@ struct ShapeRTTI : public boost::static_visitor } 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(instance->data().id()), shapes); diff --git a/src/serializers/ColladaSerializer.h b/src/serializers/ColladaSerializer.h index 84cd4b7c69..d85dc989a0 100644 --- a/src/serializers/ColladaSerializer.h +++ b/src/serializers/ColladaSerializer.h @@ -230,7 +230,7 @@ public: bool ready(); void writeHeader(); void write(const IfcGeom::TriangulationElement* o); - void write(const IfcGeom::BRepElement* /*o*/) {} + void write(const IfcGeom::NativeElement* /*o*/) {} void finalize(); bool isTesselated() const { return true; } void setUnitNameAndMagnitude(const std::string& name, float magnitude) { diff --git a/src/serializers/GeometrySerializer.h b/src/serializers/GeometrySerializer.h index 0673a1cc65..45b14d8660 100644 --- a/src/serializers/GeometrySerializer.h +++ b/src/serializers/GeometrySerializer.h @@ -28,7 +28,7 @@ typedef float real_t; #include "../serializers/Serializer.h" #include "../ifcgeom_schema_agnostic/IfcGeomIterator.h" -#include "../ifcgeom/IfcGeomElement.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* o) = 0; - virtual void write(const IfcGeom::BRepElement* o) = 0; + virtual void write(const IfcGeom::NativeElement* o) = 0; virtual void setUnitNameAndMagnitude(const std::string& name, float magnitude) = 0; const SerializerSettings& settings() const { return settings_; } diff --git a/src/serializers/IgesSerializer.h b/src/serializers/IgesSerializer.h index 93fca9b514..77845d0116 100644 --- a/src/serializers/IgesSerializer.h +++ b/src/serializers/IgesSerializer.h @@ -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()); diff --git a/src/serializers/OpenCascadeBasedSerializer.cpp b/src/serializers/OpenCascadeBasedSerializer.cpp index d19c80566d..257fa83e4e 100644 --- a/src/serializers/OpenCascadeBasedSerializer.cpp +++ b/src/serializers/OpenCascadeBasedSerializer.cpp @@ -34,7 +34,7 @@ bool OpenCascadeBasedSerializer::ready() { return succeeded; } -void OpenCascadeBasedSerializer::write(const IfcGeom::BRepElement* o) { +void OpenCascadeBasedSerializer::write(const IfcGeom::NativeElement* o) { TopoDS_Shape compound = o->geometry().as_compound(); if (o->geometry().settings().get(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS)) { @@ -44,7 +44,8 @@ void OpenCascadeBasedSerializer::write(const IfcGeom::BRepElement* o) { compound = BRepBuilderAPI_Transform(compound, scale, true).Shape(); } - writeShape(compound); + IfcGeom::OpenCascadeShape s(compound); + writeShape(&s); } #define RATHER_SMALL (1e-3) diff --git a/src/serializers/OpenCascadeBasedSerializer.h b/src/serializers/OpenCascadeBasedSerializer.h index 048c1228a4..e1f78e1401 100644 --- a/src/serializers/OpenCascadeBasedSerializer.h +++ b/src/serializers/OpenCascadeBasedSerializer.h @@ -21,7 +21,7 @@ #define OPENCASCADEBASEDSERIALIZER_H #include "../ifcgeom_schema_agnostic/IfcGeomIterator.h" - +#include "../ifcgeom/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* /*o*/) {} - void write(const IfcGeom::BRepElement* o); + void write(const IfcGeom::NativeElement* o); bool isTesselated() const { return false; } void setFile(IfcParse::IfcFile*) {} }; diff --git a/src/serializers/StepSerializer.h b/src/serializers/StepSerializer.h index db9ea54d77..5b31bace6e 100644 --- a/src/serializers/StepSerializer.h +++ b/src/serializers/StepSerializer.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() { diff --git a/src/serializers/SvgSerializer.cpp b/src/serializers/SvgSerializer.cpp index 9710b5338c..720448294a 100644 --- a/src/serializers/SvgSerializer.cpp +++ b/src/serializers/SvgSerializer.cpp @@ -283,14 +283,14 @@ SvgSerializer::path_object& SvgSerializer::start_path(IfcUtil::IfcBaseEntity* st return p; } -void SvgSerializer::write(const IfcGeom::BRepElement* o) +void SvgSerializer::write(const IfcGeom::NativeElement* o) { IfcUtil::IfcBaseEntity* storey = storey_; boost::optional storey_elevation = boost::none; /* - TODO: based on BRepElement::parent() + TODO: based on NativeElement::parent() IfcSchema::IfcObjectDefinition* obdef = static_cast(file->entityById(o->id())); diff --git a/src/serializers/SvgSerializer.h b/src/serializers/SvgSerializer.h index f1ec93cb76..81f661bd4c 100644 --- a/src/serializers/SvgSerializer.h +++ b/src/serializers/SvgSerializer.h @@ -62,7 +62,7 @@ public: void writeHeader(); bool ready(); void write(const IfcGeom::TriangulationElement* /*o*/) {} - void write(const IfcGeom::BRepElement* o); + void write(const IfcGeom::NativeElement* 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; } diff --git a/src/serializers/WavefrontObjSerializer.h b/src/serializers/WavefrontObjSerializer.h index 299dc065b6..80866eb122 100644 --- a/src/serializers/WavefrontObjSerializer.h +++ b/src/serializers/WavefrontObjSerializer.h @@ -51,7 +51,7 @@ public: void writeHeader(); void writeMaterial(const IfcGeom::Material& style); void write(const IfcGeom::TriangulationElement* o); - void write(const IfcGeom::BRepElement* /*o*/) {} + void write(const IfcGeom::NativeElement* /*o*/) {} void finalize() {} bool isTesselated() const { return true; } void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {} From d804575974c385db4038343f4e324765decbd346 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Mon, 16 Jan 2017 11:53:11 +0100 Subject: [PATCH 126/235] Cgal kernel skeleton --- .../kernels/cgal/CgalConversionFunctions.cpp | 26 +++ .../kernels/cgal/CgalConversionResult.cpp | 6 + .../kernels/cgal/CgalConversionResult.h | 77 ++++++++ .../kernels/cgal/CgalEntityMapping.cpp | 100 ++++++++++ src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 35 ++++ .../cgal/CgalEntityMappingCreateCache.h | 6 + .../kernels/cgal/CgalEntityMappingCurve.h | 6 + .../cgal/CgalEntityMappingDeclaration.h | 10 + .../kernels/cgal/CgalEntityMappingDefine.h | 18 ++ .../kernels/cgal/CgalEntityMappingFace.h | 6 + .../cgal/CgalEntityMappingPurgeCache.h | 6 + .../kernels/cgal/CgalEntityMappingShape.h | 20 ++ .../kernels/cgal/CgalEntityMappingShapeType.h | 14 ++ .../kernels/cgal/CgalEntityMappingShapes.h | 13 ++ .../kernels/cgal/CgalEntityMappingUndefine.h | 18 ++ .../kernels/cgal/CgalEntityMappingWire.h | 6 + src/ifcgeom/kernels/cgal/CgalKernel.cpp | 171 ++++++++++++++++++ src/ifcgeom/kernels/cgal/CgalKernel.h | 93 ++++++++++ src/ifcgeom/kernels/cgal/todo.cpp | 0 src/ifcgeom/kernels/cgal/todo.h | 0 src/ifcgeom_schema_agnostic_cgal/todo.cpp | 0 src/ifcgeom_schema_agnostic_cgal/todo.h | 0 22 files changed, 631 insertions(+) create mode 100644 src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp create mode 100644 src/ifcgeom/kernels/cgal/CgalConversionResult.cpp create mode 100644 src/ifcgeom/kernels/cgal/CgalConversionResult.h create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMapping.h create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingCreateCache.h create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingCurve.h create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingDeclaration.h create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingDefine.h create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingFace.h create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingPurgeCache.h create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingShape.h create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingShapeType.h create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingShapes.h create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingUndefine.h create mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingWire.h create mode 100644 src/ifcgeom/kernels/cgal/CgalKernel.cpp create mode 100644 src/ifcgeom/kernels/cgal/CgalKernel.h delete mode 100644 src/ifcgeom/kernels/cgal/todo.cpp delete mode 100644 src/ifcgeom/kernels/cgal/todo.h delete mode 100644 src/ifcgeom_schema_agnostic_cgal/todo.cpp delete mode 100644 src/ifcgeom_schema_agnostic_cgal/todo.h diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp new file mode 100644 index 0000000000..1a808195cb --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -0,0 +1,26 @@ +#include "CgalKernel.h" +#include "CgalConversionResult.h" + +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(new CgalShape(s), get_style(representation_item))); + part_succes |= true; + } + } + } + } + return part_succes; +} + +bool IfcGeom::CgalKernel::convert(const Ifc2x3::IfcExtrudedAreaSolid*, cgal_shape_t&) { + throw std::runtime_error("Not implemented IfcExtrudedAreaSolid"); +} diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp new file mode 100644 index 0000000000..e2da8ecd97 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -0,0 +1,6 @@ +#include "CgalKernel.h" +#include "CgalConversionResult.h" + +void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const { + throw std::runtime_error("Not implemented Triangulate()"); +} diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.h b/src/ifcgeom/kernels/cgal/CgalConversionResult.h new file mode 100644 index 0000000000..3fb4bb7e67 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.h @@ -0,0 +1,77 @@ +/******************************************************************************** +* * +* 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 . * +* * +********************************************************************************/ + +#ifndef CGALCONVERSIONRESULT_H +#define CGALCONVERSIONRESULT_H + +#include "../../../ifcgeom/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 { + // Get cell from placement as 4x3 matrix as implemented in OCCT. We'll have to check exact semantics. + throw std::runtime_error("Not implemented"); + } + virtual void Multiply(const ConversionResultPlacement* other) { + // Multiply matrix as implemented in OCCT. We'll have to check exact semantics. + throw std::runtime_error("Not implemented"); + } + virtual void PreMultiply(const ConversionResultPlacement* other) { + // PreMultiply matrix as implemented in OCCT. We'll have to check exact semantics. + throw std::runtime_error("Not implemented"); + } + virtual ConversionResultPlacement* clone() const { + return new CgalPlacement(trsf_); + } + 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* 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_); + } + private: + cgal_shape_t shape_; + }; + +} + +#endif \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp new file mode 100644 index 0000000000..f3002292d4 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp @@ -0,0 +1,100 @@ +/******************************************************************************** +* * +* This file is part of IfcOpenShell. * +* * +* IfcOpenShell is free software: you can redistribute it and/or modify * +* it under the terms of the Lesser GNU General Public License as published by * +* the Free Software Foundation, either version 3.0 of the License, or * +* (at your option) any later version. * +* * +* IfcOpenShell is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* Lesser GNU General Public License for more details. * +* * +* You should have received a copy of the Lesser GNU General Public License * +* along with this program. If not, see . * +* * +********************************************************************************/ + +#include "../../../ifcgeom/IfcGeomShapeType.h" +#include "../../../ifcgeom/IfcGeom.h" + +#include "CgalKernel.h" +#include "CgalConversionResult.h" + +using namespace IfcSchema; +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(new CgalShape(shp), get_style(l->as()))); + return true; + } + return false; + } + +#include "CgalEntityMappingShapes.h" + Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity); + 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->entity->id(); + bool success = false; + bool processed = false; + bool ignored = false; + +#ifndef NO_CACHE + std::map::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->entity); + } + 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->entity); + 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->entity); + 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->entity); + return false; +} diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h new file mode 100644 index 0000000000..eb2ecedf38 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -0,0 +1,35 @@ +/******************************************************************************** +* * +* This file is part of IfcOpenShell. * +* * +* IfcOpenShell is free software: you can redistribute it and/or modify * +* it under the terms of the Lesser GNU General Public License as published by * +* the Free Software Foundation, either version 3.0 of the License, or * +* (at your option) any later version. * +* * +* IfcOpenShell is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* Lesser GNU General Public License for more details. * +* * +* You should have received a copy of the Lesser GNU General Public License * +* along with this program. If not, see . * +* * +********************************************************************************/ + +/******************************************************************************** + * * + * 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/IfcUtil.h" +#include "../../../ifcparse/IfcParse.h" + +SHAPES(IfcRepresentation); + +SHAPE(IfcExtrudedAreaSolid); + +CLASS(IfcCartesianPoint,cgal_point_t); diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingCreateCache.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingCreateCache.h new file mode 100644 index 0000000000..ebfb8daca7 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingCreateCache.h @@ -0,0 +1,6 @@ +#include "CgalEntityMappingUndefine.h" +#define CLASS(T,V) \ + std::map T; +#include "CgalEntityMappingDefine.h" + +#include "CgalEntityMapping.h" diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingCurve.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingCurve.h new file mode 100644 index 0000000000..ac6736626a --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingCurve.h @@ -0,0 +1,6 @@ +#include "CgalEntityMappingUndefine.h" +#define CURVE(T) \ + if ( l->is(T::Class()) ) return convert((T*)l,r); +#include "CgalEntityMappingDefine.h" + +#include "CgalEntityMapping.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingDeclaration.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingDeclaration.h new file mode 100644 index 0000000000..7101613c26 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingDeclaration.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" \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingDefine.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingDefine.h new file mode 100644 index 0000000000..65f8704a81 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingDefine.h @@ -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 \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingFace.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingFace.h new file mode 100644 index 0000000000..ccebad4e33 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingFace.h @@ -0,0 +1,6 @@ +#include "CgalEntityMappingUndefine.h" +#define FACE(T) \ + if ( l->is(T::Class()) ) return convert((T*)l,r); +#include "CgalEntityMappingDefine.h" + +#include "CgalEntityMapping.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingPurgeCache.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingPurgeCache.h new file mode 100644 index 0000000000..ea8c2c2554 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingPurgeCache.h @@ -0,0 +1,6 @@ +#include "CgalEntityMappingUndefine.h" +#define CLASS(T,V) \ + T.clear(); +#include "CgalEntityMappingDefine.h" + +#include "CgalEntityMapping.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingShape.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingShape.h new file mode 100644 index 0000000000..736df52c62 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingShape.h @@ -0,0 +1,20 @@ +#include "CgalEntityMappingUndefine.h" +#define SHAPE(T) \ + if ( !processed && l->is(T::Class()) ) { \ + processed = true; \ + try { \ + if ( convert((T*)l,r) ) { \ + success = true; \ + } \ + } catch (const std::exception& e) { \ + Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l->entity); \ + return false; \ + } \ + if (!success) { \ + Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \ + return false; \ + } \ + } +#include "CgalEntityMappingDefine.h" + +#include "CgalEntityMapping.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingShapeType.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingShapeType.h new file mode 100644 index 0000000000..21e6a0cd31 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingShapeType.h @@ -0,0 +1,14 @@ +#include "CgalEntityMappingUndefine.h" +#define SHAPES(T) \ + if ( l->is(T::Class()) ) return ST_SHAPELIST; +#define SHAPE(T) \ + if ( l->is(T::Class()) ) return ST_SHAPE; +#define WIRE(T) \ + if ( l->is(T::Class()) ) return ST_WIRE; +#define FACE(T) \ + if ( l->is(T::Class()) ) return ST_FACE; +#define CURVE(T) \ + if ( l->is(T::Class()) ) return ST_CURVE; +#include "CgalEntityMappingDefine.h" + +#include "CgalEntityMapping.h" diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingShapes.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingShapes.h new file mode 100644 index 0000000000..778a5399ac --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingShapes.h @@ -0,0 +1,13 @@ +#include "CgalEntityMappingUndefine.h" +#define SHAPES(T) \ + if ( l->is(T::Class()) ) { \ + try { \ + return convert((T*)l,r); \ + } catch (const std::exception& e) { \ + Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l->entity); \ + } \ + return false; \ + } +#include "CgalEntityMappingDefine.h" + +#include "CgalEntityMapping.h" diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingUndefine.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingUndefine.h new file mode 100644 index 0000000000..d2d537a073 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingUndefine.h @@ -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 \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingWire.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingWire.h new file mode 100644 index 0000000000..ed5461ba75 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingWire.h @@ -0,0 +1,6 @@ +#include "CgalEntityMappingUndefine.h" +#define WIRE(T) \ + if ( l->is(T::Class()) ) return convert((T*)l,r); +#include "CgalEntityMappingDefine.h" + +#include "CgalEntityMapping.h" diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp new file mode 100644 index 0000000000..f4f830cbee --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -0,0 +1,171 @@ +/******************************************************************************** +* * +* This file is part of IfcOpenShell. * +* * +* IfcOpenShell is free software: you can redistribute it and/or modify * +* it under the terms of the Lesser GNU General Public License as published by * +* the Free Software Foundation, either version 3.0 of the License, or * +* (at your option) any later version. * +* * +* IfcOpenShell is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* Lesser GNU General Public License for more details. * +* * +* You should have received a copy of the Lesser GNU General Public License * +* along with this program. If not, see . * +* * +********************************************************************************/ + +#include "../../../ifcgeom/IfcGeomShapeType.h" +#include "../../../ifcgeom/IfcGeom.h" + +#include "CgalKernel.h" +#include "CgalConversionResult.h" + +bool IfcGeom::CgalKernel::is_identity_transform(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()) != 0) { + gp_GTrsf2d gtrsf2d; + convert(op2dnonu, gtrsf2d); + return gtrsf2d.Form() == gp_Identity; + } else if ((op2d = l->as()) != 0) { + gp_Trsf2d trsf2d; + convert(op2d, trsf2d); + return trsf2d.Form() == gp_Identity; + } else if ((op3dnonu = l->as()) != 0) { + gp_GTrsf gtrsf; + convert(op3dnonu, gtrsf); + return gtrsf.Form() == gp_Identity; + } else if ((op3d = l->as()) != 0) { + gp_Trsf trsf; + convert(op3d, trsf); + return trsf.Form() == gp_Identity; + } else if ((ax2d = l->as()) != 0) { + gp_Trsf2d trsf2d; + convert(ax2d, trsf2d); + return trsf2d.Form() == gp_Identity; + } else if ((ax3d = l->as()) != 0) { + gp_Trsf trsf; + convert(ax3d, trsf); + return trsf.Form() == gp_Identity; + } else { + throw IfcParse::IfcException("Invalid valuation for IfcAxis2Placement / IfcCartesianTransformationOperator"); + } + */ +} + +IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representation_and_product( + const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product) +{ + IfcGeom::Representation::Native* shape; + IfcGeom::ConversionResults shapes, shapes2; + + if (!convert_shapes(representation, shapes)) { + return 0; + } + + if (settings.get(IteratorSettings::APPLY_LAYERSETS)) { + Logger::Message(Logger::LOG_ERROR, "Not implemented APPLY_LAYERSETS"); + } + + int parent_id = -1; + try { + IfcSchema::IfcObjectDefinition* parent_object = get_decomposing_entity(product); + if (parent_object) { + parent_id = parent_object->entity->id(); + } + } catch (...) {} + + const std::string name = product->hasName() ? product->Name() : ""; + const std::string guid = product->GlobalId(); + + cgal_placement_t trsf; + try { + // convert(product->ObjectPlacement(), trsf); + } catch (...) {} + + // Does the IfcElement have any IfcOpenings? + // Note that openings for IfcOpeningElements are not processed + IfcSchema::IfcRelVoidsElement::list::ptr openings = find_openings(product); + + const std::string product_type = IfcSchema::Type::ToString(product->type()); + ElementSettings element_settings(settings, getValue(GV_LENGTH_UNIT), product_type); + + if (!settings.get(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && openings && openings->size()) { + Logger::Message(Logger::LOG_ERROR, "Not implemented opening subtractions"); + } + + shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), shapes); + + std::string context_string = ""; + if (representation->hasRepresentationIdentifier()) { + context_string = representation->RepresentationIdentifier(); + } else if (representation->ContextOfItems()->hasContextType()) { + context_string = representation->ContextOfItems()->ContextType(); + } + + return new NativeElement( + product->entity->id(), + parent_id, + name, + product_type, + guid, + context_string, + new CgalPlacement(trsf), + boost::shared_ptr(shape) + ); +} + +IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_processed_representation( + const IteratorSettings& /*settings*/, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, + IfcGeom::NativeElement* brep) +{ + int parent_id = -1; + try { + IfcSchema::IfcObjectDefinition* parent_object = get_decomposing_entity(product); + if (parent_object) { + parent_id = parent_object->entity->id(); + } + } catch (...) {} + + const std::string name = product->hasName() ? product->Name() : ""; + const std::string guid = product->GlobalId(); + + cgal_placement_t trsf; + try { + // convert(product->ObjectPlacement(), trsf); + } catch (...) {} + + 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 = IfcSchema::Type::ToString(product->type()); + + return new NativeElement( + product->entity->id(), + parent_id, + name, + product_type, + guid, + context_string, + new CgalPlacement(trsf), + brep->geometry_pointer() + ); +} diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h new file mode 100644 index 0000000000..a3e7167624 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -0,0 +1,93 @@ +/******************************************************************************** +* * +* 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 . * +* * +********************************************************************************/ + +#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::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 "../../../ifcgeom/IfcGeom.h" + +typedef void* cgal_shape_t; +typedef void* cgal_face_t; +typedef void* cgal_wire_t; +typedef void* cgal_curve_t; +typedef void* cgal_placement_t; +typedef void* cgal_point_t; + +namespace IfcGeom { + + class IFC_GEOM_API CgalCache { + public: +#include "CgalEntityMappingCreateCache.h" + std::map Shape; + }; + + class IFC_GEOM_API CgalKernel : public AbstractKernel { + public: + +#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_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, ConversionResults& cut_shapes); + + 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(IfcUtil::IfcBaseClass*); + virtual IfcGeom::NativeElement* create_brep_for_representation_and_product( + const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*); + virtual IfcGeom::NativeElement* create_brep_for_processed_representation( + const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::NativeElement*); + +#include "CgalEntityMappingDeclaration.h" + + }; + +} + +#endif \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/todo.cpp b/src/ifcgeom/kernels/cgal/todo.cpp deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/ifcgeom/kernels/cgal/todo.h b/src/ifcgeom/kernels/cgal/todo.h deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/ifcgeom_schema_agnostic_cgal/todo.cpp b/src/ifcgeom_schema_agnostic_cgal/todo.cpp deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/ifcgeom_schema_agnostic_cgal/todo.h b/src/ifcgeom_schema_agnostic_cgal/todo.h deleted file mode 100644 index e69de29bb2..0000000000 From 16d6420352aaefcc58a11ddb2fddde9cda2a5ac7 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 18 Jan 2019 15:19:00 +0100 Subject: [PATCH 127/235] More work on enabling cgal kernel --- cmake/CMakeLists.txt | 18 ++--- src/ifcgeom/IfcGeom.h | 2 - src/ifcgeom/IfcGeomFunctions.cpp | 35 +--------- .../kernels/cgal/CgalConversionFunctions.cpp | 6 +- .../kernels/cgal/CgalConversionResult.cpp | 11 +++- .../kernels/cgal/CgalConversionResult.h | 21 +++++- .../kernels/cgal/CgalEntityMapping.cpp | 18 ++--- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 - .../kernels/cgal/CgalEntityMappingCurve.h | 2 +- .../kernels/cgal/CgalEntityMappingFace.h | 2 +- .../kernels/cgal/CgalEntityMappingShape.h | 8 +-- .../kernels/cgal/CgalEntityMappingShapeType.h | 10 +-- .../kernels/cgal/CgalEntityMappingShapes.h | 6 +- .../kernels/cgal/CgalEntityMappingWire.h | 2 +- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 60 ++++++++++++----- src/ifcgeom/kernels/cgal/CgalKernel.h | 2 +- src/ifcgeom_schema_agnostic/Kernel.cpp | 66 +++++++++++++++---- src/ifcgeom_schema_agnostic/Kernel.h | 9 +-- src/serializers/SvgSerializer.cpp | 2 +- 19 files changed, 174 insertions(+), 107 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 10c7b93912..344f0ac5f1 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -562,10 +562,10 @@ file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/*.cpp) set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES}) foreach(schema 2x3 4) -add_library(IfcGeom_ifc${schema} ${IFCGEOM_FILES}) -set_target_properties(IfcGeom_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema} -DUSE_IFC${schema}") -TARGET_LINK_LIBRARIES(IfcGeom_ifc${schema} IfcParse ${OPENCASCADE_LIBRARIES}) -list(APPEND IfcGeom_libraries IfcGeom_ifc${schema}) +add_library(IfcGeom_occt_ifc${schema} ${IFCGEOM_FILES}) +set_target_properties(IfcGeom_occt_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema} -DUSE_IFC${schema}") +TARGET_LINK_LIBRARIES(IfcGeom_occt_ifc${schema} IfcParse ${OPENCASCADE_LIBRARIES}) +list(APPEND IfcGeom_libraries IfcGeom_occt_ifc${schema}) endforeach() ### CGAL @@ -576,10 +576,10 @@ file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/kernels/cgal/*.cpp) set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES}) foreach(schema 2x3 4) -add_library(IfcGeom_CGAL_ifc${schema} ${IFCGEOM_FILES}) -set_target_properties(IfcGeom_CGAL_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema} -DUSE_IFC${schema}") -TARGET_LINK_LIBRARIES(IfcGeom_CGAL_ifc${schema} IfcParse ${OPENCASCADE_LIBRARIES}) -list(APPEND IfcGeom_CGAL_libraries IfcGeom_CGAL_ifc${schema}) +add_library(IfcGeom_cgal_ifc${schema} ${IFCGEOM_FILES}) +set_target_properties(IfcGeom_cgal_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema} -DUSE_IFC${schema}") +TARGET_LINK_LIBRARIES(IfcGeom_cgal_ifc${schema} IfcParse ${OPENCASCADE_LIBRARIES}) +list(APPEND IfcGeom_libraries IfcGeom_cgal_ifc${schema}) endforeach() # IfcGeom, schema and kernel agnostic @@ -695,7 +695,7 @@ INSTALL(FILES ${SCHEMA_AGNOSTIC_H_FILES} DESTINATION ${INCLUDEDIR}/ifcgeom_schema_agnostic ) -INSTALL(TARGETS IfcGeom_ifc2x3 IfcGeom_ifc4 IfcGeom +INSTALL(TARGETS IfcGeom ${IfcGeom_libraries} ARCHIVE DESTINATION ${LIBDIR} LIBRARY DESTINATION ${LIBDIR} RUNTIME DESTINATION ${BINDIR} diff --git a/src/ifcgeom/IfcGeom.h b/src/ifcgeom/IfcGeom.h index f4466798bd..ab564c11f2 100644 --- a/src/ifcgeom/IfcGeom.h +++ b/src/ifcgeom/IfcGeom.h @@ -333,8 +333,6 @@ public: bool is_identity_transform(IfcUtil::IfcBaseClass*); - IfcSchema::IfcRelVoidsElement::list::ptr find_openings(IfcSchema::IfcProduct* product); - IfcSchema::IfcRepresentation* find_representation(const IfcSchema::IfcProduct*, const std::string&); std::pair initializeUnits(IfcSchema::IfcUnitAssignment*); diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/IfcGeomFunctions.cpp index 2dd9f4129b..efe0339cbe 100644 --- a/src/ifcgeom/IfcGeomFunctions.cpp +++ b/src/ifcgeom/IfcGeomFunctions.cpp @@ -216,10 +216,10 @@ namespace { }; } -void MAKE_INIT_FN(KernelImplementation_)(IfcGeom::impl::KernelFactoryImplementation* mapping) { +void MAKE_INIT_FN(KernelImplementation_opencascade_)(IfcGeom::impl::KernelFactoryImplementation* mapping) { static const std::string schema_name = STRINGIFY(IfcSchema); MAKE_TYPE_NAME(factory_t) factory; - mapping->bind(schema_name, factory); + mapping->bind(schema_name, "opencascade", factory); } #define Kernel MAKE_TYPE_NAME(Kernel) @@ -1407,35 +1407,6 @@ void IfcGeom::Kernel::sequence_of_point_to_wire(const TColgp_SequenceOfPnt& p, T w = builder.Wire(); } -IfcSchema::IfcRelVoidsElement::list::ptr IfcGeom::Kernel::find_openings(IfcSchema::IfcProduct* product) { - - IfcSchema::IfcRelVoidsElement::list::ptr openings(new IfcSchema::IfcRelVoidsElement::list); - if ( product->declaration().is(IfcSchema::IfcElement::Class()) && !product->declaration().is(IfcSchema::IfcOpeningElement::Class()) ) { - IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)product; - openings = element->HasOpenings(); - } - - // Is the IfcElement a decomposition of an IfcElement with any IfcOpeningElements? - IfcSchema::IfcObjectDefinition* obdef = product->as(); - for (;;) { -#ifdef USE_IFC4 - IfcSchema::IfcRelAggregates::list::ptr decomposes = obdef->Decomposes(); -#else - IfcSchema::IfcRelDecomposes::list::ptr decomposes = obdef->Decomposes(); -#endif - if (decomposes->size() != 1) break; - IfcSchema::IfcObjectDefinition* rel_obdef = (*decomposes->begin())->RelatingObject(); - if ( rel_obdef->declaration().is(IfcSchema::IfcElement::Class()) && !rel_obdef->declaration().is(IfcSchema::IfcOpeningElement::Class()) ) { - IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)rel_obdef; - openings->push(element->HasOpenings()); - } - - obdef = rel_obdef; - } - - return openings; -} - const IfcSchema::IfcMaterial* IfcGeom::Kernel::get_single_material_association(const IfcSchema::IfcProduct* product) { IfcSchema::IfcMaterial* single_material = 0; IfcSchema::IfcRelAssociatesMaterial::list::ptr associated_materials = product->HasAssociations()->as(); @@ -1569,7 +1540,7 @@ IfcGeom::NativeElement* IfcGeom::Kernel::create_brep_for_representation_a // Does the IfcElement have any IfcOpenings? // Note that openings for IfcOpeningElements are not processed - IfcSchema::IfcRelVoidsElement::list::ptr openings = find_openings(product); + IfcSchema::IfcRelVoidsElement::list::ptr openings = find_openings(product)->as(); const std::string product_type = product->declaration().name(); ElementSettings element_settings(settings, getValue(GV_LENGTH_UNIT), product_type); diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 1a808195cb..fcb766ca11 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -1,6 +1,8 @@ #include "CgalKernel.h" #include "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; @@ -12,7 +14,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRepresentation* l, Convers } else { cgal_shape_t s; if (convert_shape(representation_item, s)) { - shapes.push_back(ConversionResult(new CgalShape(s), get_style(representation_item))); + shapes.push_back(ConversionResult(representation_item->data().id(), new CgalShape(s))); part_succes |= true; } } @@ -21,6 +23,6 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRepresentation* l, Convers return part_succes; } -bool IfcGeom::CgalKernel::convert(const Ifc2x3::IfcExtrudedAreaSolid*, cgal_shape_t&) { +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid*, cgal_shape_t&) { throw std::runtime_error("Not implemented IfcExtrudedAreaSolid"); } diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index e2da8ecd97..3b9ee4d2d3 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -1,6 +1,15 @@ #include "CgalKernel.h" #include "CgalConversionResult.h" -void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const { +template +void triangulate_helper(const cgal_shape_t, const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation* t, int surface_style_id) { throw std::runtime_error("Not implemented Triangulate()"); } + +void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation* 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* t, int surface_style_id) const { + triangulate_helper(shape_, settings, place, t, surface_style_id); +} diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.h b/src/ifcgeom/kernels/cgal/CgalConversionResult.h index 3fb4bb7e67..3b076b487f 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.h +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.h @@ -20,7 +20,7 @@ #ifndef CGALCONVERSIONRESULT_H #define CGALCONVERSIONRESULT_H -#include "../../../ifcgeom/ConversionResult.h" +#include "../../../ifcgeom_schema_agnostic/ConversionResult.h" namespace IfcGeom { @@ -37,17 +37,28 @@ namespace IfcGeom { // Get cell from placement as 4x3 matrix as implemented in OCCT. We'll have to check exact semantics. throw std::runtime_error("Not implemented"); } + virtual void Multiply(const ConversionResultPlacement* other) { // Multiply matrix as implemented in OCCT. We'll have to check exact semantics. throw std::runtime_error("Not implemented"); } + virtual void PreMultiply(const ConversionResultPlacement* other) { // PreMultiply matrix as implemented in OCCT. We'll have to check exact semantics. throw std::runtime_error("Not implemented"); } + 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"); + } private: cgal_placement_t trsf_; }; @@ -61,13 +72,21 @@ namespace IfcGeom { 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 * t, int surface_style_id) const; + virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation* 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_; }; diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp index f3002292d4..6a11d8fa46 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp @@ -23,22 +23,22 @@ #include "CgalKernel.h" #include "CgalConversionResult.h" -using namespace IfcSchema; -using namespace IfcUtil; +#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(new CgalShape(shp), get_style(l->as()))); + r.push_back(IfcGeom::ConversionResult(l->data().id(), new CgalShape(shp))); return true; } return false; } #include "CgalEntityMappingShapes.h" - Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity); + Logger::Message(Logger::LOG_ERROR,"No operation defined for:", l); return false; } @@ -48,7 +48,7 @@ IfcGeom::ShapeType IfcGeom::CgalKernel::shape_type(const IfcBaseClass* l) { } bool IfcGeom::CgalKernel::convert_shape(const IfcBaseClass* l, cgal_shape_t& r) { - const unsigned int id = l->entity->id(); + const unsigned int id = l->data().id(); bool success = false; bool processed = false; bool ignored = false; @@ -76,25 +76,25 @@ bool IfcGeom::CgalKernel::convert_shape(const IfcBaseClass* l, cgal_shape_t& r) const char* const msg = processed ? "Failed to convert:" : "No operation defined for:"; - Logger::Message(Logger::LOG_ERROR, msg, l->entity); + 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->entity); + 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->entity); + 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->entity); + Logger::Message(Logger::LOG_ERROR,"No operation defined for:", l); return false; } diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index eb2ecedf38..3908ded811 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -25,7 +25,6 @@ * * ********************************************************************************/ -#include "../../../ifcparse/IfcUtil.h" #include "../../../ifcparse/IfcParse.h" SHAPES(IfcRepresentation); diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingCurve.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingCurve.h index ac6736626a..5bebf39992 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingCurve.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingCurve.h @@ -1,6 +1,6 @@ #include "CgalEntityMappingUndefine.h" #define CURVE(T) \ - if ( l->is(T::Class()) ) return convert((T*)l,r); + if (l->declaration().is(IfcSchema::T::Class())) return convert((IfcSchema::T*)l,r); #include "CgalEntityMappingDefine.h" #include "CgalEntityMapping.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingFace.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingFace.h index ccebad4e33..65087a1a5f 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingFace.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingFace.h @@ -1,6 +1,6 @@ #include "CgalEntityMappingUndefine.h" #define FACE(T) \ - if ( l->is(T::Class()) ) return convert((T*)l,r); + if (l->declaration().is(IfcSchema::T::Class())) return convert((IfcSchema::T*)l,r); #include "CgalEntityMappingDefine.h" #include "CgalEntityMapping.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingShape.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingShape.h index 736df52c62..14dc9d51e1 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingShape.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingShape.h @@ -1,17 +1,17 @@ #include "CgalEntityMappingUndefine.h" #define SHAPE(T) \ - if ( !processed && l->is(T::Class()) ) { \ + if ( !processed && l->declaration().is(IfcSchema::T::Class()) ) { \ processed = true; \ try { \ - if ( convert((T*)l,r) ) { \ + if (convert((IfcSchema::T*)l, r) ) { \ success = true; \ } \ } catch (const std::exception& e) { \ - Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l->entity); \ + 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->entity); \ + Logger::Message(Logger::LOG_ERROR,"Failed to convert:", l); \ return false; \ } \ } diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingShapeType.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingShapeType.h index 21e6a0cd31..ec25d81d25 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingShapeType.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingShapeType.h @@ -1,14 +1,14 @@ #include "CgalEntityMappingUndefine.h" #define SHAPES(T) \ - if ( l->is(T::Class()) ) return ST_SHAPELIST; + if (l->declaration().is(IfcSchema::T::Class())) return ST_SHAPELIST; #define SHAPE(T) \ - if ( l->is(T::Class()) ) return ST_SHAPE; + if (l->declaration().is(IfcSchema::T::Class())) return ST_SHAPE; #define WIRE(T) \ - if ( l->is(T::Class()) ) return ST_WIRE; + if (l->declaration().is(IfcSchema::T::Class())) return ST_WIRE; #define FACE(T) \ - if ( l->is(T::Class()) ) return ST_FACE; + if (l->declaration().is(IfcSchema::T::Class())) return ST_FACE; #define CURVE(T) \ - if ( l->is(T::Class()) ) return ST_CURVE; + if (l->declaration().is(IfcSchema::T::Class())) return ST_CURVE; #include "CgalEntityMappingDefine.h" #include "CgalEntityMapping.h" diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingShapes.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingShapes.h index 778a5399ac..700b4a08a2 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingShapes.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingShapes.h @@ -1,10 +1,10 @@ #include "CgalEntityMappingUndefine.h" #define SHAPES(T) \ - if ( l->is(T::Class()) ) { \ + if (l->declaration().is(IfcSchema::T::Class())) { \ try { \ - return convert((T*)l,r); \ + return convert((IfcSchema::T*)l,r); \ } catch (const std::exception& e) { \ - Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l->entity); \ + Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l); \ } \ return false; \ } diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingWire.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingWire.h index ed5461ba75..459ad8267c 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingWire.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMappingWire.h @@ -1,6 +1,6 @@ #include "CgalEntityMappingUndefine.h" #define WIRE(T) \ - if ( l->is(T::Class()) ) return convert((T*)l,r); + if (l->declaration().is(IfcSchema::T::Class())) return convert((IfcSchema::T*)l,r); #include "CgalEntityMappingDefine.h" #include "CgalEntityMapping.h" diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index f4f830cbee..42e2a36010 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -23,6 +23,23 @@ #include "CgalKernel.h" #include "CgalConversionResult.h" +namespace { + struct MAKE_TYPE_NAME(factory_t) { + IfcGeom::Kernel* operator()(IfcParse::IfcFile* file) const { + IfcGeom::MAKE_TYPE_NAME(Kernel)* k = new IfcGeom::MAKE_TYPE_NAME(Kernel); + 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(IfcUtil::IfcBaseClass* l) { Logger::Message(Logger::LOG_ERROR, "Not implemented is_identity_transform()"); return false; @@ -70,7 +87,7 @@ bool IfcGeom::CgalKernel::is_identity_transform(IfcUtil::IfcBaseClass* l) { IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representation_and_product( const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product) { - IfcGeom::Representation::Native* shape; + IfcGeom::Representation::BRep* shape; IfcGeom::ConversionResults shapes, shapes2; if (!convert_shapes(representation, shapes)) { @@ -83,11 +100,13 @@ IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representat int parent_id = -1; try { - IfcSchema::IfcObjectDefinition* parent_object = get_decomposing_entity(product); - if (parent_object) { - parent_id = parent_object->entity->id(); + IfcUtil::IfcBaseEntity* parent_object = get_decomposing_entity(product); + if (parent_object && parent_object->as()) { + parent_id = parent_object->data().id(); } - } catch (...) {} + } catch (const std::exception& e) { + Logger::Error(e); + } const std::string name = product->hasName() ? product->Name() : ""; const std::string guid = product->GlobalId(); @@ -97,18 +116,21 @@ IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representat // convert(product->ObjectPlacement(), trsf); } catch (...) {} + std::stringstream representation_id_builder; + representation_id_builder << representation->data().id(); + // Does the IfcElement have any IfcOpenings? // Note that openings for IfcOpeningElements are not processed - IfcSchema::IfcRelVoidsElement::list::ptr openings = find_openings(product); + IfcSchema::IfcRelVoidsElement::list::ptr openings = find_openings(product)->as(); - const std::string product_type = IfcSchema::Type::ToString(product->type()); + 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()) { Logger::Message(Logger::LOG_ERROR, "Not implemented opening subtractions"); } - shape = new IfcGeom::Representation::Native(element_settings, representation->entity->id(), shapes); + shape = new IfcGeom::Representation::BRep(element_settings, representation_id_builder.str(), shapes); std::string context_string = ""; if (representation->hasRepresentationIdentifier()) { @@ -118,14 +140,15 @@ IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representat } return new NativeElement( - product->entity->id(), + product->data().id(), parent_id, name, product_type, guid, context_string, new CgalPlacement(trsf), - boost::shared_ptr(shape) + boost::shared_ptr(shape), + product ); } @@ -135,11 +158,13 @@ IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_processed_r { int parent_id = -1; try { - IfcSchema::IfcObjectDefinition* parent_object = get_decomposing_entity(product); - if (parent_object) { - parent_id = parent_object->entity->id(); + IfcUtil::IfcBaseEntity* parent_object = get_decomposing_entity(product); + if (parent_object && parent_object->as()) { + parent_id = parent_object->data().id(); } - } catch (...) {} + } catch (const std::exception& e) { + Logger::Error(e); + } const std::string name = product->hasName() ? product->Name() : ""; const std::string guid = product->GlobalId(); @@ -156,16 +181,17 @@ IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_processed_r context_string = representation->ContextOfItems()->ContextType(); } - const std::string product_type = IfcSchema::Type::ToString(product->type()); + const std::string product_type = product->declaration().name(); return new NativeElement( - product->entity->id(), + product->data().id(), parent_id, name, product_type, guid, context_string, new CgalPlacement(trsf), - brep->geometry_pointer() + brep->geometry_pointer(), + product ); } diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index a3e7167624..8eef64f8da 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -52,7 +52,7 @@ namespace IfcGeom { std::map Shape; }; - class IFC_GEOM_API CgalKernel : public AbstractKernel { + class IFC_GEOM_API MAKE_TYPE_NAME(CgalKernel) : public Kernel { public: #ifndef NO_CACHE diff --git a/src/ifcgeom_schema_agnostic/Kernel.cpp b/src/ifcgeom_schema_agnostic/Kernel.cpp index ecd738a048..ecc9562e97 100644 --- a/src/ifcgeom_schema_agnostic/Kernel.cpp +++ b/src/ifcgeom_schema_agnostic/Kernel.cpp @@ -5,14 +5,14 @@ #include #include -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); } } @@ -48,23 +48,27 @@ 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*); +extern void init_KernelImplementation_cgal_Ifc2x3(IfcGeom::impl::KernelFactoryImplementation*); +extern void init_KernelImplementation_cgal_Ifc4(IfcGeom::impl::KernelFactoryImplementation*); IfcGeom::impl::KernelFactoryImplementation::KernelFactoryImplementation() { - init_KernelImplementation_Ifc2x3(this); - init_KernelImplementation_Ifc4(this); + init_KernelImplementation_opencascade_Ifc2x3(this); + init_KernelImplementation_opencascade_Ifc4(this); + init_KernelImplementation_cgal_Ifc2x3(this); + init_KernelImplementation_cgal_Ifc4(this); } -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::const_iterator it; - it = this->find(schema_name_lower); + std::map, 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); } @@ -216,4 +220,42 @@ bool IfcGeom::Kernel::is_manifold(const TopoDS_Shape& a) { return true; } -} \ No newline at end of file +} + +namespace { + template + 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->as(); + for (;;) { + auto decomposes = obdef->Decomposes()->generalize(); + if (decomposes->size() != 1) break; + typename Schema::IfcObjectDefinition* rel_obdef = (*decomposes->begin())->as()->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()) { + return find_openings_helper(inst->as()); + } else if (inst->as()) { + return find_openings_helper(inst->as()); + } else { + throw IfcParse::IfcException("Unexpected entity " + inst->declaration().name()); + } +} diff --git a/src/ifcgeom_schema_agnostic/Kernel.h b/src/ifcgeom_schema_agnostic/Kernel.h index 5f1fdac66c..75c93d2c39 100644 --- a/src/ifcgeom_schema_agnostic/Kernel.h +++ b/src/ifcgeom_schema_agnostic/Kernel.h @@ -52,7 +52,7 @@ namespace IfcGeom { GV_DIMENSIONALITY }; - Kernel(IfcParse::IfcFile* file_ = 0); + Kernel(const std::string& geometry_library, IfcParse::IfcFile* file_ = 0); virtual ~Kernel() {} @@ -85,16 +85,17 @@ namespace IfcGeom { static bool is_manifold(const TopoDS_Shape& a); static IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity*); static std::map get_layers(IfcUtil::IfcBaseEntity*); + static IfcEntityList::ptr find_openings(IfcUtil::IfcBaseEntity* product); }; namespace impl { typedef boost::function1 kernel_fn; - class KernelFactoryImplementation : public std::map { + class KernelFactoryImplementation : public std::map, 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(); diff --git a/src/serializers/SvgSerializer.cpp b/src/serializers/SvgSerializer.cpp index 720448294a..d1af9174f4 100644 --- a/src/serializers/SvgSerializer.cpp +++ b/src/serializers/SvgSerializer.cpp @@ -501,7 +501,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 to_derive_from; to_derive_from.push_back(f->schema()->declaration_by_name("IfcBuilding")); From 5a7c7ed048f7aaf27f6341bb024611d20d0e6241 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 18 Jan 2019 16:43:38 +0100 Subject: [PATCH 128/235] Shuffle project structure --- cmake/CMakeLists.txt | 45 +++++++++---------- src/examples/IfcAdvancedHouse.cpp | 2 +- src/examples/IfcOpenHouse.cpp | 2 +- src/ifcconvert/IfcConvert.cpp | 6 +-- .../kernels/cgal/CgalConversionResult.h | 2 +- .../kernels/cgal/CgalEntityMapping.cpp | 3 -- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 31 +++++++++---- src/ifcgeom/kernels/cgal/CgalKernel.h | 24 ++++++++-- .../{ => kernels/opencascade}/IfcGeom.h | 25 ++++++----- .../opencascade}/IfcGeomCurves.cpp | 2 +- .../opencascade}/IfcGeomFaces.cpp | 2 +- .../opencascade}/IfcGeomFunctions.cpp | 10 ++--- .../opencascade}/IfcGeomHelpers.cpp | 2 +- .../IfcGeomIteratorImplementation.cpp | 2 +- .../IfcGeomIteratorImplementation.h | 16 +++---- .../opencascade}/IfcGeomRenderStyles.cpp | 0 .../opencascade}/IfcGeomSerialisation.cpp | 0 .../opencascade}/IfcGeomShapeType.h | 0 .../opencascade}/IfcGeomShapes.cpp | 2 +- .../{ => kernels/opencascade}/IfcGeomTree.h | 8 ++-- .../opencascade}/IfcGeomWires.cpp | 2 +- .../{ => kernels/opencascade}/IfcRegister.cpp | 0 .../{ => kernels/opencascade}/IfcRegister.h | 4 +- .../opencascade}/IfcRegisterConvertCurve.h | 0 .../opencascade}/IfcRegisterConvertFace.h | 0 .../opencascade}/IfcRegisterConvertShape.h | 0 .../opencascade}/IfcRegisterConvertShapes.h | 0 .../opencascade}/IfcRegisterConvertWire.h | 0 .../opencascade}/IfcRegisterCreateCache.h | 0 .../opencascade}/IfcRegisterDef.h | 0 .../opencascade}/IfcRegisterGeomHeader.h | 0 .../opencascade}/IfcRegisterPurgeCache.h | 0 .../opencascade}/IfcRegisterShapeType.h | 0 .../opencascade}/IfcRegisterUndef.h | 0 .../OpenCascadeConversionResult.h | 2 +- .../opencascade}/OpenCascadeShape.cpp | 4 +- .../schema_agnostic}/ConversionResult.h | 4 +- .../schema_agnostic}/IfcGeomElement.h | 7 +-- .../schema_agnostic}/IfcGeomFilter.h | 4 +- .../schema_agnostic}/IfcGeomIterator.h | 2 +- .../IfcGeomIteratorSettings.h | 6 +-- .../schema_agnostic}/IfcGeomMaterial.cpp | 0 .../schema_agnostic}/IfcGeomMaterial.h | 2 +- .../schema_agnostic}/IfcGeomRenderStyles.h | 2 +- .../IfcGeomRepresentation.cpp | 4 +- .../schema_agnostic}/IfcGeomRepresentation.h | 6 +-- .../IteratorImplementation.cpp | 0 .../schema_agnostic}/IteratorImplementation.h | 6 +-- .../schema_agnostic}/Kernel.cpp | 3 ++ .../schema_agnostic}/Kernel.h | 9 ++-- .../schema_agnostic}/Serialization.cpp | 0 .../schema_agnostic}/Serialization.h | 5 ++- .../schema_agnostic}/SurfaceStyle.cpp | 2 +- .../schema_agnostic}/ifc_geom_api.h | 0 src/ifcgeomserver/IfcGeomServer.cpp | 4 +- src/ifcparse/IfcParse.h | 2 +- src/ifcwrap/IfcPython.i | 4 +- src/serializers/ColladaSerializer.h | 2 +- src/serializers/GeometrySerializer.h | 4 +- src/serializers/OpenCascadeBasedSerializer.h | 4 +- src/serializers/StepSerializer.h | 2 +- src/serializers/WavefrontObjSerializer.cpp | 2 +- .../schema_dependent/XmlSerializer.cpp | 2 +- 63 files changed, 155 insertions(+), 129 deletions(-) rename src/ifcgeom/{ => kernels/opencascade}/IfcGeom.h (96%) rename src/ifcgeom/{ => kernels/opencascade}/IfcGeomCurves.cpp (99%) rename src/ifcgeom/{ => kernels/opencascade}/IfcGeomFaces.cpp (99%) rename src/ifcgeom/{ => kernels/opencascade}/IfcGeomFunctions.cpp (99%) rename src/ifcgeom/{ => kernels/opencascade}/IfcGeomHelpers.cpp (99%) rename src/ifcgeom/{ => kernels/opencascade}/IfcGeomIteratorImplementation.cpp (95%) rename src/ifcgeom/{ => kernels/opencascade}/IfcGeomIteratorImplementation.h (98%) rename src/ifcgeom/{ => kernels/opencascade}/IfcGeomRenderStyles.cpp (100%) rename src/ifcgeom/{ => kernels/opencascade}/IfcGeomSerialisation.cpp (100%) rename src/ifcgeom/{ => kernels/opencascade}/IfcGeomShapeType.h (100%) rename src/ifcgeom/{ => kernels/opencascade}/IfcGeomShapes.cpp (99%) rename src/ifcgeom/{ => kernels/opencascade}/IfcGeomTree.h (97%) rename src/ifcgeom/{ => kernels/opencascade}/IfcGeomWires.cpp (99%) rename src/ifcgeom/{ => kernels/opencascade}/IfcRegister.cpp (100%) rename src/ifcgeom/{ => kernels/opencascade}/IfcRegister.h (98%) rename src/ifcgeom/{ => kernels/opencascade}/IfcRegisterConvertCurve.h (100%) rename src/ifcgeom/{ => kernels/opencascade}/IfcRegisterConvertFace.h (100%) rename src/ifcgeom/{ => kernels/opencascade}/IfcRegisterConvertShape.h (100%) rename src/ifcgeom/{ => kernels/opencascade}/IfcRegisterConvertShapes.h (100%) rename src/ifcgeom/{ => kernels/opencascade}/IfcRegisterConvertWire.h (100%) rename src/ifcgeom/{ => kernels/opencascade}/IfcRegisterCreateCache.h (100%) rename src/ifcgeom/{ => kernels/opencascade}/IfcRegisterDef.h (100%) rename src/ifcgeom/{ => kernels/opencascade}/IfcRegisterGeomHeader.h (100%) rename src/ifcgeom/{ => kernels/opencascade}/IfcRegisterPurgeCache.h (100%) rename src/ifcgeom/{ => kernels/opencascade}/IfcRegisterShapeType.h (100%) rename src/ifcgeom/{ => kernels/opencascade}/IfcRegisterUndef.h (100%) rename src/ifcgeom/{ => kernels/opencascade}/OpenCascadeConversionResult.h (98%) rename src/ifcgeom/{ => kernels/opencascade}/OpenCascadeShape.cpp (98%) rename src/{ifcgeom_schema_agnostic => ifcgeom/schema_agnostic}/ConversionResult.h (97%) rename src/{ifcgeom_schema_agnostic => ifcgeom/schema_agnostic}/IfcGeomElement.h (98%) rename src/{ifcgeom_schema_agnostic => ifcgeom/schema_agnostic}/IfcGeomFilter.h (99%) rename src/{ifcgeom_schema_agnostic => ifcgeom/schema_agnostic}/IfcGeomIterator.h (99%) rename src/{ifcgeom_schema_agnostic => ifcgeom/schema_agnostic}/IfcGeomIteratorSettings.h (98%) rename src/{ifcgeom_schema_agnostic => ifcgeom/schema_agnostic}/IfcGeomMaterial.cpp (100%) rename src/{ifcgeom_schema_agnostic => ifcgeom/schema_agnostic}/IfcGeomMaterial.h (97%) rename src/{ifcgeom_schema_agnostic => ifcgeom/schema_agnostic}/IfcGeomRenderStyles.h (98%) rename src/{ifcgeom_schema_agnostic => ifcgeom/schema_agnostic}/IfcGeomRepresentation.cpp (98%) rename src/{ifcgeom_schema_agnostic => ifcgeom/schema_agnostic}/IfcGeomRepresentation.h (98%) rename src/{ifcgeom_schema_agnostic => ifcgeom/schema_agnostic}/IteratorImplementation.cpp (100%) rename src/{ifcgeom_schema_agnostic => ifcgeom/schema_agnostic}/IteratorImplementation.h (94%) rename src/{ifcgeom_schema_agnostic => ifcgeom/schema_agnostic}/Kernel.cpp (99%) rename src/{ifcgeom_schema_agnostic => ifcgeom/schema_agnostic}/Kernel.h (93%) rename src/{ifcgeom_schema_agnostic => ifcgeom/schema_agnostic}/Serialization.cpp (100%) rename src/{ifcgeom_schema_agnostic => ifcgeom/schema_agnostic}/Serialization.h (76%) rename src/{ifcgeom_schema_agnostic => ifcgeom/schema_agnostic}/SurfaceStyle.cpp (98%) rename src/{ifcgeom_schema_agnostic => ifcgeom/schema_agnostic}/ifc_geom_api.h (100%) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 344f0ac5f1..8877c98919 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -554,42 +554,39 @@ ENDIF() if (BUILD_IFCGEOM) -### OCCT +foreach(schema 2x3 4) -# IfcGeom, schema dependent, OCCT -file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/*.h) -file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/*.cpp) +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}) -foreach(schema 2x3 4) -add_library(IfcGeom_occt_ifc${schema} ${IFCGEOM_FILES}) -set_target_properties(IfcGeom_occt_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema} -DUSE_IFC${schema}") -TARGET_LINK_LIBRARIES(IfcGeom_occt_ifc${schema} IfcParse ${OPENCASCADE_LIBRARIES}) -list(APPEND IfcGeom_libraries IfcGeom_occt_ifc${schema}) -endforeach() +add_library(IfcGeom_ifc${schema} ${IFCGEOM_FILES}) +set_target_properties(IfcGeom_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema} -DUSE_IFC${schema}") +target_link_libraries(IfcGeom_ifc${schema} IfcParse) +list(APPEND IfcGeom_libraries IfcGeom_ifc${schema}) -### CGAL +foreach(kernel opencascade cgal) +string(TOUPPER ${kernel} KERNEL_UPPER) -# IfcGeom, schema dependent, CGAL -file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/kernels/cgal/*.h) -file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/kernels/cgal/*.cpp) +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}) -foreach(schema 2x3 4) -add_library(IfcGeom_cgal_ifc${schema} ${IFCGEOM_FILES}) -set_target_properties(IfcGeom_cgal_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema} -DUSE_IFC${schema}") -TARGET_LINK_LIBRARIES(IfcGeom_cgal_ifc${schema} IfcParse ${OPENCASCADE_LIBRARIES}) -list(APPEND IfcGeom_libraries IfcGeom_cgal_ifc${schema}) +add_library(IfcGeom_${kernel}_ifc${schema} ${IFCGEOM_FILES}) +set_target_properties(IfcGeom_${kernel}_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema} -DUSE_IFC${schema}") +target_link_libraries(IfcGeom_${kernel}_ifc${schema} IfcGeom_ifc${schema} ${${KERNEL_UPPER}_LIBRARIES}) +list(APPEND IfcGeom_libraries IfcGeom_${kernel}_ifc${schema}) endforeach() -# IfcGeom, schema and kernel agnostic -file(GLOB SCHEMA_AGNOSTIC_H_FILES ../src/ifcgeom_schema_agnostic/*.h) -file(GLOB SCHEMA_AGNOSTIC_CPP_FILES ../src/ifcgeom_schema_agnostic/*.cpp) +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}) set_target_properties(IfcGeom PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS) -TARGET_LINK_LIBRARIES(IfcGeom ${IfcGeom_libraries}) +target_link_libraries(IfcGeom ${IfcGeom_libraries}) endif(BUILD_IFCGEOM) @@ -692,7 +689,7 @@ INSTALL(FILES ${IFCGEOM_H_FILES} ) INSTALL(FILES ${SCHEMA_AGNOSTIC_H_FILES} - DESTINATION ${INCLUDEDIR}/ifcgeom_schema_agnostic + DESTINATION ${INCLUDEDIR}/ifcgeom/schema_agnostic ) INSTALL(TARGETS IfcGeom ${IfcGeom_libraries} diff --git a/src/examples/IfcAdvancedHouse.cpp b/src/examples/IfcAdvancedHouse.cpp index 4372129fc9..3de0d52e34 100644 --- a/src/examples/IfcAdvancedHouse.cpp +++ b/src/examples/IfcAdvancedHouse.cpp @@ -49,7 +49,7 @@ #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 diff --git a/src/examples/IfcOpenHouse.cpp b/src/examples/IfcOpenHouse.cpp index e94042e9da..b3e0f7f10b 100644 --- a/src/examples/IfcOpenHouse.cpp +++ b/src/examples/IfcOpenHouse.cpp @@ -44,7 +44,7 @@ #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 diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 2e7ac79e7a..5c1b7d5c58 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -33,9 +33,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 diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.h b/src/ifcgeom/kernels/cgal/CgalConversionResult.h index 3b076b487f..4d78b23e2a 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.h +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.h @@ -20,7 +20,7 @@ #ifndef CGALCONVERSIONRESULT_H #define CGALCONVERSIONRESULT_H -#include "../../../ifcgeom_schema_agnostic/ConversionResult.h" +#include "../../../ifcgeom/schema_agnostic/ConversionResult.h" namespace IfcGeom { diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp index 6a11d8fa46..c92ac7c166 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp @@ -17,9 +17,6 @@ * * ********************************************************************************/ -#include "../../../ifcgeom/IfcGeomShapeType.h" -#include "../../../ifcgeom/IfcGeom.h" - #include "CgalKernel.h" #include "CgalConversionResult.h" diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index 42e2a36010..4c67c670ba 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -17,16 +17,13 @@ * * ********************************************************************************/ -#include "../../../ifcgeom/IfcGeomShapeType.h" -#include "../../../ifcgeom/IfcGeom.h" - #include "CgalKernel.h" #include "CgalConversionResult.h" namespace { struct MAKE_TYPE_NAME(factory_t) { IfcGeom::Kernel* operator()(IfcParse::IfcFile* file) const { - IfcGeom::MAKE_TYPE_NAME(Kernel)* k = new IfcGeom::MAKE_TYPE_NAME(Kernel); + IfcGeom::MAKE_TYPE_NAME(CgalKernel)* k = new IfcGeom::MAKE_TYPE_NAME(CgalKernel); return k; } }; @@ -84,7 +81,8 @@ bool IfcGeom::CgalKernel::is_identity_transform(IfcUtil::IfcBaseClass* l) { */ } -IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representation_and_product( +template +IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representation_and_product( const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product) { IfcGeom::Representation::BRep* shape; @@ -139,7 +137,7 @@ IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representat context_string = representation->ContextOfItems()->ContextType(); } - return new NativeElement( + return new NativeElement( product->data().id(), parent_id, name, @@ -152,9 +150,10 @@ IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representat ); } -IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_processed_representation( +template +IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_processed_representation( const IteratorSettings& /*settings*/, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, - IfcGeom::NativeElement* brep) + IfcGeom::NativeElement* brep) { int parent_id = -1; try { @@ -183,7 +182,7 @@ IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_processed_r const std::string product_type = product->declaration().name(); - return new NativeElement( + return new NativeElement( product->data().id(), parent_id, name, @@ -195,3 +194,17 @@ IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_processed_r product ); } + +template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representation_and_product( + const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); +template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representation_and_product( + const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); +template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representation_and_product( + const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); + +template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_processed_representation( + const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); +template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_processed_representation( + const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); +template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_processed_representation( + const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 8eef64f8da..5d9cfd21fe 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -35,7 +35,16 @@ if ( it != cache.T.end() ) { e = it->second; return true; } #endif */ -#include "../../../ifcgeom/IfcGeom.h" +#include "../../../ifcparse/macros.h" +#include "../../../ifcgeom/schema_agnostic/Kernel.h" +#include "../../../ifcgeom/schema_agnostic/IfcGeomElement.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 typedef void* cgal_shape_t; typedef void* cgal_face_t; @@ -55,6 +64,8 @@ namespace IfcGeom { class IFC_GEOM_API MAKE_TYPE_NAME(CgalKernel) : public Kernel { public: + MAKE_TYPE_NAME(CgalKernel)() : Kernel("cgal") {} + #ifndef NO_CACHE CgalCache cache; #endif @@ -79,10 +90,15 @@ namespace IfcGeom { } virtual bool is_identity_transform(IfcUtil::IfcBaseClass*); - virtual IfcGeom::NativeElement* create_brep_for_representation_and_product( + + template + IfcGeom::NativeElement* create_brep_for_representation_and_product( const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*); - virtual IfcGeom::NativeElement* create_brep_for_processed_representation( - const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::NativeElement*); + + template + IfcGeom::NativeElement* create_brep_for_processed_representation( + const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::NativeElement*); + #include "CgalEntityMappingDeclaration.h" diff --git a/src/ifcgeom/IfcGeom.h b/src/ifcgeom/kernels/opencascade/IfcGeom.h similarity index 96% rename from src/ifcgeom/IfcGeom.h rename to src/ifcgeom/kernels/opencascade/IfcGeom.h index ab564c11f2..0663450788 100644 --- a/src/ifcgeom/IfcGeom.h +++ b/src/ifcgeom/kernels/opencascade/IfcGeom.h @@ -48,19 +48,19 @@ inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance=ALMO #include #include -#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_schema_agnostic/IfcGeomElement.h" -#include "../ifcgeom_schema_agnostic/IfcGeomRepresentation.h" -#include "../ifcgeom_schema_agnostic/ConversionResult.h" -#include "../ifcgeom/IfcGeomShapeType.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 "../ifcgeom_schema_agnostic/Kernel.h" +#include "../../../ifcgeom/schema_agnostic/Kernel.h" #include "OpenCascadeConversionResult.h" -#include "../ifcgeom_schema_agnostic/ifc_geom_api.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 @@ -79,8 +79,9 @@ 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) +#define INCLUDE_SCHEMA(x) STRINGIFY(../../../ifcparse/x.h) +#include INCLUDE_SCHEMA(IfcSchema) +#undef INCLUDE_SCHEMA namespace IfcGeom { class IFC_GEOM_API geometry_exception : public std::exception { @@ -228,7 +229,7 @@ private: public: MAKE_TYPE_NAME(Kernel)() - : IfcGeom::Kernel(0) + : IfcGeom::Kernel("opencascade", 0) , deflection_tolerance(0.001) , wire_creation_tolerance(0.0001) , point_equality_tolerance(0.00001) diff --git a/src/ifcgeom/IfcGeomCurves.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomCurves.cpp similarity index 99% rename from src/ifcgeom/IfcGeomCurves.cpp rename to src/ifcgeom/kernels/opencascade/IfcGeomCurves.cpp index d2acb0523b..a2dc30343a 100644 --- a/src/ifcgeom/IfcGeomCurves.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomCurves.cpp @@ -81,7 +81,7 @@ #include #endif -#include "../ifcgeom/IfcGeom.h" +#include "../../../ifcgeom/kernels/opencascade/IfcGeom.h" #define Kernel MAKE_TYPE_NAME(Kernel) diff --git a/src/ifcgeom/IfcGeomFaces.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomFaces.cpp similarity index 99% rename from src/ifcgeom/IfcGeomFaces.cpp rename to src/ifcgeom/kernels/opencascade/IfcGeomFaces.cpp index 6ba4746f42..6e2943d3c6 100644 --- a/src/ifcgeom/IfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomFaces.cpp @@ -102,7 +102,7 @@ #include #endif -#include "../ifcgeom/IfcGeom.h" +#include "../../../ifcgeom/kernels/opencascade/IfcGeom.h" #define Kernel MAKE_TYPE_NAME(Kernel) diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp similarity index 99% rename from src/ifcgeom/IfcGeomFunctions.cpp rename to src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp index efe0339cbe..5bc687e718 100644 --- a/src/ifcgeom/IfcGeomFunctions.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp @@ -146,11 +146,11 @@ #include #include -#include "../ifcparse/macros.h" -#include "../ifcparse/IfcSIPrefix.h" -#include "../ifcparse/IfcFile.h" -#include "../ifcgeom/IfcGeom.h" -#include "../ifcgeom/IfcGeomTree.h" +#include "../../../ifcparse/macros.h" +#include "../../../ifcparse/IfcSIPrefix.h" +#include "../../../ifcparse/IfcFile.h" +#include "../../../ifcgeom/kernels/opencascade/IfcGeom.h" +#include "../../../ifcgeom/kernels/opencascade/IfcGeomTree.h" #include diff --git a/src/ifcgeom/IfcGeomHelpers.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomHelpers.cpp similarity index 99% rename from src/ifcgeom/IfcGeomHelpers.cpp rename to src/ifcgeom/kernels/opencascade/IfcGeomHelpers.cpp index 0b6df4d931..99db68c5ab 100644 --- a/src/ifcgeom/IfcGeomHelpers.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomHelpers.cpp @@ -75,7 +75,7 @@ #include -#include "../ifcgeom/IfcGeom.h" +#include "../../../ifcgeom/kernels/opencascade/IfcGeom.h" #define Kernel MAKE_TYPE_NAME(Kernel) diff --git a/src/ifcgeom/IfcGeomIteratorImplementation.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomIteratorImplementation.cpp similarity index 95% rename from src/ifcgeom/IfcGeomIteratorImplementation.cpp rename to src/ifcgeom/kernels/opencascade/IfcGeomIteratorImplementation.cpp index d693dbfa68..82fc1cc17b 100644 --- a/src/ifcgeom/IfcGeomIteratorImplementation.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomIteratorImplementation.cpp @@ -1,5 +1,5 @@ #include "IfcGeomIteratorImplementation.h" -#include "../ifcgeom_schema_agnostic/IteratorImplementation.h" +#include "../../../ifcgeom/schema_agnostic/IteratorImplementation.h" namespace IfcGeom { template class MAKE_TYPE_NAME(IteratorImplementation_); diff --git a/src/ifcgeom/IfcGeomIteratorImplementation.h b/src/ifcgeom/kernels/opencascade/IfcGeomIteratorImplementation.h similarity index 98% rename from src/ifcgeom/IfcGeomIteratorImplementation.h rename to src/ifcgeom/kernels/opencascade/IfcGeomIteratorImplementation.h index b430a79edd..1741c84e2f 100644 --- a/src/ifcgeom/IfcGeomIteratorImplementation.h +++ b/src/ifcgeom/kernels/opencascade/IfcGeomIteratorImplementation.h @@ -73,16 +73,16 @@ #include #include -#include "../ifcparse/IfcFile.h" +#include "../../../ifcparse/IfcFile.h" -#include "../ifcgeom/IfcGeom.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/kernels/opencascade/IfcGeom.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" // The infamous min & max Win32 #defines can leak here from OCE depending on the build configuration #ifdef min diff --git a/src/ifcgeom/IfcGeomRenderStyles.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomRenderStyles.cpp similarity index 100% rename from src/ifcgeom/IfcGeomRenderStyles.cpp rename to src/ifcgeom/kernels/opencascade/IfcGeomRenderStyles.cpp diff --git a/src/ifcgeom/IfcGeomSerialisation.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomSerialisation.cpp similarity index 100% rename from src/ifcgeom/IfcGeomSerialisation.cpp rename to src/ifcgeom/kernels/opencascade/IfcGeomSerialisation.cpp diff --git a/src/ifcgeom/IfcGeomShapeType.h b/src/ifcgeom/kernels/opencascade/IfcGeomShapeType.h similarity index 100% rename from src/ifcgeom/IfcGeomShapeType.h rename to src/ifcgeom/kernels/opencascade/IfcGeomShapeType.h diff --git a/src/ifcgeom/IfcGeomShapes.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp similarity index 99% rename from src/ifcgeom/IfcGeomShapes.cpp rename to src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp index 1ace031e56..7b10f3579b 100644 --- a/src/ifcgeom/IfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp @@ -101,7 +101,7 @@ #include -#include "../ifcgeom/IfcGeom.h" +#include "../../../ifcgeom/kernels/opencascade/IfcGeom.h" #include diff --git a/src/ifcgeom/IfcGeomTree.h b/src/ifcgeom/kernels/opencascade/IfcGeomTree.h similarity index 97% rename from src/ifcgeom/IfcGeomTree.h rename to src/ifcgeom/kernels/opencascade/IfcGeomTree.h index e369acc5d3..a1f5ff83e2 100644 --- a/src/ifcgeom/IfcGeomTree.h +++ b/src/ifcgeom/kernels/opencascade/IfcGeomTree.h @@ -20,10 +20,10 @@ #ifndef IFCGEOMTREE_H #define IFCGEOMTREE_H -#include "../ifcparse/IfcFile.h" -#include "../ifcgeom_schema_agnostic/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 #include diff --git a/src/ifcgeom/IfcGeomWires.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomWires.cpp similarity index 99% rename from src/ifcgeom/IfcGeomWires.cpp rename to src/ifcgeom/kernels/opencascade/IfcGeomWires.cpp index 347b9dc87e..8ccff67a3d 100644 --- a/src/ifcgeom/IfcGeomWires.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomWires.cpp @@ -95,7 +95,7 @@ #include #include -#include "../ifcgeom/IfcGeom.h" +#include "../../../ifcgeom/kernels/opencascade/IfcGeom.h" #define Kernel MAKE_TYPE_NAME(Kernel) diff --git a/src/ifcgeom/IfcRegister.cpp b/src/ifcgeom/kernels/opencascade/IfcRegister.cpp similarity index 100% rename from src/ifcgeom/IfcRegister.cpp rename to src/ifcgeom/kernels/opencascade/IfcRegister.cpp diff --git a/src/ifcgeom/IfcRegister.h b/src/ifcgeom/kernels/opencascade/IfcRegister.h similarity index 98% rename from src/ifcgeom/IfcRegister.h rename to src/ifcgeom/kernels/opencascade/IfcRegister.h index 36bed45ee0..380be6d695 100644 --- a/src/ifcgeom/IfcRegister.h +++ b/src/ifcgeom/kernels/opencascade/IfcRegister.h @@ -38,8 +38,8 @@ #include #include -#include "../ifcparse/IfcBaseClass.h" -#include "../ifcparse/IfcParse.h" +#include "../../../ifcparse/IfcBaseClass.h" +#include "../../../ifcparse/IfcParse.h" SHAPES(IfcShellBasedSurfaceModel); SHAPES(IfcFaceBasedSurfaceModel); diff --git a/src/ifcgeom/IfcRegisterConvertCurve.h b/src/ifcgeom/kernels/opencascade/IfcRegisterConvertCurve.h similarity index 100% rename from src/ifcgeom/IfcRegisterConvertCurve.h rename to src/ifcgeom/kernels/opencascade/IfcRegisterConvertCurve.h diff --git a/src/ifcgeom/IfcRegisterConvertFace.h b/src/ifcgeom/kernels/opencascade/IfcRegisterConvertFace.h similarity index 100% rename from src/ifcgeom/IfcRegisterConvertFace.h rename to src/ifcgeom/kernels/opencascade/IfcRegisterConvertFace.h diff --git a/src/ifcgeom/IfcRegisterConvertShape.h b/src/ifcgeom/kernels/opencascade/IfcRegisterConvertShape.h similarity index 100% rename from src/ifcgeom/IfcRegisterConvertShape.h rename to src/ifcgeom/kernels/opencascade/IfcRegisterConvertShape.h diff --git a/src/ifcgeom/IfcRegisterConvertShapes.h b/src/ifcgeom/kernels/opencascade/IfcRegisterConvertShapes.h similarity index 100% rename from src/ifcgeom/IfcRegisterConvertShapes.h rename to src/ifcgeom/kernels/opencascade/IfcRegisterConvertShapes.h diff --git a/src/ifcgeom/IfcRegisterConvertWire.h b/src/ifcgeom/kernels/opencascade/IfcRegisterConvertWire.h similarity index 100% rename from src/ifcgeom/IfcRegisterConvertWire.h rename to src/ifcgeom/kernels/opencascade/IfcRegisterConvertWire.h diff --git a/src/ifcgeom/IfcRegisterCreateCache.h b/src/ifcgeom/kernels/opencascade/IfcRegisterCreateCache.h similarity index 100% rename from src/ifcgeom/IfcRegisterCreateCache.h rename to src/ifcgeom/kernels/opencascade/IfcRegisterCreateCache.h diff --git a/src/ifcgeom/IfcRegisterDef.h b/src/ifcgeom/kernels/opencascade/IfcRegisterDef.h similarity index 100% rename from src/ifcgeom/IfcRegisterDef.h rename to src/ifcgeom/kernels/opencascade/IfcRegisterDef.h diff --git a/src/ifcgeom/IfcRegisterGeomHeader.h b/src/ifcgeom/kernels/opencascade/IfcRegisterGeomHeader.h similarity index 100% rename from src/ifcgeom/IfcRegisterGeomHeader.h rename to src/ifcgeom/kernels/opencascade/IfcRegisterGeomHeader.h diff --git a/src/ifcgeom/IfcRegisterPurgeCache.h b/src/ifcgeom/kernels/opencascade/IfcRegisterPurgeCache.h similarity index 100% rename from src/ifcgeom/IfcRegisterPurgeCache.h rename to src/ifcgeom/kernels/opencascade/IfcRegisterPurgeCache.h diff --git a/src/ifcgeom/IfcRegisterShapeType.h b/src/ifcgeom/kernels/opencascade/IfcRegisterShapeType.h similarity index 100% rename from src/ifcgeom/IfcRegisterShapeType.h rename to src/ifcgeom/kernels/opencascade/IfcRegisterShapeType.h diff --git a/src/ifcgeom/IfcRegisterUndef.h b/src/ifcgeom/kernels/opencascade/IfcRegisterUndef.h similarity index 100% rename from src/ifcgeom/IfcRegisterUndef.h rename to src/ifcgeom/kernels/opencascade/IfcRegisterUndef.h diff --git a/src/ifcgeom/OpenCascadeConversionResult.h b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h similarity index 98% rename from src/ifcgeom/OpenCascadeConversionResult.h rename to src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h index 8254510245..621f030960 100644 --- a/src/ifcgeom/OpenCascadeConversionResult.h +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h @@ -34,7 +34,7 @@ #include #include -#include "../ifcgeom_schema_agnostic/ConversionResult.h" +#include "../../../ifcgeom/schema_agnostic/ConversionResult.h" namespace IfcGeom { diff --git a/src/ifcgeom/OpenCascadeShape.cpp b/src/ifcgeom/kernels/opencascade/OpenCascadeShape.cpp similarity index 98% rename from src/ifcgeom/OpenCascadeShape.cpp rename to src/ifcgeom/kernels/opencascade/OpenCascadeShape.cpp index bf9e705674..a48515d07b 100644 --- a/src/ifcgeom/OpenCascadeShape.cpp +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeShape.cpp @@ -1,7 +1,7 @@ #include "OpenCascadeConversionResult.h" -#include "../ifcparse/IfcLogger.h" -#include "../ifcgeom_schema_agnostic/IfcGeomRepresentation.h" +#include "../../../ifcparse/IfcLogger.h" +#include "../../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h" #include "IfcGeom.h" diff --git a/src/ifcgeom_schema_agnostic/ConversionResult.h b/src/ifcgeom/schema_agnostic/ConversionResult.h similarity index 97% rename from src/ifcgeom_schema_agnostic/ConversionResult.h rename to src/ifcgeom/schema_agnostic/ConversionResult.h index 2f2b9d9796..e4f5b55211 100644 --- a/src/ifcgeom_schema_agnostic/ConversionResult.h +++ b/src/ifcgeom/schema_agnostic/ConversionResult.h @@ -20,8 +20,8 @@ #ifndef IFCSHAPELIST_H #define IFCSHAPELIST_H -#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h" -#include "../ifcgeom_schema_agnostic/IfcGeomIteratorSettings.h" +#include "../../ifcgeom/schema_agnostic/IfcGeomRenderStyles.h" +#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h" namespace IfcGeom { diff --git a/src/ifcgeom_schema_agnostic/IfcGeomElement.h b/src/ifcgeom/schema_agnostic/IfcGeomElement.h similarity index 98% rename from src/ifcgeom_schema_agnostic/IfcGeomElement.h rename to src/ifcgeom/schema_agnostic/IfcGeomElement.h index fa6e00a107..b8ac73eff4 100644 --- a/src/ifcgeom_schema_agnostic/IfcGeomElement.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomElement.h @@ -23,10 +23,11 @@ #include #include -#include "../ifcparse/IfcGlobalId.h" +#include "../../ifcparse/IfcGlobalId.h" + +#include "../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h" +#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h" -#include "../ifcgeom_schema_agnostic/IfcGeomRepresentation.h" -#include "../ifcgeom_schema_agnostic/IfcGeomIteratorSettings.h" #include "ifc_geom_api.h" namespace IfcGeom { diff --git a/src/ifcgeom_schema_agnostic/IfcGeomFilter.h b/src/ifcgeom/schema_agnostic/IfcGeomFilter.h similarity index 99% rename from src/ifcgeom_schema_agnostic/IfcGeomFilter.h rename to src/ifcgeom/schema_agnostic/IfcGeomFilter.h index bc86cc295b..6e9a68d340 100644 --- a/src/ifcgeom_schema_agnostic/IfcGeomFilter.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomFilter.h @@ -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 #include diff --git a/src/ifcgeom_schema_agnostic/IfcGeomIterator.h b/src/ifcgeom/schema_agnostic/IfcGeomIterator.h similarity index 99% rename from src/ifcgeom_schema_agnostic/IfcGeomIterator.h rename to src/ifcgeom/schema_agnostic/IfcGeomIterator.h index babff4709f..d011ad6657 100644 --- a/src/ifcgeom_schema_agnostic/IfcGeomIterator.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomIterator.h @@ -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 diff --git a/src/ifcgeom_schema_agnostic/IfcGeomIteratorSettings.h b/src/ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h similarity index 98% rename from src/ifcgeom_schema_agnostic/IfcGeomIteratorSettings.h rename to src/ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h index 662d475e1e..1ad0850423 100644 --- a/src/ifcgeom_schema_agnostic/IfcGeomIteratorSettings.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h @@ -21,9 +21,9 @@ #define IFCGEOMITERATORSETTINGS_H #include "ifc_geom_api.h" -#include "../ifcparse/IfcException.h" -#include "../ifcparse/IfcBaseClass.h" -#include "../ifcparse/IfcLogger.h" +#include "../../ifcparse/IfcException.h" +#include "../../ifcparse/IfcBaseClass.h" +#include "../../ifcparse/IfcLogger.h" namespace IfcGeom { diff --git a/src/ifcgeom_schema_agnostic/IfcGeomMaterial.cpp b/src/ifcgeom/schema_agnostic/IfcGeomMaterial.cpp similarity index 100% rename from src/ifcgeom_schema_agnostic/IfcGeomMaterial.cpp rename to src/ifcgeom/schema_agnostic/IfcGeomMaterial.cpp diff --git a/src/ifcgeom_schema_agnostic/IfcGeomMaterial.h b/src/ifcgeom/schema_agnostic/IfcGeomMaterial.h similarity index 97% rename from src/ifcgeom_schema_agnostic/IfcGeomMaterial.h rename to src/ifcgeom/schema_agnostic/IfcGeomMaterial.h index 8614ae20d3..c700aa7760 100644 --- a/src/ifcgeom_schema_agnostic/IfcGeomMaterial.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomMaterial.h @@ -22,7 +22,7 @@ #include -#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h" +#include "../../ifcgeom/schema_agnostic/IfcGeomRenderStyles.h" namespace IfcGeom { diff --git a/src/ifcgeom_schema_agnostic/IfcGeomRenderStyles.h b/src/ifcgeom/schema_agnostic/IfcGeomRenderStyles.h similarity index 98% rename from src/ifcgeom_schema_agnostic/IfcGeomRenderStyles.h rename to src/ifcgeom/schema_agnostic/IfcGeomRenderStyles.h index ec0b5ed265..5c98a70469 100644 --- a/src/ifcgeom_schema_agnostic/IfcGeomRenderStyles.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomRenderStyles.h @@ -20,7 +20,7 @@ #ifndef IFCGEOMRENDERSTYLES_H #define IFCGEOMRENDERSTYLES_H -#include "../ifcgeom_schema_agnostic/ifc_geom_api.h" +#include "../../ifcgeom/schema_agnostic/ifc_geom_api.h" #include #include diff --git a/src/ifcgeom_schema_agnostic/IfcGeomRepresentation.cpp b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp similarity index 98% rename from src/ifcgeom_schema_agnostic/IfcGeomRepresentation.cpp rename to src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp index 011fd96a4d..5a273eb95e 100644 --- a/src/ifcgeom_schema_agnostic/IfcGeomRepresentation.cpp +++ b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp @@ -27,8 +27,8 @@ #include #include "IfcGeomRepresentation.h" -#include "../ifcgeom/OpenCascadeConversionResult.h" -#include "../ifcgeom_schema_agnostic/Kernel.h" +#include "../../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h" +#include "../../ifcgeom/schema_agnostic/Kernel.h" IfcGeom::Representation::Serialization::Serialization(const BRep& brep) : Representation(brep.settings()) diff --git a/src/ifcgeom_schema_agnostic/IfcGeomRepresentation.h b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.h similarity index 98% rename from src/ifcgeom_schema_agnostic/IfcGeomRepresentation.h rename to src/ifcgeom/schema_agnostic/IfcGeomRepresentation.h index f67b130b43..f6232007ce 100644 --- a/src/ifcgeom_schema_agnostic/IfcGeomRepresentation.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.h @@ -35,9 +35,9 @@ #include #include -#include "../ifcgeom_schema_agnostic/IfcGeomIteratorSettings.h" -#include "../ifcgeom_schema_agnostic/IfcGeomMaterial.h" -#include "../ifcgeom_schema_agnostic/ConversionResult.h" +#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h" +#include "../../ifcgeom/schema_agnostic/IfcGeomMaterial.h" +#include "../../ifcgeom/schema_agnostic/ConversionResult.h" #include diff --git a/src/ifcgeom_schema_agnostic/IteratorImplementation.cpp b/src/ifcgeom/schema_agnostic/IteratorImplementation.cpp similarity index 100% rename from src/ifcgeom_schema_agnostic/IteratorImplementation.cpp rename to src/ifcgeom/schema_agnostic/IteratorImplementation.cpp diff --git a/src/ifcgeom_schema_agnostic/IteratorImplementation.h b/src/ifcgeom/schema_agnostic/IteratorImplementation.h similarity index 94% rename from src/ifcgeom_schema_agnostic/IteratorImplementation.h rename to src/ifcgeom/schema_agnostic/IteratorImplementation.h index 5417584c20..46dc8adccd 100644 --- a/src/ifcgeom_schema_agnostic/IteratorImplementation.h +++ b/src/ifcgeom/schema_agnostic/IteratorImplementation.h @@ -1,9 +1,9 @@ #ifndef ITERATOR_IMPLEMENTATION_H #define ITERATOR_IMPLEMENTATION_H -#include "../ifcgeom_schema_agnostic/IfcGeomFilter.h" -#include "../ifcparse/IfcFile.h" -#include "../ifcgeom_schema_agnostic/IfcGeomIteratorSettings.h" +#include "../../ifcparse/IfcFile.h" +#include "../../ifcgeom/schema_agnostic/IfcGeomFilter.h" +#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h" #include diff --git a/src/ifcgeom_schema_agnostic/Kernel.cpp b/src/ifcgeom/schema_agnostic/Kernel.cpp similarity index 99% rename from src/ifcgeom_schema_agnostic/Kernel.cpp rename to src/ifcgeom/schema_agnostic/Kernel.cpp index ecc9562e97..de6bf568a8 100644 --- a/src/ifcgeom_schema_agnostic/Kernel.cpp +++ b/src/ifcgeom/schema_agnostic/Kernel.cpp @@ -1,5 +1,8 @@ #include "Kernel.h" +#include "../../ifcparse/Ifc2x3.h" +#include "../../ifcparse/Ifc4.h" + #include #include #include diff --git a/src/ifcgeom_schema_agnostic/Kernel.h b/src/ifcgeom/schema_agnostic/Kernel.h similarity index 93% rename from src/ifcgeom_schema_agnostic/Kernel.h rename to src/ifcgeom/schema_agnostic/Kernel.h index 75c93d2c39..549e6be0c8 100644 --- a/src/ifcgeom_schema_agnostic/Kernel.h +++ b/src/ifcgeom/schema_agnostic/Kernel.h @@ -1,12 +1,9 @@ #ifndef ITERATOR_KERNEL_H #define ITERATOR_KERNEL_H -#include "../ifcparse/IfcFile.h" -#include "../ifcgeom_schema_agnostic/IfcGeomIteratorSettings.h" -#include "../ifcgeom_schema_agnostic/ConversionResult.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 diff --git a/src/ifcgeom_schema_agnostic/Serialization.cpp b/src/ifcgeom/schema_agnostic/Serialization.cpp similarity index 100% rename from src/ifcgeom_schema_agnostic/Serialization.cpp rename to src/ifcgeom/schema_agnostic/Serialization.cpp diff --git a/src/ifcgeom_schema_agnostic/Serialization.h b/src/ifcgeom/schema_agnostic/Serialization.h similarity index 76% rename from src/ifcgeom_schema_agnostic/Serialization.h rename to src/ifcgeom/schema_agnostic/Serialization.h index e7adf5f057..8feda56f8e 100644 --- a/src/ifcgeom_schema_agnostic/Serialization.h +++ b/src/ifcgeom/schema_agnostic/Serialization.h @@ -1,5 +1,6 @@ -#include "../ifcgeom_schema_agnostic/ifc_geom_api.h" -#include "../ifcparse/IfcBaseClass.h" +#include "../../ifcparse/IfcBaseClass.h" + +#include "../../ifcgeom/schema_agnostic/ifc_geom_api.h" #include diff --git a/src/ifcgeom_schema_agnostic/SurfaceStyle.cpp b/src/ifcgeom/schema_agnostic/SurfaceStyle.cpp similarity index 98% rename from src/ifcgeom_schema_agnostic/SurfaceStyle.cpp rename to src/ifcgeom/schema_agnostic/SurfaceStyle.cpp index c3db9c3756..09d1344654 100644 --- a/src/ifcgeom_schema_agnostic/SurfaceStyle.cpp +++ b/src/ifcgeom/schema_agnostic/SurfaceStyle.cpp @@ -1,4 +1,4 @@ -#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h" +#include "../../ifcgeom/schema_agnostic/IfcGeomRenderStyles.h" #include #include diff --git a/src/ifcgeom_schema_agnostic/ifc_geom_api.h b/src/ifcgeom/schema_agnostic/ifc_geom_api.h similarity index 100% rename from src/ifcgeom_schema_agnostic/ifc_geom_api.h rename to src/ifcgeom/schema_agnostic/ifc_geom_api.h diff --git a/src/ifcgeomserver/IfcGeomServer.cpp b/src/ifcgeomserver/IfcGeomServer.cpp index 7a2cc9ee90..6d9265bcd3 100644 --- a/src/ifcgeomserver/IfcGeomServer.cpp +++ b/src/ifcgeomserver/IfcGeomServer.cpp @@ -38,8 +38,8 @@ #include #endif -#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h" -#include "../ifcgeom_schema_agnostic/IfcGeomElement.h" +#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h" +#include "../ifcgeom/schema_agnostic/IfcGeomElement.h" #include "../ifcparse/IfcFile.h" #include "../ifcparse/IfcLogger.h" diff --git a/src/ifcparse/IfcParse.h b/src/ifcparse/IfcParse.h index 384e7c4465..2970a4db5c 100644 --- a/src/ifcparse/IfcParse.h +++ b/src/ifcparse/IfcParse.h @@ -27,7 +27,7 @@ #ifndef IFCPARSE_H #define IFCPARSE_H -#define IFCOPENSHELL_VERSION "0.6.0a1" +#define IFCOPENSHELL_VERSION "0.7.0-dev" #include #include diff --git a/src/ifcwrap/IfcPython.i b/src/ifcwrap/IfcPython.i index 2bdf89637c..7b54ac2e94 100644 --- a/src/ifcwrap/IfcPython.i +++ b/src/ifcwrap/IfcPython.i @@ -70,8 +70,8 @@ } %module ifcopenshell_wrapper %{ - #include "../ifcgeom_schema_agnostic/IfcGeomIterator.h" - #include "../ifcgeom_schema_agnostic/Serialization.h" + #include "../ifcgeom/schema_agnostic/IfcGeomIterator.h" + #include "../ifcgeom/schema_agnostic/Serialization.h" #include "../ifcgeom/IfcGeomTree.h" #include "../ifcparse/Ifc2x3.h" diff --git a/src/serializers/ColladaSerializer.h b/src/serializers/ColladaSerializer.h index d85dc989a0..5f58bf49b4 100644 --- a/src/serializers/ColladaSerializer.h +++ b/src/serializers/ColladaSerializer.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" diff --git a/src/serializers/GeometrySerializer.h b/src/serializers/GeometrySerializer.h index 45b14d8660..ff50154f29 100644 --- a/src/serializers/GeometrySerializer.h +++ b/src/serializers/GeometrySerializer.h @@ -27,8 +27,8 @@ typedef float real_t; #endif #include "../serializers/Serializer.h" -#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h" -#include "../ifcgeom_schema_agnostic/IfcGeomElement.h" +#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h" +#include "../ifcgeom/schema_agnostic/IfcGeomElement.h" class SerializerSettings : public IfcGeom::IteratorSettings { diff --git a/src/serializers/OpenCascadeBasedSerializer.h b/src/serializers/OpenCascadeBasedSerializer.h index e1f78e1401..dd673024b9 100644 --- a/src/serializers/OpenCascadeBasedSerializer.h +++ b/src/serializers/OpenCascadeBasedSerializer.h @@ -20,8 +20,8 @@ #ifndef OPENCASCADEBASEDSERIALIZER_H #define OPENCASCADEBASEDSERIALIZER_H -#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h" -#include "../ifcgeom/OpenCascadeConversionResult.h" +#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h" +#include "../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h" #include "../serializers/GeometrySerializer.h" class OpenCascadeBasedSerializer : public GeometrySerializer { diff --git a/src/serializers/StepSerializer.h b/src/serializers/StepSerializer.h index 5b31bace6e..5152c5d362 100644 --- a/src/serializers/StepSerializer.h +++ b/src/serializers/StepSerializer.h @@ -23,7 +23,7 @@ #include #include -#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h" +#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h" #include "../serializers/OpenCascadeBasedSerializer.h" diff --git a/src/serializers/WavefrontObjSerializer.cpp b/src/serializers/WavefrontObjSerializer.cpp index bb5e4a8f8b..f416487b67 100644 --- a/src/serializers/WavefrontObjSerializer.cpp +++ b/src/serializers/WavefrontObjSerializer.cpp @@ -20,7 +20,7 @@ #include "WavefrontObjSerializer.h" -#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h" +#include "../ifcgeom/schema_agnostic/IfcGeomRenderStyles.h" #include #include diff --git a/src/serializers/schema_dependent/XmlSerializer.cpp b/src/serializers/schema_dependent/XmlSerializer.cpp index bc0fa96b64..f4e2f10516 100644 --- a/src/serializers/schema_dependent/XmlSerializer.cpp +++ b/src/serializers/schema_dependent/XmlSerializer.cpp @@ -29,7 +29,7 @@ #include #include "../../ifcparse/IfcSIPrefix.h" -#include "../../ifcgeom/IfcGeom.h" +#include "../../ifcgeom/kernels/opencascade/IfcGeom.h" using boost::property_tree::ptree; From fa0a33f3c04b33190e2611e8ecf4b2aba53dd4df Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sat, 19 Jan 2019 12:39:47 +0100 Subject: [PATCH 129/235] Option to select Kernel from IfcConvert --- cmake/CMakeLists.txt | 16 +++- src/ifcconvert/IfcConvert.cpp | 2 +- .../IfcGeomIteratorImplementation.cpp | 6 +- .../IfcGeomIteratorImplementation.h | 95 ++++++------------- .../kernels/cgal/CgalConversionFunctions.cpp | 2 +- .../kernels/cgal/CgalEntityMapping.cpp | 1 - src/ifcgeom/kernels/cgal/CgalKernel.cpp | 25 ++++- src/ifcgeom/kernels/cgal/CgalKernel.h | 14 +-- src/ifcgeom/kernels/opencascade/IfcGeom.h | 2 +- src/ifcgeom/schema_agnostic/IfcGeomIterator.h | 8 +- .../schema_agnostic/IfcGeomRepresentation.cpp | 2 +- .../IteratorImplementation.cpp | 4 +- .../schema_agnostic/IteratorImplementation.h | 8 +- .../cgal/CgalConversionResult.cpp | 1 - .../cgal/CgalConversionResult.h | 7 ++ .../OpenCascadeConversionResult.cpp} | 5 +- .../opencascade/OpenCascadeConversionResult.h | 0 src/serializers/OpenCascadeBasedSerializer.h | 2 +- 18 files changed, 99 insertions(+), 101 deletions(-) rename src/ifcgeom/{kernels/opencascade => kernel_agnostic}/IfcGeomIteratorImplementation.cpp (78%) rename src/ifcgeom/{kernels/opencascade => kernel_agnostic}/IfcGeomIteratorImplementation.h (88%) rename src/ifcgeom/{kernels => schema_agnostic}/cgal/CgalConversionResult.cpp (97%) rename src/ifcgeom/{kernels => schema_agnostic}/cgal/CgalConversionResult.h (95%) rename src/ifcgeom/{kernels/opencascade/OpenCascadeShape.cpp => schema_agnostic/opencascade/OpenCascadeConversionResult.cpp} (98%) rename src/ifcgeom/{kernels => schema_agnostic}/opencascade/OpenCascadeConversionResult.h (100%) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 8877c98919..a96c523bc1 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -554,6 +554,18 @@ ENDIF() if (BUILD_IFCGEOM) +foreach(kernel opencascade cgal) +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}) + +add_library(IfcGeom_${kernel} ${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() + foreach(schema 2x3 4) file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/kernel_agnostic/*.h) @@ -566,15 +578,13 @@ target_link_libraries(IfcGeom_ifc${schema} IfcParse) list(APPEND IfcGeom_libraries IfcGeom_ifc${schema}) foreach(kernel opencascade cgal) -string(TOUPPER ${kernel} KERNEL_UPPER) - 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} ${IFCGEOM_FILES}) set_target_properties(IfcGeom_${kernel}_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema} -DUSE_IFC${schema}") -target_link_libraries(IfcGeom_${kernel}_ifc${schema} IfcGeom_ifc${schema} ${${KERNEL_UPPER}_LIBRARIES}) +target_link_libraries(IfcGeom_${kernel}_ifc${schema} IfcGeom_${kernel} IfcGeom_ifc${schema}) list(APPEND IfcGeom_libraries IfcGeom_${kernel}_ifc${schema}) endforeach() diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 5c1b7d5c58..1c174dae13 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -652,7 +652,7 @@ int main(int argc, char** argv) return EXIT_FAILURE; } - IfcGeom::Iterator context_iterator(settings, ifc_file, filter_funcs); + IfcGeom::Iterator context_iterator(settings, ifc_file, filter_funcs, "cgal"); 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. diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomIteratorImplementation.cpp b/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.cpp similarity index 78% rename from src/ifcgeom/kernels/opencascade/IfcGeomIteratorImplementation.cpp rename to src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.cpp index 82fc1cc17b..6bc2225c0f 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomIteratorImplementation.cpp +++ b/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.cpp @@ -1,5 +1,5 @@ #include "IfcGeomIteratorImplementation.h" -#include "../../../ifcgeom/schema_agnostic/IteratorImplementation.h" +#include "../../ifcgeom/schema_agnostic/IteratorImplementation.h" namespace IfcGeom { template class MAKE_TYPE_NAME(IteratorImplementation_); @@ -14,8 +14,8 @@ namespace IfcGeom { namespace { template struct MAKE_TYPE_NAME(factory_t) { - IfcGeom::IteratorImplementation* operator()(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector& filters) const { - return new IfcGeom::MAKE_TYPE_NAME(IteratorImplementation_)(settings, file, filters); + IfcGeom::IteratorImplementation* operator()(const std::string& geometry_engine, const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector& filters) const { + return new IfcGeom::MAKE_TYPE_NAME(IteratorImplementation_)(geometry_engine, settings, file, filters); } }; } diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomIteratorImplementation.h b/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.h similarity index 88% rename from src/ifcgeom/kernels/opencascade/IfcGeomIteratorImplementation.h rename to src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.h index 1741c84e2f..0f1577eab0 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomIteratorImplementation.h +++ b/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.h @@ -73,16 +73,18 @@ #include #include -#include "../../../ifcparse/IfcFile.h" +#include "../../ifcparse/IfcFile.h" -#include "../../../ifcgeom/kernels/opencascade/IfcGeom.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/kernels/opencascade/IfcGeom.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/schema_agnostic/Kernel.h" // The infamous min & max Win32 #defines can leak here from OCE depending on the build configuration #ifdef min @@ -101,7 +103,7 @@ namespace IfcGeom { 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(Kernel)* kernel; IteratorSettings settings; IfcParse::IfcFile* ifc_file; @@ -141,29 +143,12 @@ namespace IfcGeom { IfcSchema::IfcProduct* product; }; - void initUnits() { - IfcSchema::IfcProject::list::ptr projects = ifc_file->instances_by_type(); - if (projects->size() == 1) { - IfcSchema::IfcProject* project = *projects->begin(); - std::pair 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(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 allowed_context_types; allowed_context_types.insert("model"); @@ -185,9 +170,6 @@ namespace IfcGeom { context_types.insert("plan"); } - double lowest_precision_encountered = std::numeric_limits::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); @@ -237,15 +219,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()); @@ -254,21 +228,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(); @@ -310,7 +269,7 @@ namespace IfcGeom { bool success = false; try { - success = kernel.convert(product->ObjectPlacement(), trsf); + success = kernel->convert(product->ObjectPlacement(), trsf); } catch (const std::exception& e) { Logger::Error(e); } catch (...) { @@ -357,7 +316,7 @@ namespace IfcGeom { // 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(); + kernel->purge_cache(); } ifcproducts.reset(); ++ representation_iterator; @@ -378,7 +337,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; } @@ -396,7 +355,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; } @@ -416,7 +375,7 @@ 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); + 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; @@ -450,7 +409,7 @@ 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); @@ -476,9 +435,9 @@ namespace IfcGeom { NativeElement* element; if (ifcproduct_iterator == ifcproducts->begin() || !geometry_reuse_ok_for_current_representation_) { - element = kernel.create_brep_for_representation_and_product(settings, representation, product); + element = kernel->create_brep_for_representation_and_product(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); @@ -614,7 +573,7 @@ namespace IfcGeom { ifc_product = ifc_entity->as(); parent_id = -1; try { - IfcSchema::IfcObjectDefinition* parent_object = kernel.get_decomposing_entity(ifc_product)->template as(); + IfcSchema::IfcObjectDefinition* parent_object = kernel->get_decomposing_entity(ifc_product)->template as(); if (parent_object) { parent_id = parent_object->data().id(); } @@ -625,7 +584,7 @@ namespace IfcGeom { } try { - kernel.convert(ifc_product->ObjectPlacement(), trsf); + kernel->convert(ifc_product->ObjectPlacement(), trsf); } catch (const std::exception& e) { Logger::Error(e); } catch (...) { @@ -706,26 +665,28 @@ namespace IfcGeom { unit_name = "METER"; unit_magnitude = 1.f; - kernel.setValue(IfcGeom::Kernel::GV_DIMENSIONALITY, (settings.get(IteratorSettings::INCLUDE_CURVES) + 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& filters) + MAKE_TYPE_NAME(IteratorImplementation_)(const std::string& geometry_library, const IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector& filters) : settings(settings) , ifc_file(file) , filters_(filters) , owns_ifc_file(false) { + kernel = (MAKE_TYPE_NAME(Kernel)*) impl::kernel_implementations().construct(file->schema()->name(), geometry_library, file); + // kernel = new Kernel(geometry_library, file); _initialize(); } diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index fcb766ca11..9cb297835c 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -1,5 +1,5 @@ #include "CgalKernel.h" -#include "CgalConversionResult.h" +#include "../../../ifcgeom/schema_agnostic/cgal/CgalConversionResult.h" #define CgalKernel MAKE_TYPE_NAME(CgalKernel) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp index c92ac7c166..a5ecf67624 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp @@ -18,7 +18,6 @@ ********************************************************************************/ #include "CgalKernel.h" -#include "CgalConversionResult.h" #define CgalKernel MAKE_TYPE_NAME(CgalKernel) diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index 4c67c670ba..5983748042 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -18,7 +18,6 @@ ********************************************************************************/ #include "CgalKernel.h" -#include "CgalConversionResult.h" namespace { struct MAKE_TYPE_NAME(factory_t) { @@ -208,3 +207,27 @@ template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::CgalKernel const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_processed_representation( const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); + + +void IfcGeom::CgalKernel::setValue(GeomValue var, double value) { + switch (var) { + case GV_DEFLECTION_TOLERANCE: + deflection_tolerance = value; + break; + case GV_DIMENSIONALITY: + dimensionality = value; + break; + default: + throw std::runtime_error("Not implemented for this kernel"); + } +} + +double IfcGeom::CgalKernel::getValue(GeomValue var) const { + switch (var) { + case GV_DEFLECTION_TOLERANCE: + return deflection_tolerance; + case GV_DIMENSIONALITY: + return dimensionality; + } + throw std::runtime_error("Not implemented for this kernel"); +} \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 5d9cfd21fe..86f878fd4c 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -38,6 +38,7 @@ if ( it != cache.T.end() ) { e = it->second; return true; } #include "../../../ifcparse/macros.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" @@ -46,13 +47,6 @@ if ( it != cache.T.end() ) { e = it->second; return true; } #include INCLUDE_SCHEMA(IfcSchema) #undef INCLUDE_SCHEMA -typedef void* cgal_shape_t; -typedef void* cgal_face_t; -typedef void* cgal_wire_t; -typedef void* cgal_curve_t; -typedef void* cgal_placement_t; -typedef void* cgal_point_t; - namespace IfcGeom { class IFC_GEOM_API CgalCache { @@ -78,6 +72,9 @@ namespace IfcGeom { bool convert_curve(const IfcUtil::IfcBaseClass* L, cgal_curve_t& result); bool convert_face(const IfcUtil::IfcBaseClass* L, cgal_face_t& result); + virtual void setValue(GeomValue var, double value); + virtual double getValue(GeomValue var) const; + // bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, ConversionResults& cut_shapes); void purge_cache() { @@ -102,6 +99,9 @@ namespace IfcGeom { #include "CgalEntityMappingDeclaration.h" + private: + double deflection_tolerance; + double dimensionality; }; } diff --git a/src/ifcgeom/kernels/opencascade/IfcGeom.h b/src/ifcgeom/kernels/opencascade/IfcGeom.h index 0663450788..c3f933ad27 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeom.h +++ b/src/ifcgeom/kernels/opencascade/IfcGeom.h @@ -58,7 +58,7 @@ inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance=ALMO #include "../../../ifcgeom/kernels/opencascade/IfcGeomShapeType.h" #include "../../../ifcgeom/schema_agnostic/Kernel.h" -#include "OpenCascadeConversionResult.h" +#include "../../../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h" #include "../../../ifcgeom/schema_agnostic/ifc_geom_api.h" diff --git a/src/ifcgeom/schema_agnostic/IfcGeomIterator.h b/src/ifcgeom/schema_agnostic/IfcGeomIterator.h index d011ad6657..2af27e32ce 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomIterator.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomIterator.h @@ -83,19 +83,19 @@ namespace IfcGeom { IteratorImplementation* implementation_; public: - Iterator(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file) + Iterator(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::string& geometry_library="opencascade") : file_(file) , settings_(settings) { - implementation_ = iterator_implementations().construct(file_->schema()->name(), settings, file, filters_); + implementation_ = iterator_implementations().construct(file_->schema()->name(), geometry_library, settings, file, filters_); } - Iterator(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector& filters) + Iterator(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector& filters, const std::string& geometry_library = "opencascade") : file_(file) , settings_(settings) , filters_(filters) { - implementation_ = iterator_implementations().construct(file_->schema()->name(), settings, file, filters_); + implementation_ = iterator_implementations().construct(file_->schema()->name(), geometry_library, settings, file, filters_); } bool initialize() { diff --git a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp index 5a273eb95e..e7230d8b17 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp +++ b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp @@ -27,7 +27,7 @@ #include #include "IfcGeomRepresentation.h" -#include "../../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h" +#include "../../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h" #include "../../ifcgeom/schema_agnostic/Kernel.h" IfcGeom::Representation::Serialization::Serialization(const BRep& brep) diff --git a/src/ifcgeom/schema_agnostic/IteratorImplementation.cpp b/src/ifcgeom/schema_agnostic/IteratorImplementation.cpp index 10608d8cb7..5b039fd615 100644 --- a/src/ifcgeom/schema_agnostic/IteratorImplementation.cpp +++ b/src/ifcgeom/schema_agnostic/IteratorImplementation.cpp @@ -31,14 +31,14 @@ void IteratorFactoryImplementation::bind(const std::string& schema_name, } template -IfcGeom::IteratorImplementation* IteratorFactoryImplementation::construct(const std::string& schema_name, const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector& filters) { +IfcGeom::IteratorImplementation* IteratorFactoryImplementation::construct(const std::string& schema_name, const std::string& geometry_library, const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector& filters) { const std::string schema_name_lower = boost::to_lower_copy(schema_name); typename std::map::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); + return it->second(geometry_library, settings, file, filters); } diff --git a/src/ifcgeom/schema_agnostic/IteratorImplementation.h b/src/ifcgeom/schema_agnostic/IteratorImplementation.h index 46dc8adccd..eb7399c697 100644 --- a/src/ifcgeom/schema_agnostic/IteratorImplementation.h +++ b/src/ifcgeom/schema_agnostic/IteratorImplementation.h @@ -23,9 +23,9 @@ namespace IfcGeom { class NativeElement; } -typedef boost::function3*, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector&> iterator_float_float_fn; -typedef boost::function3*, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector&> iterator_float_double_fn; -typedef boost::function3*, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector&> iterator_double_double_fn; +typedef boost::function4*, const std::string&, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector&> iterator_float_float_fn; +typedef boost::function4*, const std::string&, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector&> iterator_float_double_fn; +typedef boost::function4*, const std::string&, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector&> iterator_double_double_fn; template struct get_factory_type {}; @@ -50,7 +50,7 @@ class IteratorFactoryImplementation : public std::map::type fn); - IfcGeom::IteratorImplementation* construct(const std::string& schema_name, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector&); + IfcGeom::IteratorImplementation* construct(const std::string& schema_name, const std::string& geometry_library, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector&); }; template diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.cpp similarity index 97% rename from src/ifcgeom/kernels/cgal/CgalConversionResult.cpp rename to src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.cpp index 3b9ee4d2d3..3f98bc00d9 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.cpp @@ -1,4 +1,3 @@ -#include "CgalKernel.h" #include "CgalConversionResult.h" template diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.h b/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.h similarity index 95% rename from src/ifcgeom/kernels/cgal/CgalConversionResult.h rename to src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.h index 4d78b23e2a..6f231d1efa 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.h +++ b/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.h @@ -20,6 +20,13 @@ #ifndef CGALCONVERSIONRESULT_H #define CGALCONVERSIONRESULT_H +typedef void* cgal_shape_t; +typedef void* cgal_face_t; +typedef void* cgal_wire_t; +typedef void* cgal_curve_t; +typedef void* cgal_placement_t; +typedef void* cgal_point_t; + #include "../../../ifcgeom/schema_agnostic/ConversionResult.h" namespace IfcGeom { diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeShape.cpp b/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.cpp similarity index 98% rename from src/ifcgeom/kernels/opencascade/OpenCascadeShape.cpp rename to src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.cpp index a48515d07b..b113ba45ce 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeShape.cpp +++ b/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.cpp @@ -3,8 +3,6 @@ #include "../../../ifcparse/IfcLogger.h" #include "../../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h" -#include "IfcGeom.h" - #include #include @@ -198,5 +196,6 @@ void IfcGeom::OpenCascadeShape::Triangulate(const IfcGeom::IteratorSettings & se } int IfcGeom::OpenCascadeShape::surface_genus() const { - return IfcGeom::Kernel::surface_genus(shape_); + throw std::runtime_error("Not implemented"); + // return IfcGeom::Kernel::surface_genus(shape_); } \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h b/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h similarity index 100% rename from src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h rename to src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h diff --git a/src/serializers/OpenCascadeBasedSerializer.h b/src/serializers/OpenCascadeBasedSerializer.h index dd673024b9..bb92b4fd1c 100644 --- a/src/serializers/OpenCascadeBasedSerializer.h +++ b/src/serializers/OpenCascadeBasedSerializer.h @@ -21,7 +21,7 @@ #define OPENCASCADEBASEDSERIALIZER_H #include "../ifcgeom/schema_agnostic/IfcGeomIterator.h" -#include "../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h" +#include "../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h" #include "../serializers/GeometrySerializer.h" class OpenCascadeBasedSerializer : public GeometrySerializer { From 8c5349feaad6ef63444b5076502843f61f2d7ca8 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 20 Jan 2019 13:16:42 +0100 Subject: [PATCH 130/235] Introduce AbstractKernel --- cmake/CMakeLists.txt | 3 +- src/ifcconvert/IfcConvert.cpp | 5 +- .../kernel_agnostic/AbstractKernel.cpp | 557 +++++++++++ src/ifcgeom/kernel_agnostic/AbstractKernel.h | 74 ++ .../IfcGeomIteratorImplementation.cpp | 1 - .../IfcGeomIteratorImplementation.h | 44 +- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 153 +-- src/ifcgeom/kernels/cgal/CgalKernel.h | 25 +- src/ifcgeom/kernels/opencascade/IfcGeom.h | 131 +-- .../kernels/opencascade/IfcGeomFunctions.cpp | 877 +++--------------- .../kernels/opencascade/IfcGeomHelpers.cpp | 4 - .../opencascade/IfcGeomRenderStyles.cpp | 140 --- .../schema_agnostic/ConversionResult.h | 1 + src/ifcgeom/schema_agnostic/Kernel.h | 2 +- .../cgal/CgalConversionResult.h | 4 + .../opencascade/OpenCascadeConversionResult.h | 6 + src/serializers/SvgSerializer.cpp | 6 +- 17 files changed, 832 insertions(+), 1201 deletions(-) create mode 100644 src/ifcgeom/kernel_agnostic/AbstractKernel.cpp create mode 100644 src/ifcgeom/kernel_agnostic/AbstractKernel.h delete mode 100644 src/ifcgeom/kernels/opencascade/IfcGeomRenderStyles.cpp diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index a96c523bc1..27f4159424 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -427,7 +427,8 @@ 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() # Link against the static VC runtime # TODO Make this configurable diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 1c174dae13..3d426b9d67 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -182,6 +182,7 @@ int main(int argc, char** argv) exclusion_traverse_filter exclude_traverse_filter; std::string filter_filename; std::string default_material_filename; + std::string geometry_kernel; po::options_description ifc_options("IFC options"); ifc_options.add_options() @@ -190,6 +191,8 @@ int main(int argc, char** argv) po::options_description geom_options("Geometry options"); geom_options.add_options() + ("kernel", po::value(&geometry_kernel)->default_value("opencascade"), + "Geometry kernel to use (opencascade or cgal).") ("plan", "Specifies whether to include curves in the output result. Typically " "these are representations of type Plan or Axis. Excluded by default.") @@ -652,7 +655,7 @@ int main(int argc, char** argv) return EXIT_FAILURE; } - IfcGeom::Iterator context_iterator(settings, ifc_file, filter_funcs, "cgal"); + IfcGeom::Iterator context_iterator(settings, ifc_file, filter_funcs, geometry_kernel); 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. diff --git a/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp new file mode 100644 index 0000000000..41e4ad5689 --- /dev/null +++ b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp @@ -0,0 +1,557 @@ +#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_WIRE_CREATION_TOLERANCE: + wire_creation_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_WIRE_CREATION_TOLERANCE: + return wire_creation_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(); + if (associated_materials->size() == 1) { + IfcSchema::IfcMaterialSelect* associated_material = (*associated_materials->begin())->RelatingMaterial(); + single_material = associated_material->as(); + + // 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::IfcMaterialLayerSet* layerset = associated_material->as()->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(); + 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::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(); + 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(); + 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 + std::pair _get_surface_style(const IfcSchema::IfcStyledItem* si) { +#ifdef USE_IFC4 + IfcEntityList::ptr style_assignments = si->Styles(); + for (IfcEntityList::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) { + if (!(*kt)->declaration().is(IfcSchema::IfcPresentationStyleAssignment::Class())) { + continue; + } + IfcSchema::IfcPresentationStyleAssignment* style_assignment = (IfcSchema::IfcPresentationStyleAssignment*) *kt; +#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(0, 0); + } + + template + std::pair get_surface_style(const IfcSchema::IfcRepresentationItem* representation_item) { + // For certain representation items, most notably boolean operands, + // a style definition might reside on one of its operands. + representation_item = find_item_carrying_style(representation_item); + + if (representation_item->as()) { + return _get_surface_style(representation_item->as()); + } + 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(*styled_items->begin()); + } + return std::make_pair(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(colour_or_factor), rgb); + } else if (colour_or_factor->declaration().is(IfcSchema::IfcNormalisedRatioMeasure::Class())) { + return process_colour(static_cast(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(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()); + } + for (IfcSchema::IfcStyledItem::list::it it = styles->begin(); it != styles->end(); ++it) { + const std::pair ss = get_surface_style(*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& shading_styles) { + if (shading_styles.second == 0) { + return 0; + } + int surface_style_id = shading_styles.first->data().id(); + std::map::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::IfcSurfaceStyleShading* shading = shading_styles.second->as(); + + 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(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 +IfcGeom::NativeElement* 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(); + 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()) { + 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(); + + 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( + product->data().id(), + parent_id, + name, + product_type, + guid, + context_string, + trsf, + boost::shared_ptr(shape), + product + ); + + if (settings.get(IteratorSettings::VALIDATE_QUANTITIES)) { + validate_quantities(product, elem->geometry()); + } + + return elem; +} + +template +IfcGeom::NativeElement* IfcGeom::AbstractKernel::create_brep_for_processed_representation( + const IteratorSettings& /*settings*/, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, + IfcGeom::NativeElement* brep) { + int parent_id = -1; + try { + IfcUtil::IfcBaseEntity* parent_object = get_decomposing_entity(product); + if (parent_object && parent_object->as()) { + 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( + product->data().id(), + parent_id, + name, + product_type, + guid, + context_string, + trsf, + brep->geometry_pointer(), + product + ); +} + +template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::AbstractKernel::create_brep_for_representation_and_product( + const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); +template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::AbstractKernel::create_brep_for_representation_and_product( + const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); +template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::AbstractKernel::create_brep_for_representation_and_product( + const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); + +template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::AbstractKernel::create_brep_for_processed_representation( + const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); +template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::AbstractKernel::create_brep_for_processed_representation( + const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); +template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::AbstractKernel::create_brep_for_processed_representation( + const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); \ No newline at end of file diff --git a/src/ifcgeom/kernel_agnostic/AbstractKernel.h b/src/ifcgeom/kernel_agnostic/AbstractKernel.h new file mode 100644 index 0000000000..a88431c4ce --- /dev/null +++ b/src/ifcgeom/kernel_agnostic/AbstractKernel.h @@ -0,0 +1,74 @@ +#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 + +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 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& shading_style); + + template + IfcGeom::NativeElement* create_brep_for_representation_and_product( + const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*); + + template + IfcGeom::NativeElement* create_brep_for_processed_representation( + const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::NativeElement*); + }; + +} + +#endif \ No newline at end of file diff --git a/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.cpp b/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.cpp index 6bc2225c0f..2c9e313eef 100644 --- a/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.cpp +++ b/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.cpp @@ -1,5 +1,4 @@ #include "IfcGeomIteratorImplementation.h" -#include "../../ifcgeom/schema_agnostic/IteratorImplementation.h" namespace IfcGeom { template class MAKE_TYPE_NAME(IteratorImplementation_); diff --git a/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.h b/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.h index 0f1577eab0..a93b1186cf 100644 --- a/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.h +++ b/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.h @@ -73,9 +73,9 @@ #include #include +#include "../../ifcparse/macros.h" #include "../../ifcparse/IfcFile.h" -#include "../../ifcgeom/kernels/opencascade/IfcGeom.h" #include "../../ifcgeom/schema_agnostic/IfcGeomElement.h" #include "../../ifcgeom/schema_agnostic/IfcGeomMaterial.h" #include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h" @@ -84,7 +84,11 @@ #include "../../ifcgeom/schema_agnostic/IfcGeomFilter.h" #include "../../ifcgeom/schema_agnostic/IteratorImplementation.h" -#include "../../ifcgeom/schema_agnostic/Kernel.h" +#include "../../ifcgeom/kernel_agnostic/AbstractKernel.h" + +#define INCLUDE_SCHEMA(x) STRINGIFY(../../ifcparse/x.h) +#include INCLUDE_SCHEMA(IfcSchema) +#undef INCLUDE_SCHEMA // The infamous min & max Win32 #defines can leak here from OCE depending on the build configuration #ifdef min @@ -103,7 +107,7 @@ namespace IfcGeom { 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; @@ -265,11 +269,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 (...) { @@ -280,13 +284,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)); } } } @@ -311,13 +316,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; @@ -554,7 +552,7 @@ namespace IfcGeom { } const Element* 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; @@ -584,7 +582,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 (...) { @@ -605,7 +603,7 @@ namespace IfcGeom { ElementSettings element_settings(settings, unit_magnitude, instance_type); - Element* ifc_object = new Element(element_settings, id, parent_id, product_name, instance_type, product_guid, "", new OpenCascadePlacement(trsf), ifc_product); + Element* ifc_object = new Element(element_settings, id, parent_id, product_name, instance_type, product_guid, "", trsf, ifc_product); return ifc_object; } @@ -685,7 +683,7 @@ namespace IfcGeom { , filters_(filters) , owns_ifc_file(false) { - kernel = (MAKE_TYPE_NAME(Kernel)*) impl::kernel_implementations().construct(file->schema()->name(), geometry_library, file); + kernel = (MAKE_TYPE_NAME(AbstractKernel)*) impl::kernel_implementations().construct(file->schema()->name(), geometry_library, file); // kernel = new Kernel(geometry_library, file); _initialize(); } diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index 5983748042..e796e39f01 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -36,7 +36,7 @@ void MAKE_INIT_FN(KernelImplementation_cgal_)(IfcGeom::impl::KernelFactoryImplem #define CgalKernel MAKE_TYPE_NAME(CgalKernel) -bool IfcGeom::CgalKernel::is_identity_transform(IfcUtil::IfcBaseClass* l) { +bool IfcGeom::CgalKernel::is_identity_transform(const IfcUtil::IfcBaseClass* l) { Logger::Message(Logger::LOG_ERROR, "Not implemented is_identity_transform()"); return false; /* @@ -80,154 +80,15 @@ bool IfcGeom::CgalKernel::is_identity_transform(IfcUtil::IfcBaseClass* l) { */ } -template -IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representation_and_product( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product) -{ - IfcGeom::Representation::BRep* shape; - IfcGeom::ConversionResults shapes, shapes2; - - if (!convert_shapes(representation, shapes)) { - return 0; - } - - if (settings.get(IteratorSettings::APPLY_LAYERSETS)) { - Logger::Message(Logger::LOG_ERROR, "Not implemented APPLY_LAYERSETS"); - } - - int parent_id = -1; - try { - IfcUtil::IfcBaseEntity* parent_object = get_decomposing_entity(product); - if (parent_object && parent_object->as()) { - 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(); - - cgal_placement_t trsf; - try { - // convert(product->ObjectPlacement(), trsf); - } catch (...) {} - - std::stringstream representation_id_builder; - representation_id_builder << representation->data().id(); - - // Does the IfcElement have any IfcOpenings? - // Note that openings for IfcOpeningElements are not processed - IfcSchema::IfcRelVoidsElement::list::ptr openings = find_openings(product)->as(); - - 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()) { - Logger::Message(Logger::LOG_ERROR, "Not implemented opening subtractions"); - } - - 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(); - } - - return new NativeElement( - product->data().id(), - parent_id, - name, - product_type, - guid, - context_string, - new CgalPlacement(trsf), - boost::shared_ptr(shape), - product - ); +bool IfcGeom::CgalKernel::apply_layerset(const IfcSchema::IfcProduct* product, IfcGeom::ConversionResults& shapes) { + throw std::runtime_error("not implemented"); } -template -IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_processed_representation( - const IteratorSettings& /*settings*/, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, - IfcGeom::NativeElement* brep) -{ - int parent_id = -1; - try { - IfcUtil::IfcBaseEntity* parent_object = get_decomposing_entity(product); - if (parent_object && parent_object->as()) { - 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(); - - cgal_placement_t trsf; - try { - // convert(product->ObjectPlacement(), trsf); - } catch (...) {} - - 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( - product->data().id(), - parent_id, - name, - product_type, - guid, - context_string, - new CgalPlacement(trsf), - brep->geometry_pointer(), - product - ); +bool IfcGeom::CgalKernel::validate_quantities(const IfcSchema::IfcProduct* product, const IfcGeom::Representation::BRep& brep) { + throw std::runtime_error("not implemented"); } -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representation_and_product( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representation_and_product( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_representation_and_product( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); - -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_processed_representation( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_processed_representation( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::CgalKernel::create_brep_for_processed_representation( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); - - -void IfcGeom::CgalKernel::setValue(GeomValue var, double value) { - switch (var) { - case GV_DEFLECTION_TOLERANCE: - deflection_tolerance = value; - break; - case GV_DIMENSIONALITY: - dimensionality = value; - break; - default: - throw std::runtime_error("Not implemented for this kernel"); - } +bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* product, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcGeom::ConversionResults& shapes, const IfcGeom::ConversionResultPlacement* trsf, IfcGeom::ConversionResults& opened_shapes) { + throw std::runtime_error("not implemented"); } -double IfcGeom::CgalKernel::getValue(GeomValue var) const { - switch (var) { - case GV_DEFLECTION_TOLERANCE: - return deflection_tolerance; - case GV_DIMENSIONALITY: - return dimensionality; - } - throw std::runtime_error("Not implemented for this kernel"); -} \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 86f878fd4c..3a6be54476 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -36,6 +36,9 @@ if ( it != cache.T.end() ) { e = it->second; return true; } */ #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" @@ -55,10 +58,11 @@ namespace IfcGeom { std::map Shape; }; - class IFC_GEOM_API MAKE_TYPE_NAME(CgalKernel) : public Kernel { + class IFC_GEOM_API MAKE_TYPE_NAME(CgalKernel) : public MAKE_TYPE_NAME(AbstractKernel) { public: - MAKE_TYPE_NAME(CgalKernel)() : Kernel("cgal") {} + MAKE_TYPE_NAME(CgalKernel)() + : MAKE_TYPE_NAME(AbstractKernel)("cgal") {} #ifndef NO_CACHE CgalCache cache; @@ -72,9 +76,6 @@ namespace IfcGeom { bool convert_curve(const IfcUtil::IfcBaseClass* L, cgal_curve_t& result); bool convert_face(const IfcUtil::IfcBaseClass* L, cgal_face_t& result); - virtual void setValue(GeomValue var, double value); - virtual double getValue(GeomValue var) const; - // bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, ConversionResults& cut_shapes); void purge_cache() { @@ -86,16 +87,10 @@ namespace IfcGeom { #endif } - virtual bool is_identity_transform(IfcUtil::IfcBaseClass*); - - template - IfcGeom::NativeElement* create_brep_for_representation_and_product( - const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*); - - template - IfcGeom::NativeElement* create_brep_for_processed_representation( - const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::NativeElement*); - + 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); #include "CgalEntityMappingDeclaration.h" diff --git a/src/ifcgeom/kernels/opencascade/IfcGeom.h b/src/ifcgeom/kernels/opencascade/IfcGeom.h index c3f933ad27..9af42283ec 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeom.h +++ b/src/ifcgeom/kernels/opencascade/IfcGeom.h @@ -52,6 +52,8 @@ inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance=ALMO #include "../../../ifcparse/IfcParse.h" #include "../../../ifcparse/IfcBaseClass.h" +#include "../../../ifcgeom/kernel_agnostic/AbstractKernel.h" + #include "../../../ifcgeom/schema_agnostic/IfcGeomElement.h" #include "../../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h" #include "../../../ifcgeom/schema_agnostic/ConversionResult.h" @@ -108,7 +110,7 @@ public: std::map 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: /* @@ -203,46 +205,23 @@ private: double epsilon() const { return eps_; } - }; - - double deflection_tolerance; - double wire_creation_tolerance; - double point_equality_tolerance; - double max_faces_to_sew; - double ifc_length_unit; - double ifc_planeangle_unit; - double modelling_precision; - double dimensionality; + }; #ifndef NO_CACHE MAKE_TYPE_NAME(Cache) cache; #endif - std::map style_cache; - - const SurfaceStyle* internalize_surface_style(const std::pair& 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("opencascade", 0) - , deflection_tolerance(0.001) - , wire_creation_tolerance(0.0001) - , point_equality_tolerance(0.00001) - , max_faces_to_sew(-1.0) - , ifc_length_unit(1.0) - , ifc_planeangle_unit(-1.0) - , modelling_precision(0.00001) - , dimensionality(1.) - , placement_rel_to(0) + : 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; } @@ -267,8 +246,7 @@ public: 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 ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, ConversionResults& cut_shapes); - bool convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, ConversionResults& 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&, std::vector&, std::vector&); @@ -302,8 +280,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); @@ -332,91 +308,25 @@ public: 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*); + 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 initializeUnits(IfcSchema::IfcUnitAssignment*); - template - IfcGeom::NativeElement* create_brep_for_representation_and_product( - const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*); - - template - IfcGeom::NativeElement* create_brep_for_processed_representation( - const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::NativeElement*); - - 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 std::pair _get_surface_style(const IfcSchema::IfcStyledItem* si) { -#ifdef USE_IFC4 - IfcEntityList::ptr style_assignments = si->Styles(); - for (IfcEntityList::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) { - if (!(*kt)->declaration().is(IfcSchema::IfcPresentationStyleAssignment::Class())) { - continue; - } - IfcSchema::IfcPresentationStyleAssignment* style_assignment = (IfcSchema::IfcPresentationStyleAssignment*) *kt; -#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(0,0); - } - - template std::pair get_surface_style(const IfcSchema::IfcRepresentationItem* representation_item) { - // For certain representation items, most notably boolean operands, - // a style definition might reside on one of its operands. - representation_item = find_item_carrying_style(representation_item); - - if (representation_item->as()) { - return _get_surface_style(representation_item->as()); - } - 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(*styled_items->begin()); - } - return std::make_pair(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::NativeElement* convert( const IteratorSettings& settings, IfcUtil::IfcBaseClass* representation, IfcUtil::IfcBaseClass* product) @@ -433,12 +343,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()) { - return convert(item->as(), trsf); - } else { - return false; + gp_Trsf occt_trsf; + if (convert(item->as(), occt_trsf)) { + trsf = new OpenCascadePlacement(occt_trsf); + return true; + } } + return false; } }; diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp index 5bc687e718..66819ef849 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp @@ -506,259 +506,6 @@ const TopoDS_Shape& IfcGeom::Kernel::ensure_fit_for_subtraction(const TopoDS_Sha return solid; } -bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, - const IfcGeom::ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::ConversionResults& cut_shapes) { - - // TODO: Refactor convert_openings() convert_openings_fast() and convert(IfcBooleanResult) to use - // the same code base and conform to the same checks and logging messages. - - // Iterate over IfcOpeningElements - IfcGeom::ConversionResults opening_shapes; - unsigned int last_size = 0; - for ( IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++ it ) { - IfcSchema::IfcRelVoidsElement* v = *it; - IfcSchema::IfcFeatureElementSubtraction* fes = v->RelatedOpeningElement(); - if ( fes->declaration().is(IfcSchema::IfcOpeningElement::Class()) ) { - if (!fes->hasRepresentation()) continue; - - // Convert the IfcRepresentation of the IfcOpeningElement - gp_Trsf opening_trsf; - if (fes->hasObjectPlacement()) { - try { - convert(fes->ObjectPlacement(),opening_trsf); - } catch (const std::exception& e) { - Logger::Error(e); - } catch (...) { - Logger::Error("Failed to construct placement"); - } - } - - // Move the opening into the coordinate system of the IfcProduct - opening_trsf.PreMultiply(entity_trsf.Inverted()); - - IfcSchema::IfcProductRepresentation* prodrep = fes->Representation(); - IfcSchema::IfcRepresentation::list::ptr reps = prodrep->Representations(); - - for ( IfcSchema::IfcRepresentation::list::it it2 = reps->begin(); it2 != reps->end(); ++ it2 ) { - convert_shapes(*it2,opening_shapes); - } - - const unsigned int current_size = (const unsigned int) opening_shapes.size(); - for ( unsigned int i = last_size; i < current_size; ++ i ) { - OpenCascadePlacement p((gp_GTrsf)opening_trsf); - opening_shapes[i].prepend(&p); - } - last_size = current_size; - } - } - - // Iterate over the shapes of the IfcProduct - for ( IfcGeom::ConversionResults::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) { - TopoDS_Shape entity_shape_solid; - const TopoDS_Shape& entity_shape_unlocated = ensure_fit_for_subtraction(*(OpenCascadeShape*) it3->Shape(), entity_shape_solid); - const OpenCascadePlacement* entity_shape_gtrsf = (OpenCascadePlacement*) it3->Placement(); - - TopoDS_Shape entity_shape = apply_transformation(entity_shape_unlocated, entity_shape_gtrsf); - - // Iterate over the shapes of the IfcOpeningElements - for ( IfcGeom::ConversionResults::const_iterator it4 = opening_shapes.begin(); it4 != opening_shapes.end(); ++ it4 ) { - TopoDS_Shape opening_shape_solid; - const TopoDS_Shape& opening_shape_unlocated = ensure_fit_for_subtraction(*(OpenCascadeShape*) it4->Shape(),opening_shape_solid); - const OpenCascadePlacement* opening_shape_gtrsf = (OpenCascadePlacement*)it4->Placement(); - TopoDS_Shape opening_shape = apply_transformation(opening_shape_unlocated, opening_shape_gtrsf); - - double opening_volume; - if (Logger::LOG_WARNING >= Logger::Verbosity()) { - opening_volume = shape_volume(opening_shape); - if ( opening_volume <= ALMOST_ZERO ) - Logger::Message(Logger::LOG_WARNING,"Empty opening for:",entity); - } - - if (entity_shape.ShapeType() == TopAbs_COMPSOLID) { - - // For compound solids process the subtraction for the constituent - // solids individually and write the result back as a compound solid. - - TopoDS_CompSolid compound; - BRep_Builder builder; - builder.MakeCompSolid(compound); - - TopExp_Explorer exp(entity_shape, TopAbs_SOLID); - - for (; exp.More(); exp.Next()) { - -#if OCC_VERSION_HEX < 0x60900 - BRepAlgoAPI_Cut brep_cut(exp.Current(), opening_shape); -#else - BRepAlgoAPI_Cut brep_cut; - TopTools_ListOfShape s1s; - s1s.Append(exp.Current()); - TopTools_ListOfShape s2s; - s2s.Append(opening_shape); - brep_cut.SetFuzzyValue(getValue(GV_PRECISION)); - brep_cut.SetArguments(s1s); - brep_cut.SetTools(s2s); - brep_cut.Build(); -#endif - - bool added = false; - if ( brep_cut.IsDone() ) { - TopoDS_Shape brep_cut_result = brep_cut; - BRepCheck_Analyzer analyser(brep_cut_result); - bool is_valid = analyser.IsValid() != 0; - if (is_valid) { - TopExp_Explorer exp2(brep_cut_result, TopAbs_SOLID); - for (; exp2.More(); exp2.Next()) { - builder.Add(compound, exp2.Current()); - added = true; - } - } - } - if (!added) { - // Add the original in case subtraction fails - builder.Add(compound, exp.Current()); - } else { - Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",entity); - } - } - - entity_shape = compound; - - } else { -#if OCC_VERSION_HEX < 0x60900 - BRepAlgoAPI_Cut brep_cut(entity_shape,opening_shape); -#else - BRepAlgoAPI_Cut brep_cut; - TopTools_ListOfShape s1s; - s1s.Append(entity_shape); - TopTools_ListOfShape s2s; - s2s.Append(opening_shape); - brep_cut.SetFuzzyValue(getValue(GV_PRECISION)); - brep_cut.SetArguments(s1s); - brep_cut.SetTools(s2s); - brep_cut.Build(); -#endif - - if ( brep_cut.IsDone() ) { - TopoDS_Shape brep_cut_result = brep_cut; - - ShapeFix_Shape fix(brep_cut_result); - try { - fix.Perform(); - brep_cut_result = fix.Shape(); - } catch (...) { - Logger::Error("Shape healing failed on opening subtraction result", entity); - } - - BRepCheck_Analyzer analyser(brep_cut_result); - bool is_valid = analyser.IsValid() != 0; - if ( is_valid ) { - entity_shape = brep_cut_result; - if (Logger::LOG_WARNING >= Logger::Verbosity()) { - const double volume_after_subtraction = shape_volume(entity_shape); - double original_shape_volume = shape_volume(entity_shape); - if ( ALMOST_THE_SAME(original_shape_volume,volume_after_subtraction) ) - Logger::Message(Logger::LOG_WARNING,"Subtraction yields unchanged volume:",entity); - } - } else { - Logger::Message(Logger::LOG_ERROR,"Invalid result from subtraction:",entity); - } - } else { - Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",entity); - } - } - - } - cut_shapes.push_back(IfcGeom::ConversionResult(it3->ItemId(), it3->Placement()->clone(), new OpenCascadeShape(entity_shape), &it3->Style())); - } - - return true; -} - -#if OCC_VERSION_HEX < 0x60900 -bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, - const IfcGeom::ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::ConversionResults& cut_shapes) { - - // Create a compound of all opening shapes in order to speed up the boolean operations - TopoDS_Compound opening_compound; - BRep_Builder builder; - builder.MakeCompound(opening_compound); - - for ( IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++ it ) { - IfcSchema::IfcRelVoidsElement* v = *it; - IfcSchema::IfcFeatureElementSubtraction* fes = v->RelatedOpeningElement(); - if ( fes->declaration().is(IfcSchema::IfcOpeningElement::Class()) ) { - if (!fes->hasRepresentation()) continue; - - // Convert the IfcRepresentation of the IfcOpeningElement - gp_Trsf opening_trsf; - if (fes->hasObjectPlacement()) { - try { - convert(fes->ObjectPlacement(),opening_trsf); - } catch (const std::exception& e) { - Logger::Error(e); - } catch (...) { - Logger::Error("Failed to construct placement"); - } - } - - // Move the opening into the coordinate system of the IfcProduct - opening_trsf.PreMultiply(entity_trsf.Inverted()); - - IfcSchema::IfcProductRepresentation* prodrep = fes->Representation(); - IfcSchema::IfcRepresentation::list::ptr reps = prodrep->Representations(); - - IfcGeom::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 ) { - gp_GTrsf gtrsf = opening_shapes[i].Placement(); - gtrsf.PreMultiply(opening_trsf); - TopoDS_Shape opening_shape = apply_transformation(opening_shapes[i].Shape(), gtrsf); - builder.Add(opening_compound, opening_shape); - } - - } - } - - // Iterate over the shapes of the IfcProduct - for ( IfcGeom::ConversionResults::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) { - TopoDS_Shape entity_shape_solid; - const TopoDS_Shape& entity_shape_unlocated = ensure_fit_for_subtraction(it3->Shape(),entity_shape_solid); - const gp_GTrsf& entity_shape_gtrsf = it3->Placement(); - if (entity_shape_gtrsf.Form() == gp_Other) { - Logger::Message(Logger::LOG_WARNING, "Applying non uniform transformation to:", entity); - } - TopoDS_Shape entity_shape = apply_transformation(entity_shape_unlocated, entity_shape_gtrsf); - - BRepAlgoAPI_Cut brep_cut(entity_shape,opening_compound); - - bool is_valid = false; - if ( brep_cut.IsDone() ) { - TopoDS_Shape brep_cut_result = brep_cut; - - BRepCheck_Analyzer analyser(brep_cut_result); - is_valid = analyser.IsValid() != 0; - if ( is_valid ) { - cut_shapes.push_back(IfcGeom::ConversionResult(it3->ItemId(), brep_cut_result, &it3->Style())); - } - } - if ( !is_valid ) { - // Apparently processing the boolean operation failed or resulted in an invalid result - // in which case the original shape without the subtractions is returned instead - // we try convert the openings in the original way, one by one. - Logger::Message(Logger::LOG_WARNING,"Subtracting combined openings compound failed:",entity); - return false; - } - - } - return true; -} -#else - namespace { struct opening_sorter { bool operator()(const std::pair& a, const std::pair& b) const { @@ -767,8 +514,10 @@ namespace { }; } -bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, - const IfcGeom::ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::ConversionResults& cut_shapes) { +bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, + const IfcGeom::ConversionResults& entity_shapes, const ConversionResultPlacement* entity_place, IfcGeom::ConversionResults& cut_shapes) { + + const gp_Trsf entity_trsf = ((OpenCascadePlacement*)entity_place)->trsf().Trsf(); std::vector< std::pair > opening_vector; @@ -859,7 +608,6 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, } return true; } -#endif bool IfcGeom::Kernel::convert_wire_to_face(const TopoDS_Wire& w, TopoDS_Face& face) { TopoDS_Wire wire = w; @@ -1084,63 +832,6 @@ void IfcGeom::Kernel::apply_tolerance(TopoDS_Shape& s, double t) { #endif } -void IfcGeom::Kernel::setValue(GeomValue var, double value) { - switch (var) { - case GV_DEFLECTION_TOLERANCE: - deflection_tolerance = value; - break; - case GV_WIRE_CREATION_TOLERANCE: - wire_creation_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::Kernel::getValue(GeomValue var) const { - switch (var) { - case GV_DEFLECTION_TOLERANCE: - return deflection_tolerance; - case GV_WIRE_CREATION_TOLERANCE: - return wire_creation_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; -} - namespace { // Returns the vertex part of an TopoDS_Edge edge that is not TopoDS_Vertex vertex @@ -1407,422 +1098,6 @@ void IfcGeom::Kernel::sequence_of_point_to_wire(const TColgp_SequenceOfPnt& p, T w = builder.Wire(); } -const IfcSchema::IfcMaterial* IfcGeom::Kernel::get_single_material_association(const IfcSchema::IfcProduct* product) { - IfcSchema::IfcMaterial* single_material = 0; - IfcSchema::IfcRelAssociatesMaterial::list::ptr associated_materials = product->HasAssociations()->as(); - if (associated_materials->size() == 1) { - IfcSchema::IfcMaterialSelect* associated_material = (*associated_materials->begin())->RelatingMaterial(); - single_material = associated_material->as(); - - // 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::IfcMaterialLayerSet* layerset = associated_material->as()->ForLayerSet(); - if (layerset->MaterialLayers()->size() == 1) { - IfcSchema::IfcMaterialLayer* layer = (*layerset->MaterialLayers()->begin()); - if (layer->hasMaterial()) { - single_material = layer->Material(); - } - } - } - } - return single_material; -} - -template -IfcGeom::NativeElement* IfcGeom::Kernel::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, shapes2; - - if ( !convert_shapes(representation, shapes) ) { - return 0; - } - - if (settings.get(IteratorSettings::APPLY_LAYERSETS)) { - TopoDS_Shape merge; - if (flatten_shape_list(shapes, merge, false)) { - if (count(merge, TopAbs_FACE) > 0) { - std::vector thickness; - std::vector layers; - std::vector< std::vector > folded_layers; - std::vector styles; - if (convert_layerset(product, layers, styles, thickness)) { - - 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(); - if (associates_material) { - unsigned layerset_id = associates_material->RelatingMaterial()->data().id(); - representation_id_builder << "-layerset-" << layerset_id; - break; - } - } - - if (styles.size() > 1) { - // If there's only a single layer there is no need to manipulate geometries. - bool success = true; - if (product->as() && fold_layers(product->as(), shapes, layers, thickness, folded_layers)) { - if (apply_folded_layerset(shapes, folded_layers, styles, shapes2)) { - std::swap(shapes, shapes2); - success = true; - } - } else { - if (apply_layerset(shapes, layers, styles, shapes2)) { - std::swap(shapes, shapes2); - success = true; - } - } - - if (!success) { - Logger::Error("Failed processing layerset"); - } - } - } - } - } - } - - 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()) { - 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(); - - gp_Trsf trsf; - try { - convert(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(); - - 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 { -#if OCC_VERSION_HEX < 0x60900 - const bool faster_booleans = settings.get(IteratorSettings::FASTER_BOOLEANS); -#else - const bool faster_booleans = true; -#endif - if (faster_booleans) { - bool success = convert_openings_fast(product,openings,shapes,trsf,opened_shapes); -#if OCC_VERSION_HEX < 0x60900 - if (!success) { - opened_shapes.clear(); - convert_openings(product,openings,shapes,trsf,opened_shapes); - } -#else - (void)success; -#endif - } else { - 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 ) { - OpenCascadePlacement p(trsf); - it->prepend(&p); - } - trsf = gp_Trsf(); - 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 ) { - OpenCascadePlacement p(trsf); - it->prepend(&p); - } - trsf = gp_Trsf(); - 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( - product->data().id(), - parent_id, - name, - product_type, - guid, - context_string, - new OpenCascadePlacement(trsf), - boost::shared_ptr(shape), - product - ); - - if (settings.get(IteratorSettings::VALIDATE_QUANTITIES)) { - auto rels = product->IsDefinedBy(); - for (auto& rel : *rels) { - if (rel->as()) { - auto pdef = rel->as()->RelatingPropertyDefinition(); - if (pdef->as()) { - std::string organization_name; - try { - // A couple of files are not according to the schema here. - organization_name = pdef->as()->OwnerHistory()->OwningApplication()->ApplicationDeveloper()->Name(); - } catch (...) {} - if (organization_name == "IfcOpenShell") { - auto qs = pdef->as()->Quantities(); - for (auto& q : *qs) { - if (q->as() && q->Name() == "Total Surface Area") { - double a_calc; - double a_file = q->as()->AreaValue(); - if (elem->geometry().calculate_surface_area(a_calc)) { - double diff = std::abs(a_calc - a_file); - if (diff / std::sqrt(a_file) > getValue(GV_PRECISION)) { - Logger::Error("Validation of surface area failed for:", product); - } else { - Logger::Notice("Validation of surface area succeeded for:", product); - } - } else { - Logger::Error("Validation of surface area failed for:", product); - } - } else if (q->as() && q->Name() == "Volume") { - double v_calc; - double v_file = q->as()->VolumeValue(); - if (elem->geometry().calculate_volume(v_calc)) { - double diff = std::abs(v_calc - v_file); - if (diff / std::sqrt(v_file) > getValue(GV_PRECISION)) { - Logger::Error("Validation of volume failed for:", product); - } else { - Logger::Notice("Validation of volume succeeded for:", product); - } - } else { - Logger::Error("Validation of volume failed for:", product); - } - } else if (q->as() && q->Name() == "Shape Validation Properties") { - auto qs2 = q->as()->HasQuantities(); - bool all_succeeded = qs2->size() > 0; - for (auto& q2 : *qs2) { - if (q2->as() && q2->Name() == "Surface Genus" && q2->hasDescription()) { - int item_id = boost::lexical_cast(q2->Description().substr(1)); - int genus = q2->as()->CountValue(); - for (auto& part : elem->geometry()) { - if (part.ItemId() == item_id) { - if (surface_genus(*(OpenCascadeShape*)part.Shape()) != genus) { - all_succeeded = false; - } - } - } - } - } - if (!all_succeeded) { - Logger::Error("Validation of surface genus failed for:", product); - } else { - Logger::Notice("Validation of surface genus succeeded for:", product); - } - } - } - } - } - } - } - } - - return elem; -} - -IfcSchema::IfcRepresentation* IfcGeom::Kernel::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(); - 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::Kernel::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::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(); - 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(); - products->push(ps); - } - } - } - } - } - - return products; -} - -template -IfcGeom::NativeElement* IfcGeom::Kernel::create_brep_for_processed_representation( - const IteratorSettings& /*settings*/, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, - IfcGeom::NativeElement* brep) -{ - int parent_id = -1; - try { - IfcUtil::IfcBaseEntity* parent_object = get_decomposing_entity(product); - if (parent_object && parent_object->as()) { - 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(); - - gp_Trsf trsf; - try { - convert(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( - product->data().id(), - parent_id, - name, - product_type, - guid, - context_string, - new OpenCascadePlacement(trsf), - brep->geometry_pointer(), - product - ); -} - -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::Kernel::create_brep_for_representation_and_product( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::Kernel::create_brep_for_representation_and_product( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::Kernel::create_brep_for_representation_and_product( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); - -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::Kernel::create_brep_for_processed_representation( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::Kernel::create_brep_for_processed_representation( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::Kernel::create_brep_for_processed_representation( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); - std::pair IfcGeom::Kernel::initializeUnits(IfcSchema::IfcUnitAssignment* unit_assignment) { // Set default units, set length to meters, angles to undefined setValue(IfcGeom::Kernel::GV_LENGTH_UNIT, 1.0); @@ -2951,36 +2226,14 @@ bool IfcGeom::Kernel::project(const Handle_Geom_Surface& srf, const TopoDS_Shape return vertex_count > 0; } -const IfcSchema::IfcRepresentationItem* IfcGeom::Kernel::find_item_carrying_style(const IfcSchema::IfcRepresentationItem* item) { - if (item->StyledByItem()->size()) { - return item; - } +bool IfcGeom::Kernel::is_identity_transform(const IfcUtil::IfcBaseClass* l) { + const IfcSchema::IfcAxis2Placement2D* ax2d; + const IfcSchema::IfcAxis2Placement3D* ax3d; - 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; -} - -bool IfcGeom::Kernel::is_identity_transform(IfcUtil::IfcBaseClass* l) { - IfcSchema::IfcAxis2Placement2D* ax2d; - IfcSchema::IfcAxis2Placement3D* ax3d; - - IfcSchema::IfcCartesianTransformationOperator2D* op2d; - IfcSchema::IfcCartesianTransformationOperator3D* op3d; - IfcSchema::IfcCartesianTransformationOperator2DnonUniform* op2dnonu; - IfcSchema::IfcCartesianTransformationOperator3DnonUniform* op3dnonu; + const IfcSchema::IfcCartesianTransformationOperator2D* op2d; + const IfcSchema::IfcCartesianTransformationOperator3D* op3d; + const IfcSchema::IfcCartesianTransformationOperator2DnonUniform* op2dnonu; + const IfcSchema::IfcCartesianTransformationOperator3DnonUniform* op3dnonu; if((op2dnonu = l->as()) != 0) { gp_GTrsf2d gtrsf2d; @@ -3846,4 +3099,112 @@ IfcGeom::Kernel::faceset_helper::faceset_helper(Kernel* kernel, const IfcSchema: if (loops_removed || (non_manifold && l->declaration().is(IfcSchema::IfcClosedShell::Class()))) { Logger::Warning(boost::lexical_cast(loops_removed) + " loops removed and " + boost::lexical_cast(non_manifold) + " non-manifold edges for:", l); } +} + +bool IfcGeom::Kernel::apply_layerset(const IfcSchema::IfcProduct* product, IfcGeom::ConversionResults& shapes) { + IfcGeom::ConversionResults shapes2; + + bool success = false; + + TopoDS_Shape merge; + if (flatten_shape_list(shapes, merge, false)) { + if (count(merge, TopAbs_FACE) > 0) { + std::vector thickness; + std::vector layers; + std::vector< std::vector > folded_layers; + std::vector styles; + if (convert_layerset(product, layers, styles, thickness)) { + if (styles.size() > 1) { + // If there's only a single layer there is no need to manipulate geometries. + success = true; + if (product->as() && fold_layers(product->as(), shapes, layers, thickness, folded_layers)) { + if (apply_folded_layerset(shapes, folded_layers, styles, shapes2)) { + std::swap(shapes, shapes2); + success = true; + } + } else { + if (apply_layerset(shapes, layers, styles, shapes2)) { + std::swap(shapes, shapes2); + success = true; + } + } + + if (!success) { + Logger::Error("Failed processing layerset"); + } + } + } + } + } + + return success; +} + +bool IfcGeom::Kernel::validate_quantities(const IfcSchema::IfcProduct* product, const IfcGeom::Representation::BRep& brep) { + auto rels = product->IsDefinedBy(); + for (auto& rel : *rels) { + if (rel->as()) { + auto pdef = rel->as()->RelatingPropertyDefinition(); + if (pdef->as()) { + std::string organization_name; + try { + // A couple of files are not according to the schema here. + organization_name = pdef->as()->OwnerHistory()->OwningApplication()->ApplicationDeveloper()->Name(); + } catch (...) {} + if (organization_name == "IfcOpenShell") { + auto qs = pdef->as()->Quantities(); + for (auto& q : *qs) { + if (q->as() && q->Name() == "Total Surface Area") { + double a_calc; + double a_file = q->as()->AreaValue(); + if (brep.calculate_surface_area(a_calc)) { + double diff = std::abs(a_calc - a_file); + if (diff / std::sqrt(a_file) > getValue(GV_PRECISION)) { + Logger::Error("Validation of surface area failed for:", product); + } else { + Logger::Notice("Validation of surface area succeeded for:", product); + } + } else { + Logger::Error("Validation of surface area failed for:", product); + } + } else if (q->as() && q->Name() == "Volume") { + double v_calc; + double v_file = q->as()->VolumeValue(); + if (brep.calculate_volume(v_calc)) { + double diff = std::abs(v_calc - v_file); + if (diff / std::sqrt(v_file) > getValue(GV_PRECISION)) { + Logger::Error("Validation of volume failed for:", product); + } else { + Logger::Notice("Validation of volume succeeded for:", product); + } + } else { + Logger::Error("Validation of volume failed for:", product); + } + } else if (q->as() && q->Name() == "Shape Validation Properties") { + auto qs2 = q->as()->HasQuantities(); + bool all_succeeded = qs2->size() > 0; + for (auto& q2 : *qs2) { + if (q2->as() && q2->Name() == "Surface Genus" && q2->hasDescription()) { + int item_id = boost::lexical_cast(q2->Description().substr(1)); + int genus = q2->as()->CountValue(); + for (auto& part : brep) { + if (part.ItemId() == item_id) { + if (surface_genus(*(OpenCascadeShape*)part.Shape()) != genus) { + all_succeeded = false; + } + } + } + } + } + if (!all_succeeded) { + Logger::Error("Validation of surface genus failed for:", product); + } else { + Logger::Notice("Validation of surface genus succeeded for:", product); + } + } + } + } + } + } + } } \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomHelpers.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomHelpers.cpp index 99db68c5ab..1c941b88d6 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomHelpers.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomHelpers.cpp @@ -362,10 +362,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()) ) { diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomRenderStyles.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomRenderStyles.cpp deleted file mode 100644 index edc2085b79..0000000000 --- a/src/ifcgeom/kernels/opencascade/IfcGeomRenderStyles.cpp +++ /dev/null @@ -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 . * - * * - ********************************************************************************/ - -#include - -#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(colour_or_factor), rgb); - } else if (colour_or_factor->declaration().is(IfcSchema::IfcNormalisedRatioMeasure::Class())) { - return process_colour(static_cast(colour_or_factor), rgb); - } else { - return false; - } - } - -} - -#define Kernel MAKE_TYPE_NAME(Kernel) - -const IfcGeom::SurfaceStyle* IfcGeom::Kernel::internalize_surface_style(const std::pair& shading_styles) { - if (shading_styles.second == 0) { - return 0; - } - int surface_style_id = shading_styles.first->data().id(); - std::map::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::IfcSurfaceStyleShading* shading = shading_styles.second->as(); - - 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(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(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()); - } - for (IfcSchema::IfcStyledItem::list::it it = styles->begin(); it != styles->end(); ++it) { - const std::pair ss = get_surface_style(*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); -} diff --git a/src/ifcgeom/schema_agnostic/ConversionResult.h b/src/ifcgeom/schema_agnostic/ConversionResult.h index e4f5b55211..e413f2c0ea 100644 --- a/src/ifcgeom/schema_agnostic/ConversionResult.h +++ b/src/ifcgeom/schema_agnostic/ConversionResult.h @@ -34,6 +34,7 @@ namespace IfcGeom { 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; diff --git a/src/ifcgeom/schema_agnostic/Kernel.h b/src/ifcgeom/schema_agnostic/Kernel.h index 549e6be0c8..5bbb050649 100644 --- a/src/ifcgeom/schema_agnostic/Kernel.h +++ b/src/ifcgeom/schema_agnostic/Kernel.h @@ -72,7 +72,7 @@ namespace IfcGeom { 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); } diff --git a/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.h b/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.h index 6f231d1efa..9bb534437f 100644 --- a/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.h +++ b/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.h @@ -66,6 +66,10 @@ namespace IfcGeom { 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_; }; diff --git a/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h b/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h index 621f030960..75a41dd1b1 100644 --- a/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h +++ b/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h @@ -69,6 +69,12 @@ namespace IfcGeom { 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_; }; diff --git a/src/serializers/SvgSerializer.cpp b/src/serializers/SvgSerializer.cpp index d1af9174f4..06427e4331 100644 --- a/src/serializers/SvgSerializer.cpp +++ b/src/serializers/SvgSerializer.cpp @@ -512,9 +512,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; } From 30479ca0a62ac2296663afed96ed984a05f04679 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 23 Jan 2019 12:34:21 +0100 Subject: [PATCH 131/235] Fixes for compilation of cgal kernel --- cmake/CMakeLists.txt | 2 +- nix/build-all.py | 15 +++++- .../kernels/cgal/CgalConversionFunctions.cpp | 51 ++++++++++--------- .../kernels/cgal/CgalEntityMapping.cpp | 29 ++++++----- src/ifcgeom/kernels/cgal/CgalKernel.h | 2 + .../kernels/opencascade/IfcGeomFaces.cpp | 15 +++++- .../kernels/opencascade/IfcGeomFunctions.cpp | 26 +++++++--- src/ifcgeom/kernels/opencascade/IfcGeomTree.h | 23 ++++++--- .../schema_agnostic/IfcGeomRepresentation.cpp | 15 ++++-- .../schema_agnostic/IfcGeomRepresentation.h | 19 +------ src/ifcgeom/schema_agnostic/Kernel.cpp | 29 ++++++++--- src/ifcgeom/schema_agnostic/Kernel.h | 8 ++- .../cgal/CgalConversionResult.cpp | 25 ++++++--- .../OpenCascadeBasedSerializer.cpp | 4 +- src/serializers/SvgSerializer.cpp | 7 ++- 15 files changed, 171 insertions(+), 99 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 75dbc3319b..6eeefff91f 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -279,8 +279,8 @@ ENDIF() IF(NOT libMPFR) MESSAGE(FATAL_ERROR "Unable to find MPFR library files, aborting") ENDIF() -list(APPEND CGAL_LIBRARIES "${libGMP}") list(APPEND CGAL_LIBRARIES "${libMPFR}") +list(APPEND CGAL_LIBRARIES "${libGMP}") diff --git a/nix/build-all.py b/nix/build-all.py index b7c10d50a6..ff5889a622 100644 --- a/nix/build-all.py +++ b/nix/build-all.py @@ -67,7 +67,7 @@ PYTHON_VERSIONS=["2.7.12", "3.2.6", "3.3.6", "3.4.6", "3.5.3", "3.6.2"] # OCCT_VERSION="7.2.0" # OCCT_HASH="88af392" OCCT_VERSION="7.3.0" -BOOST_VERSION="1.59.0" +BOOST_VERSION="1.69.0" PCRE_VERSION="8.39" LIBXML_VERSION="2.9.3" CMAKE_VERSION="3.4.1" @@ -75,6 +75,7 @@ ICU_VERSION="56.1" SWIG_VERSION="3.0.12" GMP_VERSION="6.1.2" MPFR_VERSION="3.1.5" +CGAL_VERSION="4.13" # binaries cp="cp" @@ -659,7 +660,7 @@ if "cgal" in targets: if BUILD_CFG != "Debug": # CGAL only supports Debug and Release for CMAKE_BUILD_TYPE BUILD_CFG = "Release" - build_dependency(name="cgal", 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/" % (DEPS_DIR,)], download_url="https://github.com/CGAL/cgal.git", download_name="cgal", download_tool=download_tool_git) + 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)], 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 cecho("Building IfcOpenShell:", GREEN) @@ -703,6 +704,16 @@ elif "occ" in targets: "-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()), diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 651a53fca3..c09f8e5810 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -3,6 +3,9 @@ #define CgalKernel MAKE_TYPE_NAME(CgalKernel) +// @todo two distinct uses of the word Kernel is getting confusing +typedef Kernel Kernel_; + bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRepresentation* l, ConversionResults& shapes) { IfcSchema::IfcRepresentationItem::list::ptr items = l->Items(); bool part_succes = false; @@ -26,7 +29,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRepresentation* l, Convers 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->entity); + Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", l); return false; } @@ -49,10 +52,10 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal std::list face_list; face_list.push_back(face); - for (std::vector::const_iterator current_vertex = face.outer.begin(); + for (std::vector::const_iterator current_vertex = face.outer.begin(); current_vertex != face.outer.end(); ++current_vertex) { - std::vector::const_iterator next_vertex = current_vertex; + std::vector::const_iterator next_vertex = current_vertex; ++next_vertex; if (next_vertex == face.outer.end()) { next_vertex = face.outer.begin(); @@ -65,14 +68,14 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal } cgal_face_t top_face; - for (std::vector::const_reverse_iterator vertex = face.outer.rbegin(); + for (std::vector::const_reverse_iterator vertex = face.outer.rbegin(); vertex != face.outer.rend(); ++vertex) { top_face.outer.push_back(*vertex+height*dir); } face_list.push_back(top_face); // Naive creation - cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); PolyhedronBuilder builder(&face_list); polyhedron.delegate(builder); @@ -91,7 +94,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_point_t& point) { std::vector xyz = l->Coordinates(); if (xyz.size() == 3) { - point = Kernel::Point_3(xyz.size() ? (xyz[0]*getValue(GV_LENGTH_UNIT)) : 0.0f, + 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; @@ -104,7 +107,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_po bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcDirection* l, cgal_direction_t& dir) { // IN_CACHE(IfcDirection,l,cgal_direction_t,dir) std::vector xyz = l->DirectionRatios(); - dir = Kernel::Vector_3(xyz.size() ? xyz[0] : 0.0f, + 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) @@ -114,15 +117,15 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcDirection* l, cgal_directi 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 axis = Kernel::Vector_3(0,0,1); - cgal_direction_t refDirection = Kernel::Vector_3(1,0,0); // TODO: Put identity for now. Check? + cgal_direction_t axis = Kernel_::Vector_3(0,0,1); + cgal_direction_t refDirection = Kernel_::Vector_3(1,0,0); // TODO: Put identity for now. Check? IfcGeom::CgalKernel::convert(l->Location(),o); bool hasRef = l->hasRefDirection(); if ( hasRef ) IfcGeom::CgalKernel::convert(l->RefDirection(),refDirection); // TODO: From Thomas' email. Should be checked. - Kernel::Vector_3 y = CGAL::cross_product(Kernel::Vector_3(0.0, 0.0, 1.0), refDirection); - trsf = Kernel::Aff_transformation_3(refDirection.cartesian(0), y.cartesian(0), 0.0, o.cartesian(0), + Kernel_::Vector_3 y = CGAL::cross_product(Kernel_::Vector_3(0.0, 0.0, 1.0), refDirection); + 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, y.cartesian(2), 1.0, 0.0); @@ -133,8 +136,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement2D* l, cgal_ 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); // TODO: Put identity for now. Check? + cgal_direction_t axis = Kernel_::Vector_3(0,0,1); + cgal_direction_t refDirection = Kernel_::Vector_3(1,0,0); // TODO: Put identity for now. Check? IfcGeom::CgalKernel::convert(l->Location(),o); bool hasRef = l->hasRefDirection(); if ( l->hasAxis() ) IfcGeom::CgalKernel::convert(l->Axis(),axis); @@ -145,8 +148,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement3D* l, cgal_ // std::cout << "Origin: " << o << std::endl; // TODO: From Thomas' email. Should be checked. - Kernel::Vector_3 y = CGAL::cross_product(axis, refDirection); - trsf = Kernel::Aff_transformation_3(refDirection.cartesian(0), y.cartesian(0), axis.cartesian(0), o.cartesian(0), + Kernel_::Vector_3 y = CGAL::cross_product(axis, refDirection); + trsf = Kernel_::Aff_transformation_3(refDirection.cartesian(0), y.cartesian(0), axis.cartesian(0), o.cartesian(0), refDirection.cartesian(1), y.cartesian(1), axis.cartesian(1), o.cartesian(1), refDirection.cartesian(2), y.cartesian(2), axis.cartesian(2), o.cartesian(2)); @@ -163,8 +166,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement3D* l, cgal_ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_placement_t& trsf) { // TODO: These macros don't work for the CGAL types. Need to check why. // IN_CACHE(IfcObjectPlacement,l,cgal_placement_t,trsf) - if ( ! l->is(IfcSchema::Type::IfcLocalPlacement) ) { - Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l->entity); + if ( ! l->as() ) { + Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l); return false; } @@ -180,7 +183,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_p cgal_placement_t trsf2; IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement(); - if ( relplacement->is(IfcSchema::Type::IfcAxis2Placement3D) ) { + if ( relplacement->as() ) { IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2); // std::cout << "trsf2" << std::endl; @@ -201,7 +204,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_p } if ( current->hasPlacementRelTo() ) { IfcSchema::IfcObjectPlacement* relto = current->PlacementRelTo(); - if ( relto->is(IfcSchema::Type::IfcLocalPlacement) ) + if ( relto->as() ) current = (IfcSchema::IfcLocalPlacement*)current->PlacementRelTo(); else break; } else break; @@ -215,7 +218,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleProfileDef* l, cg const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT); if ( x < ALMOST_ZERO || y < ALMOST_ZERO ) { - Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); + Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l); return false; } @@ -229,10 +232,10 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleProfileDef* l, cg } 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)); + 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)); return true; } diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp index f32a578d27..9f9a01684e 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp @@ -21,6 +21,9 @@ #define CgalKernel MAKE_TYPE_NAME(CgalKernel) +// @todo two distinct uses of the word Kernel is getting confusing +typedef Kernel Kernel_; + using namespace IfcUtil; bool IfcGeom::CgalKernel::convert_shapes(const IfcBaseClass* l, ConversionResults& r) { @@ -84,11 +87,11 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, Conv const SurfaceStyle* indiv_style = get_style(l->Outer()); IfcSchema::IfcClosedShell::list::ptr voids(new IfcSchema::IfcClosedShell::list); - if (l->is(IfcSchema::Type::IfcFacetedBrepWithVoids)) { + if (l->as()) { voids = l->as()->Voids(); } #ifdef USE_IFC4 - if (l->is(IfcSchema::Type::IfcAdvancedBrepWithVoids)) { + if (l->as()) { voids = l->as()->Voids(); } #endif @@ -102,7 +105,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, Conv // } } - shape.push_back(ConversionResult(new CgalShape(s), indiv_style ? indiv_style : collective_style)); + shape.push_back(ConversionResult(l->data().id(), new CgalShape(s), indiv_style ? indiv_style : collective_style)); return true; } return false; @@ -121,7 +124,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_ } catch (...) {} if (!success) { - Logger::Message(Logger::LOG_WARNING, "Failed to convert face:", (*it)->entity); + Logger::Message(Logger::LOG_WARNING, "Failed to convert face:", *it); continue; } @@ -134,7 +137,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_ } // Naive creation - cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); PolyhedronBuilder builder(&face_list); polyhedron.delegate(builder); @@ -169,11 +172,11 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcFace* l, cgal_face_t& face for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) { IfcSchema::IfcFaceBound* bound = *it; - if (bound->is(IfcSchema::Type::IfcFaceOuterBound)) num_outer_bounds ++; + if (bound->as()) num_outer_bounds ++; } if (num_outer_bounds != 1) { - Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l->entity); + Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l); return false; } @@ -183,11 +186,11 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcFace* l, cgal_face_t& face IfcSchema::IfcFaceBound* bound = *it; IfcSchema::IfcLoop* loop = bound->Bound(); - const bool is_interior = !bound->is(IfcSchema::Type::IfcFaceOuterBound); + const bool is_interior = !bound->as(); cgal_wire_t wire; if (!convert_wire(loop, wire)) { - Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop->entity); + Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop); return false; } @@ -212,7 +215,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& IfcSchema::IfcCartesianPoint::list::ptr points = l->Polygon(); // Parse and store the points in a sequence - cgal_wire_t polygon = std::vector(); + cgal_wire_t polygon = std::vector(); for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) { cgal_point_t pnt; IfcGeom::CgalKernel::convert(*it, pnt); @@ -222,7 +225,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& // 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->entity); + Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l); return false; } @@ -232,11 +235,11 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& 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->entity); + Logger::Message(Logger::LOG_WARNING, ss.str(), l); } if (count < 3) { - Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity); + Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l); return false; } diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 00492f8089..6519b0ad68 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -35,6 +35,8 @@ if ( it != cache.T.end() ) { e = it->second; return true; } #endif */ +#define ALMOST_ZERO 1.e-9 + #include "../../../ifcparse/macros.h" #include "../../../ifcgeom/kernel_agnostic/AbstractKernel.h" diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomFaces.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomFaces.cpp index 6e2943d3c6..1f752e30fd 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomFaces.cpp @@ -106,6 +106,19 @@ #define Kernel MAKE_TYPE_NAME(Kernel) +namespace { + int count_occt(const TopoDS_Shape& s, TopAbs_ShapeEnum t) { + IfcGeom::OpenCascadeShape Ss(s); + return IfcGeom::Kernel::count(&Ss, (int) t); + } + + int is_manifold_occt(const TopoDS_Shape& s) { + IfcGeom::OpenCascadeShape Ss(s); + return IfcGeom::Kernel::is_manifold(&Ss); + } +} + + bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) { IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds(); @@ -239,7 +252,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) { if (face_surface.IsNull()) { gp_Pln pln; - if (count(wire, TopAbs_EDGE) > 128 && approximate_plane_through_wire(wire, pln)) { + if (count_occt(wire, TopAbs_EDGE) > 128 && approximate_plane_through_wire(wire, pln)) { // tfk: optimization find the underlying surface ourselves since it's going // to be planar in IFC if no explicit surface is given. Should we always do this? // @todo is this still relevant considering the code above diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp index 66819ef849..24bb7b858a 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp @@ -337,6 +337,18 @@ namespace { } } +namespace { + int count_occt(const TopoDS_Shape& s, TopAbs_ShapeEnum t) { + IfcGeom::OpenCascadeShape Ss(s); + return IfcGeom::Kernel::count(&Ss, (int) t); + } + + int is_manifold_occt(const TopoDS_Shape& s) { + IfcGeom::OpenCascadeShape Ss(s); + return IfcGeom::Kernel::is_manifold(&Ss); + } +} + bool IfcGeom::Kernel::create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& shape) { TopTools_ListOfShape face_list; TopExp_Explorer exp(compound, TopAbs_FACE); @@ -388,7 +400,7 @@ bool IfcGeom::Kernel::create_solid_from_faces(const TopTools_ListOfShape& face_l } BRepCheck_Analyzer ana(shape); - valid_shell = ana.IsValid() != 0 && count(shape, TopAbs_SHELL) > 0; + valid_shell = ana.IsValid() != 0 && count_occt(shape, TopAbs_SHELL) > 0; } catch (const Standard_Failure& e) { if (e.GetMessageString() && strlen(e.GetMessageString())) { Logger::Error(e.GetMessageString()); @@ -1899,12 +1911,12 @@ bool IfcGeom::Kernel::apply_folded_layerset(const ConversionResults& items, cons TopoDS_Shape Bn = BRepPrimAPI_MakeHalfSpace(B, jt->second.second).Solid(); TopoDS_Shape a = BRepAlgoAPI_Cut(A, Bn); - if (count(a, TopAbs_FACE) == 1) { + if (count_occt(a, TopAbs_FACE) == 1) { A = TopoDS::Face(TopExp_Explorer(a, TopAbs_FACE).Current()); } TopoDS_Shape b = BRepAlgoAPI_Cut(B, An); - if (count(b, TopAbs_FACE) == 1) { + if (count_occt(b, TopAbs_FACE) == 1) { B = TopoDS::Face(TopExp_Explorer(b, TopAbs_FACE).Current()); } } @@ -2504,7 +2516,7 @@ bool IfcGeom::Kernel::wire_intersections(const TopoDS_Wire& wire, TopTools_ListO return false; } - int n = count(wire, TopAbs_EDGE); + int n = count_occt(wire, TopAbs_EDGE); if (n < 3) { wires.Append(wire); return false; @@ -2936,7 +2948,7 @@ bool IfcGeom::Kernel::boolean_operation(const TopoDS_Shape& a, const TopTools_Li if (success) { - success = !is_manifold(a) || is_manifold(r); + success = !is_manifold_occt(a) || is_manifold_occt(r); if (success) { @@ -3108,7 +3120,7 @@ bool IfcGeom::Kernel::apply_layerset(const IfcSchema::IfcProduct* product, IfcGe TopoDS_Shape merge; if (flatten_shape_list(shapes, merge, false)) { - if (count(merge, TopAbs_FACE) > 0) { + if (count_occt(merge, TopAbs_FACE) > 0) { std::vector thickness; std::vector layers; std::vector< std::vector > folded_layers; @@ -3189,7 +3201,7 @@ bool IfcGeom::Kernel::validate_quantities(const IfcSchema::IfcProduct* product, int genus = q2->as()->CountValue(); for (auto& part : brep) { if (part.ItemId() == item_id) { - if (surface_genus(*(OpenCascadeShape*)part.Shape()) != genus) { + if (surface_genus(part.Shape()) != genus) { all_succeeded = false; } } diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomTree.h b/src/ifcgeom/kernels/opencascade/IfcGeomTree.h index a1f5ff83e2..f3c97f9c23 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomTree.h +++ b/src/ifcgeom/kernels/opencascade/IfcGeomTree.h @@ -113,7 +113,8 @@ namespace IfcGeom { std::vector 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 +123,24 @@ namespace IfcGeom { typename std::vector::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 +156,8 @@ namespace IfcGeom { std::vector 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 +174,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,7 +275,7 @@ namespace IfcGeom { if (it.initialize()) { do { IfcGeom::NativeElement* elem = (IfcGeom::NativeElement*)it.get(); - add((IfcUtil::IfcBaseEntity*)f.instance_by_id(elem->id()), elem->geometry().as_compound()); + add((IfcUtil::IfcBaseEntity*)f.instance_by_id(elem->id()), ((OpenCascadeShape*)elem->geometry().as_compound())->shape()); } while (it.next()); } } diff --git a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp index e7230d8b17..ea52aaaf3e 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp +++ b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -34,7 +35,10 @@ IfcGeom::Representation::Serialization::Serialization(const BRep& brep) : Representation(brep.settings()) , id_(brep.id()) { - TopoDS_Compound compound = brep.as_compound(); + 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(); @@ -82,7 +86,7 @@ TopoDS_Shape apply_transformation(const TopoDS_Shape& s, const gp_GTrsf& t) { } } -TopoDS_Compound IfcGeom::Representation::BRep::as_compound() const { +IfcGeom::ConversionResultShape* IfcGeom::Representation::BRep::as_compound() const { TopoDS_Compound compound; BRep_Builder builder; builder.MakeCompound(compound); @@ -103,7 +107,8 @@ TopoDS_Compound IfcGeom::Representation::BRep::as_compound() const { const TopoDS_Shape moved_shape = apply_transformation(s, trsf); builder.Add(compound, moved_shape); } - return compound; + + return new OpenCascadeShape(compound); } namespace { @@ -212,7 +217,7 @@ bool IfcGeom::Representation::BRep::calculate_volume(double& volume) const { volume = 0.; for (IfcGeom::ConversionResults::const_iterator it = begin(); it != end(); ++it) { - if (Kernel::is_manifold(*(OpenCascadeShape*)it->Shape())) { + if (Kernel::is_manifold(it->Shape())) { GProp_GProps prop; BRepGProp::VolumeProperties(*(OpenCascadeShape*)it->Shape(), prop); volume += prop.Mass(); @@ -240,7 +245,7 @@ bool IfcGeom::Representation::BRep::calculate_projected_surface_area(const Conve double x, y, z; surface_area_along_direction(settings().deflection_tolerance(), *(OpenCascadeShape*)it->Shape(), ax, x, y, z); - if (Kernel::is_manifold(*(OpenCascadeShape*)it->Shape())) { + if (Kernel::is_manifold(it->Shape())) { x /= 2.; y /= 2.; z /= 2.; diff --git a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.h b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.h index f6232007ce..e938f00a1d 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.h @@ -20,27 +20,10 @@ #ifndef IFCGEOMREPRESENTATION_H #define IFCGEOMREPRESENTATION_H -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - #include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h" #include "../../ifcgeom/schema_agnostic/IfcGeomMaterial.h" #include "../../ifcgeom/schema_agnostic/ConversionResult.h" -#include - #include namespace IfcGeom { @@ -77,7 +60,7 @@ namespace IfcGeom { IfcGeom::ConversionResults::const_iterator end() const { return shapes_.end(); } const IfcGeom::ConversionResults& shapes() const { return shapes_; } const std::string& id() const { return id_; } - TopoDS_Compound as_compound() const; + ConversionResultShape* as_compound() const; bool calculate_volume(double&) const; bool calculate_surface_area(double&) const; diff --git a/src/ifcgeom/schema_agnostic/Kernel.cpp b/src/ifcgeom/schema_agnostic/Kernel.cpp index de6bf568a8..a75f04053a 100644 --- a/src/ifcgeom/schema_agnostic/Kernel.cpp +++ b/src/ifcgeom/schema_agnostic/Kernel.cpp @@ -3,6 +3,9 @@ #include "../../ifcparse/Ifc2x3.h" #include "../../ifcparse/Ifc4.h" +// @todo remove +#include "../../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h" + #include #include #include @@ -19,7 +22,11 @@ IfcGeom::Kernel::Kernel(const std::string& geometry_library, IfcParse::IfcFile* } } -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); @@ -35,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; @@ -202,11 +213,15 @@ std::map 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; } } diff --git a/src/ifcgeom/schema_agnostic/Kernel.h b/src/ifcgeom/schema_agnostic/Kernel.h index 5bbb050649..7bc04705bd 100644 --- a/src/ifcgeom/schema_agnostic/Kernel.h +++ b/src/ifcgeom/schema_agnostic/Kernel.h @@ -7,8 +7,6 @@ #include -#include - namespace IfcGeom { template @@ -76,10 +74,10 @@ namespace IfcGeom { 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*); static std::map get_layers(IfcUtil::IfcBaseEntity*); static IfcEntityList::ptr find_openings(IfcUtil::IfcBaseEntity* product); diff --git a/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.cpp b/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.cpp index fa1b9a5958..8651236af9 100644 --- a/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.cpp @@ -1,9 +1,14 @@ #include "CgalConversionResult.h" +#include "../../../ifcparse/IfcLogger.h" +#include "../../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h" + template -void triangulate_helper(const cgal_shape_t, const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation* t, int surface_style_id) { - cgal_shape_t s = shape_; - const cgal_placement_t& trsf = dynamic_cast(place)->trsf(); +void triangulate_helper(const cgal_shape_t& shape_const, const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation* 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(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; @@ -17,6 +22,7 @@ void triangulate_helper(const cgal_shape_t, const IfcGeom::IteratorSettings & se boost::associative_property_map> vertex_normals_map(vertex_normals); std::map face_normals; boost::associative_property_map> face_normals_map(face_normals); + if (CGAL::Polygon_mesh_processing::triangulate_faces(s)) { // std::cout << "Triangulated model: " << s.size_of_facets() << " facets and " << s.size_of_vertices() << " vertices" << std::endl; } else { @@ -35,14 +41,21 @@ void triangulate_helper(const cgal_shape_t, const IfcGeom::IteratorSettings & se 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))); - for (int i = 0; i < 3; ++i) t->normals().push_back(CGAL::to_double(face_normals_map[face].cartesian(i))); - t->faces().push_back(num_vertices); + + 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->material_ids().push_back(surface_style_id); + + 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* t, int surface_style_id) const { diff --git a/src/serializers/OpenCascadeBasedSerializer.cpp b/src/serializers/OpenCascadeBasedSerializer.cpp index 257fa83e4e..f3be07c51f 100644 --- a/src/serializers/OpenCascadeBasedSerializer.cpp +++ b/src/serializers/OpenCascadeBasedSerializer.cpp @@ -35,7 +35,9 @@ bool OpenCascadeBasedSerializer::ready() { } void OpenCascadeBasedSerializer::write(const IfcGeom::NativeElement* 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; if (o->geometry().settings().get(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS)) { gp_Trsf scale; diff --git a/src/serializers/SvgSerializer.cpp b/src/serializers/SvgSerializer.cpp index 06427e4331..6e89083c9f 100644 --- a/src/serializers/SvgSerializer.cpp +++ b/src/serializers/SvgSerializer.cpp @@ -19,6 +19,8 @@ * * ********************************************************************************/ +#include "../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h" + #include #include #include @@ -342,7 +344,10 @@ void SvgSerializer::write(const IfcGeom::NativeElement* 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 From 4d39dbca2a2f3cd02caf0c92634aea6bbd6eddde Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 23 Jan 2019 15:10:20 +0100 Subject: [PATCH 132/235] Build static cgal, fix null pointer access --- nix/build-all.py | 2 +- src/ifcgeom/schema_agnostic/IfcGeomElement.h | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/nix/build-all.py b/nix/build-all.py index ff5889a622..ff3373bae2 100644 --- a/nix/build-all.py +++ b/nix/build-all.py @@ -660,7 +660,7 @@ if "cgal" in targets: 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)], download_url="https://github.com/CGAL/cgal.git", download_name="cgal", download_tool=download_tool_git, revision="releases/CGAL-{CGAL_VERSION}".format(**locals())) + 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 cecho("Building IfcOpenShell:", GREEN) diff --git a/src/ifcgeom/schema_agnostic/IfcGeomElement.h b/src/ifcgeom/schema_agnostic/IfcGeomElement.h index b8ac73eff4..44d885f635 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomElement.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomElement.h @@ -45,8 +45,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

(matrix_value)); @@ -65,7 +67,7 @@ namespace IfcGeom { public: Transformation(const ElementSettings& settings, const ConversionResultPlacement* trsf) : settings_(settings) - , trsf_(trsf->clone()) + , trsf_(trsf ? trsf->clone() : nullptr) , matrix_(settings, trsf) {} const ConversionResultPlacement* data() const { return trsf_; } From 24b552a822d2d4515927d867e276c6eb9bb6f36d Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 23 Jan 2019 17:27:13 +0100 Subject: [PATCH 133/235] Merge fixes --- cmake/CMakeLists.txt | 2 +- .../kernels/cgal/CgalConversionFunctions.cpp | 41 +-- .../kernels/cgal/CgalEntityMapping.cpp | 22 +- .../kernels/cgal/CgalIfcGeomCurves.cpp | 15 +- src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp | 289 +++++++++--------- .../kernels/cgal/CgalIfcGeomPrimitives.cpp | 55 ++-- .../kernels/cgal/CgalIfcGeomShapes.cpp | 275 ++++++++--------- .../cgal/CgalIfcGeomShapesWithStyles.cpp | 45 ++- src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp | 61 ++-- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 47 +-- src/ifcgeom/kernels/cgal/CgalKernel.h | 25 +- src/ifcgeom/schema_agnostic/Kernel.cpp | 8 +- .../cgal/CgalConversionResult.cpp | 15 +- .../cgal/CgalConversionResult.h | 22 +- 14 files changed, 472 insertions(+), 450 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 7a31f62eff..8f6dd2516d 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -308,7 +308,7 @@ get_filename_component(libTKernelExt ${libTKernel} EXT) if("${libTKernelExt}" STREQUAL ".a") find_package(Threads) # OPENCASCADE_LIBRARIES repeated three times below in order to fix cyclic dependencies - use --start-group ... --end-group instead? - set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) + 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() diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 026b491b88..dfa70275c8 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -1,4 +1,7 @@ #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; @@ -15,10 +18,10 @@ void IfcGeom::CgalKernel::remove_duplicate_points_from_loop(cgal_wire_t& polygon } } -CGAL::Polyhedron_3 IfcGeom::CgalKernel::create_polyhedron(std::list &face_list) { +CGAL::Polyhedron_3 IfcGeom::CgalKernel::create_polyhedron(std::list &face_list) { // Naive creation - CGAL::Polyhedron_3 polyhedron; + CGAL::Polyhedron_3 polyhedron; PolyhedronBuilder builder(&face_list); polyhedron.delegate(builder); @@ -31,7 +34,7 @@ CGAL::Polyhedron_3 IfcGeom::CgalKernel::create_polyhedron(std::list(); + return CGAL::Polyhedron_3(); } if (polyhedron.is_closed()) { if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); @@ -43,61 +46,61 @@ CGAL::Polyhedron_3 IfcGeom::CgalKernel::create_polyhedron(std::list IfcGeom::CgalKernel::create_polyhedron(CGAL::Nef_polyhedron_3 &nef_polyhedron) { +CGAL::Polyhedron_3 IfcGeom::CgalKernel::create_polyhedron(CGAL::Nef_polyhedron_3 &nef_polyhedron) { if (nef_polyhedron.is_simple()) { try { - CGAL::Polyhedron_3 polyhedron; + CGAL::Polyhedron_3 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(); + return CGAL::Polyhedron_3(); } } else { Logger::Message(Logger::LOG_ERROR, "Nef polyhedron not simple: cannot create polyhedron!"); - return CGAL::Polyhedron_3(); + return CGAL::Polyhedron_3(); } } -CGAL::Nef_polyhedron_3 IfcGeom::CgalKernel::create_nef_polyhedron(std::list &face_list) { - CGAL::Polyhedron_3 polyhedron = create_polyhedron(face_list); +CGAL::Nef_polyhedron_3 IfcGeom::CgalKernel::create_nef_polyhedron(std::list &face_list) { + CGAL::Polyhedron_3 polyhedron = create_polyhedron(face_list); CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron); - CGAL::Nef_polyhedron_3 nef_polyhedron; + CGAL::Nef_polyhedron_3 nef_polyhedron; try { - nef_polyhedron = CGAL::Nef_polyhedron_3(polyhedron); + nef_polyhedron = CGAL::Nef_polyhedron_3(polyhedron); } catch (...) { Logger::Message(Logger::LOG_ERROR, "Conversion to Nef polyhedron failed!"); return nef_polyhedron; } return nef_polyhedron; } -CGAL::Nef_polyhedron_3 IfcGeom::CgalKernel::create_nef_polyhedron(CGAL::Polyhedron_3 &polyhedron) { +CGAL::Nef_polyhedron_3 IfcGeom::CgalKernel::create_nef_polyhedron(CGAL::Polyhedron_3 &polyhedron) { if (polyhedron.is_valid()) { CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron); - CGAL::Nef_polyhedron_3 nef_polyhedron; + CGAL::Nef_polyhedron_3 nef_polyhedron; try { - nef_polyhedron = CGAL::Nef_polyhedron_3(polyhedron); + nef_polyhedron = CGAL::Nef_polyhedron_3(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(); + return CGAL::Nef_polyhedron_3(); } } -//CGAL::Polyhedron_3 IfcGeom::CgalKernel::triangulate_faces(CGAL::Polyhedron_3 &polyhedron) { +//CGAL::Polyhedron_3 IfcGeom::CgalKernel::triangulate_faces(CGAL::Polyhedron_3 &polyhedron) { // std::list face_list; // -// for (CGAL::Polyhedron_3::Facet_const_iterator current_facet = polyhedron.facets_begin(); +// for (CGAL::Polyhedron_3::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::Halfedge_around_facet_const_circulator current_halfedge = current_facet->facet_begin(); +// CGAL::Polyhedron_3::Halfedge_around_facet_const_circulator current_halfedge = current_facet->facet_begin(); // do { // face_list.back().outer.push_back(current_halfedge->vertex()->point()); // ++current_halfedge; @@ -106,7 +109,7 @@ CGAL::Nef_polyhedron_3 IfcGeom::CgalKernel::create_nef_polyhedron(CGAL:: // // // Polygon // else { -// std::list points_in_polygon; +// std::list points_in_polygon; // // } // } diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp index 26d5f819c1..a604069f8b 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp @@ -17,28 +17,24 @@ * * ********************************************************************************/ -#include "../../../ifcgeom/IfcGeomShapeType.h" -#include "../../../ifcgeom/IfcGeom.h" - #include "CgalKernel.h" -#include "CgalConversionResult.h" -using namespace IfcSchema; +#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(new CgalShape(shp), get_style(l->as()))); + r.push_back(IfcGeom::ConversionResult(l->data().id(), new CgalShape(shp), get_style(l->as()))); return true; } return false; } #include "CgalEntityMappingShapes.h" - Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity); + Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l); return false; } @@ -48,7 +44,7 @@ IfcGeom::ShapeType IfcGeom::CgalKernel::shape_type(const IfcBaseClass* l) { } bool IfcGeom::CgalKernel::convert_shape(const IfcBaseClass* l, cgal_shape_t& r) { - const unsigned int id = l->entity->id(); + const unsigned int id = l->data().id(); bool success = false; bool processed = false; bool ignored = false; @@ -76,25 +72,25 @@ bool IfcGeom::CgalKernel::convert_shape(const IfcBaseClass* l, cgal_shape_t& r) const char* const msg = processed ? "Failed to convert:" : "No operation defined for:"; - Logger::Message(Logger::LOG_ERROR, msg, l->entity); + 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->entity); + 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->entity); + 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->entity); + Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l); return false; } diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomCurves.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomCurves.cpp index 536bc74b66..1653a496f5 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomCurves.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomCurves.cpp @@ -1,14 +1,17 @@ #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->entity); + 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->is(IfcSchema::Type::IfcAxis2Placement3D)) { + if (placement->as()) { IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf); } else { cgal_placement_t trsf2d; @@ -21,7 +24,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCircle* l, cgal_curve_t& c 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)); + curve.push_back(Kernel_::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); } for (auto &vertex: curve) { @@ -35,12 +38,12 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcEllipse* l, cgal_curve_t& double x = l->SemiAxis1() * getValue(GV_LENGTH_UNIT); double y = l->SemiAxis2() * getValue(GV_LENGTH_UNIT); if (x < ALMOST_ZERO || y < ALMOST_ZERO) { - Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l->entity); + Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l); return false; } cgal_placement_t trsf; IfcSchema::IfcAxis2Placement* placement = l->Position(); - if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) { + if (placement->as()) { convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf); } else { cgal_placement_t trsf2d; @@ -53,7 +56,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcEllipse* l, cgal_curve_t& 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)); + curve.push_back(Kernel_::Point_3(x*cos(current_angle), y*sin(current_angle), 0)); } for (auto &vertex: curve) { diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp index e1a4383dc4..8fde4c292a 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp @@ -1,4 +1,7 @@ #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; @@ -30,7 +33,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleProfileDef* l, cg const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT); if ( x < ALMOST_ZERO || y < ALMOST_ZERO ) { - Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); + Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l); return false; } @@ -41,10 +44,10 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleProfileDef* l, cg #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)); + 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); @@ -62,7 +65,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRoundedRectangleProfileDef const double r = l->RoundingRadius() * getValue(GV_LENGTH_UNIT); if ( x < ALMOST_ZERO || y < ALMOST_ZERO || r < ALMOST_ZERO ) { - Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); + Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l); return false; } @@ -76,29 +79,29 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRoundedRectangleProfileDef 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)); + 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)); + 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)); + 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)); + 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)); + face.outer.push_back(Kernel_::Point_3(x-r+r*cos(current_angle), -y+r+r*sin(current_angle), 0)); } } @@ -124,7 +127,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleHollowProfileDef* const double r2 = fr2 ? l->InnerFilletRadius() * getValue(GV_LENGTH_UNIT) : 0.; if ( x < ALMOST_ZERO || y < ALMOST_ZERO ) { - Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); + Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l); return false; } @@ -138,57 +141,57 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleHollowProfileDef* 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)); + 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)); + 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)); + 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)); + 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)); + 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)); + 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)); + 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)); + 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)); + 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)); + face.inner.back().push_back(Kernel_::Point_3(x-d-r1+r1*cos(current_angle), -y+d+r1+r1*sin(current_angle), 0)); } } @@ -213,7 +216,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTrapeziumProfileDef* l, cg const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT); if ( x1 < ALMOST_ZERO || w < ALMOST_ZERO || y < ALMOST_ZERO ) { - Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); + Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l); return false; } @@ -224,10 +227,10 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTrapeziumProfileDef* l, cg #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)); + 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); @@ -242,7 +245,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTrapeziumProfileDef* l, cg 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->entity); + Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l); return false; } @@ -257,7 +260,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCircleProfileDef* l, cgal_ 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.outer.push_back(Kernel_::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); } if (has_position) { @@ -275,7 +278,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCircleHollowProfileDef* l, const double t = l->WallThickness() * getValue(GV_LENGTH_UNIT); if ( r == 0.0f || t == 0.0f ) { - Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); + Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l); return false; } @@ -290,13 +293,13 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCircleHollowProfileDef* l, 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.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)); + face.inner.back().push_back(Kernel_::Point_3((r-t)*cos(current_angle), (r-t)*sin(current_angle), 0)); } if (has_position) { @@ -318,7 +321,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcEllipseProfileDef* l, cgal double ry = l->SemiAxis2() * getValue(GV_LENGTH_UNIT); if ( rx < ALMOST_ZERO || ry < ALMOST_ZERO ) { - Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); + Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l); return false; } @@ -333,7 +336,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcEllipseProfileDef* l, cgal 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)); + face.outer.push_back(Kernel_::Point_3(rx*cos(current_angle), ry*sin(current_angle), 0)); } if (has_position) { @@ -353,11 +356,11 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcFace* l, cgal_face_t& face for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) { IfcSchema::IfcFaceBound* bound = *it; - if (bound->is(IfcSchema::Type::IfcFaceOuterBound)) num_outer_bounds ++; + if (bound->as()) num_outer_bounds ++; } if (num_outer_bounds != 1) { - Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l->entity); + Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l); return false; } @@ -367,11 +370,11 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcFace* l, cgal_face_t& face IfcSchema::IfcFaceBound* bound = *it; IfcSchema::IfcLoop* loop = bound->Bound(); - const bool is_interior = !bound->is(IfcSchema::Type::IfcFaceOuterBound); + const bool is_interior = !bound->as(); cgal_wire_t wire; if (!convert_wire(loop, wire)) { - Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop->entity); + Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop); return false; } @@ -406,7 +409,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCShapeProfileDef* l, cgal_ } if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) { - Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); + Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l); return false; } @@ -420,57 +423,57 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCShapeProfileDef* l, cgal_ 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)); + 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)); + 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-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)); + 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)); + 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)); + 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)); + 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-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)); + 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)); + 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)); + face.outer.push_back(Kernel_::Point_3(-x+f2+f2*cos(current_angle), y-f2+f2*sin(current_angle), 0)); } } @@ -504,7 +507,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcLShapeProfileDef* l, cgal_ } if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d < ALMOST_ZERO ) { - Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); + Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l); return false; } @@ -536,7 +539,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcLShapeProfileDef* l, cgal_ const double det = a1*b2 - a2*b1; if (ALMOST_THE_SAME(det, 0.)) { - Logger::Message(Logger::LOG_NOTICE, "Legs do not intersect for:",l->entity); + Logger::Message(Logger::LOG_NOTICE, "Legs do not intersect for:",l); return false; } @@ -553,30 +556,30 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcLShapeProfileDef* l, cgal_ 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)); + 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)); + 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)); + 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)); + 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)); + 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)); + 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+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)); + } face.outer.push_back(Kernel_::Point_3(-x, y, 0.0)); if (has_position) { IfcGeom::CgalKernel::convert(l->Position(), trsf2d); @@ -604,7 +607,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcIShapeProfileDef* l, cgal_ bool doFillet2 = doFillet1; double x2 = x1, dy2 = dy1, f2 = f1; - if (l->is(IfcSchema::Type::IfcAsymmetricIShapeProfileDef)) { + if (l->as()) { IfcSchema::IfcAsymmetricIShapeProfileDef* assym = (IfcSchema::IfcAsymmetricIShapeProfileDef*) l; x2 = assym->TopFlangeWidth() / 2. * getValue(GV_LENGTH_UNIT); doFillet2 = assym->hasTopFlangeFilletRadius(); @@ -617,7 +620,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcIShapeProfileDef* l, cgal_ } if ( x1 < ALMOST_ZERO || x2 < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || dy1 < ALMOST_ZERO || dy2 < ALMOST_ZERO ) { - Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); + Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l); return false; } @@ -630,36 +633,36 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcIShapeProfileDef* l, cgal_ 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)); + 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)); + 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)); + 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(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)); + } 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)); + 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)); + 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(-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)); + } face.outer.push_back(Kernel_::Point_3(-x1, -y+dy1, 0.0)); if (has_position) { IfcGeom::CgalKernel::convert(l->Position(), trsf2d); @@ -686,7 +689,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTShapeProfileDef* l, cgal_ const double webSlope = hasWebSlope ? (l->WebSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.; if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) { - Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); + Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l); return false; } @@ -734,7 +737,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTShapeProfileDef* l, cgal_ const double det = a1*b2 - a2*b1; if (ALMOST_THE_SAME(det, 0.)) { - Logger::Message(Logger::LOG_NOTICE, "Web and flange do not intersect for:",l->entity); + Logger::Message(Logger::LOG_NOTICE, "Web and flange do not intersect for:",l); return false; } @@ -755,48 +758,48 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTShapeProfileDef* l, cgal_ face = cgal_face_t(); if (f2 == 0.0) { - face.outer.push_back(Kernel::Point_3(d1/2.-dx2, -y, 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)); + 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)); + 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)); + 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)); + 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-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)); + } 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)); + 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)); + 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)); + 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)); + 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)); + 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)); + face.outer.push_back(Kernel_::Point_3(-d1/2.+dx2+f2+f2*cos(current_angle), -y+f2+f2*sin(current_angle), 0)); } } @@ -839,7 +842,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcUShapeProfileDef* l, cgal_ } if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) { - Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); + Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l); return false; } @@ -852,38 +855,38 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcUShapeProfileDef* l, cgal_ 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)); + 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)); + 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)); + 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)); + 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)); + 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)); + 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)); + 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)); + 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-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)); + } 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); @@ -915,7 +918,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcZShapeProfileDef* l, cgal_ } if ( x == 0.0f || y == 0.0f || dx == 0.0f || dy == 0.0f ) { - Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); + Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l); return false; } @@ -928,37 +931,37 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcZShapeProfileDef* l, cgal_ 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)); + 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)); + 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)); + 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)); + 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+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)); + } 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)); + 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)); + 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)); + 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)); + face.outer.push_back(Kernel_::Point_3(-dx-f1+f1*cos(current_angle), y-dy-f1+f1*sin(current_angle), 0)); } } diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp index f91617f8f3..6e630578e8 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp @@ -1,8 +1,11 @@ #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 xyz = l->Coordinates(); - point = Kernel::Point_3(xyz.size() ? (xyz[0]*getValue(GV_LENGTH_UNIT)) : 0.0f, + 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; @@ -12,7 +15,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_po bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcDirection* l, cgal_direction_t& dir) { // IN_CACHE(IfcDirection,l,cgal_direction_t,dir) std::vector xyz = l->DirectionRatios(); - dir = Kernel::Vector_3(xyz.size() ? xyz[0] : 0.0f, + 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) @@ -32,18 +35,18 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPlane* pln, cgal_plane_t& // 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); + 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); + 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); + 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; @@ -80,11 +83,11 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPlane* pln, cgal_plane_t& 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); + 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); + 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 || @@ -95,7 +98,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement2D* l, cgal_ } // TODO: Should be checked. - trsf = Kernel::Aff_transformation_3(refDirection.cartesian(0), y.cartesian(0), 0.0, o.cartesian(0), + 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); @@ -106,14 +109,14 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement2D* l, cgal_ 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); + 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); + 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 || @@ -127,7 +130,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement3D* l, cgal_ } // TODO: Should be checked. - trsf = Kernel::Aff_transformation_3(x.cartesian(0), y.cartesian(0), axis.cartesian(0), o.cartesian(0), + 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)); @@ -144,7 +147,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement3D* l, cgal_ 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); + 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); @@ -155,7 +158,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis1Placement* l, cgal_pl } // TODO: Should be checked. - ax = Kernel::Aff_transformation_3(1.0, 0.0, axis.cartesian(0), o.cartesian(0), + 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)); @@ -165,8 +168,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis1Placement* l, cgal_pl bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_placement_t& trsf) { // IN_CACHE(IfcObjectPlacement,l,cgal_placement_t,trsf) - if ( ! l->is(IfcSchema::Type::IfcLocalPlacement) ) { - Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l->entity); + if ( ! l->as() ) { + Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l); return false; } @@ -182,7 +185,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_p cgal_placement_t trsf2; IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement(); - if ( relplacement->is(IfcSchema::Type::IfcAxis2Placement3D) ) { + if ( relplacement->as() ) { IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2); // std::cout << "trsf2" << std::endl; @@ -203,7 +206,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_p } if ( current->hasPlacementRelTo() ) { IfcSchema::IfcObjectPlacement* relto = current->PlacementRelTo(); - if ( relto->is(IfcSchema::Type::IfcLocalPlacement) ) + if ( relto->as() ) current = (IfcSchema::IfcLocalPlacement*)current->PlacementRelTo(); else break; } else break; @@ -228,7 +231,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOpe } // TODO: Untested - trsf = Kernel::Aff_transformation_3(scale*axis1.cartesian(0), axis2.cartesian(0), 0.0, origin.cartesian(0), + 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); @@ -251,7 +254,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOpe 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), + 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); @@ -275,7 +278,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOpe } // TODO: Untested - trsf = Kernel::Aff_transformation_3(scale*axis1.cartesian(0), axis2.cartesian(0), axis3.cartesian(0), origin.cartesian(0), + 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)); @@ -305,7 +308,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOpe 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), + 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)); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index f6af7fc884..80d4a83a7b 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -1,9 +1,12 @@ #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->entity); + Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", l); return false; } @@ -28,10 +31,10 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal std::list face_list; face_list.push_back(bottom_face); - for (std::vector::const_iterator current_vertex = bottom_face.outer.begin(); + for (std::vector::const_iterator current_vertex = bottom_face.outer.begin(); current_vertex != bottom_face.outer.end(); ++current_vertex) { - std::vector::const_iterator next_vertex = current_vertex; + std::vector::const_iterator next_vertex = current_vertex; ++next_vertex; if (next_vertex == bottom_face.outer.end()) { next_vertex = bottom_face.outer.begin(); @@ -44,7 +47,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal } cgal_face_t top_face; - for (std::vector::const_reverse_iterator vertex = bottom_face.outer.rbegin(); + for (std::vector::const_reverse_iterator vertex = bottom_face.outer.rbegin(); vertex != bottom_face.outer.rend(); ++vertex) { top_face.outer.push_back(*vertex+height*dir); @@ -56,7 +59,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal return true; } - CGAL::Nef_polyhedron_3 nef_shape = create_nef_polyhedron(face_list); + CGAL::Nef_polyhedron_3 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 @@ -69,10 +72,10 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal remove_duplicate_points_from_loop(hole_bottom_face.outer); face_list.push_back(hole_bottom_face); - for (std::vector::const_iterator current_vertex = inner.begin(); + for (std::vector::const_iterator current_vertex = inner.begin(); current_vertex != inner.end(); ++current_vertex) { - std::vector::const_iterator next_vertex = current_vertex; + std::vector::const_iterator next_vertex = current_vertex; ++next_vertex; if (next_vertex == inner.end()) { next_vertex = inner.begin(); @@ -85,7 +88,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal } cgal_face_t hole_top_face; - for (std::vector::const_reverse_iterator vertex = inner.rbegin(); + for (std::vector::const_reverse_iterator vertex = inner.rbegin(); vertex != inner.rend(); ++vertex) { hole_top_face.outer.push_back(*vertex+height*dir); @@ -94,7 +97,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal try { nef_shape -= create_nef_polyhedron(face_list); } catch (...) { - Logger::Message(Logger::LOG_ERROR, "IfcExtrudedAreaSolid: cannot subtract opening for:", l->entity); + Logger::Message(Logger::LOG_ERROR, "IfcExtrudedAreaSolid: cannot subtract opening for:", l); return false; } } @@ -109,7 +112,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal nef_shape.convert_to_polyhedron(shape); return true; } catch (...) { - Logger::Message(Logger::LOG_ERROR, "IfcExtrudedAreaSolid: cannot convert Nef to polyhedron for:", l->entity); + Logger::Message(Logger::LOG_ERROR, "IfcExtrudedAreaSolid: cannot convert Nef to polyhedron for:", l); return false; } @@ -119,7 +122,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal 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->entity); + Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", l); return false; } @@ -148,12 +151,12 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* std::list face_list; face_list.push_back(face1); - std::vector::const_iterator current_face1_vertex = face1.outer.begin(); - std::vector::const_iterator current_face2_vertex = face2.outer.begin(); + std::vector::const_iterator current_face1_vertex = face1.outer.begin(); + std::vector::const_iterator current_face2_vertex = face2.outer.begin(); while (current_face1_vertex != face1.outer.end() && current_face2_vertex != face2.outer.end()) { - std::vector::const_iterator next_face1_vertex = current_face1_vertex; - std::vector::const_iterator next_face2_vertex = current_face2_vertex; + std::vector::const_iterator next_face1_vertex = current_face1_vertex; + std::vector::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(); @@ -169,7 +172,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* } cgal_face_t top_face; - for (std::vector::const_reverse_iterator vertex = face2.outer.rbegin(); + for (std::vector::const_reverse_iterator vertex = face2.outer.rbegin(); vertex != face2.outer.rend(); ++vertex) { top_face.outer.push_back(*vertex); @@ -182,14 +185,14 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* } // std::ofstream f1; -// CGAL::Polyhedron_3 outer_polyhedron; +// CGAL::Polyhedron_3 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 nef_shape = create_nef_polyhedron(face_list); + CGAL::Nef_polyhedron_3 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 @@ -212,8 +215,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* current_face2_vertex = hole_face2.outer.begin(); while (current_face1_vertex != hole_face1.outer.end() && current_face2_vertex != hole_face2.outer.end()) { - std::vector::const_iterator next_face1_vertex = current_face1_vertex; - std::vector::const_iterator next_face2_vertex = current_face2_vertex; + std::vector::const_iterator next_face1_vertex = current_face1_vertex; + std::vector::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(); @@ -229,14 +232,14 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* } cgal_face_t top_hole_face; - for (std::vector::const_reverse_iterator vertex = hole_face2.outer.rbegin(); + for (std::vector::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 inner_polyhedron; +// CGAL::Polyhedron_3 inner_polyhedron; // PolyhedronBuilder builder(&face_list); // inner_polyhedron.delegate(builder); // f2.open("/Users/ken/Desktop/inner.off"); @@ -283,7 +286,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_ } catch (...) {} if (!success) { - Logger::Message(Logger::LOG_WARNING, "Failed to convert face:", (*it)->entity); + Logger::Message(Logger::LOG_WARNING, "Failed to convert face:", (*it)); continue; } @@ -312,45 +315,45 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBlock* l, cgal_shape_t& sh // 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)); + 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)); + 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)); + 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)); + 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)); + 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)); + 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); @@ -367,10 +370,10 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha cgal_wire_t boundary_wire; IfcSchema::IfcBooleanOperand* operand1 = l->FirstOperand(); IfcSchema::IfcBooleanOperand* operand2 = l->SecondOperand(); - bool is_halfspace = operand2->is(IfcSchema::Type::IfcHalfSpaceSolid); + bool is_halfspace = operand2->as(); if ( shape_type(operand1) == ST_SHAPELIST ) { - Logger::Message(Logger::LOG_ERROR, "s1: ST_SHAPELIST Unsupported", operand1->entity); + Logger::Message(Logger::LOG_ERROR, "s1: ST_SHAPELIST Unsupported", operand1); // if (!(convert_shapes(operand1, items1) && flatten_shape_list(items1, s1, true))) { return false; // } @@ -379,44 +382,44 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha return false; } } else { - Logger::Message(Logger::LOG_ERROR, "s1: Invalid representation item for boolean operation", operand1->entity); + 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()->entity); +// 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->entity); + 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->entity); + 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->entity); + Logger::Message(Logger::LOG_ERROR,"Failed to convert SecondOperand of:",l); return true; } // if (!is_halfspace) { // const double second_operand_volume = shape_volume(s2); // if ( second_operand_volume <= ALMOST_ZERO ) -// Logger::Message(Logger::LOG_WARNING,"Empty solid for:",operand2->entity); +// Logger::Message(Logger::LOG_WARNING,"Empty solid for:",operand2); // } - const IfcSchema::IfcBooleanOperator::IfcBooleanOperator op = l->Operator(); + const IfcSchema::IfcBooleanOperator::Value op = l->Operator(); if (!s1.is_valid()) { - Logger::Message(Logger::LOG_ERROR, "s1: Not valid?", operand1->entity); + Logger::Message(Logger::LOG_ERROR, "s1: Not valid?", operand1); return false; } else { // std::ofstream f1; -// CGAL::Polyhedron_3 p1; +// CGAL::Polyhedron_3 p1; // s1.convert_to_Polyhedron(p1); // f1.open("/Users/ken/Desktop/s1.off"); // f1 << p1 << std::endl; @@ -426,13 +429,13 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha bool is_plane = false; cgal_plane_t plane; if (!s2.is_valid()) { - Logger::Message(Logger::LOG_ERROR, "s2: Not valid?", operand2->entity); + 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(operand2); IfcSchema::IfcSurface* surface = hss->BaseSurface(); - if (surface->is(IfcSchema::Type::IfcPlane) ) { + if (surface->as() ) { is_plane = true; IfcGeom::CgalKernel::convert((IfcSchema::IfcPlane *)surface, plane); if (hss->AgreementFlag()) plane = plane.opposite(); @@ -453,7 +456,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha } } else { // std::ofstream f2; -// CGAL::Polyhedron_3 p2; +// CGAL::Polyhedron_3 p2; // s2.convert_to_Polyhedron(p2); // f2.open("/Users/ken/Desktop/s2.off"); // f2 << p2 << std::endl; @@ -463,27 +466,27 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) { // std::cout << "Difference" << std::endl; - CGAL::Nef_polyhedron_3 nef_result; + CGAL::Nef_polyhedron_3 nef_result; try { - nef_result = CGAL::Nef_polyhedron_3(s1); + nef_result = CGAL::Nef_polyhedron_3(s1); } catch (...) { - Logger::Message(Logger::LOG_ERROR, "s1: cannot convert to Nef?", operand1->entity); + 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::Intersection_mode::CLOSED_HALFSPACE); + if (is_plane) nef_result = nef_result.intersection(plane, CGAL::Nef_polyhedron_3::Intersection_mode::CLOSED_HALFSPACE); } else { - CGAL::Nef_polyhedron_3 nef_s2; + CGAL::Nef_polyhedron_3 nef_s2; try { - nef_s2 = CGAL::Nef_polyhedron_3(s2); + nef_s2 = CGAL::Nef_polyhedron_3(s2); } catch (...) { - Logger::Message(Logger::LOG_ERROR, "s2: cannot convert to Nef?", operand2->entity); + 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->entity); + Logger::Message(Logger::LOG_ERROR, "s2: not simple?", operand2); return false; } else { -// CGAL::Polyhedron_3 result; +// CGAL::Polyhedron_3 result; // nef_result.convert_to_polyhedron(result); // std::ofstream fresult; // fresult.open("/Users/ken/Desktop/result.off"); @@ -500,12 +503,12 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) { // std::cout << "Union" << std::endl; - CGAL::Nef_polyhedron_3 nef_result = CGAL::Nef_polyhedron_3(s1)+CGAL::Nef_polyhedron_3(s2); + CGAL::Nef_polyhedron_3 nef_result = CGAL::Nef_polyhedron_3(s1)+CGAL::Nef_polyhedron_3(s2); if (!nef_result.is_simple()) { std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; return false; } else { -// CGAL::Polyhedron_3 result; +// CGAL::Polyhedron_3 result; // nef_result.convert_to_polyhedron(result); // std::ofstream fresult; // fresult.open("/Users/ken/Desktop/result.off"); @@ -522,12 +525,12 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) { // std::cout << "Intersection" << std::endl; - CGAL::Nef_polyhedron_3 nef_result = CGAL::Nef_polyhedron_3(s1)*CGAL::Nef_polyhedron_3(s2); + CGAL::Nef_polyhedron_3 nef_result = CGAL::Nef_polyhedron_3(s1)*CGAL::Nef_polyhedron_3(s2); if (!nef_result.is_simple()) { std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; return false; } else { -// CGAL::Polyhedron_3 result; +// CGAL::Polyhedron_3 result; // nef_result.convert_to_polyhedron(result); // std::ofstream fresult; // fresult.open("/Users/ken/Desktop/result.off"); @@ -549,19 +552,19 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& s // Make icosahedron float golden_ratio = (1.0+sqrtf(5.0))/2.0; float normalising_factor = sqrtf(golden_ratio*golden_ratio+1.0); - std::vector 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::vector 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 face_list; @@ -669,24 +672,24 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& s for (unsigned int current_refinement = 0; current_refinement < refinements; ++current_refinement) { std::list 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 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); + 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, + 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, + 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, + 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); @@ -717,7 +720,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& s shape = create_polyhedron(face_list); for (auto &vertex: vertices(shape)) { - vertex->point() = Kernel::Point_3(r*vertex->point().x(), + vertex->point() = Kernel_::Point_3(r*vertex->point().x(), r*vertex->point().y(), r*vertex->point().z()); vertex->point() = vertex->point().transform(trsf); @@ -734,31 +737,31 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangularPyramid* l, cga // 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)); + 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.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.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.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)); + 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); @@ -780,7 +783,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, 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)); + face_list.back().outer.push_back(Kernel_::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); } // Side faces @@ -789,17 +792,17 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, 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)); + 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)); + face_list.back().outer.push_back(Kernel_::Point_3(r*cos(current_angle), r*sin(current_angle), h)); } cgal_placement_t trsf; @@ -822,7 +825,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCone* l, cgal 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)); + face_list.back().outer.push_back(Kernel_::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); } // Side faces @@ -831,9 +834,9 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCone* l, cgal 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)); + 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; @@ -853,10 +856,10 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, cg for (std::vector< std::vector >::const_iterator it = coordinates.begin(); it != coordinates.end(); ++it) { const std::vector& coords = *it; if (coords.size() != 3) { - Logger::Message(Logger::LOG_ERROR, "Invalid dimensions encountered on Coordinates", l->entity); + 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), + points.push_back(Kernel_::Point_3(coords[0] * getValue(GV_LENGTH_UNIT), coords[1] * getValue(GV_LENGTH_UNIT), coords[2] * getValue(GV_LENGTH_UNIT))); } @@ -868,7 +871,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, cg for(std::vector< std::vector >::const_iterator it = indices.begin(); it != indices.end(); ++ it) { const std::vector& tri = *it; if (tri.size() != 3) { - Logger::Message(Logger::LOG_ERROR, "Invalid dimensions encountered on CoordIndex", l->entity); + Logger::Message(Logger::LOG_ERROR, "Invalid dimensions encountered on CoordIndex", l); return false; } @@ -876,13 +879,13 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, cg 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->entity); + 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 + 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); @@ -897,8 +900,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, cg bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, cgal_shape_t& shape) { IfcSchema::IfcSurface* surface = l->BaseSurface(); - if ( ! surface->is(IfcSchema::Type::IfcPlane) ) { - Logger::Message(Logger::LOG_ERROR, "Unsupported BaseSurface:", surface->entity); + if ( ! surface->as() ) { + Logger::Message(Logger::LOG_ERROR, "Unsupported BaseSurface:", surface); return false; } cgal_plane_t pln; @@ -911,6 +914,6 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, cgal_sh // 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(); + shape = CGAL::Polyhedron_3(); return true; } diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp index c28d6ee8e2..ef3adc858f 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp @@ -1,5 +1,7 @@ #include "CgalKernel.h" -#include "CgalConversionResult.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(); @@ -12,7 +14,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRepresentation* l, Convers } else { cgal_shape_t s; if (convert_shape(representation_item, s)) { - shapes.push_back(ConversionResult(new CgalShape(s), get_style(representation_item))); + shapes.push_back(ConversionResult(representation_item->data().id(), new CgalShape(s), get_style(representation_item))); part_succes |= true; } } @@ -32,14 +34,14 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcGeometricSet* l, Conversio if (convert_shape(element, s)) { part_succes = true; const IfcGeom::SurfaceStyle* style = 0; - if (element->is(IfcSchema::Type::IfcPoint)) { + if (element->as()) { style = get_style((IfcSchema::IfcPoint*) element); - } else if (element->is(IfcSchema::Type::IfcCurve)) { + } else if (element->as()) { style = get_style((IfcSchema::IfcCurve*) element); - } else if (element->is(IfcSchema::Type::IfcSurface)) { + } else if (element->as()) { style = get_style((IfcSchema::IfcSurface*) element); } - shapes.push_back(ConversionResult(new CgalShape(s), style ? style : parent_style)); + shapes.push_back(ConversionResult(element->data().id(), new CgalShape(s), style ? style : parent_style)); } } return part_succes; @@ -51,11 +53,11 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, for( IfcEntityList::it it = shells->begin(); it != shells->end(); ++ it ) { cgal_shape_t s; const SurfaceStyle* shell_style = 0; - if ((*it)->is(IfcSchema::Type::IfcRepresentationItem)) { + if ((*it)->as()) { shell_style = get_style((IfcSchema::IfcRepresentationItem*)*it); } if (convert_shape(*it,s)) { - shapes.push_back(ConversionResult(new CgalShape(s), shell_style ? shell_style : collective_style)); + shapes.push_back(ConversionResult((*it)->data().id(), new CgalShape(s), shell_style ? shell_style : collective_style)); } } return true; @@ -65,31 +67,28 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, Conv cgal_shape_t s; const SurfaceStyle* collective_style = get_style(l); if (convert_shape(l->Outer(),s) ) { - CGAL::Nef_polyhedron_3 nef_s = create_nef_polyhedron(s); + CGAL::Nef_polyhedron_3 nef_s = create_nef_polyhedron(s); const SurfaceStyle* indiv_style = get_style(l->Outer()); IfcSchema::IfcClosedShell::list::ptr voids(new IfcSchema::IfcClosedShell::list); - if (l->is(IfcSchema::Type::IfcFacetedBrepWithVoids)) { + if (l->as()) { voids = l->as()->Voids(); } #ifdef USE_IFC4 - if (l->is(IfcSchema::Type::IfcAdvancedBrepWithVoids)) { + if (l->as()) { voids = l->as()->Voids(); } #endif for (IfcSchema::IfcClosedShell::list::it it = voids->begin(); it != voids->end(); ++it) { cgal_shape_t s2; - // TODO: This looks weird. Aren't we removing the outer shell again and again? - // Maybe it should be - // if (convert_shape(*it, s2)) { - if (convert_shape(l->Outer(), s2)) { - nef_s -= CGAL::Nef_polyhedron_3(s2); + if (convert_shape(*it, s2)) { + nef_s -= CGAL::Nef_polyhedron_3(s2); } } s = create_polyhedron(nef_s); - shape.push_back(ConversionResult(new CgalShape(s), indiv_style ? indiv_style : collective_style)); + shape.push_back(ConversionResult(l->data().id(), new CgalShape(s), indiv_style ? indiv_style : collective_style)); return true; } return false; @@ -98,19 +97,19 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, Conv bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcMappedItem* l, ConversionResults& shapes) { cgal_placement_t gtrsf; IfcSchema::IfcCartesianTransformationOperator* transform = l->MappingTarget(); - if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3DnonUniform) ) { + if ( transform->as() ) { IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3DnonUniform*)transform,gtrsf); - } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2DnonUniform) ) { + } else if ( transform->as() ) { IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator2DnonUniform*)transform,gtrsf); - } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3D) ) { + } else if ( transform->as() ) { IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,gtrsf); - } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2D) ) { + } else if ( transform->as() ) { IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator2D*)transform,gtrsf); } IfcSchema::IfcRepresentationMap* map = l->MappingSource(); IfcSchema::IfcAxis2Placement* placement = map->MappingOrigin(); cgal_placement_t trsf; - if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) { + if (placement->as()) { IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf); } else { cgal_placement_t trsf_2d; @@ -155,7 +154,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcFaceBasedSurfaceModel* l, cgal_shape_t s; const SurfaceStyle* shell_style = get_style(*it); if (convert_shape(*it,s)) { - shapes.push_back(ConversionResult(new CgalShape(s), shell_style ? shell_style : collective_style)); + shapes.push_back(ConversionResult((*it)->data().id(), new CgalShape(s), shell_style ? shell_style : collective_style)); part_success |= true; } } diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp index 08a947efd6..70d4fbee0a 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp @@ -1,14 +1,17 @@ +#include "CgalKernel.h" +#include "../../../ifcgeom/schema_agnostic/cgal/CgalConversionResult.h" + +#define CgalKernel MAKE_TYPE_NAME(CgalKernel) + // For MSVC to have M_PI #define _USE_MATH_DEFINES #include -#include "CgalKernel.h" - 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(); + cgal_wire_t polygon = std::vector(); for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) { cgal_point_t pnt; IfcGeom::CgalKernel::convert(*it, pnt); @@ -18,7 +21,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& // 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->entity); + Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l); return false; } @@ -28,11 +31,11 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& 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->entity); + Logger::Message(Logger::LOG_WARNING, ss.str(), l); } if (count < 3) { - Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity); + Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l); return false; } @@ -50,7 +53,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyline* l, cgal_wire_t& IfcSchema::IfcCartesianPoint::list::ptr points = l->Points(); // Parse and store the points in a sequence - cgal_wire_t polygon = std::vector(); + cgal_wire_t polygon = std::vector(); for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) { cgal_point_t pnt; IfcGeom::CgalKernel::convert(*it, pnt); @@ -91,15 +94,15 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcOrientedEdge* l, cgal_wire } bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcEdge* l, cgal_wire_t& result) { - if (!l->EdgeStart()->is(IfcSchema::Type::IfcVertexPoint) || !l->EdgeEnd()->is(IfcSchema::Type::IfcVertexPoint)) { - Logger::Message(Logger::LOG_ERROR, "Only IfcVertexPoints are supported for EdgeStart and -End", l->entity); + if (!l->EdgeStart()->as() || !l->EdgeEnd()->as()) { + 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->is(IfcSchema::Type::IfcCartesianPoint) || !pnt2->is(IfcSchema::Type::IfcCartesianPoint)) { - Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l->entity); + if (!pnt1->as() || !pnt2->as()) { + Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l); return false; } @@ -120,7 +123,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcEdge* l, cgal_wire_t& resu 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->entity); + Logger::Message(Logger::LOG_WARNING,"Creating a composite curve without unit information:",l); // Temporarily pretend we do have unit information setValue(GV_PLANEANGLE_UNIT,1.0); @@ -181,7 +184,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCompositeCurve* l, cgal_wi IfcSchema::IfcCurve* curve = (*it)->ParentCurve(); cgal_wire_t wire2; if ( !convert_wire(curve,wire2) ) { - Logger::Message(Logger::LOG_ERROR,"Failed to convert curve:",curve->entity); + Logger::Message(Logger::LOG_ERROR,"Failed to convert curve:",curve); continue; } if ( ! (*it)->SameSense() ) std::reverse(wire2.begin(),wire2.end()); @@ -191,7 +194,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCompositeCurve* l, cgal_wi } else if (w.empty()) { w = wire2; } else if (w.back() == w.front()) { - std::vector::const_iterator vertex = wire2.begin(); + std::vector::const_iterator vertex = wire2.begin(); ++vertex; while (vertex != wire2.end()) { w.push_back(*vertex); @@ -210,7 +213,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCompositeCurve* l, cgal_wi bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTrimmedCurve* l, cgal_wire_t& wire) { IfcSchema::IfcCurve* basis_curve = l->BasisCurve(); - bool isConic = basis_curve->is(IfcSchema::Type::IfcConic); + bool isConic = basis_curve->as(); double parameterFactor = isConic ? getValue(GV_PLANEANGLE_UNIT) : getValue(GV_LENGTH_UNIT); cgal_curve_t curve; if ( !convert_curve(basis_curve,curve) ) return false; @@ -225,10 +228,10 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTrimmedCurve* l, cgal_wire cgal_wire_t w; for ( IfcEntityList::it it = trims1->begin(); it != trims1->end(); it ++ ) { IfcUtil::IfcBaseClass* i = *it; - if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) { + if ( i->as() ) { IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[sense_agreement] ); has_pnts[sense_agreement] = true; - } else if ( i->is(IfcSchema::Type::IfcParameterValue) ) { + } else if ( i->as() ) { const double value = *((IfcSchema::IfcParameterValue*)i); flts[sense_agreement] = value * parameterFactor; has_flts[sense_agreement] = true; @@ -236,10 +239,10 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTrimmedCurve* l, cgal_wire } for ( IfcEntityList::it it = trims2->begin(); it != trims2->end(); it ++ ) { IfcUtil::IfcBaseClass* i = *it; - if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) { + if ( i->as() ) { IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[1-sense_agreement] ); has_pnts[1-sense_agreement] = true; - } else if ( i->is(IfcSchema::Type::IfcParameterValue) ) { + } else if ( i->as() ) { const double value = *((IfcSchema::IfcParameterValue*)i); flts[1-sense_agreement] = value * parameterFactor; has_flts[1-sense_agreement] = true; @@ -250,13 +253,13 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTrimmedCurve* l, cgal_wire 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->entity); + 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::const_iterator point = curve.begin(); + std::vector::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)) { @@ -277,7 +280,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTrimmedCurve* l, cgal_wire } else { bool found = false; int loops_to_go = 2; - std::vector::const_reverse_iterator point = curve.rbegin(); + std::vector::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)) { @@ -299,7 +302,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTrimmedCurve* l, cgal_wire // is defined by an IfcCartesianPoint and an IfcVector with Magnitude. Because // the vector is normalised when passed to Geom_Line constructor the magnitude // needs to be factored in with the IfcParameterValue here. - if ( basis_curve->is(IfcSchema::Type::IfcLine) ) { + if ( basis_curve->as() ) { IfcSchema::IfcLine* line = static_cast(basis_curve); const double magnitude = line->Dir()->Magnitude(); flts[0] *= magnitude; flts[1] *= magnitude; @@ -309,19 +312,19 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTrimmedCurve* l, cgal_wire } else { const int segments_of_full_curve = 12; double segment_angle = 2.0*3.141592653589793/segments_of_full_curve; - if ( basis_curve->is(IfcSchema::Type::IfcEllipse) ) { + if ( basis_curve->as() ) { IfcSchema::IfcEllipse* ellipse = static_cast(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->is(IfcSchema::Type::IfcCircle) ) { + 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* circle = static_cast(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)); + 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]) ) { diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index e1f149dd85..2a36bc2adf 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -88,13 +88,14 @@ bool IfcGeom::CgalKernel::validate_quantities(const IfcSchema::IfcProduct* produ throw std::runtime_error("not implemented"); } -bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* product, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcGeom::ConversionResults& shapes, const IfcGeom::ConversionResultPlacement* trsf, IfcGeom::ConversionResults& opened_shapes) { +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 opening_shapelist; for ( IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++ it ) { IfcSchema::IfcRelVoidsElement* v = *it; IfcSchema::IfcFeatureElementSubtraction* fes = v->RelatedOpeningElement(); - if ( fes->is(IfcSchema::Type::IfcOpeningElement) ) { + if ( fes->as() ) { if (!fes->hasRepresentation()) continue; // Convert the IfcRepresentation of the IfcOpeningElement @@ -143,13 +144,13 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* product, cgal_shape_t original_entity_shape(entity_shape); if (!entity_shape.is_valid()) { - Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Invalid entity:", entity->entity); + 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 entity:", entity->entity); + Logger::Message(Logger::LOG_ERROR, "Subtraction of openings not supported for non-closed geometry:", product); return false; } @@ -158,26 +159,26 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* product, try { success = CGAL::Polygon_mesh_processing::triangulate_faces(entity_shape); } catch (...) { - Logger::Message(Logger::LOG_ERROR, "Triangulation of entity crashed:", entity->entity); + Logger::Message(Logger::LOG_ERROR, "Triangulation of geometry crashed:", product); return false; } if (!success) { - Logger::Message(Logger::LOG_ERROR, "Triangulation of entity failed:", entity->entity); + 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 entity:", entity->entity); + Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Self-intersecting geometry:", product); return false; } - CGAL::Nef_polyhedron_3 nef_brep_cut_result; + CGAL::Nef_polyhedron_3 nef_brep_cut_result; try { - nef_brep_cut_result = CGAL::Nef_polyhedron_3(entity_shape); + nef_brep_cut_result = CGAL::Nef_polyhedron_3(entity_shape); } catch (...) { - Logger::Message(Logger::LOG_ERROR, "Could not convert entity to Nef:", entity->entity); + Logger::Message(Logger::LOG_ERROR, "Could not convert geometry to Nef:", product); return false; } @@ -185,17 +186,17 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* product, 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 entity from Nef:", entity->entity); + 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 entity:", entity->entity); + 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 entity:", entity->entity); + Logger::Message(Logger::LOG_ERROR, "Subtraction of opening makes no sense. Not closed opening in geometry:", product); return false; } @@ -204,25 +205,25 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* product, try { success = CGAL::Polygon_mesh_processing::triangulate_faces(opening); } catch (...) { - Logger::Message(Logger::LOG_ERROR, "Triangulation of opening of entity crashed:", entity->entity); + 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 entity failed:", entity->entity); + 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 entity:", entity->entity); + Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Self-intersecting opening of geometry:", product); } - CGAL::Nef_polyhedron_3 nef_opening; + CGAL::Nef_polyhedron_3 nef_opening; try { - nef_opening = CGAL::Nef_polyhedron_3(opening); + nef_opening = CGAL::Nef_polyhedron_3(opening); } catch (...) { - Logger::Message(Logger::LOG_ERROR, "Could not convert opening of entity to Nef:", entity->entity); + Logger::Message(Logger::LOG_ERROR, "Could not convert opening of geometry to Nef:", product); return false; } @@ -230,14 +231,14 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* product, 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 entity from Nef:", entity->entity); + 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 entity:", entity->entity); + Logger::Message(Logger::LOG_ERROR, "Could not subtract Nef opening of geometry:", product); return false; } } @@ -245,11 +246,11 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* product, try { nef_brep_cut_result.convert_to_polyhedron(entity_shape); } catch (...) { - Logger::Message(Logger::LOG_ERROR, "Could not convert entity with openings from Nef:", entity->entity); + Logger::Message(Logger::LOG_ERROR, "Could not convert geometry with openings from Nef:", product); return false; } - cut_shapes.push_back(IfcGeom::ConversionResult(new CgalShape(entity_shape), &it3->Style())); + opened_shapes.push_back(IfcGeom::ConversionResult(it3->ItemId(), new CgalShape(entity_shape), &it3->Style())); } return true; } diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index fdd2b020d5..34f0e3c900 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -35,8 +35,15 @@ if ( it != cache.T.end() ) { e = it->second; return true; } #endif */ +#include + #define ALMOST_ZERO 1.e-9 +template +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" @@ -52,7 +59,7 @@ if ( it != cache.T.end() ) { e = it->second; return true; } #include INCLUDE_SCHEMA(IfcSchema) #undef INCLUDE_SCHEMA -struct PolyhedronBuilder : public CGAL::Modifier_base::HalfedgeDS> { +struct PolyhedronBuilder : public CGAL::Modifier_base::HalfedgeDS> { private: std::list *face_list; public: @@ -60,10 +67,10 @@ public: this->face_list = face_list; } - void operator()(CGAL::Polyhedron_3::HalfedgeDS &hds) { - std::list points; + void operator()(CGAL::Polyhedron_3::HalfedgeDS &hds) { + std::list points; std::list> facet_vertices; - CGAL::Polyhedron_incremental_builder_3::HalfedgeDS> builder(hds, true); + CGAL::Polyhedron_incremental_builder_3::HalfedgeDS> builder(hds, true); for (auto &face: *face_list) { facet_vertices.push_back(std::list()); @@ -127,11 +134,11 @@ namespace IfcGeom { 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 triangulate_faces(CGAL::Polyhedron_3 &polyhedron); - CGAL::Polyhedron_3 create_polyhedron(std::list &face_list); - CGAL::Polyhedron_3 create_polyhedron(CGAL::Nef_polyhedron_3 &nef_polyhedron); - CGAL::Nef_polyhedron_3 create_nef_polyhedron(std::list &face_list); - CGAL::Nef_polyhedron_3 create_nef_polyhedron(CGAL::Polyhedron_3 &polyhedron); +// CGAL::Polyhedron_3 triangulate_faces(CGAL::Polyhedron_3 &polyhedron); + CGAL::Polyhedron_3 create_polyhedron(std::list &face_list); + CGAL::Polyhedron_3 create_polyhedron(CGAL::Nef_polyhedron_3 &nef_polyhedron); + CGAL::Nef_polyhedron_3 create_nef_polyhedron(std::list &face_list); + CGAL::Nef_polyhedron_3 create_nef_polyhedron(CGAL::Polyhedron_3 &polyhedron); void purge_cache() { // Rather hack-ish, but a stopgap solution to keep memory under control diff --git a/src/ifcgeom/schema_agnostic/Kernel.cpp b/src/ifcgeom/schema_agnostic/Kernel.cpp index a75f04053a..64ee0ce269 100644 --- a/src/ifcgeom/schema_agnostic/Kernel.cpp +++ b/src/ifcgeom/schema_agnostic/Kernel.cpp @@ -183,7 +183,7 @@ namespace { std::map layers; if (prod->hasRepresentation()) { IfcEntityList::ptr r = IfcParse::traverse(prod->Representation()); - typename Schema::IfcRepresentation::list::ptr representations = r->as(); + typename Schema::IfcRepresentation::list::ptr representations = r->template as(); 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) { @@ -191,7 +191,7 @@ namespace { } } - typename Schema::IfcRepresentationItem::list::ptr items = r->as(); + typename Schema::IfcRepresentationItem::list::ptr items = r->template as(); for (typename Schema::IfcRepresentationItem::list::it it = items->begin(); it != items->end(); ++it) { typename Schema::IfcPresentationLayerAssignment::list::ptr a = getLayerAssignments(*it)->template as(); for (typename Schema::IfcPresentationLayerAssignment::list::it jt = a->begin(); jt != a->end(); ++jt) { @@ -251,11 +251,11 @@ namespace { } // Is the IfcElement a decomposition of an IfcElement with any IfcOpeningElements? - typename Schema::IfcObjectDefinition* obdef = product->as(); + typename Schema::IfcObjectDefinition* obdef = product->template as(); for (;;) { auto decomposes = obdef->Decomposes()->generalize(); if (decomposes->size() != 1) break; - typename Schema::IfcObjectDefinition* rel_obdef = (*decomposes->begin())->as()->RelatingObject(); + typename Schema::IfcObjectDefinition* rel_obdef = (*decomposes->begin())->template as()->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()); diff --git a/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.cpp b/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.cpp index 24d3ed83c6..cd59ecd70a 100644 --- a/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.cpp @@ -23,10 +23,10 @@ void triangulate_helper(const cgal_shape_t& shape_const, const IfcGeom::Iterator } // Triangulate the shape and compute the normals -// std::map vertex_normals; -// boost::associative_property_map> vertex_normals_map(vertex_normals); - std::map face_normals; - boost::associative_property_map> face_normals_map(face_normals); +// std::map vertex_normals; +// boost::associative_property_map> vertex_normals_map(vertex_normals); + std::map face_normals; + boost::associative_property_map> face_normals_map(face_normals); bool success = false; try { @@ -37,8 +37,8 @@ void triangulate_helper(const cgal_shape_t& shape_const, const IfcGeom::Iterator } if (!success) { - Logger::Message(Logger::LOG_ERROR, return; -"Triangulation failed"); + 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; @@ -50,12 +50,13 @@ void triangulate_helper(const cgal_shape_t& shape_const, const IfcGeom::Iterator // 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::Halfedge_around_facet_const_circulator current_halfedge = face->facet_begin(); + CGAL::Polyhedron_3::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)), diff --git a/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.h b/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.h index 38a3bc87d5..df085e0c8d 100644 --- a/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.h +++ b/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.h @@ -38,24 +38,24 @@ #include #include -typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; +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 cgal_curve_t; -typedef std::vector cgal_wire_t; +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 cgal_curve_t; +typedef std::vector cgal_wire_t; struct cgal_face_t { cgal_wire_t outer; std::vector inner; }; -typedef CGAL::Polyhedron_3 cgal_shape_t; -typedef boost::graph_traits>::vertex_descriptor cgal_vertex_descriptor_t; -typedef boost::graph_traits>::face_descriptor cgal_face_descriptor_t; +typedef CGAL::Polyhedron_3 cgal_shape_t; +typedef boost::graph_traits>::vertex_descriptor cgal_vertex_descriptor_t; +typedef boost::graph_traits>::face_descriptor cgal_face_descriptor_t; #include "../../../ifcgeom/schema_agnostic/ConversionResult.h" From 3afb9169b1f0854e53b4c629fd429158bacffac3 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 25 Jan 2019 14:25:34 +0100 Subject: [PATCH 134/235] Implement missing virtual function in CgalKernel --- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 11 +++++++++++ src/ifcgeom/kernels/cgal/CgalKernel.h | 1 + 2 files changed, 12 insertions(+) diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index 2a36bc2adf..c885fa5974 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -88,6 +88,17 @@ bool IfcGeom::CgalKernel::validate_quantities(const IfcSchema::IfcProduct* produ throw std::runtime_error("not implemented"); } +bool IfcGeom::CgalKernel::convert_placement(IfcUtil::IfcBaseClass* item, ConversionResultPlacement*& trsf) { + if (item->as()) { + cgal_placement_t cgal_trsf; + if (convert(item->as(), 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 opening_shapelist; diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 34f0e3c900..4f3186589d 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -153,6 +153,7 @@ namespace IfcGeom { 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" From 5b066c9f9523389628c65fb2afb54de749b7e2ab Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 25 Jan 2019 15:19:52 +0100 Subject: [PATCH 135/235] Don't convert to Nef if there are no voids --- .../cgal/CgalIfcGeomShapesWithStyles.cpp | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp index ef3adc858f..b1c2110955 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp @@ -66,10 +66,9 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, 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) ) { - CGAL::Nef_polyhedron_3 nef_s = create_nef_polyhedron(s); - const SurfaceStyle* indiv_style = get_style(l->Outer()); - IfcSchema::IfcClosedShell::list::ptr voids(new IfcSchema::IfcClosedShell::list); if (l->as()) { voids = l->as()->Voids(); @@ -79,15 +78,20 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, Conv voids = l->as()->Voids(); } #endif - - 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(s2); + + if (voids->size()) { + CGAL::Nef_polyhedron_3 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(s2); + } } + + s = create_polyhedron(nef_s); } - s = create_polyhedron(nef_s); shape.push_back(ConversionResult(l->data().id(), new CgalShape(s), indiv_style ? indiv_style : collective_style)); return true; } From f9e839817da69f8a4cbd5b7f1e913021ad3e70d2 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sat, 27 Apr 2019 14:37:31 +0200 Subject: [PATCH 136/235] Add opensourceBIM/voxel to nix build script --- nix/build-all.py | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/nix/build-all.py b/nix/build-all.py index 34b0c819e9..19a1886b02 100644 --- a/nix/build-all.py +++ b/nix/build-all.py @@ -185,11 +185,12 @@ cecho(""" - How many compiler processes may be run in parallel. dependency_tree = { 'IfcParse': ('icu', 'boost', 'libxml2'), - 'IfcGeom': ('IfcParse', 'occ', 'cgal'), + 'IfcGeom': ('IfcParse', 'occ', 'cgal', 'voxel'), 'IfcConvert': ('IfcGeom', 'OpenCOLLADA'), 'OpenCOLLADA': ('libxml2', 'pcre'), - 'IfcGeomServer': ('IfcGeom',), + 'IfcGeomServer': ('IfcGeom', ), 'IfcOpenShell-Python': ('python', 'swig', 'IfcGeom'), + 'voxel': ('occ',), 'swig': ('pcre',), 'icu': (), 'boost': (), @@ -532,6 +533,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()), @@ -548,6 +551,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( @@ -662,6 +668,23 @@ if "cgal" in targets: 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=[ + "-IFCSUPPORT=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) @@ -689,16 +712,12 @@ cmake_args=[ "-DBOOST_ROOT=" "{DEPS_DIR}/install/boost-{BOOST_VERSION}".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 From b862f633dbd5b0dee16991ee79236a77692e0c42 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Tue, 30 Apr 2019 13:24:28 +0200 Subject: [PATCH 137/235] Fix voxel library in nix build script --- nix/build-all.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nix/build-all.py b/nix/build-all.py index 19a1886b02..c47830922c 100644 --- a/nix/build-all.py +++ b/nix/build-all.py @@ -321,6 +321,7 @@ def git_clone(clone_url, target_dir, revision=None): logger.info("directory '%s' exists, skipping cloning" % (target_dir,)) if revision != None: run([git, "checkout", revision], cwd=target_dir) + run([git, "pull"], cwd=target_dir) def build_dependency(name, mode, build_tool_args, download_url, download_name, download_tool=download_tool_default, revision=None, patch=None, additional_files={}, no_append_name=False): """Handles building of dependencies with different tools (which are @@ -674,7 +675,7 @@ if "voxel" in targets: "voxel", "cmake", build_tool_args=[ - "-IFCSUPPORT=Off", + "-DIFC_SUPPORT=Off", "-DOCC_INCLUDE_DIR=" +occ_include_dir, "-DOCC_LIBRARY_DIR=" +occ_library_dir, "-DCMAKE_INSTALL_PREFIX={DEPS_DIR}/install/voxel".format(**locals()), @@ -683,7 +684,7 @@ if "voxel" in targets: download_url="https://github.com/opensourceBIM/voxel.git", download_name="voxel", download_tool=download_tool_git, - revision=master + revision="master" ) cecho("Building IfcOpenShell:", GREEN) From 8e6a6ec56d5ea914b87a3182bbed30f13f7430b0 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Tue, 30 Apr 2019 14:36:55 +0200 Subject: [PATCH 138/235] Add voxelization_toolkit to win build script --- win/build-deps.cmd | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/win/build-deps.cmd b/win/build-deps.cmd index b691332345..ad5edc0a65 100644 --- a/win/build-deps.cmd +++ b/win/build-deps.cmd @@ -405,6 +405,26 @@ IF EXIST "%DEPS_DIR%\swigwin-%SWIG_VERSION%". ( ) IF EXIST "%DEPS_DIR%\swigwin\". robocopy "%DEPS_DIR%\swigwin" "%INSTALL_DIR%\swigwin" /E /IS /MOVE /njh /njs +:voxel +:: Note OpenCOLLADA has only Release and Debug builds. +set DEPENDENCY_NAME=voxel +set DEPENDENCY_DIR=%DEPS_DIR%\voxel +:: Use a fixed revision in order to prevent introducing breaking changes +call :GitCloneAndCheckoutRevision https://github.com/opensourceBIM/voxelization_toolkit.git "%DEPENDENCY_DIR%" +IF NOT %ERRORLEVEL%==0 GOTO :Error +cd "%DEPENDENCY_DIR%" +call :RunCMake -DCMAKE_INSTALL_PREFIX="%INSTALL_DIR%\voxel" ^ + -DIFC_SUPPORT=Off ^ + -DOCC_INCLUDE_DIR="%OCC_INCLUDE_DIR%" ^ + -DOCC_LIBRARY_DIR="%OCC_LIBRARY_DIR%" ^ + -DBOOST_ROOT="%DEPS_DIR%\boost_%BOOST_VER%" ^ + -DBOOST_LIBRARYDIR="%DEPS_DIR%\boost_%BOOST_VER%\stage\vs%VS_VER%-%VS_PLATFORM%\lib" +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :BuildSolution "%DEPENDENCY_DIR%\%BUILD_DIR%\voxel.sln" %BUILD_CFG% +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :InstallCMakeProject "%DEPENDENCY_DIR%\%BUILD_DIR%" %BUILD_CFG% +IF NOT %ERRORLEVEL%==0 GOTO :Error + :Successful echo. call "%~dp0\utils\cecho.cmd" 0 10 "%PROJECT_NAME% dependencies built." From 33bcf786fd5feaed963f32c2be034eea9b4bb3be Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 3 May 2019 10:46:59 +0200 Subject: [PATCH 139/235] MPIR and MPFR in win build script --- win/build-deps.cmd | 59 +++++++++++++++++++++++++++++++++++------ win/patches/mpfr.patch | 5 ++++ win/patches/mpfr2.patch | 5 ++++ 3 files changed, 61 insertions(+), 8 deletions(-) create mode 100644 win/patches/mpfr.patch create mode 100644 win/patches/mpfr2.patch diff --git a/win/build-deps.cmd b/win/build-deps.cmd index ad5edc0a65..53dced8eb8 100644 --- a/win/build-deps.cmd +++ b/win/build-deps.cmd @@ -73,7 +73,7 @@ IF NOT DEFINED IFCOS_USE_PYTHON2 set IFCOS_USE_PYTHON2=FALSE IF NOT DEFINED IFCOS_NUM_BUILD_PROCS set IFCOS_NUM_BUILD_PROCS=%NUMBER_OF_PROCESSORS% :: For subroutines -set MSBUILD_CMD=MSBuild.exe /nologo /m:%IFCOS_NUM_BUILD_PROCS% /t:%BUILD_TYPE% +set MSBUILD_CMD=MSBuild.exe /nologo /m:%IFCOS_NUM_BUILD_PROCS% REM /clp:ErrorsOnly;WarningsOnly :: Note BUILD_TYPE not passed, Clean e.g. wouldn't delete the installed files. set INSTALL_CMD=MSBuild.exe /nologo /m:%IFCOS_NUM_BUILD_PROCS% @@ -406,10 +406,8 @@ IF EXIST "%DEPS_DIR%\swigwin-%SWIG_VERSION%". ( IF EXIST "%DEPS_DIR%\swigwin\". robocopy "%DEPS_DIR%\swigwin" "%INSTALL_DIR%\swigwin" /E /IS /MOVE /njh /njs :voxel -:: Note OpenCOLLADA has only Release and Debug builds. set DEPENDENCY_NAME=voxel set DEPENDENCY_DIR=%DEPS_DIR%\voxel -:: Use a fixed revision in order to prevent introducing breaking changes call :GitCloneAndCheckoutRevision https://github.com/opensourceBIM/voxelization_toolkit.git "%DEPENDENCY_DIR%" IF NOT %ERRORLEVEL%==0 GOTO :Error cd "%DEPENDENCY_DIR%" @@ -425,6 +423,47 @@ IF NOT %ERRORLEVEL%==0 GOTO :Error call :InstallCMakeProject "%DEPENDENCY_DIR%\%BUILD_DIR%" %BUILD_CFG% IF NOT %ERRORLEVEL%==0 GOTO :Error +:mpir +set DEPENDENCY_NAME=mpir +set DEPENDENCY_DIR=%DEPS_DIR%\mpir +call :GitCloneAndCheckoutRevision https://github.com/BrianGladman/mpir.git "%DEPENDENCY_DIR%" +IF NOT %ERRORLEVEL%==0 GOTO :Error +cd "%DEPENDENCY_DIR%" +git reset --hard +REM There probably need to be quotes here around the filename +powershell -c "get-content %~dp0patches\mpir.patch | %%{$_ -replace \"sdk\",\"%UCRTVersion%\"} | %%{$_ -replace \"fn\",\"lib_mpir_cxx\"}" | git apply --unidiff-zero +powershell -c "get-content %~dp0patches\mpir.patch | %%{$_ -replace \"sdk\",\"%UCRTVersion%\"} | %%{$_ -replace \"fn\",\"lib_mpir_gc\"}" | git apply --unidiff-zero +cd msvc +cd vs%VS_VER:~2,2% +call .\msbuild.bat gc LIB %VS_PLATFORM% Release +IF NOT %ERRORLEVEL%==0 GOTO :Error +IF NOT EXIST "%INSTALL_DIR%\mpir". mkdir "%INSTALL_DIR%\mpir" +copy ..\..\lib\%VS_PLATFORM%\Release\* "%INSTALL_DIR%\mpir" +IF NOT %ERRORLEVEL%==0 GOTO :Error + +:mpfr +set DEPENDENCY_NAME=mpfr +set DEPENDENCY_DIR=%DEPS_DIR%\mpfr +call :GitCloneAndCheckoutRevision https://github.com/BrianGladman/mpfr.git "%DEPENDENCY_DIR%" +IF NOT %ERRORLEVEL%==0 GOTO :Error +cd "%DEPENDENCY_DIR%" +git reset --hard +for /f "delims=|" %%f in ('dir /s/b build.vc15\*.vcxproj') do ( + set "full=%%f" + set rel=!full:*%DEPENDENCY_DIR%=! + set relnix=!rel:\=/! + powershell -c "get-content %~dp0patches\mpfr.patch | %%{$_ -replace \"sdk\",\"%UCRTVersion%\"} | %%{$_ -replace \"fn\",\"!relnix!\"}" | git apply --unidiff-zero + git diff --exit-code -- %%f + IF !ERRORLEVEL!==0 ( + powershell -c "get-content %~dp0patches\mpfr2.patch | %%{$_ -replace \"sdk\",\"%UCRTVersion%\"} | %%{$_ -replace \"fn\",\"!relnix!\"}" | git apply --unidiff-zero + ) +) +call :BuildSolution "%DEPENDENCY_DIR%\build.vc15\lib_mpfr.sln" %DEBUG_OR_RELEASE% lib_mpfr +IF NOT %ERRORLEVEL%==0 GOTO :Error +IF NOT EXIST "%INSTALL_DIR%\mpfr". mkdir "%INSTALL_DIR%\mpfr" +copy lib\%VS_PLATFORM%\Release\* "%INSTALL_DIR%\mpfr" +IF NOT %ERRORLEVEL%==0 GOTO :Error + :Successful echo. call "%~dp0\utils\cecho.cmd" 0 10 "%PROJECT_NAME% dependencies built." @@ -516,12 +555,11 @@ if not exist "%~2". ( call cecho.cmd 0 13 "Cloning %DEPENDENCY_NAME% into %~2." pushd "%DEPS_DIR%" call git clone %1 %2 - set RET=%ERRORLEVEL% - if not %RET%==0 exit /b %RET% + set RET=!ERRORLEVEL! + if not !RET!==0 exit /b !RET! popd ) else ( call cecho.cmd 0 13 "%DEPENDENCY_NAME% already cloned." - set RET=0 ) pushd "%2" call git fetch @@ -550,10 +588,15 @@ exit /b %RET% :: TODO add BuildCMakeProject which utilizes cmake --build :: BuildSolution - Builds/Rebuilds/Cleans a solution using MSBuild -:: Params: %1 solutioName, %2 configuration +:: Params: %1 solutioName, %2 configuration, %3 individual project name +:: NOTE: %3 does not account for BUILD_TYPE and probably assumes Build :BuildSolution call cecho.cmd 0 13 "Building %2 %DEPENDENCY_NAME%. Please be patient, this will take a while." -%MSBUILD_CMD% %1 /p:configuration=%2;platform=%VS_PLATFORM% +set TARGET=/t:%BUILD_TYPE% +IF NOT "%3"=="" ( + set TARGET=/t:%3 +) +%MSBUILD_CMD% %1 %TARGET% /p:configuration=%2;platform=%VS_PLATFORM% exit /b %ERRORLEVEL% :: InstallCMakeProject - Builds the INSTALL project of CMake-based project diff --git a/win/patches/mpfr.patch b/win/patches/mpfr.patch new file mode 100644 index 0000000000..0ca9f4f15b --- /dev/null +++ b/win/patches/mpfr.patch @@ -0,0 +1,5 @@ +--- afn ++++ bfn +@@ -26 +26 @@ +- 10.0.17134.0 ++ sdk diff --git a/win/patches/mpfr2.patch b/win/patches/mpfr2.patch new file mode 100644 index 0000000000..1a18a7e65d --- /dev/null +++ b/win/patches/mpfr2.patch @@ -0,0 +1,5 @@ +--- afn ++++ bfn +@@ -26 +26 @@ +- 10.0.16299.0 ++ sdk From adc0e92528f4c8db437b2bc39ee3c0494bac3801 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 10 May 2019 13:42:16 +0200 Subject: [PATCH 140/235] Fix remaining conflict --- cmake/CMakeLists.txt | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 630e74b551..3e7e7cde55 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -593,16 +593,11 @@ 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}) -<<<<<<< HEAD -add_library(IfcGeom_${kernel} ${IFCGEOM_FILES}) +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() -======= -add_library(IfcGeom_ifc2x3 STATIC ${IFCGEOM_FILES}) -add_library(IfcGeom_ifc4 STATIC ${IFCGEOM_FILES}) ->>>>>>> v0.6.0 foreach(schema 2x3 4) @@ -610,7 +605,7 @@ 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} ${IFCGEOM_FILES}) +add_library(IfcGeom_ifc${schema} STATIC ${IFCGEOM_FILES}) set_target_properties(IfcGeom_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema} -DUSE_IFC${schema}") target_link_libraries(IfcGeom_ifc${schema} IfcParse) list(APPEND IfcGeom_libraries IfcGeom_ifc${schema}) @@ -620,7 +615,7 @@ 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} ${IFCGEOM_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} -DUSE_IFC${schema}") target_link_libraries(IfcGeom_${kernel}_ifc${schema} IfcGeom_${kernel} IfcGeom_ifc${schema}) list(APPEND IfcGeom_libraries IfcGeom_${kernel}_ifc${schema}) From a24ad023a5f029ee8ec6da8d14ea0816dcbe772f Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 10 May 2019 13:46:13 +0200 Subject: [PATCH 141/235] CGAL win build script --- cmake/CMakeLists.txt | 15 +++++++-------- win/build-deps.cmd | 21 +++++++++++++++++++++ win/run-cmake.bat | 12 ++++++++++++ 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 3e7e7cde55..17f4a1e173 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -285,18 +285,20 @@ IF(libCGAL) list(APPEND CGAL_LIBRARIES "${lib_path}") endforeach() ELSE() - FILE(GLOB CGAL_LIBRARIES ${CGAL_LIBRARY_DIR}/CGAL*.lib) + 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_library_names}") + 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() -# TODO: Remove hardcoded version numbers for windows -FIND_LIBRARY(libGMP NAMES gmp "libgmp-10" PATHS ${GMP_LIBRARY_DIR} NO_DEFAULT_PATH) -FIND_LIBRARY(libMPFR NAMES mpfr "libmpfr-4" PATHS ${MPFR_LIBRARY_DIR} NO_DEFAULT_PATH) + +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() @@ -306,9 +308,6 @@ ENDIF() list(APPEND CGAL_LIBRARIES "${libMPFR}") list(APPEND CGAL_LIBRARIES "${libGMP}") - - - if(MSVC) add_definitions(-DHAVE_NO_DLL) add_debug_variants(OPENCASCADE_LIBRARIES "${OPENCASCADE_LIBRARIES}" d) diff --git a/win/build-deps.cmd b/win/build-deps.cmd index d4bae43551..56ea0b66fd 100644 --- a/win/build-deps.cmd +++ b/win/build-deps.cmd @@ -437,6 +437,27 @@ IF NOT EXIST "%INSTALL_DIR%\mpfr". mkdir "%INSTALL_DIR%\mpfr" copy lib\%VS_PLATFORM%\Release\* "%INSTALL_DIR%\mpfr" IF NOT %ERRORLEVEL%==0 GOTO :Error +:cgal +set DEPENDENCY_NAME=mpfr +set DEPENDENCY_DIR=%DEPS_DIR%\cgal +call :GitCloneAndCheckoutRevision https://github.com/CGAL/cgal.git "%DEPENDENCY_DIR%" releases/CGAL-4.13.1 +IF NOT %ERRORLEVEL%==0 GOTO :Error +cd "%DEPENDENCY_DIR%" +call :RunCMake -DCMAKE_INSTALL_PREFIX="%INSTALL_DIR%\cgal" ^ + -DBOOST_ROOT="%DEPS_DIR%\boost_%BOOST_VER%" ^ + -DGMP_INCLUDE_DIR="%INSTALL_DIR%\mpir" ^ + -DGMP_LIBRARIES="%INSTALL_DIR%\mpir\mpir.lib" ^ + -DMPFR_INCLUDE_DIR="%INSTALL_DIR%\mpfr" ^ + -DMPFR_LIBRARIES="%INSTALL_DIR%\mpfr\mpfr.lib" ^ + -DCGAL_BUILD_SHARED_LIBS=Off ^ + -DBUILD_SHARED_LIBS=Off ^ + -DBOOST_LIBRARYDIR="%DEPS_DIR%\boost_%BOOST_VER%\stage\vs%VS_VER%-%VS_PLATFORM%\lib" +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :BuildSolution "%DEPENDENCY_DIR%\%BUILD_DIR%\CGAL.sln" %BUILD_CFG% +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :InstallCMakeProject "%DEPENDENCY_DIR%\%BUILD_DIR%" %BUILD_CFG% +IF NOT %ERRORLEVEL%==0 GOTO :Error + :Successful echo. call "%~dp0\utils\cecho.cmd" 0 10 "%PROJECT_NAME% dependencies built." diff --git a/win/run-cmake.bat b/win/run-cmake.bat index 8154b3a4bc..48a2dec6fe 100755 --- a/win/run-cmake.bat +++ b/win/run-cmake.bat @@ -78,6 +78,12 @@ set PYTHON_EXECUTABLE=%PYTHONHOME%\python.exe set SWIG_DIR=%INSTALL_DIR%\swigwin set PATH=%PATH%;%SWIG_DIR%;%PYTHONHOME% set JSON_INCLUDE_DIR=%INSTALL_DIR%\json +set CGAL_INCLUDE_DIR=%INSTALL_DIR%\cgal\include +set CGAL_LIBRARY_DIR=%INSTALL_DIR%\cgal\lib +set GMP_INCLUDE_DIR=%INSTALL_DIR%\mpir +set GMP_LIBRARY_DIR=%INSTALL_DIR%\mpir +set MPFR_INCLUDE_DIR=%INSTALL_DIR%\mpfr +set MPFR_LIBRARY_DIR=%INSTALL_DIR%\mpfr echo. call cecho.cmd 0 10 "Script configuration:" @@ -99,6 +105,12 @@ echo PYTHON_LIBRARY = %PYTHON_LIBRARY% echo PYTHON_EXECUTABLE = %PYTHON_EXECUTABLE% echo SWIG_DIR = %SWIG_DIR% echo JSON_INCLUDE_DIR = %JSON_INCLUDE_DIR% +echo CGAL_INCLUDE_DIR = %CGAL_INCLUDE_DIR% +echo CGAL_LIBRARY_DIR = %CGAL_LIBRARY_DIR% +echo GMP_INCLUDE_DIR = %GMP_INCLUDE_DIR% +echo GMP_LIBRARY_DIR = %GMP_LIBRARY_DIR% +echo MPFR_INCLUDE_DIR = %MPFR_INCLUDE_DIR% +echo MPFR_LIBRARY_DIR = %MPFR_LIBRARY_DIR% echo. echo CMAKE_INSTALL_PREFIX = %CMAKE_INSTALL_PREFIX% echo. From de3633e7422f1aa54fde74e91e824c277a47f3e7 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 10 May 2019 14:35:00 +0200 Subject: [PATCH 142/235] Cmake find voxels --- cmake/CMakeLists.txt | 13 +++++++++++-- win/run-cmake.bat | 6 +++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 17f4a1e173..a68764ff46 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -43,6 +43,7 @@ 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) if (${HAS_MAX}) OPTION(BUILD_IFCMAX "Build IfcMax, a 3ds Max plug-in, Windows-only." ON) endif() @@ -115,6 +116,8 @@ 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) UNIFY_ENVVARS_AND_CACHE(JSON_INCLUDE_DIR) @@ -172,6 +175,12 @@ 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}) +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}") @@ -497,7 +506,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} + ${CGAL_INCLUDE_DIR} ${GMP_INCLUDE_DIR} ${MPFR_INCLUDE_DIR} ${VOXEL_INCLUDE_DIR} ) function(files_for_ifc_version IFC_VERSION RESULT_NAME) @@ -688,7 +697,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} ${OPENCASCADE_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}") diff --git a/win/run-cmake.bat b/win/run-cmake.bat index 48a2dec6fe..058aa3498a 100755 --- a/win/run-cmake.bat +++ b/win/run-cmake.bat @@ -84,6 +84,8 @@ set GMP_INCLUDE_DIR=%INSTALL_DIR%\mpir set GMP_LIBRARY_DIR=%INSTALL_DIR%\mpir set MPFR_INCLUDE_DIR=%INSTALL_DIR%\mpfr set MPFR_LIBRARY_DIR=%INSTALL_DIR%\mpfr +set VOXEL_INCLUDE_DIR=%INSTALL_DIR%\voxel\include +set VOXEL_LIBRARY_DIR=%INSTALL_DIR%\voxel\lib echo. call cecho.cmd 0 10 "Script configuration:" @@ -111,6 +113,8 @@ echo GMP_INCLUDE_DIR = %GMP_INCLUDE_DIR% echo GMP_LIBRARY_DIR = %GMP_LIBRARY_DIR% echo MPFR_INCLUDE_DIR = %MPFR_INCLUDE_DIR% echo MPFR_LIBRARY_DIR = %MPFR_LIBRARY_DIR% +echo VOXEL_INCLUDE_DIR = %VOXEL_INCLUDE_DIR% +echo VOXEL_LIBRARY_DIR = %VOXEL_LIBRARY_DIR% echo. echo CMAKE_INSTALL_PREFIX = %CMAKE_INSTALL_PREFIX% echo. @@ -119,7 +123,7 @@ set CMAKELISTS_DIR=..\cmake :: Delete CMakeCache.txt if command-line options were provided for this batch script. if not (%1)==() if exist CMakeCache.txt. del /Q CMakeCache.txt call cecho.cmd 0 13 "Running CMake for %PROJECT_NAME%." -cmake.exe %CMAKELISTS_DIR% -G %GENERATOR% -DCMAKE_INSTALL_PREFIX="%CMAKE_INSTALL_PREFIX%" %ARGUMENTS% +cmake.exe %CMAKELISTS_DIR% -G %GENERATOR% -DCMAKE_INSTALL_PREFIX="%CMAKE_INSTALL_PREFIX%" -DUSE_VOXELS=On %ARGUMENTS% IF NOT %ERRORLEVEL%==0 GOTO :Error echo. From 310013dfe40617fbacaa809567af99b82cfddf69 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 10 May 2019 14:35:20 +0200 Subject: [PATCH 143/235] Fix compilation error from merge --- src/ifcconvert/IfcConvert.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 015c5c492d..013672f366 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -193,6 +193,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,16 +215,6 @@ int main(int argc, char** argv) { ("input-file", new po::typed_value(0), "input IFC file") ("output-file", new po::typed_value(0), "output geometry file"); - - double deflection_tolerance; - inclusion_filter include_filter; - inclusion_traverse_filter include_traverse_filter; - exclusion_filter exclude_filter; - exclusion_traverse_filter exclude_traverse_filter; - std::string filter_filename; - std::string default_material_filename; - std::string geometry_kernel; - po::options_description ifc_options("IFC options"); ifc_options.add_options() ("calculate-quantities", "Calculate or fix the physical quantity definitions " From e566af84c2cb524adf91ca944a7401f5353ea2b2 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 10 May 2019 14:35:42 +0200 Subject: [PATCH 144/235] Fix geom server for schema agnosticism --- src/ifcgeomserver/IfcGeomServer.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ifcgeomserver/IfcGeomServer.cpp b/src/ifcgeomserver/IfcGeomServer.cpp index fe82a3f87c..a89ff64998 100644 --- a/src/ifcgeomserver/IfcGeomServer.cpp +++ b/src/ifcgeomserver/IfcGeomServer.cpp @@ -47,11 +47,15 @@ #include #endif +#include "../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h" + #include #include #include #include #include +#include +#include #include @@ -479,7 +483,7 @@ public: boost::optional largest_face_dir; { - TopoDS_Compound compound = elem_->geometry().as_compound(true); + TopoDS_Compound compound = TopoDS::Compound(((IfcGeom::OpenCascadeShape*) elem_->geometry().as_compound(true))->shape()); TopExp_Explorer exp(compound, TopAbs_FACE); for (; exp.More(); exp.Next()) { GProp_GProps prop; From 9cb321e73d9c92e889a34c7fc218ca5218929630 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 10 May 2019 14:38:42 +0200 Subject: [PATCH 145/235] Move include up for M_PI def on MSVC --- src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp index 70d4fbee0a..457fc7dc63 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp @@ -1,12 +1,12 @@ +// For MSVC to have M_PI +#define _USE_MATH_DEFINES +#include + #include "CgalKernel.h" #include "../../../ifcgeom/schema_agnostic/cgal/CgalConversionResult.h" #define CgalKernel MAKE_TYPE_NAME(CgalKernel) -// For MSVC to have M_PI -#define _USE_MATH_DEFINES -#include - bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& result) { IfcSchema::IfcCartesianPoint::list::ptr points = l->Polygon(); From 4400a6ea4fa478fbaf29b70809e44aaec5975d47 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 15 May 2019 11:13:58 +0200 Subject: [PATCH 146/235] Make use of cgal configurable --- cmake/CMakeLists.txt | 46 +++++++++++++++---------- src/ifcgeom/schema_agnostic/Kernel.cpp | 4 +++ win/build-deps.cmd | 47 +++++++++++++------------- win/patches/V7_3_0.patch | 2 +- win/patches/cgal_no_zlib.patch | 13 +++++++ win/patches/mpfr.patch | 6 ++-- win/patches/mpfr_runtime.patch | 8 +++++ win/patches/mpir.patch | 7 ++++ win/patches/mpir_runtime.patch | 13 +++++++ 9 files changed, 102 insertions(+), 44 deletions(-) create mode 100644 win/patches/cgal_no_zlib.patch create mode 100644 win/patches/mpfr_runtime.patch create mode 100644 win/patches/mpir.patch create mode 100644 win/patches/mpir_runtime.patch diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index a68764ff46..8dbaed09d6 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -44,10 +44,12 @@ 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) if (${HAS_MAX}) OPTION(BUILD_IFCMAX "Build IfcMax, a 3ds Max plug-in, Windows-only." ON) endif() OPTION(BUILD_SHARED_LIBS "Build IfcParse and IfcGeom as shared libs (SO/DLL)." OFF) +OPTION(USE_STATIC_MSVC_RUNTIME "Link to the static runtime on MSVC." ON) # TODO QtViewer is deprecated ATM as it uses the 0.4 API # OPTION(BUILD_QTVIEWER "Build IfcOpenShell Qt GUI Viewer (requires Qt 4 framework)." OFF) @@ -147,8 +149,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 @@ -268,6 +272,11 @@ 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 "") @@ -316,6 +325,7 @@ IF(NOT libMPFR) ENDIF() list(APPEND CGAL_LIBRARIES "${libMPFR}") list(APPEND CGAL_LIBRARIES "${libGMP}") +endif() if(MSVC) add_definitions(-DHAVE_NO_DLL) @@ -473,20 +483,22 @@ IF(MSVC) # @todo currently fails # add_definitions(-permissive-) endif() - # Link against the static VC runtime - # TODO Make this configurable - IF("$ENV{CONDA_BUILD}" STREQUAL "") - FOREACH(flag CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL - CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE - CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO) - 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() + + 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() ElSE() add_definitions(-Wall -Wextra) if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") @@ -595,7 +607,7 @@ TARGET_LINK_LIBRARIES(IfcParse ${Boost_LIBRARIES} ${BCRYPT_LIBRARIES} ${LIBXML2_ if (BUILD_IFCGEOM) -foreach(kernel opencascade cgal) +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) @@ -618,7 +630,7 @@ set_target_properties(IfcGeom_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_ target_link_libraries(IfcGeom_ifc${schema} IfcParse) list(APPEND IfcGeom_libraries IfcGeom_ifc${schema}) -foreach(kernel opencascade cgal) +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}) diff --git a/src/ifcgeom/schema_agnostic/Kernel.cpp b/src/ifcgeom/schema_agnostic/Kernel.cpp index 2ae967b35b..b006963b58 100644 --- a/src/ifcgeom/schema_agnostic/Kernel.cpp +++ b/src/ifcgeom/schema_agnostic/Kernel.cpp @@ -64,14 +64,18 @@ IfcGeom::impl::KernelFactoryImplementation& IfcGeom::impl::kernel_implementation 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_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, const std::string& geometry_library, IfcGeom::impl::kernel_fn fn) { diff --git a/win/build-deps.cmd b/win/build-deps.cmd index 56ea0b66fd..045bec841f 100644 --- a/win/build-deps.cmd +++ b/win/build-deps.cmd @@ -149,11 +149,18 @@ echo. cd "%DEPS_DIR%" +:: Define the version strings at the top in case individual dependencies are skipped +set BOOST_VERSION=1.67.0 +set BOOST_VER=%BOOST_VERSION:.=_% +set OCCT_VERSION=7.3.0 +set OCE_VERSION=OCE-0.18 +set PYTHON_VERSION=3.4.3 +set SWIG_VERSION=3.0.12 + :: Note all of the dependencies have appropriate label so that user can easily skip something if wanted :: by modifying this file and using goto. :Boost :: NOTE Boost < 1.64 doesn't work without tricks if the user has only VS 2017 installed and no earlier versions. -set BOOST_VERSION=1.67.0 :: Version string with underscores instead of dots. set BOOST_VER=%BOOST_VERSION:.=_% :: DEPENDENCY_NAME is used for logging and DEPENDENCY_DIR for saving from some redundant typing @@ -191,7 +198,8 @@ if %VS_VER% LSS 2017 ( set BOOST_VC_VER=-%VC_VER%.0 ) -call .\b2 toolset=msvc%BOOST_VC_VER% runtime-link=static address-model=%ARCH_BITS% -j%IFCOS_NUM_BUILD_PROCS% ^ +if NOT "%USE_STATIC_RUNTIME%"=="FALSE" set RUNTIME_LINK_STATIC=runtime-link=static +call .\b2 toolset=msvc%BOOST_VC_VER% %RUNTIME_LINK_STATIC% address-model=%ARCH_BITS% -j%IFCOS_NUM_BUILD_PROCS% ^ variant=%DEBUG_OR_RELEASE_LOWERCASE% %BOOST_LIBS% stage --stagedir=stage/vs%VS_VER%-%VS_PLATFORM% IF NOT %ERRORLEVEL%==0 GOTO :Error @@ -216,7 +224,8 @@ IF NOT %ERRORLEVEL%==0 git apply --reject --whitespace=fix "%~dp0patches\OpenCOL :: uncomment to following line in order to delete the CMakeCache.txt always if experiencing problems. REM IF EXIST "%DEPENDENCY_DIR%\%BUILD_DIR%\CMakeCache.txt". del "%DEPENDENCY_DIR%\%BUILD_DIR%\CMakeCache.txt" :: NOTE Enforce that the embedded LibXml2 and PCRE are used as there might be problems with arbitrary versions of the libraries. -call :RunCMake -DCMAKE_INSTALL_PREFIX="%INSTALL_DIR%\OpenCOLLADA" -DUSE_STATIC_MSVC_RUNTIME=1 -DCMAKE_DEBUG_POSTFIX=d ^ +if NOT "%USE_STATIC_RUNTIME%"=="FALSE" set STATIC_RUNTIME_1=-DUSE_STATIC_MSVC_RUNTIME=1 +call :RunCMake -DCMAKE_INSTALL_PREFIX="%INSTALL_DIR%\OpenCOLLADA" %STATIC_RUNTIME_1% -DCMAKE_DEBUG_POSTFIX=d ^ -DLIBXML2_LIBRARIES="" -DLIBXML2_INCLUDE_DIR="" -DPCRE_INCLUDE_DIR="" -DPCRE_LIBRARIES="" IF NOT %ERRORLEVEL%==0 GOTO :Error REM IF NOT EXIST "%DEPS_DIR%\OpenCOLLADA\%BUILD_DIR%\lib\%DEBUG_OR_RELEASE%\OpenCOLLADASaxFrameworkLoader.lib". @@ -227,7 +236,6 @@ IF NOT %ERRORLEVEL%==0 GOTO :Error if %IFCOS_USE_OCCT%==FALSE goto :OCE :OCCT -set OCCT_VERSION=7.3.0 SET OCCT_VER=V%OCCT_VERSION:.=_% set OCC_INCLUDE_DIR=%INSTALL_DIR%\opencascade-%OCCT_VERSION%\inc>>"%~dp0\BuildDepsCache-%TARGET_ARCH%.txt" @@ -268,10 +276,11 @@ if not %ERRORLEVEL%==0 ( ) findstr IfcOpenShell "%DEPENDENCY_DIR%\CMakeLists.txt">NUL if not %ERRORLEVEL%==0 goto :Error - +OCCT_USE_STATIC_RUNTIME cd "%DEPENDENCY_DIR%" +if NOT "%USE_STATIC_RUNTIME%"=="FALSE" set STATIC_RUNTIME_1=-DOCCT_USE_STATIC_RUNTIME=1 call :RunCMake -DINSTALL_DIR="%INSTALL_DIR%\opencascade-%OCCT_VERSION%" -DBUILD_LIBRARY_TYPE="Static" -DCMAKE_DEBUG_POSTFIX=d ^ - -DBUILD_MODULE_Draw=0 -D3RDPARTY_FREETYPE_DIR="%INSTALL_DIR%\freetype" + -DBUILD_MODULE_Draw=0 -D3RDPARTY_FREETYPE_DIR="%INSTALL_DIR%\freetype" %STATIC_RUNTIME_1% if not %ERRORLEVEL%==0 goto :Error call :BuildSolution "%DEPENDENCY_DIR%\%BUILD_DIR%\OCCT.sln" %BUILD_CFG% if not %ERRORLEVEL%==0 goto :Error @@ -303,7 +312,6 @@ echo OCC_LIBRARY_DIR=%OCC_LIBRARY_DIR%>>"%~dp0\BuildDepsCache-%TARGET_ARCH%.txt" set DEPENDENCY_NAME=Open CASCADE Community Edition set DEPENDENCY_DIR=%DEPS_DIR%\oce -set OCE_VERSION=OCE-0.18 call :GitCloneAndCheckoutRevision https://github.com/tpaviot/oce.git "%DEPENDENCY_DIR%" %OCE_VERSION% IF NOT %ERRORLEVEL%==0 GOTO :Error :: Use the oce-win-bundle for OCE's dependencies @@ -313,8 +321,9 @@ IF NOT %ERRORLEVEL%==0 GOTO :Error cd "%DEPENDENCY_DIR%" :: NOTE Specify OCE_NO_LIBRARY_VERSION as rc.exe can fail due to long filenames and huge command-line parameter :: input (more than 32,000 characters). Could maybe try using subst for the build dir to overcome this. +if NOT "%USE_STATIC_RUNTIME%"=="FALSE" set STATIC_RUNTIME_1=-DOCE_USE_STATIC_MSVC_RUNTIME=1 call :RunCMake -DOCE_BUILD_SHARED_LIB=0 -DOCE_INSTALL_PREFIX="%INSTALL_DIR%\oce" -DOCE_TESTING=0 ^ - -DOCE_NO_LIBRARY_VERSION=1 -DOCE_USE_STATIC_MSVC_RUNTIME=1 + -DOCE_NO_LIBRARY_VERSION=1 %STATIC_RUNTIME_1% IF NOT %ERRORLEVEL%==0 GOTO :Error call :BuildSolution "%DEPENDENCY_DIR%\%BUILD_DIR%\OCE.sln" %BUILD_CFG% IF NOT %ERRORLEVEL%==0 GOTO :Error @@ -324,7 +333,6 @@ IF NOT %ERRORLEVEL%==0 GOTO :Error :Python :: TODO Update to 3.5 when it's released as it will have an option to install debug libraries. :: NOTE If updating the default Python version, change PY_VER_MAJOR_MINOR accordingly in run-cmake.bat -set PYTHON_VERSION=3.4.3 IF "%IFCOS_USE_PYTHON2%"=="TRUE" set PYTHON_VERSION=2.7.10 set PY_VER_MAJOR_MINOR=%PYTHON_VERSION:~0,3% set PY_VER_MAJOR_MINOR=%PY_VER_MAJOR_MINOR:.=% @@ -362,7 +370,6 @@ IF "%IFCOS_INSTALL_PYTHON%"=="TRUE" ( ) :SWIG -set SWIG_VERSION=3.0.12 set DEPENDENCY_NAME=SWIG %SWIG_VERSION% set DEPENDENCY_DIR=N/A set SWIG_ZIP=swigwin-%SWIG_VERSION%.zip @@ -406,6 +413,7 @@ git reset --hard REM There probably need to be quotes here around the filename powershell -c "get-content %~dp0patches\mpir.patch | %%{$_ -replace \"sdk\",\"%UCRTVersion%\"} | %%{$_ -replace \"fn\",\"lib_mpir_cxx\"}" | git apply --unidiff-zero powershell -c "get-content %~dp0patches\mpir.patch | %%{$_ -replace \"sdk\",\"%UCRTVersion%\"} | %%{$_ -replace \"fn\",\"lib_mpir_gc\"}" | git apply --unidiff-zero +if NOT "%USE_STATIC_RUNTIME%"=="FALSE" git apply "%~dp0patches\mpir_runtime.patch" cd msvc cd vs%VS_VER:~2,2% call .\msbuild.bat gc LIB %VS_PLATFORM% Release @@ -421,16 +429,8 @@ call :GitCloneAndCheckoutRevision https://github.com/BrianGladman/mpfr.git "%DEP IF NOT %ERRORLEVEL%==0 GOTO :Error cd "%DEPENDENCY_DIR%" git reset --hard -for /f "delims=|" %%f in ('dir /s/b build.vc15\*.vcxproj') do ( - set "full=%%f" - set rel=!full:*%DEPENDENCY_DIR%=! - set relnix=!rel:\=/! - powershell -c "get-content %~dp0patches\mpfr.patch | %%{$_ -replace \"sdk\",\"%UCRTVersion%\"} | %%{$_ -replace \"fn\",\"!relnix!\"}" | git apply --unidiff-zero - git diff --exit-code -- %%f - IF !ERRORLEVEL!==0 ( - powershell -c "get-content %~dp0patches\mpfr2.patch | %%{$_ -replace \"sdk\",\"%UCRTVersion%\"} | %%{$_ -replace \"fn\",\"!relnix!\"}" | git apply --unidiff-zero - ) -) +powershell -c "get-content %~dp0patches\mpfr.patch | %%{$_ -replace \"sdk\",\"%UCRTVersion%\"}" | git apply --unidiff-zero +if NOT "%USE_STATIC_RUNTIME%"=="FALSE" git apply "%~dp0patches\mpfr_runtime.patch" call :BuildSolution "%DEPENDENCY_DIR%\build.vc15\lib_mpfr.sln" %DEBUG_OR_RELEASE% lib_mpfr IF NOT %ERRORLEVEL%==0 GOTO :Error IF NOT EXIST "%INSTALL_DIR%\mpfr". mkdir "%INSTALL_DIR%\mpfr" @@ -438,19 +438,20 @@ copy lib\%VS_PLATFORM%\Release\* "%INSTALL_DIR%\mpfr" IF NOT %ERRORLEVEL%==0 GOTO :Error :cgal -set DEPENDENCY_NAME=mpfr +set DEPENDENCY_NAME=cgal set DEPENDENCY_DIR=%DEPS_DIR%\cgal call :GitCloneAndCheckoutRevision https://github.com/CGAL/cgal.git "%DEPENDENCY_DIR%" releases/CGAL-4.13.1 IF NOT %ERRORLEVEL%==0 GOTO :Error cd "%DEPENDENCY_DIR%" +git reset --hard +git apply "%~dp0patches\cgal_no_zlib.patch" call :RunCMake -DCMAKE_INSTALL_PREFIX="%INSTALL_DIR%\cgal" ^ -DBOOST_ROOT="%DEPS_DIR%\boost_%BOOST_VER%" ^ -DGMP_INCLUDE_DIR="%INSTALL_DIR%\mpir" ^ -DGMP_LIBRARIES="%INSTALL_DIR%\mpir\mpir.lib" ^ -DMPFR_INCLUDE_DIR="%INSTALL_DIR%\mpfr" ^ -DMPFR_LIBRARIES="%INSTALL_DIR%\mpfr\mpfr.lib" ^ - -DCGAL_BUILD_SHARED_LIBS=Off ^ - -DBUILD_SHARED_LIBS=Off ^ + -DBUILD_SHARED_LIBS=On ^ -DBOOST_LIBRARYDIR="%DEPS_DIR%\boost_%BOOST_VER%\stage\vs%VS_VER%-%VS_PLATFORM%\lib" IF NOT %ERRORLEVEL%==0 GOTO :Error call :BuildSolution "%DEPENDENCY_DIR%\%BUILD_DIR%\CGAL.sln" %BUILD_CFG% diff --git a/win/patches/V7_3_0.patch b/win/patches/V7_3_0.patch index efc9154b75..637c8c5de7 100644 --- a/win/patches/V7_3_0.patch +++ b/win/patches/V7_3_0.patch @@ -27,7 +27,7 @@ index 09da18d38..a07b9cf74 100644 +# set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNo_Exception") +# set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNo_Exception") + -+if (MSVC) ++if (OCCT_USE_STATIC_RUNTIME AND MSVC) + 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) diff --git a/win/patches/cgal_no_zlib.patch b/win/patches/cgal_no_zlib.patch new file mode 100644 index 0000000000..1b24a17e19 --- /dev/null +++ b/win/patches/cgal_no_zlib.patch @@ -0,0 +1,13 @@ +diff --git a/Installation/cmake/modules/CGAL_SetupCGAL_ImageIODependencies.cmake b/Installation/cmake/modules/CGAL_SetupCGAL_ImageIODependencies.cmake +index 8ac856d037..742fa8df69 100644 +--- a/Installation/cmake/modules/CGAL_SetupCGAL_ImageIODependencies.cmake ++++ b/Installation/cmake/modules/CGAL_SetupCGAL_ImageIODependencies.cmake +@@ -23,7 +23,7 @@ set(CGAL_SetupCGAL_ImageIODependencies_included TRUE) + # Used Modules + # ^^^^^^^^^^^^ + # - :module:`FindZLIB` +-find_package( ZLIB ) ++# find_package( ZLIB ) + + define_property(TARGET PROPERTY CGAL_TARGET_USES_ZLIB + BRIEF_DOCS "Tells if the target uses ZLIB as a dependency" diff --git a/win/patches/mpfr.patch b/win/patches/mpfr.patch index 0ca9f4f15b..32a5520021 100644 --- a/win/patches/mpfr.patch +++ b/win/patches/mpfr.patch @@ -1,5 +1,5 @@ ---- afn -+++ bfn -@@ -26 +26 @@ +--- a/build.vc15/lib_mpfr/lib_mpfr.vcxproj ++++ a/build.vc15/lib_mpfr/lib_mpfr.vcxproj +@@ -25 +25 @@ - 10.0.17134.0 + sdk diff --git a/win/patches/mpfr_runtime.patch b/win/patches/mpfr_runtime.patch new file mode 100644 index 0000000000..1f3df90d82 --- /dev/null +++ b/win/patches/mpfr_runtime.patch @@ -0,0 +1,8 @@ +--- a/build.vc15/lib_mpfr/lib_mpfr.vcxproj ++++ a/build.vc15/lib_mpfr/lib_mpfr.vcxproj +@@ -148 +148 @@ +- MultiThreaded ++ MultiThreadedDLL +@@ -179 +179 @@ +- MultiThreaded ++ MultiThreadedDLL diff --git a/win/patches/mpir.patch b/win/patches/mpir.patch new file mode 100644 index 0000000000..0bbb105617 --- /dev/null +++ b/win/patches/mpir.patch @@ -0,0 +1,7 @@ +diff --git a/msvc/vs17/fn/fn.vcxproj b/msvc/vs17/fn/fn.vcxproj +index d8d87f8f..e543adc8 100644 +--- a/msvc/vs17/fn/fn.vcxproj ++++ b/msvc/vs17/fn/fn.vcxproj +@@ -25 +25 @@ +- 10.0.17134.0 ++ sdk diff --git a/win/patches/mpir_runtime.patch b/win/patches/mpir_runtime.patch new file mode 100644 index 0000000000..abb5f0bc86 --- /dev/null +++ b/win/patches/mpir_runtime.patch @@ -0,0 +1,13 @@ +diff --git a/msvc/mpir_release_lib.props b/msvc/mpir_release_lib.props +index d46f9649..832c6937 100644 +--- a/msvc/mpir_release_lib.props ++++ b/msvc/mpir_release_lib.props +@@ -9,7 +9,7 @@ + + + $(IntDir)du\m\my\%(RelativeDir) +- MultiThreaded ++ MultiThreadedDLL + $(TargetDir)$(TargetName).pdb + + From 4fa283fb3c73edf2ada0232e8033dc5108be09f6 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 15 May 2019 13:57:50 +0200 Subject: [PATCH 147/235] Write voxelization logic in geom server --- cmake/CMakeLists.txt | 3 +- src/ifcgeomserver/IfcGeomServer.cpp | 48 ++++++++++++++++++++++++----- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 8dbaed09d6..7ced7c3279 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -165,7 +165,7 @@ 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) @@ -183,6 +183,7 @@ 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}) diff --git a/src/ifcgeomserver/IfcGeomServer.cpp b/src/ifcgeomserver/IfcGeomServer.cpp index a89ff64998..2eb4d9d335 100644 --- a/src/ifcgeomserver/IfcGeomServer.cpp +++ b/src/ifcgeomserver/IfcGeomServer.cpp @@ -59,6 +59,12 @@ #include +#ifdef USE_VOXELS +#include +#include +#include +#endif + template union data_field { char buffer[sizeof(T)]; @@ -470,9 +476,9 @@ public: 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); @@ -483,7 +489,6 @@ public: boost::optional largest_face_dir; { - TopoDS_Compound compound = TopoDS::Compound(((IfcGeom::OpenCascadeShape*) elem_->geometry().as_compound(true))->shape()); TopExp_Explorer exp(compound, TopAbs_FACE); for (; exp.More(); exp.Next()) { GProp_GProps prop; @@ -503,19 +508,48 @@ 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; + auto surface = storage_for(bounds); + threaded_processor proc(surface, silent); + surface = (regular_voxel_storage*) proc.voxels(); + double vsize = surface->voxel_size(); + delete surface; + auto surface_count = surface->count(); + traversal_voxel_filler_inverse filler; + auto volume = filler(surface); + auto volume_count = volume->count(); + delete volume; + double total_volume = (volume_count + surface_count / 2) * (vsize * vsize * vsize); + put_json(TOTAL_SHAPE_VOLUME, total_volume); + } +#endif + if (largest_face_dir) { put_json(LARGEST_FACE_DIRECTION, *largest_face_dir); put_json(LARGEST_FACE_AREA, largest_face_area); From d45d84317329750ff5a6b9169cd99291bc5fa5dd Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 15 May 2019 14:27:31 +0200 Subject: [PATCH 148/235] Fix CMake error --- cmake/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 7ced7c3279..71e2057b2b 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -172,7 +172,9 @@ if(USE_MMAP OR USE_VOXELS) else() set(BOOST_COMPONENTS ${BOOST_COMPONENTS} iostreams) endif() - add_definitions(-DUSE_MMAP) + if(USE_MMAP) + add_definitions(-DUSE_MMAP) + endif() endif() if (IFCXML_SUPPORT) From bbf271a10ea83b5c715c40e8193345f4aa22fe83 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 15 May 2019 17:07:16 +0200 Subject: [PATCH 149/235] Fix volume calculation with voxels in geom server --- src/ifcgeomserver/IfcGeomServer.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ifcgeomserver/IfcGeomServer.cpp b/src/ifcgeomserver/IfcGeomServer.cpp index 2eb4d9d335..1acef29553 100644 --- a/src/ifcgeomserver/IfcGeomServer.cpp +++ b/src/ifcgeomserver/IfcGeomServer.cpp @@ -535,15 +535,17 @@ public: bounds[1].get(i) = bbox_xyz[i + 3]; } progress_writer silent; - auto surface = storage_for(bounds); - threaded_processor proc(surface, silent); + auto surface = storage_for(bounds, 256U); + processor proc(surface, silent); + std::vector > geometries = { {1, compound} }; + proc.process(geometries.begin(), geometries.end(), SURFACE(), output(MERGED())); surface = (regular_voxel_storage*) proc.voxels(); double vsize = surface->voxel_size(); - delete surface; auto surface_count = surface->count(); traversal_voxel_filler_inverse filler; auto volume = filler(surface); auto volume_count = volume->count(); + delete surface; delete volume; double total_volume = (volume_count + surface_count / 2) * (vsize * vsize * vsize); put_json(TOTAL_SHAPE_VOLUME, total_volume); From 0cb2c812274d7501a5df4552f3931313280f5253 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 15 May 2019 17:13:29 +0200 Subject: [PATCH 150/235] Rough draft of a client application for the C++ IfcGeomServer binary --- .../ifcopenshell/geom/client.py | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 src/ifcopenshell-python/ifcopenshell/geom/client.py diff --git a/src/ifcopenshell-python/ifcopenshell/geom/client.py b/src/ifcopenshell-python/ifcopenshell/geom/client.py new file mode 100644 index 0000000000..d4eca22783 --- /dev/null +++ b/src/ifcopenshell-python/ifcopenshell/geom/client.py @@ -0,0 +1,103 @@ +############################################################################### +# # +# 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 . # +# # +############################################################################### + +""" +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 + +message = namedtuple("message", ("header", "contents")) + +def process(geomserver_exe, ifc_filename): + + proc = subprocess.Popen([geomserver_exe], stdout=subprocess.PIPE, stdin=subprocess.PIPE) + + def cast(data, dtype, n=None): + arr = numpy.frombuffer(data, dtype=dtype) + if n is None: return arr[0] + else: return arr + + def read(dtype, n=None): + data = proc.stdout.read(dtype().nbytes * (n or 1)) + return cast(data, dtype, n) + + def read_message(header_assertion=None): + header, size = read(numpy.int32, 2) + assert header_assertion is None or header_assertion == header + contents = b"" + if size > 0: + contents = proc.stdout.read(size) + 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, [numpy.int32((1 << 4)), 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) + print(read_message(message_headers.ENTITY).contents) + 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:]: + process(exe, fn) From 92f7d2683569c4497703d71560cb9c9f3f0d596a Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sat, 3 Aug 2019 15:09:50 +0200 Subject: [PATCH 151/235] Work on Python wrapper --- src/ifcgeom/kernels/opencascade/IfcGeomTree.h | 1 + src/ifcgeom/schema_agnostic/IfcGeomElement.h | 10 +++++----- .../schema_agnostic/IfcGeomRepresentation.h | 4 ++-- src/ifcwrap/IfcGeomWrapper.i | 19 ++++++++++--------- src/ifcwrap/IfcPython.i | 2 +- 5 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomTree.h b/src/ifcgeom/kernels/opencascade/IfcGeomTree.h index dbc723ac29..c5c657a370 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomTree.h +++ b/src/ifcgeom/kernels/opencascade/IfcGeomTree.h @@ -24,6 +24,7 @@ #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 #include diff --git a/src/ifcgeom/schema_agnostic/IfcGeomElement.h b/src/ifcgeom/schema_agnostic/IfcGeomElement.h index f01a397563..0cefed19de 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomElement.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomElement.h @@ -38,7 +38,7 @@ namespace IfcGeom { private: std::vector

_data; public: - Matrix(const ElementSettings& settings, const ConversionResultPlacement* 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 @@ -66,12 +66,12 @@ namespace IfcGeom { ConversionResultPlacement* trsf_; Matrix

matrix_; public: - Transformation(const ElementSettings& settings, const ConversionResultPlacement* trsf) + Transformation(const ElementSettings& settings, const IfcGeom::ConversionResultPlacement* trsf) : settings_(settings) , trsf_(trsf ? trsf->clone() : nullptr) , matrix_(settings, trsf) {} - const ConversionResultPlacement* data() const { return trsf_; } + const IfcGeom::ConversionResultPlacement* data() const { return trsf_; } const Matrix

& matrix() const { return matrix_; } Transformation inverted() const { @@ -133,7 +133,7 @@ namespace IfcGeom { void SetParents(std::vector*> 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 ConversionResultPlacement* 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) { @@ -170,7 +170,7 @@ namespace IfcGeom { const boost::shared_ptr& geometry_pointer() const { return _geometry; } const Representation::BRep& geometry() const { return *_geometry; } NativeElement(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, - const std::string& context, const ConversionResultPlacement* trsf, const boost::shared_ptr& geometry, + const std::string& context, const IfcGeom::ConversionResultPlacement* trsf, const boost::shared_ptr& geometry, IfcUtil::IfcBaseEntity* product) : Element(geometry->settings() ,id, parent_id, name, type, guid, context, trsf, product) , _geometry(geometry) diff --git a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.h b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.h index e04f0f9d48..a2886803fc 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.h @@ -60,11 +60,11 @@ namespace IfcGeom { IfcGeom::ConversionResults::const_iterator end() const { return shapes_.end(); } const IfcGeom::ConversionResults& shapes() const { return shapes_; } const std::string& id() const { return id_; } - ConversionResultShape* as_compound(bool force_meters = false) const; + 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 ConversionResultPlacement* ax, double& along_x, double& along_y, double& along_z) 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 { diff --git a/src/ifcwrap/IfcGeomWrapper.i b/src/ifcwrap/IfcGeomWrapper.i index fe6687936d..5af6ceac67 100644 --- a/src/ifcwrap/IfcGeomWrapper.i +++ b/src/ifcwrap/IfcGeomWrapper.i @@ -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 template static boost::variant*, 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::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.)); diff --git a/src/ifcwrap/IfcPython.i b/src/ifcwrap/IfcPython.i index 7b54ac2e94..84c0320d20 100644 --- a/src/ifcwrap/IfcPython.i +++ b/src/ifcwrap/IfcPython.i @@ -72,7 +72,7 @@ %module ifcopenshell_wrapper %{ #include "../ifcgeom/schema_agnostic/IfcGeomIterator.h" #include "../ifcgeom/schema_agnostic/Serialization.h" - #include "../ifcgeom/IfcGeomTree.h" + #include "../ifcgeom/kernels/opencascade/IfcGeomTree.h" #include "../ifcparse/Ifc2x3.h" #include "../ifcparse/Ifc4.h" From f6aa7c893030edad90c1a41b9b1e1dba518a7ff9 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sat, 3 Aug 2019 15:43:14 +0200 Subject: [PATCH 152/235] Additional merge issues --- src/ifcgeom/kernels/opencascade/IfcGeom.h | 49 ----------------------- src/serializers/GltfSerializer.h | 2 +- 2 files changed, 1 insertion(+), 50 deletions(-) diff --git a/src/ifcgeom/kernels/opencascade/IfcGeom.h b/src/ifcgeom/kernels/opencascade/IfcGeom.h index 594170865d..596ddc6fa2 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeom.h +++ b/src/ifcgeom/kernels/opencascade/IfcGeom.h @@ -328,55 +328,6 @@ public: std::pair initializeUnits(IfcSchema::IfcUnitAssignment*); - template std::pair _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(0,0); - } - - template std::pair get_surface_style(const IfcSchema::IfcRepresentationItem* representation_item) { - // For certain representation items, most notably boolean operands, - // a style definition might reside on one of its operands. - representation_item = find_item_carrying_style(representation_item); - - if (representation_item->as()) { - return _get_surface_style(representation_item->as()); - } - 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(*styled_items->begin()); - } - return std::make_pair(0,0); - } - void purge_cache() { // Rather hack-ish, but a stopgap solution to keep memory under control // for large files. SurfaceStyles need to be kept at all costs, as they diff --git a/src/serializers/GltfSerializer.h b/src/serializers/GltfSerializer.h index 428aa074c8..dc5312d9f1 100644 --- a/src/serializers/GltfSerializer.h +++ b/src/serializers/GltfSerializer.h @@ -43,7 +43,7 @@ public: bool ready(); void writeHeader(); void write(const IfcGeom::TriangulationElement* o); - void write(const IfcGeom::BRepElement* /*o*/) {} + void write(const IfcGeom::NativeElement* /*o*/) {} void finalize(); bool isTesselated() const { return true; } void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {} From c8def0474ebb2a3291d0e3bdcb14d48ebd9c695c Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sat, 3 Aug 2019 16:11:02 +0200 Subject: [PATCH 153/235] Update examples --- src/examples/IfcAdvancedHouse.cpp | 11 +++-------- src/examples/IfcOpenHouse.cpp | 13 +++++-------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/examples/IfcAdvancedHouse.cpp b/src/examples/IfcAdvancedHouse.cpp index 3de0d52e34..a4d493babd 100644 --- a/src/examples/IfcAdvancedHouse.cpp +++ b/src/examples/IfcAdvancedHouse.cpp @@ -38,17 +38,12 @@ #include -#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" #if USE_VLD diff --git a/src/examples/IfcOpenHouse.cpp b/src/examples/IfcOpenHouse.cpp index b3e0f7f10b..31d46468fd 100644 --- a/src/examples/IfcOpenHouse.cpp +++ b/src/examples/IfcOpenHouse.cpp @@ -33,17 +33,14 @@ #include #include -#ifdef USE_IFC4 -#include "../ifcparse/Ifc4.h" -#define IfcSchema Ifc4 -#else -#include "../ifcparse/Ifc2x3.h" -#define IfcSchema Ifc2x3 -#endif +#include +#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" #if USE_VLD From 467ebb68a3e0f04ddc087890418a59e0f3f36225 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 4 Aug 2019 09:36:31 +0200 Subject: [PATCH 154/235] First step at reorganizing --- cmake/CMakeLists.txt | 27 ++-- src/ifcgeom/abstract_mapping.h | 15 ++ src/ifcgeom/kernels/opencascade/IfcGeom.h | 26 ++-- .../kernels/opencascade/IfcGeomCurves.cpp | 2 +- .../kernels/opencascade/IfcGeomFaces.cpp | 2 +- .../kernels/opencascade/IfcGeomFunctions.cpp | 8 +- .../kernels/opencascade/IfcGeomHelpers.cpp | 2 +- .../opencascade/IfcGeomSerialisation.cpp | 4 +- .../kernels/opencascade/IfcGeomShapes.cpp | 2 +- .../kernels/opencascade/IfcGeomWires.cpp | 2 +- .../kernels/opencascade/IfcRegister.cpp | 2 +- src/ifcgeom/schema/bind_convert_decl.i | 7 + src/ifcgeom/schema/bind_convert_impl.i | 15 ++ src/ifcgeom/schema/mapping.cpp | 30 ++++ src/ifcgeom/schema/mapping.h | 22 +++ src/ifcgeom/schema/mapping.i | 130 ++++++++++++++++++ src/ifcgeom/taxonomy.h | 96 +++++++++++++ src/ifcparse/macros.h | 6 +- .../schema_dependent/XmlSerializer.cpp | 18 +-- .../schema_dependent/XmlSerializer.h | 4 +- 20 files changed, 363 insertions(+), 57 deletions(-) create mode 100644 src/ifcgeom/abstract_mapping.h create mode 100644 src/ifcgeom/schema/bind_convert_decl.i create mode 100644 src/ifcgeom/schema/bind_convert_impl.i create mode 100644 src/ifcgeom/schema/mapping.cpp create mode 100644 src/ifcgeom/schema/mapping.h create mode 100644 src/ifcgeom/schema/mapping.i create mode 100644 src/ifcgeom/taxonomy.h diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 0722a38b04..a65f8054fe 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -631,9 +631,10 @@ TARGET_LINK_LIBRARIES(IfcParse ${Boost_LIBRARIES} ${BCRYPT_LIBRARIES} ${LIBXML2_ if (BUILD_IFCGEOM) 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) +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} STATIC ${IFCGEOM_FILES}) @@ -644,30 +645,20 @@ endforeach() 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}) +file(GLOB IFCGEOM_I_FILES ../src/ifcgeom/schema/*.i) +file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/schema/*.h) +file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/schema/*.cpp) +set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES} ${IFCGEOM_I_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) +file(GLOB SCHEMA_AGNOSTIC_H_FILES ../src/ifcgeom/*.h) +file(GLOB SCHEMA_AGNOSTIC_CPP_FILES ../src/ifcgeom/*.cpp) set(SCHEMA_AGNOSTIC_FILES ${SCHEMA_AGNOSTIC_H_FILES} ${SCHEMA_AGNOSTIC_CPP_FILES}) add_library(IfcGeom ${SCHEMA_AGNOSTIC_FILES}) diff --git a/src/ifcgeom/abstract_mapping.h b/src/ifcgeom/abstract_mapping.h new file mode 100644 index 0000000000..1a89e3fa03 --- /dev/null +++ b/src/ifcgeom/abstract_mapping.h @@ -0,0 +1,15 @@ +#include "../ifcparse/IfcBaseClass.h" +#include "../ifcgeom/taxonomy.h" + +namespace ifcopenshell { + +namespace geometry { + + class abstract_mapping { + public: + virtual ifcopenshell::geometry::taxonomy::item* map(const IfcUtil::IfcBaseClass*) = 0; + }; + +} + +} \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/IfcGeom.h b/src/ifcgeom/kernels/opencascade/IfcGeom.h index 596ddc6fa2..d0575a5de2 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeom.h +++ b/src/ifcgeom/kernels/opencascade/IfcGeom.h @@ -107,13 +107,13 @@ namespace IfcGeom { : geometry_exception("Too many faces for operation") {} }; -class IFC_GEOM_API MAKE_TYPE_NAME(Cache) { +class IFC_GEOM_API POSTFIX_SCHEMA(Cache) { public: #include "IfcRegisterCreateCache.h" std::map Shape; }; -class IFC_GEOM_API MAKE_TYPE_NAME(Kernel) : public IfcGeom::MAKE_TYPE_NAME(AbstractKernel) { +class IFC_GEOM_API POSTFIX_SCHEMA(Kernel) : public IfcGeom::POSTFIX_SCHEMA(AbstractKernel) { private: /* @@ -125,7 +125,7 @@ private: */ class faceset_helper { private: - MAKE_TYPE_NAME(Kernel)* kernel_; + POSTFIX_SCHEMA(Kernel)* kernel_; std::set duplicates_; std::map vertex_mapping_; std::map, TopoDS_Edge> edges_; @@ -154,7 +154,7 @@ private: } } public: - faceset_helper(MAKE_TYPE_NAME(Kernel)* kernel, const IfcSchema::IfcConnectedFaceSet* l); + faceset_helper(POSTFIX_SCHEMA(Kernel)* kernel, const IfcSchema::IfcConnectedFaceSet* l); ~faceset_helper(); @@ -220,24 +220,24 @@ private: }; #ifndef NO_CACHE - MAKE_TYPE_NAME(Cache) cache; + POSTFIX_SCHEMA(Cache) cache; #endif faceset_helper* faceset_helper_; public: - MAKE_TYPE_NAME(Kernel)() - : IfcGeom::MAKE_TYPE_NAME(AbstractKernel)("opencascade") + POSTFIX_SCHEMA(Kernel)() + : IfcGeom::POSTFIX_SCHEMA(AbstractKernel)("opencascade") , faceset_helper_(nullptr) {} - MAKE_TYPE_NAME(Kernel)(const MAKE_TYPE_NAME(Kernel)& other) - : IfcGeom::MAKE_TYPE_NAME(AbstractKernel)("opencascade") + POSTFIX_SCHEMA(Kernel)(const POSTFIX_SCHEMA(Kernel)& other) + : IfcGeom::POSTFIX_SCHEMA(AbstractKernel)("opencascade") { *this = other; } - MAKE_TYPE_NAME(Kernel)& operator=(const MAKE_TYPE_NAME(Kernel)& other) { + POSTFIX_SCHEMA(Kernel)& operator=(const POSTFIX_SCHEMA(Kernel)& other) { setValue(GV_DEFLECTION_TOLERANCE, other.getValue(GV_DEFLECTION_TOLERANCE)); setValue(GV_MAX_FACES_TO_ORIENT, other.getValue(GV_MAX_FACES_TO_ORIENT)); setValue(GV_LENGTH_UNIT, other.getValue(GV_LENGTH_UNIT)); @@ -333,7 +333,7 @@ public: // 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)(); + cache = POSTFIX_SCHEMA(Cache)(); #endif } @@ -368,8 +368,8 @@ public: }; -IfcUtil::IfcBaseClass* MAKE_TYPE_NAME(tesselate_)(const TopoDS_Shape& shape, double deflection); -IfcUtil::IfcBaseClass* MAKE_TYPE_NAME(serialise_)(const TopoDS_Shape& shape, bool advanced); +IfcUtil::IfcBaseClass* POSTFIX_SCHEMA(tesselate_)(const TopoDS_Shape& shape, double deflection); +IfcUtil::IfcBaseClass* POSTFIX_SCHEMA(serialise_)(const TopoDS_Shape& shape, bool advanced); } #endif diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomCurves.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomCurves.cpp index 8d79b14a60..728fa4eabc 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomCurves.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomCurves.cpp @@ -83,7 +83,7 @@ #include #endif -#define Kernel MAKE_TYPE_NAME(Kernel) +#define Kernel POSTFIX_SCHEMA(Kernel) bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircle* l, Handle(Geom_Curve)& curve) { const double r = l->Radius() * getValue(GV_LENGTH_UNIT); diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomFaces.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomFaces.cpp index b4387d1b72..58cd6dda47 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomFaces.cpp @@ -106,7 +106,7 @@ #include #endif -#define Kernel MAKE_TYPE_NAME(Kernel) +#define Kernel POSTFIX_SCHEMA(Kernel) namespace { /* Returns whether wire conforms to a polyhedron, i.e. only edges with linear curves*/ diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp index 6d06c33fa9..afbc7b2588 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp @@ -167,9 +167,9 @@ #endif namespace { - struct MAKE_TYPE_NAME(factory_t) { + struct POSTFIX_SCHEMA(factory_t) { IfcGeom::Kernel* operator()(IfcParse::IfcFile* file) const { - IfcGeom::MAKE_TYPE_NAME(Kernel)* k = new IfcGeom::MAKE_TYPE_NAME(Kernel); + IfcGeom::POSTFIX_SCHEMA(Kernel)* k = new IfcGeom::POSTFIX_SCHEMA(Kernel); if (file) { double unit_magnitude = 1.; @@ -222,11 +222,11 @@ namespace { void MAKE_INIT_FN(KernelImplementation_opencascade_)(IfcGeom::impl::KernelFactoryImplementation* mapping) { static const std::string schema_name = STRINGIFY(IfcSchema); - MAKE_TYPE_NAME(factory_t) factory; + POSTFIX_SCHEMA(factory_t) factory; mapping->bind(schema_name, "opencascade", factory); } -#define Kernel MAKE_TYPE_NAME(Kernel) +#define Kernel POSTFIX_SCHEMA(Kernel) namespace { void copy_operand(const TopTools_ListOfShape& l, TopTools_ListOfShape& r) { diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomHelpers.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomHelpers.cpp index 2710933042..4be6bae286 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomHelpers.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomHelpers.cpp @@ -77,7 +77,7 @@ #include "../../../ifcgeom/kernels/opencascade/IfcGeom.h" -#define Kernel MAKE_TYPE_NAME(Kernel) +#define Kernel POSTFIX_SCHEMA(Kernel) namespace { diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomSerialisation.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomSerialisation.cpp index 181b4b3fc8..def77c5064 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomSerialisation.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomSerialisation.cpp @@ -493,7 +493,7 @@ int convert_to_ifc(const TopoDS_Shape& s, U*& item, bool advanced) { return faces->size(); } -IfcUtil::IfcBaseClass* IfcGeom::MAKE_TYPE_NAME(serialise_)(const TopoDS_Shape& shape, bool advanced) { +IfcUtil::IfcBaseClass* IfcGeom::POSTFIX_SCHEMA(serialise_)(const TopoDS_Shape& shape, bool advanced) { #ifndef USE_IFC4 advanced = false; #endif @@ -604,7 +604,7 @@ IfcUtil::IfcBaseClass* IfcGeom::MAKE_TYPE_NAME(serialise_)(const TopoDS_Shape& s return new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps); } -IfcUtil::IfcBaseClass* IfcGeom::MAKE_TYPE_NAME(tesselate_)(const TopoDS_Shape& shape, double deflection) { +IfcUtil::IfcBaseClass* IfcGeom::POSTFIX_SCHEMA(tesselate_)(const TopoDS_Shape& shape, double deflection) { BRepMesh_IncrementalMesh(shape, deflection); IfcSchema::IfcFace::list::ptr faces(new IfcSchema::IfcFace::list); diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp index 60d2ac89ae..5001639a6d 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp @@ -105,7 +105,7 @@ #include -#define Kernel MAKE_TYPE_NAME(Kernel) +#define Kernel POSTFIX_SCHEMA(Kernel) bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolid* l, TopoDS_Shape& shape) { const double height = l->Depth() * getValue(GV_LENGTH_UNIT); diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomWires.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomWires.cpp index a2a56ce4c5..383691072c 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomWires.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomWires.cpp @@ -97,7 +97,7 @@ #include "../../../ifcgeom/kernels/opencascade/IfcGeom.h" -#define Kernel MAKE_TYPE_NAME(Kernel) +#define Kernel POSTFIX_SCHEMA(Kernel) namespace { // Returns the other vertex of an edge diff --git a/src/ifcgeom/kernels/opencascade/IfcRegister.cpp b/src/ifcgeom/kernels/opencascade/IfcRegister.cpp index b0574c2008..35b6baedcf 100644 --- a/src/ifcgeom/kernels/opencascade/IfcRegister.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcRegister.cpp @@ -20,7 +20,7 @@ #include "IfcGeom.h" #include "IfcGeomShapeType.h" -#define Kernel MAKE_TYPE_NAME(Kernel) +#define Kernel POSTFIX_SCHEMA(Kernel) using namespace IfcUtil; diff --git a/src/ifcgeom/schema/bind_convert_decl.i b/src/ifcgeom/schema/bind_convert_decl.i new file mode 100644 index 0000000000..3f2fc443d2 --- /dev/null +++ b/src/ifcgeom/schema/bind_convert_decl.i @@ -0,0 +1,7 @@ +#ifdef BIND +#undef BIND +#endif + +#define BIND(T) ifcopenshell::geometry::taxonomy::item* convert(const IfcSchema::T*); + +#include "mapping.i" diff --git a/src/ifcgeom/schema/bind_convert_impl.i b/src/ifcgeom/schema/bind_convert_impl.i new file mode 100644 index 0000000000..abc10ab4f0 --- /dev/null +++ b/src/ifcgeom/schema/bind_convert_impl.i @@ -0,0 +1,15 @@ +#ifdef BIND +#undef BIND +#endif + +#define BIND(T) \ + if (l->declaration().is(IfcSchema::T::Class())) { \ + try { \ + return map((IfcSchema::T*)l); \ + } catch (const std::exception& e) { \ + Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l); \ + } \ + return false; \ + } + +#include "mapping.i" diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp new file mode 100644 index 0000000000..f87fa8ef86 --- /dev/null +++ b/src/ifcgeom/schema/mapping.cpp @@ -0,0 +1,30 @@ +/******************************************************************************** +* * +* This file is part of IfcOpenShell. * +* * +* IfcOpenShell is free software: you can redistribute it and/or modify * +* it under the terms of the Lesser GNU General Public License as published by * +* the Free Software Foundation, either version 3.0 of the License, or * +* (at your option) any later version. * +* * +* IfcOpenShell is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* Lesser GNU General Public License for more details. * +* * +* You should have received a copy of the Lesser GNU General Public License * +* along with this program. If not, see . * +* * +********************************************************************************/ + +#include "mapping.h" + +#include "../../ifcparse/IfcLogger.h" + +using namespace IfcUtil; + +ifcopenshell::geometry::taxonomy::item* ifcopenshell::geometry::POSTFIX_SCHEMA(mapping)::map(const IfcBaseClass* l) { +#include "bind_convert_impl.i" + Logger::Message(Logger::LOG_ERROR, "No operation defined for:", l); + return nullptr; +} diff --git a/src/ifcgeom/schema/mapping.h b/src/ifcgeom/schema/mapping.h new file mode 100644 index 0000000000..99d97be600 --- /dev/null +++ b/src/ifcgeom/schema/mapping.h @@ -0,0 +1,22 @@ +#include "../abstract_mapping.h" +#include "../../ifcparse/macros.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 ifcopenshell { + +namespace geometry { + + class POSTFIX_SCHEMA(mapping) : public abstract_mapping { + virtual ifcopenshell::geometry::taxonomy::item* map(const IfcUtil::IfcBaseClass*); +#include "bind_convert_decl.i" + }; + +} + +} \ No newline at end of file diff --git a/src/ifcgeom/schema/mapping.i b/src/ifcgeom/schema/mapping.i new file mode 100644 index 0000000000..1dc894d273 --- /dev/null +++ b/src/ifcgeom/schema/mapping.i @@ -0,0 +1,130 @@ +/******************************************************************************** +* * +* This file is part of IfcOpenShell. * +* * +* IfcOpenShell is free software: you can redistribute it and/or modify * +* it under the terms of the Lesser GNU General Public License as published by * +* the Free Software Foundation, either version 3.0 of the License, or * +* (at your option) any later version. * +* * +* IfcOpenShell is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* Lesser GNU General Public License for more details. * +* * +* You should have received a copy of the Lesser GNU General Public License * +* along with this program. If not, see . * +* * +********************************************************************************/ + +/******************************************************************************** + * * + * This file 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 * + * * + ********************************************************************************/ + +BIND(IfcShellBasedSurfaceModel); +BIND(IfcFaceBasedSurfaceModel); +BIND(IfcRepresentation); +BIND(IfcMappedItem); +// IfcFacetedBrep included +// IfcAdvancedBrep included +// IfcFacetedBrepWithVoids included +// IfcAdvancedBrepWithVoids included +BIND(IfcManifoldSolidBrep); +BIND(IfcGeometricSet); + +#ifdef SCHEMA_HAS_IfcCylindricalSurface +BIND(IfcCylindricalSurface); +#endif +#ifdef SCHEMA_HAS_IfcAdvancedBrep +BIND(IfcAdvancedBrep); +#endif +// FIXME: Surfaces should have a shape type of their own +#ifdef SCHEMA_HAS_IfcBSplineSurfaceWithKnots +BIND(IfcBSplineSurfaceWithKnots); +#endif +#ifdef SCHEMA_HAS_IfcTriangulatedFaceSet +BIND(IfcTriangulatedFaceSet); +#endif +#ifdef SCHEMA_HAS_IfcExtrudedAreaSolidTapered +BIND(IfcExtrudedAreaSolidTapered); +#endif +BIND(IfcExtrudedAreaSolid); +BIND(IfcRevolvedAreaSolid); +BIND(IfcConnectedFaceSet); +BIND(IfcBooleanResult); +BIND(IfcPolygonalBoundedHalfSpace); +BIND(IfcHalfSpaceSolid); +BIND(IfcSurfaceOfLinearExtrusion); +BIND(IfcSurfaceOfRevolution); +BIND(IfcBlock); +BIND(IfcRectangularPyramid); +BIND(IfcRightCircularCylinder); +BIND(IfcRightCircularCone); +BIND(IfcSphere); +BIND(IfcCsgSolid); +BIND(IfcCurveBoundedPlane); +BIND(IfcRectangularTrimmedSurface); +BIND(IfcSurfaceCurveSweptAreaSolid); +BIND(IfcSweptDiskSolid); + +BIND(IfcArbitraryProfileDefWithVoids); +BIND(IfcArbitraryClosedProfileDef); +BIND(IfcRoundedRectangleProfileDef); +BIND(IfcRectangleHollowProfileDef); +BIND(IfcRectangleProfileDef); +BIND(IfcTrapeziumProfileDef) +BIND(IfcCShapeProfileDef); +// IfcAsymmetricIShapeProfileDef included +BIND(IfcIShapeProfileDef); +BIND(IfcLShapeProfileDef); +BIND(IfcTShapeProfileDef); +BIND(IfcUShapeProfileDef); +BIND(IfcZShapeProfileDef); +BIND(IfcCircleHollowProfileDef); +BIND(IfcCircleProfileDef); +BIND(IfcEllipseProfileDef); +BIND(IfcCenterLineProfileDef); +BIND(IfcCompositeProfileDef); +BIND(IfcDerivedProfileDef); +// IfcFaceSurface included +// IfcAdvancedFace included in case of IFC4 +BIND(IfcFace); + +BIND(IfcEdgeCurve); +BIND(IfcSubedge); +BIND(IfcOrientedEdge); +BIND(IfcEdge); +BIND(IfcEdgeLoop); +BIND(IfcPolyline); +BIND(IfcPolyLoop); +BIND(IfcCompositeCurve); +BIND(IfcTrimmedCurve); +BIND(IfcArbitraryOpenProfileDef); +#ifdef SCHEMA_HAS_IfcIndexedPolyCurve +BIND(IfcIndexedPolyCurve) +#endif + +BIND(IfcCircle); +BIND(IfcEllipse); +BIND(IfcLine); +#ifdef SCHEMA_HAS_IfcBSplineCurveWithKnots +// IfcRationalBSplineCurveWithKnots included +BIND(IfcBSplineCurveWithKnots); +#endif + +BIND(IfcCartesianPoint); +BIND(IfcDirection); +BIND(IfcAxis2Placement2D); +BIND(IfcAxis2Placement3D); +BIND(IfcAxis1Placement); +BIND(IfcCartesianTransformationOperator2DnonUniform); +BIND(IfcCartesianTransformationOperator3DnonUniform); +BIND(IfcCartesianTransformationOperator2D); +BIND(IfcCartesianTransformationOperator3D); +BIND(IfcObjectPlacement); +BIND(IfcVector); +BIND(IfcPlane); \ No newline at end of file diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h new file mode 100644 index 0000000000..10eb3b8704 --- /dev/null +++ b/src/ifcgeom/taxonomy.h @@ -0,0 +1,96 @@ +#include + +namespace ifcopenshell { + +namespace geometry { + +namespace taxonomy { + +struct item { + int instance_id; + virtual item* clone() const = 0; +}; + +struct matrix4 : public item { + enum tag_t { + IDENTITY, AFFINE_WO_SCALE, AFFINE_W_UNIFORM_SCALE, AFFINE_W_NONUNIFORM_SCALE, OTHER + }; + tag_t tag; + std::array components; + matrix4() : components({1. ,0., 0., 0., 0., 1., 0., 0., 0., 0., 1. ,0., 0., 0., 0., 1.}), tag(IDENTITY) {} + + virtual item* clone() const { return new matrix4(*this); } +}; + +struct geom_item : public item { + // geometry::style surface_style; + matrix4 matrix; +}; + +template +struct cartesian_base : public item { + std::array components; +}; + +struct point3 : public cartesian_base<3> { + virtual item* clone() const { return new point3(*this); } +}; + +struct direction3 : public cartesian_base<3> { + virtual item* clone() const { return new direction3(*this); } +}; + +struct line : public item { + virtual item* clone() const { return new line(*this); } +}; + +struct circle : public item { + virtual item* clone() const { return new circle(*this); } +}; + +struct ellipse : public item { + virtual item* clone() const { return new ellipse(*this); } +}; + +struct bspline : public item { + virtual item* clone() const { return new bspline(*this); } +}; + +typedef boost::variant curve; + +struct edge : public item { + boost::variant start, end; + boost::optional basis; + + virtual item* clone() const { return new edge(*this); } +}; + +struct boundary : public item { + std::vector edges; + + virtual item* clone() const { return new boundary(*this); } +}; + +struct face : public item { + boundary outer; + std::vector inner; + + virtual item* clone() const { return new face(*this); } +}; + +struct sweep : public item { + face basis; +}; + +struct extrusion : public sweep { + direction3 direction; + double depth; + + virtual item* clone() const { return new extrusion(*this); } +}; + +} + +} + +} diff --git a/src/ifcparse/macros.h b/src/ifcparse/macros.h index 8db482967b..9552139bf5 100644 --- a/src/ifcparse/macros.h +++ b/src/ifcparse/macros.h @@ -20,9 +20,9 @@ #ifndef IFCOPENSHELL_MACROS_H #define IFCOPENSHELL_MACROS_H -#define MAKE_TYPE_NAME__(a, b) a ## b -#define MAKE_TYPE_NAME_(a, b) MAKE_TYPE_NAME__(a, b) -#define MAKE_TYPE_NAME(t) MAKE_TYPE_NAME_(t, IfcSchema) +#define POSTFIX_SCHEMA__(a, b) a ## _ ## b +#define POSTFIX_SCHEMA_(a, b) POSTFIX_SCHEMA__(a, b) +#define POSTFIX_SCHEMA(t) POSTFIX_SCHEMA_(t, IfcSchema) #define STRINGIFY_(x) #x #define STRINGIFY(x) STRINGIFY_(x) diff --git a/src/serializers/schema_dependent/XmlSerializer.cpp b/src/serializers/schema_dependent/XmlSerializer.cpp index 6a3a719fc1..d47c184555 100644 --- a/src/serializers/schema_dependent/XmlSerializer.cpp +++ b/src/serializers/schema_dependent/XmlSerializer.cpp @@ -35,9 +35,9 @@ using boost::property_tree::ptree; #include "XmlSerializer.h" namespace { - struct MAKE_TYPE_NAME(factory_t) { + struct POSTFIX_SCHEMA(factory_t) { XmlSerializer* operator()(IfcParse::IfcFile* file, const std::string& xml_filename) const { - MAKE_TYPE_NAME(XmlSerializer)* s = new MAKE_TYPE_NAME(XmlSerializer)(file, xml_filename); + POSTFIX_SCHEMA(XmlSerializer)* s = new POSTFIX_SCHEMA(XmlSerializer)(file, xml_filename); s->setFile(file); return s; } @@ -46,14 +46,14 @@ namespace { void MAKE_INIT_FN(XmlSerializer)(XmlSerializerFactory::Factory* mapping) { static const std::string schema_name = STRINGIFY(IfcSchema); - MAKE_TYPE_NAME(factory_t) factory; + POSTFIX_SCHEMA(factory_t) factory; mapping->bind(schema_name, factory); } namespace { // TODO: Make this a member of XmlSerializer? -std::map MAKE_TYPE_NAME(argument_name_map); +std::map POSTFIX_SCHEMA(argument_name_map); // Format an IFC attribute and maybe returns as string. Only literal scalar // values are converted. Things like entity instances and lists are omitted. @@ -127,7 +127,7 @@ boost::optional format_attribute(const Argument* argument, IfcUtil: } else if (e->declaration().is(IfcSchema::IfcLocalPlacement::Class())) { IfcSchema::IfcLocalPlacement* placement = e->as(); gp_Trsf trsf; - IfcGeom::MAKE_TYPE_NAME(Kernel) kernel; + IfcGeom::POSTFIX_SCHEMA(Kernel) kernel; if (kernel.convert(placement, trsf)) { std::stringstream stream; @@ -163,8 +163,8 @@ ptree& format_entity_instance(IfcUtil::IfcBaseEntity* instance, ptree& child, pt std::string argument_name = instance->declaration().attribute_by_index(i)->name(); std::map::const_iterator argument_name_it; - argument_name_it = MAKE_TYPE_NAME(argument_name_map).find(argument_name); - if (argument_name_it != MAKE_TYPE_NAME(argument_name_map).end()) { + argument_name_it = POSTFIX_SCHEMA(argument_name_map).find(argument_name); + if (argument_name_it != POSTFIX_SCHEMA(argument_name_map).end()) { argument_name = argument_name_it->second; } const IfcUtil::ArgumentType argument_type = instance->data().getArgument(i)->type(); @@ -360,8 +360,8 @@ void format_quantities(IfcSchema::IfcPhysicalQuantity::list::ptr quantities, ptr } // ~unnamed namespace -void MAKE_TYPE_NAME(XmlSerializer)::finalize() { - MAKE_TYPE_NAME(argument_name_map).insert(std::make_pair("GlobalId", "id")); +void POSTFIX_SCHEMA(XmlSerializer)::finalize() { + POSTFIX_SCHEMA(argument_name_map).insert(std::make_pair("GlobalId", "id")); IfcSchema::IfcProject::list::ptr projects = file->instances_by_type(); if (projects->size() != 1) { diff --git a/src/serializers/schema_dependent/XmlSerializer.h b/src/serializers/schema_dependent/XmlSerializer.h index c6508850d1..9e55d7f1f6 100644 --- a/src/serializers/schema_dependent/XmlSerializer.h +++ b/src/serializers/schema_dependent/XmlSerializer.h @@ -26,12 +26,12 @@ #define INCLUDE_PARENT_PARENT_DIR(x) STRINGIFY(../../ifcparse/x.h) #include INCLUDE_PARENT_PARENT_DIR(IfcSchema) -class MAKE_TYPE_NAME(XmlSerializer) : public XmlSerializer { +class POSTFIX_SCHEMA(XmlSerializer) : public XmlSerializer { private: IfcParse::IfcFile* file; public: - MAKE_TYPE_NAME(XmlSerializer)(IfcParse::IfcFile* file, const std::string& xml_filename) + POSTFIX_SCHEMA(XmlSerializer)(IfcParse::IfcFile* file, const std::string& xml_filename) : XmlSerializer(0, "") { this->file = file; From dae35f59ce16b95c897d8f17c7dd8c23697c2e3c Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 4 Aug 2019 11:27:10 +0200 Subject: [PATCH 155/235] Implement mapping of IfcExtrudedAreaSolid --- src/ifcgeom/schema/bind_convert_decl.i | 2 +- src/ifcgeom/schema/mapping.cpp | 56 +++++++++++++++++++++++++- src/ifcgeom/schema/mapping.i | 3 +- src/ifcgeom/taxonomy.h | 52 ++++++++++++++++++------ 4 files changed, 97 insertions(+), 16 deletions(-) diff --git a/src/ifcgeom/schema/bind_convert_decl.i b/src/ifcgeom/schema/bind_convert_decl.i index 3f2fc443d2..b612616039 100644 --- a/src/ifcgeom/schema/bind_convert_decl.i +++ b/src/ifcgeom/schema/bind_convert_decl.i @@ -2,6 +2,6 @@ #undef BIND #endif -#define BIND(T) ifcopenshell::geometry::taxonomy::item* convert(const IfcSchema::T*); +#define BIND(T) ifcopenshell::geometry::taxonomy::item* map(const IfcSchema::T*); #include "mapping.i" diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index f87fa8ef86..64b3dc81e9 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -22,9 +22,63 @@ #include "../../ifcparse/IfcLogger.h" using namespace IfcUtil; +using namespace ifcopenshell::geometry; -ifcopenshell::geometry::taxonomy::item* ifcopenshell::geometry::POSTFIX_SCHEMA(mapping)::map(const IfcBaseClass* l) { +#define mapping POSTFIX_SCHEMA(mapping) + +taxonomy::item* mapping::map(const IfcBaseClass* l) { #include "bind_convert_impl.i" Logger::Message(Logger::LOG_ERROR, "No operation defined for:", l); return nullptr; } + +namespace { + // A RAII-based mechanism to cast the conversion results + // from map() into the right type expected by the higher + // level typology items. An exception is thrown if the + // types do not match or the result was nullptr. A copy + // will be assigned to the higher level topology member + // and the original pointer will be deleted. + + // This class is also able to uplift some topology items + // to higher level types, such as a loop to a face, which + // is why the cast operator does not return a reference. + template + class as { + private: + taxonomy::item* item_; + + public: + as(taxonomy::item* item) : item_(item) {} + operator T() const { + if (!item_) { + throw taxonomy::topology_error; + } + T* t = dynamic_cast(item_); + if (t) { + return *t; + } else { + if constexpr (std::is_same::value) { + topology::loop* loop = dynamic_cast(item_); + if (loop) { + return topology::face(loop.id, loop.matrix, *loop); + } + } + throw taxonomy::topology_error; + } + } + ~as() { + delete item; + } + }; +}; + +taxonomy::item* mapping::map(const IfcSchema::IfcExtrudedAreaSolid* inst) { + return new taxonomy::extrusion( + inst->data().id(), + as(map(inst->Position())), + as(map(inst->SweptArea())), + as(map(inst->ExtrudedDirection())), + inst->Depth() + ); +} diff --git a/src/ifcgeom/schema/mapping.i b/src/ifcgeom/schema/mapping.i index 1dc894d273..b6a863d353 100644 --- a/src/ifcgeom/schema/mapping.i +++ b/src/ifcgeom/schema/mapping.i @@ -20,8 +20,7 @@ /******************************************************************************** * * * 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 * + * entities. * * * ********************************************************************************/ diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index 10eb3b8704..90ed25b764 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -1,5 +1,7 @@ #include +#include + namespace ifcopenshell { namespace geometry { @@ -9,6 +11,8 @@ namespace taxonomy { struct item { int instance_id; virtual item* clone() const = 0; + + item(int id) : instance_id(id) {} }; struct matrix4 : public item { @@ -25,61 +29,78 @@ struct matrix4 : public item { struct geom_item : public item { // geometry::style surface_style; matrix4 matrix; + + geom_item(int id) : item(id) {} + geom_item(int id, matrix4 m) : item(id), matrix(m) {} }; template -struct cartesian_base : public item { +struct cartesian_base : public geom_item { std::array components; + + cartesian_base(double x, double y, double z = 0.) : components{ {x, y, z} } {} }; struct point3 : public cartesian_base<3> { virtual item* clone() const { return new point3(*this); } + + point3(double x, double y, double z = 0.) : cartesian_base(x, y, z) {} }; struct direction3 : public cartesian_base<3> { virtual item* clone() const { return new direction3(*this); } + + direction3(double x, double y, double z = 0.) : cartesian_base(x, y, z) {} }; -struct line : public item { +struct line : public geom_item { virtual item* clone() const { return new line(*this); } }; -struct circle : public item { +struct circle : public geom_item { virtual item* clone() const { return new circle(*this); } }; -struct ellipse : public item { +struct ellipse : public geom_item { virtual item* clone() const { return new ellipse(*this); } }; -struct bspline : public item { +struct bspline : public geom_item { virtual item* clone() const { return new bspline(*this); } }; typedef boost::variant curve; -struct edge : public item { +struct edge : public geom_item { boost::variant start, end; boost::optional basis; virtual item* clone() const { return new edge(*this); } }; -struct boundary : public item { +struct loop : public geom_item { std::vector edges; - virtual item* clone() const { return new boundary(*this); } + virtual item* clone() const { return new loop(*this); } }; -struct face : public item { - boundary outer; - std::vector inner; +struct face : public geom_item { + loop outer; + std::vector inner; virtual item* clone() const { return new face(*this); } + + face(int id, loop o) : geom_item(id), outer(o) {} + face(int id, loop o, std::vector i) : geom_item(id), outer(o), inner(i) {} + face(int id, matrix4 m, loop o) : geom_item(id, m), outer(o) {} + face(int id, matrix4 m, loop o, std::vector i) : geom_item(id, m), outer(o), inner(i) {} }; -struct sweep : public item { +struct sweep : public geom_item { face basis; + + sweep(int id, face b) : geom_item(id), basis(b) {} + sweep(int id, matrix4 m, face b) : geom_item(id, m), basis(b) {} }; struct extrusion : public sweep { @@ -87,10 +108,17 @@ struct extrusion : public sweep { double depth; virtual item* clone() const { return new extrusion(*this); } + extrusion(int id, matrix4 m, face basis, direction3 dir, double d) : sweep(id, m, basis), direction(dir), depth(d) {} +}; + +class topology_error : public std::runtime_error { + }; } + + } } From ddeaf5a375584c170925b1ef09f3ea37df8906aa Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 16 Aug 2019 17:40:13 +0200 Subject: [PATCH 156/235] More work --- cmake/CMakeLists.txt | 65 +- src/ifcgeom/abstract_mapping.cpp | 35 + src/ifcgeom/abstract_mapping.h | 43 +- .../kernel_agnostic/AbstractKernel.cpp | 626 ++------ src/ifcgeom/kernel_agnostic/AbstractKernel.h | 74 +- .../IfcGeomIteratorImplementation.cpp | 31 - .../IfcGeomIteratorImplementation.h | 950 ------------ src/ifcgeom/kernel_agnostic/blog.txt | 71 + src/ifcgeom/kernels/opencascade/IfcGeom.h | 375 ----- .../{IfcGeomCurves.cpp => IfcGeomCurves.cpp_} | 0 .../{IfcGeomFaces.cpp => IfcGeomFaces.cpp_} | 0 ...eomFunctions.cpp => IfcGeomFunctions.cpp_} | 0 ...IfcGeomHelpers.cpp => IfcGeomHelpers.cpp_} | 0 ...lisation.cpp => IfcGeomSerialisation.cpp_} | 0 .../kernels/opencascade/IfcGeomShapes.cpp | 1160 +-------------- .../kernels/opencascade/IfcGeomShapes.cpp_ | 1289 +++++++++++++++++ .../{IfcGeomWires.cpp => IfcGeomWires.cpp_} | 0 .../{IfcRegister.cpp => IfcRegister.cpp_} | 0 .../kernels/opencascade/OpenCascadeKernel.h | 251 ++++ src/ifcgeom/schema/bind_convert_impl.i | 14 +- src/ifcgeom/schema/mapping.cpp | 646 ++++++++- src/ifcgeom/schema/mapping.h | 14 + src/ifcgeom/schema/mapping.i | 6 +- .../schema_agnostic/ConversionResult.h | 29 +- src/ifcgeom/schema_agnostic/Converter.cpp | 413 ++++++ .../schema_agnostic/{Kernel.h => Converter.h} | 60 +- src/ifcgeom/schema_agnostic/IfcGeomElement.h | 80 +- src/ifcgeom/schema_agnostic/IfcGeomFilter.h | 12 +- src/ifcgeom/schema_agnostic/IfcGeomIterator.h | 130 -- .../IfcGeomIteratorImplementation.cpp | 1 + .../IfcGeomIteratorImplementation.h | 617 ++++++++ .../schema_agnostic/IfcGeomMaterial.cpp | 35 - src/ifcgeom/schema_agnostic/IfcGeomMaterial.h | 51 - .../schema_agnostic/IfcGeomRenderStyles.h | 68 +- .../schema_agnostic/IfcGeomRepresentation.h | 81 +- .../IteratorImplementation.cpp | 47 - .../schema_agnostic/IteratorImplementation.h | 81 -- src/ifcgeom/schema_agnostic/Kernel.cpp | 268 ---- src/ifcgeom/schema_agnostic/SurfaceStyle.cpp | 93 +- .../opencascade/OpenCascadeConversionResult.h | 109 +- .../IfcGeomIteratorSettings.h => settings.h} | 28 +- src/ifcgeom/taxonomy.h | 125 +- src/ifcparse/IfcBaseClass.h | 15 + src/ifcparse/macros.h | 2 +- src/serializers/ColladaSerializer.cpp | 65 +- src/serializers/ColladaSerializer.h | 58 +- src/serializers/GeometrySerializer.h | 20 +- src/serializers/OpenCascadeBasedSerializer.h | 1 - .../schema_dependent/XmlSerializer.cpp | 112 +- .../schema_dependent/XmlSerializer.h | 3 + win/build-deps.cmd | 11 + win/run-cmake.bat | 2 + 52 files changed, 4083 insertions(+), 4184 deletions(-) create mode 100644 src/ifcgeom/abstract_mapping.cpp delete mode 100644 src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.cpp delete mode 100644 src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.h create mode 100644 src/ifcgeom/kernel_agnostic/blog.txt delete mode 100644 src/ifcgeom/kernels/opencascade/IfcGeom.h rename src/ifcgeom/kernels/opencascade/{IfcGeomCurves.cpp => IfcGeomCurves.cpp_} (100%) rename src/ifcgeom/kernels/opencascade/{IfcGeomFaces.cpp => IfcGeomFaces.cpp_} (100%) rename src/ifcgeom/kernels/opencascade/{IfcGeomFunctions.cpp => IfcGeomFunctions.cpp_} (100%) rename src/ifcgeom/kernels/opencascade/{IfcGeomHelpers.cpp => IfcGeomHelpers.cpp_} (100%) rename src/ifcgeom/kernels/opencascade/{IfcGeomSerialisation.cpp => IfcGeomSerialisation.cpp_} (100%) create mode 100644 src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp_ rename src/ifcgeom/kernels/opencascade/{IfcGeomWires.cpp => IfcGeomWires.cpp_} (100%) rename src/ifcgeom/kernels/opencascade/{IfcRegister.cpp => IfcRegister.cpp_} (100%) create mode 100644 src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h create mode 100644 src/ifcgeom/schema_agnostic/Converter.cpp rename src/ifcgeom/schema_agnostic/{Kernel.h => Converter.h} (58%) delete mode 100644 src/ifcgeom/schema_agnostic/IfcGeomIterator.h create mode 100644 src/ifcgeom/schema_agnostic/IfcGeomIteratorImplementation.cpp create mode 100644 src/ifcgeom/schema_agnostic/IfcGeomIteratorImplementation.h delete mode 100644 src/ifcgeom/schema_agnostic/IfcGeomMaterial.cpp delete mode 100644 src/ifcgeom/schema_agnostic/IfcGeomMaterial.h delete mode 100644 src/ifcgeom/schema_agnostic/IteratorImplementation.cpp delete mode 100644 src/ifcgeom/schema_agnostic/IteratorImplementation.h delete mode 100644 src/ifcgeom/schema_agnostic/Kernel.cpp rename src/ifcgeom/{schema_agnostic/IfcGeomIteratorSettings.h => settings.h} (94%) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index a65f8054fe..a77db1cddf 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -122,6 +122,7 @@ 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) +UNIFY_ENVVARS_AND_CACHE(EIGEN_DIR) if (GLTF_SUPPORT AND BUILD_CONVERT) UNIFY_ENVVARS_AND_CACHE(JSON_INCLUDE_DIR) @@ -527,7 +528,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} + ${CGAL_INCLUDE_DIR} ${GMP_INCLUDE_DIR} ${MPFR_INCLUDE_DIR} ${VOXEL_INCLUDE_DIR} ${EIGEN_DIR} ) function(files_for_ifc_version IFC_VERSION RESULT_NAME) @@ -607,15 +608,15 @@ endif() set(IFCOPENSHELL_LIBRARIES IfcParse) if (BUILD_IFCGEOM) foreach(s ${SCHEMA_VERSIONS}) - set(IFCGEOM_SCHEMA_LIBRARIES ${IFCGEOM_SCHEMA_LIBRARIES} IfcGeom_ifc${s}) + set(IFCGEOM_SCHEMA_LIBRARIES ${IFCGEOM_SCHEMA_LIBRARIES} geometry_mapping_ifc${s}) endforeach() - set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES} IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES}) + set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} IfcGeom geometry_mapping ${IFCGEOM_SCHEMA_LIBRARIES}) endif() if (BUILD_CONVERT) foreach(s ${SCHEMA_VERSIONS}) - set(SERIALIZER_SCHEMA_LIBRARIES ${SERIALIZER_SCHEMA_LIBRARIES} Serializers_ifc${s}) + set(SERIALIZER_SCHEMA_LIBRARIES ${SERIALIZER_SCHEMA_LIBRARIES} serializers_ifc${s}) endforeach() - set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} Serializers ${SERIALIZER_SCHEMA_LIBRARIES}) + set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} serializers ${SERIALIZER_SCHEMA_LIBRARIES}) endif() # IfcParse @@ -637,12 +638,21 @@ 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} 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}) +add_library(geometry_kernel_${kernel} STATIC ${IFCGEOM_FILES}) +set_target_properties(geometry_kernel_${kernel} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS") +target_link_libraries(geometry_kernel_${kernel} ${${KERNEL_UPPER}_LIBRARIES}) +list(APPEND kernel_libraries geometry_kernel_${kernel}) + endforeach() +file(GLOB SCHEMA_AGNOSTIC_H_FILES ../src/ifcgeom/kernel_agnostic/*.h) +file(GLOB SCHEMA_AGNOSTIC_CPP_FILES ../src/ifcgeom/kernel_agnostic/*.cpp) +set(SCHEMA_AGNOSTIC_FILES ${SCHEMA_AGNOSTIC_H_FILES} ${SCHEMA_AGNOSTIC_CPP_FILES}) + +add_library(geometry_kernels ${SCHEMA_AGNOSTIC_FILES}) +set_target_properties(geometry_kernels PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS) +target_link_libraries(geometry_kernels ${kernel_libraries}) + foreach(schema ${SCHEMA_VERSIONS}) file(GLOB IFCGEOM_I_FILES ../src/ifcgeom/schema/*.i) @@ -650,10 +660,10 @@ file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/schema/*.h) file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/schema/*.cpp) set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES} ${IFCGEOM_I_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}) +add_library(geometry_mapping_ifc${schema} STATIC ${IFCGEOM_FILES}) +set_target_properties(geometry_mapping_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema}") +target_link_libraries(geometry_mapping_ifc${schema} IfcParse) +list(APPEND mapping_libraries geometry_mapping_ifc${schema}) endforeach() @@ -661,20 +671,27 @@ file(GLOB SCHEMA_AGNOSTIC_H_FILES ../src/ifcgeom/*.h) file(GLOB SCHEMA_AGNOSTIC_CPP_FILES ../src/ifcgeom/*.cpp) set(SCHEMA_AGNOSTIC_FILES ${SCHEMA_AGNOSTIC_H_FILES} ${SCHEMA_AGNOSTIC_CPP_FILES}) -add_library(IfcGeom ${SCHEMA_AGNOSTIC_FILES}) -set_target_properties(IfcGeom PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS) +add_library(geometry_mappings ${SCHEMA_AGNOSTIC_FILES}) +set_target_properties(geometry_mappings PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS) +target_link_libraries(geometry_mappings ${mapping_libraries}) if (UNIX) find_package(Threads) endif() -TARGET_LINK_LIBRARIES(IfcGeom ${IfcGeom_libraries} ${CMAKE_THREAD_LIBS_INIT}) +file(GLOB SCHEMA_AGNOSTIC_H_FILES ../src/ifcgeom/schema_agnostic/*.h) +file(GLOB SCHEMA_AGNOSTIC_CPP_FILES ../src/ifcgeom/schema_agnostic/*.cpp) +set(SCHEMA_AGNOSTIC_FILES ${SCHEMA_AGNOSTIC_H_FILES} ${SCHEMA_AGNOSTIC_CPP_FILES}) + +add_library(IfcGeom ${SCHEMA_AGNOSTIC_FILES}) +set_target_properties(IfcGeom PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS) +target_link_libraries(IfcGeom geometry_mappings geometry_kernels ${CMAKE_THREAD_LIBS_INIT}) endif(BUILD_IFCGEOM) if (BUILD_CONVERT) -# Serializers +# serializers file(GLOB SERIALIZERS_H_FILES ../src/serializers/*.h) file(GLOB SERIALIZERS_CPP_FILES ../src/serializers/*.cpp) set(SERIALIZERS_FILES ${SERIALIZERS_H_FILES} ${SERIALIZERS_CPP_FILES}) @@ -683,15 +700,15 @@ file(GLOB SERIALIZERS_S_CPP_FILES ../src/serializers/schema_dependent/*.cpp) set(SERIALIZERS_S_FILES ${SERIALIZERS_S_H_FILES} ${SERIALIZERS_S_CPP_FILES}) foreach(s ${SCHEMA_VERSIONS}) - add_library(Serializers_ifc${s} STATIC ${SERIALIZERS_S_FILES}) - set_target_properties(Serializers_ifc${s} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${s} ${CONVERT_PRECISION}") - TARGET_LINK_LIBRARIES(Serializers_ifc${s} IfcGeom ${OPENCASCADE_LIBRARIES}) + add_library(serializers_ifc${s} STATIC ${SERIALIZERS_S_FILES}) + set_target_properties(serializers_ifc${s} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${s} ${CONVERT_PRECISION}") + TARGET_LINK_LIBRARIES(serializers_ifc${s} IfcGeom ${OPENCASCADE_LIBRARIES}) endforeach() -add_library(Serializers ${SERIALIZERS_FILES}) -set_target_properties(Serializers PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS ${CONVERT_PRECISION}") +add_library(serializers ${SERIALIZERS_FILES}) +set_target_properties(serializers PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS ${CONVERT_PRECISION}") -TARGET_LINK_LIBRARIES(Serializers ${SERIALIZER_SCHEMA_LIBRARIES}) +TARGET_LINK_LIBRARIES(serializers ${SERIALIZER_SCHEMA_LIBRARIES}) # IfcConvert file(GLOB IFCCONVERT_CPP_FILES ../src/ifcconvert/*.cpp) @@ -778,7 +795,7 @@ INSTALL(TARGETS IfcGeom ${IfcGeom_libraries} endif() if(BUILD_CONVERT) -INSTALL(TARGETS Serializers ${SERIALIZER_SCHEMA_LIBRARIES} +INSTALL(TARGETS serializers ${SERIALIZER_SCHEMA_LIBRARIES} ARCHIVE DESTINATION ${LIBDIR} LIBRARY DESTINATION ${LIBDIR} RUNTIME DESTINATION ${BINDIR} diff --git a/src/ifcgeom/abstract_mapping.cpp b/src/ifcgeom/abstract_mapping.cpp new file mode 100644 index 0000000000..387e2c53a3 --- /dev/null +++ b/src/ifcgeom/abstract_mapping.cpp @@ -0,0 +1,35 @@ +#include "abstract_mapping.h" + +#include "../ifcparse/IfcFile.h" + +ifcopenshell::geometry::impl::MappingFactoryImplementation& ifcopenshell::geometry::impl::mapping_implementations() { + static MappingFactoryImplementation impl; + return impl; +} + +extern void init_MappingImplementation_Ifc2x3(ifcopenshell::geometry::impl::MappingFactoryImplementation*); +extern void init_MappingImplementation_Ifc4(ifcopenshell::geometry::impl::MappingFactoryImplementation*); +extern void init_MappingImplementation_Ifc4x1(ifcopenshell::geometry::impl::MappingFactoryImplementation*); +extern void init_MappingImplementation_Ifc4x2(ifcopenshell::geometry::impl::MappingFactoryImplementation*); + +ifcopenshell::geometry::impl::MappingFactoryImplementation::MappingFactoryImplementation() { + init_MappingImplementation_Ifc2x3(this); + init_MappingImplementation_Ifc4(this); + init_MappingImplementation_Ifc4x1(this); + init_MappingImplementation_Ifc4x2(this); +} + +void ifcopenshell::geometry::impl::MappingFactoryImplementation::bind(const std::string& schema_name, ifcopenshell::geometry::impl::mapping_fn fn) { + const std::string schema_name_lower = boost::to_lower_copy(schema_name); + this->insert(std::make_pair(schema_name_lower, fn)); +} + +ifcopenshell::geometry::abstract_mapping* ifcopenshell::geometry::impl::MappingFactoryImplementation::construct(IfcParse::IfcFile* file) { + const std::string schema_name_lower = boost::to_lower_copy(file->schema()->name()); + std::map::const_iterator it; + it = this->find(schema_name_lower); + if (it == end()) { + throw IfcParse::IfcException("No geometry mapping registered for " + schema_name_lower); + } + return it->second(file); +} diff --git a/src/ifcgeom/abstract_mapping.h b/src/ifcgeom/abstract_mapping.h index 1a89e3fa03..7dbb4d413e 100644 --- a/src/ifcgeom/abstract_mapping.h +++ b/src/ifcgeom/abstract_mapping.h @@ -1,15 +1,56 @@ +#ifndef ABSTRACT_MAPPING_H +#define ABSTRACT_MAPPING_H + #include "../ifcparse/IfcBaseClass.h" +#include "../ifcparse/IfcEntityList.h" #include "../ifcgeom/taxonomy.h" +#include "../ifcgeom/settings.h" + +#include + +#include +#include namespace ifcopenshell { namespace geometry { + + class Element; + class NativeElement; + + struct geometry_conversion_task { + int index; + IfcUtil::IfcBaseEntity* representation; + IfcEntityList::ptr products; + std::vector breps; + std::vector elements; + }; + + typedef boost::function filter_t; class abstract_mapping { public: virtual ifcopenshell::geometry::taxonomy::item* map(const IfcUtil::IfcBaseClass*) = 0; + virtual void get_representations(std::vector& tasks, std::vector& filters, settings& s) = 0; + virtual IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity* product, bool include_openings = true) = 0; + virtual std::map get_layers(IfcUtil::IfcBaseEntity*); }; + + namespace impl { + typedef boost::function1 mapping_fn; + + class MappingFactoryImplementation : public std::map { + public: + MappingFactoryImplementation(); + void bind(const std::string& schema_name, mapping_fn); + abstract_mapping* construct(IfcParse::IfcFile*); + }; + + MappingFactoryImplementation& mapping_implementations(); + } } -} \ No newline at end of file +} + +#endif diff --git a/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp index 4d920610b2..18f5d0c53d 100644 --- a/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp +++ b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp @@ -2,551 +2,101 @@ #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(); - if (associated_materials->size() == 1) { - IfcSchema::IfcMaterialSelect* associated_material = (*associated_materials->begin())->RelatingMaterial(); - single_material = associated_material->as(); - - // 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::IfcMaterialLayerSet* layerset = associated_material->as()->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(); - 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::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(); - 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(); - 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; + /* A compile-time for loop over the taxonomy kinds */ + template + struct dispatch_conversion { + static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel* kernel, const ifcopenshell::geometry::taxonomy::item* item, ifcopenshell::geometry::ConversionResults& results) { + if (N == item->kind()) { + auto concrete_item = static_cast*>(item); + return kernel->convert_impl(concrete_item, results); + } else { + return dispatch_conversion::dispatch(kernel, item, results); } } + }; - // 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 - std::pair _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(0, 0); - } - - template - std::pair get_surface_style(const IfcSchema::IfcRepresentationItem* representation_item) { - // For certain representation items, most notably boolean operands, - // a style definition might reside on one of its operands. - representation_item = find_item_carrying_style(representation_item); - - if (representation_item->as()) { - return _get_surface_style(representation_item->as()); - } - 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(*styled_items->begin()); - } - return std::make_pair(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(colour_or_factor), rgb); - } else if (colour_or_factor->declaration().is(IfcSchema::IfcNormalisedRatioMeasure::Class())) { - return process_colour(static_cast(colour_or_factor), rgb); - } else { + template <> + struct dispatch_conversion { + static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel*, const ifcopenshell::geometry::taxonomy::item*, ifcopenshell::geometry::ConversionResults&) { return false; } - } + }; } -const IfcGeom::SurfaceStyle* IfcGeom::AbstractKernel::get_style(const IfcSchema::IfcRepresentationItem* item) { - return internalize_surface_style(get_surface_style(item)); +bool ifcopenshell::geometry::kernels::AbstractKernel::convert(const taxonomy::item* item, ifcopenshell::geometry::ConversionResults& results) { + return dispatch_conversion<0>::dispatch(this, item, results); } -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()); - } - for (IfcSchema::IfcStyledItem::list::it it = styles->begin(); it != styles->end(); ++it) { - const std::pair ss = get_surface_style(*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& shading_styles) { - if (shading_styles.second == 0) { - return 0; - } - int surface_style_id = shading_styles.first->data().id(); - std::map::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::IfcSurfaceStyleShading* shading = shading_styles.second->as(); - - 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(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 -IfcGeom::NativeElement* 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(); - 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()) { - 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(); - - 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( - product->data().id(), - parent_id, - name, - product_type, - guid, - context_string, - trsf, - boost::shared_ptr(shape), - product - ); - - if (settings.get(IteratorSettings::VALIDATE_QUANTITIES)) { - validate_quantities(product, elem->geometry()); - } - - return elem; -} - -template -IfcGeom::NativeElement* IfcGeom::AbstractKernel::create_brep_for_processed_representation( - const IteratorSettings& /*settings*/, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, - IfcGeom::NativeElement* brep) { - int parent_id = -1; - try { - IfcUtil::IfcBaseEntity* parent_object = get_decomposing_entity(product); - if (parent_object && parent_object->as()) { - 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( - product->data().id(), - parent_id, - name, - product_type, - guid, - context_string, - trsf, - brep->geometry_pointer(), - product - ); -} - -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::AbstractKernel::create_brep_for_representation_and_product( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::AbstractKernel::create_brep_for_representation_and_product( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::AbstractKernel::create_brep_for_representation_and_product( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); - -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::AbstractKernel::create_brep_for_processed_representation( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::AbstractKernel::create_brep_for_processed_representation( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); -template IFC_GEOM_API IfcGeom::NativeElement* IfcGeom::AbstractKernel::create_brep_for_processed_representation( - const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, IfcGeom::NativeElement* brep); \ No newline at end of file +//void ifcopenshell::geometry::kernels::AbstractKernel::set_conversion_placement_rel_to(const IfcParse::declaration* type) { +// placement_rel_to = type; +//} +// +//void ifcopenshell::geometry::kernels::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 ifcopenshell::geometry::kernels::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; +//} +// +// +// +// +//template IFC_GEOM_API ifcopenshell::geometry::kernels::NativeElement* ifcopenshell::geometry::kernels::AbstractKernel::create_brep_for_representation_and_product( +// const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); +//template IFC_GEOM_API ifcopenshell::geometry::kernels::NativeElement* ifcopenshell::geometry::kernels::AbstractKernel::create_brep_for_representation_and_product( +// const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); +//template IFC_GEOM_API ifcopenshell::geometry::kernels::NativeElement* ifcopenshell::geometry::kernels::AbstractKernel::create_brep_for_representation_and_product( +// const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product); +// +//template IFC_GEOM_API ifcopenshell::geometry::kernels::NativeElement* ifcopenshell::geometry::kernels::AbstractKernel::create_brep_for_processed_representation( +// const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, ifcopenshell::geometry::kernels::NativeElement* brep); +//template IFC_GEOM_API ifcopenshell::geometry::kernels::NativeElement* ifcopenshell::geometry::kernels::AbstractKernel::create_brep_for_processed_representation( +// const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, ifcopenshell::geometry::kernels::NativeElement* brep); +//template IFC_GEOM_API ifcopenshell::geometry::kernels::NativeElement* ifcopenshell::geometry::kernels::AbstractKernel::create_brep_for_processed_representation( +// const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, ifcopenshell::geometry::kernels::NativeElement* brep); \ No newline at end of file diff --git a/src/ifcgeom/kernel_agnostic/AbstractKernel.h b/src/ifcgeom/kernel_agnostic/AbstractKernel.h index dcfdd207d1..dcff03cebc 100644 --- a/src/ifcgeom/kernel_agnostic/AbstractKernel.h +++ b/src/ifcgeom/kernel_agnostic/AbstractKernel.h @@ -3,19 +3,12 @@ #include "../../ifcparse/macros.h" #include "../../ifcgeom/schema_agnostic/ifc_geom_api.h" -#include "../../ifcgeom/schema_agnostic/Kernel.h" #include "../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h" +#include "../../ifcgeom/taxonomy.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 ifcopenshell { namespace geometry { namespace kernels { -namespace IfcGeom { - - class IFC_GEOM_API MAKE_TYPE_NAME(AbstractKernel) : public IfcGeom::Kernel { + class IFC_GEOM_API AbstractKernel { protected: // For stopping PlacementRelTo recursion in convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& trsf) const IfcParse::declaration* placement_rel_to; @@ -29,11 +22,11 @@ namespace IfcGeom { double modelling_precision; double dimensionality; - std::map style_cache; + std::string geometry_library; public: - MAKE_TYPE_NAME(AbstractKernel)(const std::string& geometry_library) - : IfcGeom::Kernel(geometry_library, nullptr) + AbstractKernel(const std::string& geometry_library) + : geometry_library(geometry_library) , deflection_tolerance(0.001) , wire_creation_tolerance(0.0001) , point_equality_tolerance(0.00001) @@ -42,36 +35,39 @@ namespace IfcGeom { , ifc_planeangle_unit(-1.0) , modelling_precision(0.00001) , dimensionality(1.) - , placement_rel_to(0) - {} + , 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; + bool convert(const taxonomy::item*, ifcopenshell::geometry::ConversionResults&); - 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& shading_style); - - template - IfcGeom::NativeElement* create_brep_for_representation_and_product( - const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*); - - template - IfcGeom::NativeElement* create_brep_for_processed_representation( - const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::NativeElement*); + virtual bool convert_impl(const taxonomy::matrix4*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } + virtual bool convert_impl(const taxonomy::point3*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } + virtual bool convert_impl(const taxonomy::direction3*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } + virtual bool convert_impl(const taxonomy::line*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } + virtual bool convert_impl(const taxonomy::circle*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } + virtual bool convert_impl(const taxonomy::ellipse*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } + virtual bool convert_impl(const taxonomy::bspline*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } + virtual bool convert_impl(const taxonomy::edge*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } + virtual bool convert_impl(const taxonomy::loop*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } + virtual bool convert_impl(const taxonomy::face*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } + virtual bool convert_impl(const taxonomy::extrusion*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } + virtual bool convert_impl(const taxonomy::node*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } }; + namespace impl { + typedef boost::function1 < AbstractKernel*, const std::string&> kernel_fn; + + class KernelFactoryImplementation : public std::map { + public: + KernelFactoryImplementation(); + void bind(const std::string& geometry_library, kernel_fn); + AbstractKernel* construct(const std::string& geometry_library, IfcParse::IfcFile*); + }; + + KernelFactoryImplementation& kernel_implementations(); + } + +} +} } #endif \ No newline at end of file diff --git a/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.cpp b/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.cpp deleted file mode 100644 index d4a0a5e3b8..0000000000 --- a/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "IfcGeomIteratorImplementation.h" - -namespace IfcGeom { - template class MAKE_TYPE_NAME(IteratorImplementation_); - template class MAKE_TYPE_NAME(IteratorImplementation_); - template class MAKE_TYPE_NAME(IteratorImplementation_); -} - -#define MAKE_INIT_FN__(a, b) init_ ## a ## b -#define MAKE_INIT_FN_(a, b) MAKE_INIT_FN__(a, b) -#define MAKE_INIT_FN(t) MAKE_INIT_FN_(t, IfcSchema) - -namespace { - template - struct MAKE_TYPE_NAME(factory_t) { - IfcGeom::IteratorImplementation* operator()(const std::string& geometry_engine, const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector& filters, int num_threads) const { - return new IfcGeom::MAKE_TYPE_NAME(IteratorImplementation_)(geometry_engine, settings, file, filters, num_threads); - } - }; -} - -template -void MAKE_INIT_FN(IteratorImplementation_)(IteratorFactoryImplementation* mapping) { - static const std::string schema_name = STRINGIFY(IfcSchema); - MAKE_TYPE_NAME(factory_t) factory; - mapping->bind(schema_name, factory); -} - -template void MAKE_INIT_FN(IteratorImplementation_)(IteratorFactoryImplementation*); -template void MAKE_INIT_FN(IteratorImplementation_)(IteratorFactoryImplementation*); -template void MAKE_INIT_FN(IteratorImplementation_)(IteratorFactoryImplementation*); diff --git a/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.h b/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.h deleted file mode 100644 index e145f1cd7d..0000000000 --- a/src/ifcgeom/kernel_agnostic/IfcGeomIteratorImplementation.h +++ /dev/null @@ -1,950 +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 . * - * * - ********************************************************************************/ - -/******************************************************************************** - * * - * Geometrical data in an IFC file consists of shapes (IfcShapeRepresentation) * - * and instances (SUBTYPE OF IfcBuildingElement e.g. IfcWindow). * - * * - * IfcGeom::Representation::Triangulation is a class that represents a * - * triangulated IfcShapeRepresentation. * - * Triangulation.verts is a 1 dimensional vector of float defining the * - * cartesian coordinates of the vertices of the triangulated shape in the * - * format of [x1,y1,z1,..,xn,yn,zn] * - * Triangulation.faces is a 1 dimensional vector of int containing the * - * indices of the triangles referencing positions in Triangulation.verts * - * Triangulation.edges is a 1 dimensional vector of int in {0,1} that dictates* - * the visibility of the edges that span the faces in Triangulation.faces * - * * - * IfcGeom::Element represents the actual IfcBuildingElements. * - * IfcGeomObject.name is the GUID of the element * - * IfcGeomObject.type is the datatype of the element e.g. IfcWindow * - * IfcGeomObject.mesh is a pointer to an IfcMesh * - * IfcGeomObject.transformation.matrix is a 4x3 matrix that defines the * - * orientation and translation of the mesh in relation to the world origin * - * * - * IfcGeom::Iterator::initialize() * - * finds the most suitable representation contexts. Returns true iff * - * at least a single representation will process successfully * - * * - * IfcGeom::Iterator::get() * - * returns a pointer to the current IfcGeom::Element * - * * - * IfcGeom::Iterator::next() * - * returns true iff a following entity is available for a successive call to * - * IfcGeom::Iterator::get() * - * * - * IfcGeom::Iterator::progress() * - * returns an int in [0..100] that indicates the overall progress * - * * - ********************************************************************************/ - -#ifndef IFCGEOMITERATOR_H -#define IFCGEOMITERATOR_H - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include "../../ifcparse/macros.h" -#include "../../ifcparse/IfcFile.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/kernel_agnostic/AbstractKernel.h" - -#define INCLUDE_SCHEMA(x) STRINGIFY(../../ifcparse/x.h) -#include INCLUDE_SCHEMA(IfcSchema) -#undef INCLUDE_SCHEMA - -#include - -// The infamous min & max Win32 #defines can leak here from OCE depending on the build configuration -#ifdef min -#undef min -#endif -#ifdef max -#undef max -#endif - -namespace { - template - struct geometry_conversion_task { - int index; - IfcSchema::IfcRepresentation *representation; - IfcSchema::IfcProduct::list::ptr products; - std::vector*> breps; - std::vector*> elements; - }; - - template - IfcGeom::Element* process_based_on_settings( - const IfcGeom::IteratorSettings& settings, - IfcGeom::NativeElement* elem, - IfcGeom::TriangulationElement* previous=nullptr) - { - if (settings.get(IfcGeom::IteratorSettings::USE_BREP_DATA)) { - try { - return new IfcGeom::SerializedElement(*elem); - } catch (...) { - Logger::Message(Logger::LOG_ERROR, "Getting a serialized element from model failed."); - return nullptr; - } - } else if (!settings.get(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION)) { - try { - if (!previous) { - return new IfcGeom::TriangulationElement(*elem); - } else { - return new IfcGeom::TriangulationElement(*elem, previous->geometry_pointer()); - } - } catch (...) { - Logger::Message(Logger::LOG_ERROR, "Getting a triangulation element from model failed."); - return nullptr; - } - } else { - return elem; - } - } - - template - void create_element( - IfcGeom::MAKE_TYPE_NAME(AbstractKernel)* kernel, - const IfcGeom::IteratorSettings& settings, - geometry_conversion_task* rep) - { - IfcSchema::IfcRepresentation *representation = rep->representation; - IfcSchema::IfcProduct *product = *rep->products->begin(); - auto brep = kernel->create_brep_for_representation_and_product(settings, representation, product); - if (!brep) { - return; - } - - auto elem = process_based_on_settings(settings, brep); - if (!elem) { - return; - } - - rep->breps = { brep }; - rep->elements = { elem }; - - for (auto it = rep->products->begin() + 1; it != rep->products->end(); ++it) { - auto brep2 = kernel->create_brep_for_processed_representation(settings, representation, *it, brep); - if (brep2) { - auto elem2 = process_based_on_settings(settings, brep, dynamic_cast*>(elem)); - if (elem2) { - rep->breps.push_back(brep2); - rep->elements.push_back(elem2); - } - } - } - } -} - -namespace IfcGeom { - - template - class MAKE_TYPE_NAME(IteratorImplementation_) : public IteratorImplementation { - private: - - int num_threads_; - std::atomic progress_; - std::vector> tasks_; - std::vector*> all_processed_elements_; - std::vector*> all_processed_native_elements_; - typename std::vector*>::const_iterator task_result_iterator_; - typename std::vector*>::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(AbstractKernel)* kernel; - IteratorSettings settings; - - IfcParse::IfcFile* ifc_file; - - // A container and iterator for IfcRepresentations - IfcSchema::IfcRepresentation::list::ptr representations; - IfcSchema::IfcRepresentation::list::it representation_iterator; - - // The object is fetched beforehand to be sure that get() returns a valid element - TriangulationElement* current_triangulation; - NativeElement* current_shape_model; - SerializedElement* current_serialization; - - // A container and iterator for IfcBuildingElements for the current IfcRepresentation referenced by *representation_iterator - IfcSchema::IfcProduct::list::ptr ifcproducts; - IfcSchema::IfcProduct::list::it ifcproduct_iterator; - - - IfcSchema::IfcRepresentation::list::ptr ok_mapped_representations; - - int done; - int total; - - std::string unit_name; - double unit_magnitude; - - gp_XYZ bounds_min_; - gp_XYZ bounds_max_; - - std::vector filters_; - - struct filter_match - { - filter_match(IfcSchema::IfcProduct *prod) : product(prod) {} - bool operator()(const filter_t& filter) const { return filter(product); } - - IfcSchema::IfcProduct* product; - }; - - /// @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() { - - std::set allowed_context_types; - allowed_context_types.insert("model"); - allowed_context_types.insert("plan"); - allowed_context_types.insert("notdefined"); - - std::set context_types; - if (!settings.get(IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES)) { - // Really this should only be 'Model', as per - // the standard 'Design' is deprecated. So, - // just for backwards compatibility: - context_types.insert("model"); - context_types.insert("design"); - // Some earlier (?) versions DDS-CAD output their own ContextTypes - context_types.insert("model view"); - context_types.insert("detail view"); - } - if (settings.get(IteratorSettings::INCLUDE_CURVES)) { - context_types.insert("plan"); - } - - representations = IfcSchema::IfcRepresentation::list::ptr(new IfcSchema::IfcRepresentation::list); - ok_mapped_representations = IfcSchema::IfcRepresentation::list::ptr(new IfcSchema::IfcRepresentation::list); - - IfcSchema::IfcGeometricRepresentationContext::list::it it; - IfcSchema::IfcGeometricRepresentationSubContext::list::it jt; - IfcSchema::IfcGeometricRepresentationContext::list::ptr contexts = - ifc_file->instances_by_type(); - - IfcSchema::IfcGeometricRepresentationContext::list::ptr filtered_contexts (new IfcSchema::IfcGeometricRepresentationContext::list); - - for (it = contexts->begin(); it != contexts->end(); ++it) { - IfcSchema::IfcGeometricRepresentationContext* context = *it; - if (context->declaration().is(IfcSchema::IfcGeometricRepresentationSubContext::Class())) { - // Continue, as the list of subcontexts will be considered - // by the parent's context inverse attributes. - continue; - } - try { - if (context->hasContextType()) { - std::string context_type = context->ContextType(); - boost::to_lower(context_type); - - if (allowed_context_types.find(context_type) == allowed_context_types.end()) { - Logger::Warning(std::string("ContextType '") + context->ContextType() + "' not allowed:", context); - } - if (context_types.find(context_type) != context_types.end()) { - filtered_contexts->push(context); - } - } - } catch (const std::exception& e) { - Logger::Error(e); - } - } - - // In case no contexts are identified based on their ContextType, all contexts are - // considered. Note that sub contexts are excluded as they are considered later on. - if (filtered_contexts->size() == 0) { - for (it = contexts->begin(); it != contexts->end(); ++it) { - IfcSchema::IfcGeometricRepresentationContext* context = *it; - if (!context->declaration().is(IfcSchema::IfcGeometricRepresentationSubContext::Class())) { - filtered_contexts->push(context); - } - } - } - - for (it = filtered_contexts->begin(); it != filtered_contexts->end(); ++it) { - IfcSchema::IfcGeometricRepresentationContext* context = *it; - - representations->push(context->RepresentationsInContext()); - - IfcSchema::IfcGeometricRepresentationSubContext::list::ptr sub_contexts = context->HasSubContexts(); - for (jt = sub_contexts->begin(); jt != sub_contexts->end(); ++jt) { - representations->push((*jt)->RepresentationsInContext()); - } - // There is no need for full recursion as the following is governed by the schema: - // WR31: The parent context shall not be another geometric representation sub context. - } - - if (representations->size() == 0) { - Logger::Warning("No representations encountered in relevant contexts, using all"); - representations = ifc_file->instances_by_type(); - } - - if (representations->size() == 0) { - Logger::Warning("No representations encountered, aborting"); - return false; - } - - representation_iterator = representations->begin(); - ifcproducts.reset(); - - done = 0; - total = representations->size(); - - if (num_threads_ != 1) { - collect(); - process_concurrently(); - } else { - if (!create()) { - return false; - } - } - - return true; - } - - void collect() { - int i = 0; - IfcSchema::IfcProduct::list* previous = nullptr; - while (auto rp = get_next_task()) { - // Note that get_next_task() mutates the state of the iterator - // we use that capture all products that can be processed as - // part of this representation and then keep iterating until - // the underlying list of products changes. - if (ifcproducts.get() != previous) { - previous = ifcproducts.get(); - geometry_conversion_task t; - t.index = i++; - t.representation = *representation_iterator; - t.products = ifcproducts; - tasks_.emplace_back(t); - } - - _nextShape(); - } - } - - void process_concurrently() { - size_t conc_threads = num_threads_; - if (conc_threads > tasks_.size()) { - conc_threads = tasks_.size(); - } - - std::vector kernel_pool; - kernel_pool.reserve(conc_threads); - for (unsigned i = 0; i < conc_threads; ++i) { - kernel_pool.push_back((MAKE_TYPE_NAME(AbstractKernel)*) impl::kernel_implementations().construct(ifc_file->schema()->name(), geometry_library_, ifc_file)); - } - - std::vector> threadpool; - - int old_progress = -1; - int processed = 0; - - Logger::ProgressBar(0); - - for (auto& rep : tasks_) { - MAKE_TYPE_NAME(AbstractKernel)* K = nullptr; - if (threadpool.size() < kernel_pool.size()) { - K = kernel_pool[threadpool.size()]; - } - - while (threadpool.size() == conc_threads) { - for (int i = 0; i < (int)threadpool.size(); i++) { - std::future &fu = threadpool[i]; - std::future_status status; - status = fu.wait_for(std::chrono::seconds(0)); - if (status == std::future_status::ready) { - fu.get(); - - processed += 1; - progress_ = processed * 50 / tasks_.size(); - if (progress_ != old_progress) { - Logger::ProgressBar(progress_); - old_progress = progress_; - } - - std::swap(threadpool[i], threadpool.back()); - threadpool.pop_back(); - std::swap(kernel_pool[i], kernel_pool.back()); - K = kernel_pool.back(); - break; - } // if - } // for - } // while - - std::future fu = std::async(std::launch::async, create_element, K, std::ref(settings), &rep); - threadpool.emplace_back(std::move(fu)); - } - - for (std::future &fu : threadpool) { - fu.get(); - - processed += 1; - progress_ = processed * 50 / tasks_.size(); - if (progress_ != old_progress) { - Logger::ProgressBar(progress_); - old_progress = progress_; - } - } - - for (auto& rep : tasks_) { - all_processed_elements_.insert(all_processed_elements_.end(), rep.elements.begin(), rep.elements.end()); - all_processed_native_elements_.insert(all_processed_native_elements_.end(), rep.breps.begin(), rep.breps.end()); - } - - task_result_iterator_ = all_processed_elements_.begin(); - native_task_result_iterator_ = all_processed_native_elements_.begin(); - - Logger::Status("\rDone creating geometry (" + boost::lexical_cast(all_processed_elements_.size()) + - " objects) "); - } - - /// Computes model's bounding box (bounds_min and bounds_max). - /// @note Can take several minutes for large files. - void compute_bounds() - { - for (int i = 1; i < 4; ++i) { - bounds_min_.SetCoord(i, std::numeric_limits::infinity()); - bounds_max_.SetCoord(i, -std::numeric_limits::infinity()); - } - - IfcSchema::IfcProduct::list::ptr products = ifc_file->instances_by_type(); - for (IfcSchema::IfcProduct::list::it iter = products->begin(); iter != products->end(); ++iter) { - IfcSchema::IfcProduct* product = *iter; - if (product->hasObjectPlacement()) { - // Use a fresh trsf every time in order to prevent the result to be concatenated - ConversionResultPlacement* trsf; - bool success = false; - - try { - success = kernel->convert_placement(product->ObjectPlacement(), trsf); - } catch (const std::exception& e) { - Logger::Error(e); - } catch (...) { - Logger::Error("Failed to construct placement"); - } - - if (!success) { - continue; - } - - 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)); - } - } - } - - int progress() const { - if (num_threads_ == 1) { - return 100 * done / total; - } else { - return progress_; - } - } - - const std::string& getUnitName() const { return unit_name; } - - /// @note Double always as per IFC specification. - double getUnitMagnitude() const { return unit_magnitude; } - - std::string getLog() const { return Logger::GetLog(); } - - IfcParse::IfcFile* file() const { return ifc_file; } - - const std::vector& filters() const { return filters_; } - std::vector& filters() { return filters_; } - - const gp_XYZ& bounds_min() const { return bounds_min_; } - const gp_XYZ& bounds_max() const { return bounds_max_; } - - private: - // Move to the next IfcRepresentation - void _nextShape() { - ifcproducts.reset(); - ++ representation_iterator; - ++ done; - } - - bool geometry_reuse_ok_for_current_representation_; - - bool reuse_ok_(const IfcSchema::IfcProduct::list::ptr& products) { - // With world coords enabled, object transformations are directly applied to - // the BRep. There is no way to re-use the geometry for multiple products. - if (settings.get(IteratorSettings::USE_WORLD_COORDS)) { - return false; - } - - std::set associated_single_materials; - - for (IfcSchema::IfcProduct::list::it it = products->begin(); it != products->end(); ++it) { - IfcSchema::IfcProduct* product = *it; - - if (!settings.get(IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && kernel->find_openings(product)->size()) { - return false; - } - - if (settings.get(IteratorSettings::APPLY_LAYERSETS)) { - IfcSchema::IfcRelAssociates::list::ptr associations = product->HasAssociations(); - for (IfcSchema::IfcRelAssociates::list::it jt = associations->begin(); jt != associations->end(); ++jt) { - IfcSchema::IfcRelAssociatesMaterial* assoc = (*jt)->as(); - if (assoc) { - if (assoc->RelatingMaterial()->declaration().is(IfcSchema::IfcMaterialLayerSetUsage::Class())) { - // TODO: Check whether single layer? - return false; - } - } - } - } - - // Note that this can be a nullptr (!), but the fact that set size should be one still holds - associated_single_materials.insert(kernel->get_single_material_association(product)); - if (associated_single_materials.size() > 1) return false; - } - - return associated_single_materials.size() == 1; - } - - boost::optional> get_next_task() { - for (;;) { - IfcSchema::IfcRepresentation* representation; - - if (representation_iterator == representations->end()) { - representations.reset(); - return boost::none; // reached the end of our list of representations - } - representation = *representation_iterator; - - 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); - } - } - - if (ifcproducts->size() == 0) { - _nextShape(); - continue; - } - - geometry_reuse_ok_for_current_representation_ = reuse_ok_(ifcproducts); - - IfcSchema::IfcRepresentationMap::list::ptr maps = representation->RepresentationMap(); - - if (!geometry_reuse_ok_for_current_representation_ && maps->size() == 1) { - // unfiltered_products contains products represented by this representation by means of mapped items. - // For example because of openings applied to products, reuse might not be acceptable and then the - // products will be processed by means of their immediate representation and not the mapped representation. - - // IfcRepresentationMaps are also used for IfcTypeProducts, so an additional check is performed whether the map - // is indeed used by IfcMappedItems. - IfcSchema::IfcRepresentationMap* map = *maps->begin(); - if (map->MapUsage()->size() > 0) { - _nextShape(); - continue; - } - } - - // 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); - 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))); - } - - if (representation_processed_as_mapped_item) { - ok_mapped_representations->push(representation_mapped_to); - _nextShape(); - continue; - } - - ifcproduct_iterator = ifcproducts->begin(); - } - - // Have we reached the end of our list of IfcProducts? - if (ifcproduct_iterator == ifcproducts->end()) { - _nextShape(); - continue; - } - - IfcSchema::IfcProduct* product = *ifcproduct_iterator; - - - return std::make_pair(representation, product); - } - } - - NativeElement* create_shape_model_for_next_entity() { - for (;;) { - auto rp = get_next_task(); - if (!rp) { - return nullptr; - } - auto representation = rp->first; - auto product = rp->second; - - Logger::SetProduct(product); - - NativeElement* element; - if (ifcproduct_iterator == ifcproducts->begin() || !geometry_reuse_ok_for_current_representation_) { - element = kernel->create_brep_for_representation_and_product(settings, representation, product); - } else { - element = kernel->create_brep_for_processed_representation(settings, representation, product, current_shape_model); - } - - Logger::SetProduct(boost::none); - - if (!element) { - _nextShape(); - continue; - } - - return element; - } - } - - void free_shapes() { - // Free all possible representations of the current geometrical entity - delete current_triangulation; - current_triangulation = 0; - delete current_serialization; - current_serialization = 0; - delete current_shape_model; - current_shape_model = 0; - } - - public: - /// Returns what would be the product for the next shape representation - /// @todo Double-check and test the impl. - //IfcSchema::IfcProduct* peek_next() const - //{ - // if (ifcproducts && ifcproduct_iterator + 1 != ifcproducts->end()){ - // return *(ifcproduct_iterator + 1); - // } else { - // return 0; - // } - //} - - /// @todo Would this be as simple as the following code? - //void skip_next() { if (ifcproducts) { ++ifcproduct_iterator; } } - - /// Moves to the next shape representation, create its geometry, and returns the associated product. - /// Use get() to retrieve the created geometry. - IfcUtil::IfcBaseClass* next() { - if (num_threads_ != 1) { - task_result_iterator_++; - native_task_result_iterator_++; - if (task_result_iterator_ == all_processed_elements_.end()) { - return nullptr; - } else { - return (*task_result_iterator_)->product(); - } - } else { - // Increment the iterator over the list of products using the current - // shape representation - if (ifcproducts) { - ++ifcproduct_iterator; - } - - return create(); - } - } - - /// Gets the representation of the current geometrical entity. - Element* get() - { - // TODO: Test settings and throw - Element* ret = 0; - - if (num_threads_ != 1) { - ret = *task_result_iterator_; - } else { - if (current_triangulation) { - ret = current_triangulation; - } else if (current_serialization) { - ret = current_serialization; - } else if (current_shape_model) { - ret = current_shape_model; - } - } - - // If we want to organize the element considering their hierarchy - if (settings.get(IteratorSettings::SEARCH_FLOOR)) - { - // We are going to build a vector with the element parents. - // First, create the parent vector - std::vector*> parents; - - // if the element has a parent - if (ret->parent_id() != -1) - { - const IfcGeom::Element* parent_object = NULL; - bool hasParent = true; - - // get the parent - try { - parent_object = get_object(ret->parent_id()); - } catch (const std::exception& e) { - Logger::Error(e); - hasParent = false; - } - - // Add the previously found parent to the vector - if (hasParent) parents.insert(parents.begin(), parent_object); - - // We need to find all the parents - while (parent_object != NULL && hasParent && parent_object->parent_id() != -1) - { - // Find the next parent - try { - parent_object = get_object(parent_object->parent_id()); - } catch (const std::exception& e) { - Logger::Error(e); - hasParent = false; - } - - // Add the previously found parent to the vector - if (hasParent) parents.insert(parents.begin(), parent_object); - - hasParent = hasParent && parent_object->parent_id() != -1; - } - - // when done push the parent list in the Element object - ret->SetParents(parents); - } - } - - return ret; - } - - /// Gets the native (Open Cascade) representation of the current geometrical entity. - NativeElement* get_native() - { - // TODO: Test settings and throw - if (num_threads_ != 1) { - return *native_task_result_iterator_; - } else { - return current_shape_model; - } - } - - const Element* get_object(int id) { - ConversionResultPlacement* trsf; - int parent_id = -1; - std::string instance_type, product_name, product_guid; - IfcSchema::IfcProduct* ifc_product = 0; - - try { - IfcUtil::IfcBaseClass* ifc_entity = ifc_file->instance_by_id(id); - instance_type = ifc_entity->declaration().name(); - - if (ifc_entity->declaration().is(IfcSchema::IfcRoot::Class())) { - IfcSchema::IfcRoot* ifc_root = ifc_entity->as(); - product_guid = ifc_root->GlobalId(); - product_name = ifc_root->hasName() ? ifc_root->Name() : ""; - } - - if (ifc_entity->declaration().is(IfcSchema::IfcProduct::Class())) { - ifc_product = ifc_entity->as(); - parent_id = -1; - try { - IfcSchema::IfcObjectDefinition* parent_object = kernel->get_decomposing_entity(ifc_product)->template as(); - if (parent_object) { - parent_id = parent_object->data().id(); - } - } catch (const std::exception& e) { - Logger::Error(e); - } catch (...) { - Logger::Error("Failed to find decomposing entity"); - } - - try { - kernel->convert_placement(ifc_product->ObjectPlacement(), trsf); - } catch (const std::exception& e) { - Logger::Error(e); - } catch (...) { - Logger::Error("Failed to construct placement"); - } - } - } catch (const std::exception& e) { - Logger::Error(e); - } catch (const Standard_Failure& e) { - if (e.GetMessageString() && strlen(e.GetMessageString())) { - Logger::Error(e.GetMessageString()); - } else { - Logger::Error("Unknown error returning product"); - } - } catch (...) { - Logger::Error("Unknown error returning product"); - } - - ElementSettings element_settings(settings, unit_magnitude, instance_type); - - Element* ifc_object = new Element(element_settings, id, parent_id, product_name, instance_type, product_guid, "", trsf, ifc_product); - return ifc_object; - } - - IfcUtil::IfcBaseClass* create() { - IfcGeom::NativeElement* next_shape_model = 0; - IfcGeom::SerializedElement* next_serialization = 0; - IfcGeom::TriangulationElement* next_triangulation = 0; - - try { - next_shape_model = create_shape_model_for_next_entity(); - } catch (const std::exception& e) { - Logger::Error(e); - } catch (const Standard_Failure& e) { - if (e.GetMessageString() && strlen(e.GetMessageString())) { - Logger::Error(e.GetMessageString()); - } else { - Logger::Error("Unknown error creating geometry"); - } - } catch (...) { - Logger::Error("Unknown error creating geometry"); - } - - if (next_shape_model) { - if (settings.get(IteratorSettings::USE_BREP_DATA)) { - try { - next_serialization = new SerializedElement(*next_shape_model); - } catch (...) { - Logger::Message(Logger::LOG_ERROR, "Getting a serialized element from model failed."); - } - } else if (!settings.get(IteratorSettings::DISABLE_TRIANGULATION)) { - try { - if (ifcproduct_iterator == ifcproducts->begin() || !geometry_reuse_ok_for_current_representation_) { - next_triangulation = new TriangulationElement(*next_shape_model); - } else { - next_triangulation = new TriangulationElement(*next_shape_model, current_triangulation->geometry_pointer()); - } - } catch (...) { - Logger::Message(Logger::LOG_ERROR, "Getting a triangulation element from model failed."); - } - } - } - - free_shapes(); - - current_shape_model = next_shape_model; - current_serialization = next_serialization; - current_triangulation = next_triangulation; - - return next_shape_model ? next_shape_model->product() : 0; - } - private: - void _initialize() { - current_triangulation = 0; - current_shape_model = 0; - current_serialization = 0; - - unit_name = "METER"; - unit_magnitude = 1.f; - - kernel->setValue(IfcGeom::Kernel::GV_MAX_FACES_TO_ORIENT, settings.get(IteratorSettings::SEW_SHELLS) ? std::numeric_limits::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()); - } else if (settings.get(IteratorSettings::SITE_LOCAL_PLACEMENT)) { - kernel->set_conversion_placement_rel_to(&IfcSchema::IfcSite::Class()); - } - } - - bool owns_ifc_file; - public: - MAKE_TYPE_NAME(IteratorImplementation_)(const std::string& geometry_library, const IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector& 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(); - } - - ~MAKE_TYPE_NAME(IteratorImplementation_)() { - if (owns_ifc_file) { - delete ifc_file; - } - - if (settings.get(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION)) { - for (auto& p : all_processed_native_elements_) { - delete p; - } - } - - for (auto& p : all_processed_elements_) { - delete p; - } - - free_shapes(); - } - }; -} - -#endif diff --git a/src/ifcgeom/kernel_agnostic/blog.txt b/src/ifcgeom/kernel_agnostic/blog.txt new file mode 100644 index 0000000000..e188c8d407 --- /dev/null +++ b/src/ifcgeom/kernel_agnostic/blog.txt @@ -0,0 +1,71 @@ +v0.6.0 + +People not following the development of IfcOpenShell actively and happily using the master branch of the github repository might be surprised to know there is a lot of activity happening in the v0.6.0 and v0.7.0 branches. This post discusses the changes in the v0.6.0 branch. The following post will elaborate on some of the design decisions we are making in the v0.7.0 branch. + +Schemas + +The most significant improvement in the v0.6.0 branch is that multiple schemas (IFC2X3, IFC4, IFC4X1 and IFC4X2) are supported from within the same executable, module or plug-in. Previously, selecting the schema had been a compile-time option. + +In IfcOpenShell and most other EXPRESS-based toolkits, the IFC schema is compiled into (a) the early-bound definitions: a class hierarchy with member functions and (b) a set of methods to operate on the schema definitions at runtime (late-bound access). C++ only allows very limited introspection (but the development of C++ is very active, see for example P1240 https://github.com/cplusplus/papers/issues/545) so to complement the lack of introspection a set of methods exists to query for example all attribute names or the sub- and supertypes of an entity. In the master branch these methods are static, in the v0.6.0 branch these are the member functions of a schema class, that is a more complete reference mirrorring the EXPRESS schema definition at runtime. See IfcBaseEntity::declararation() or IfcParse::schema::declaration_by_name("IfcWall")->as_entity()->all_attribute_names(). + +Writing schema agnostic code + +The code generated from the four schemas are completely orthogonal class hiercharies. For the C++ compiler there is no relationship between a Ifc2x3::IfcWall and a Ifc4::IfcWall. But IfcOpenShell offers three ways to write code that adapts to the schema of the file known at runtime. + +(a) preprocessor + +This is the approach taken in the IfcGeom modules in v0.6.0. Essentially the same code base is compiled multiple times where the schema is available as a preprocessor constant. This means you can enable specific code paths with for example #ifdef directives. In this way the added entities in Ifc4 (IfcBSplineSurface, yay!) can be selectively compiled for example. + +https://github.com/IfcOpenShell/IfcOpenShell/blob/v0.6.0/src/ifcgeom/IfcGeomFaces.cpp#L1127 + +Smaller code blocks can be written as macros as well. + +https://github.com/IfcOpenShell/IfcOpenShell/blob/v0.6.0/src/ifcgeom_schema_agnostic/Kernel.cpp#L74 + +Benefits: fairly readible code, full autocompletion typically in an IDE when using the static library approach +Downsides: Some infrastructure required to compile the different libraries and select the correct implementation at runtime + +(b) late-bound access + +There are two modes of accessing schemas. In the early-bound approach function signatures and return types are known at compilation time. In the late-bound approach attribute names are referenced by strings and types are + +Ifc2x3::IfcWall* wall; +// Early-bound access; +std::string global_id = wall->GlobalId(); +// Late-bound access. +std::string global_id = *wall->get("GlobalId"); +// ERROR: By dereferencing the return type, it is casted into a string, which will cause an exception *at runtime* when the types do not match. +int global_id = *wall->get("GlobalId"); + +Benefits: +fairly readible code +no complicated setup of different libraries +Downsides: +no code completion +errors are only spotted at runtime, not compile-time +late-bound manipulation of inverse attributes is not well supported currently in IfcOpenShell +less means for the compiler to create highly optimized code + +(c) templates + +C++ has very extensive support for compile time generic arguments: templates. + +template +void print_globalid(Schema::IfcWall* wall) { + std::cout << wall->GlobalId(); +} + +Benefits: +no complicated setup of different libraries +no autocompletion typically, but errors caught at compile-time +Downsides: +fairly unreadible code due to additional template and typename keywords. +error messages are harder to make sense up (due to two phase lookup rules for example) + +All three approaches are used in the IfcOpenShell code-base. + +Other improvements: + +Multi-threading in collaboration with TNO, MAUC and Airsquire + +Direct binary glTF output (previously supported through Collada and Collada2Gltf) in collaboration with Schuco US. diff --git a/src/ifcgeom/kernels/opencascade/IfcGeom.h b/src/ifcgeom/kernels/opencascade/IfcGeom.h deleted file mode 100644 index d0575a5de2..0000000000 --- a/src/ifcgeom/kernels/opencascade/IfcGeom.h +++ /dev/null @@ -1,375 +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 . * - * * - ********************************************************************************/ - -#ifndef IFCGEOM_H -#define IFCGEOM_H - -#include - -static const double ALMOST_ZERO = 1.e-9; - -template -inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance=ALMOST_ZERO) { - return fabs(a-b) < tolerance; -} - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../../../ifcparse/macros.h" -#include "../../../ifcparse/IfcParse.h" -#include "../../../ifcparse/IfcBaseClass.h" - -#include "../../../ifcgeom/kernel_agnostic/AbstractKernel.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 "../../../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 -// #define NO_CACHE - -#ifdef NO_CACHE - -#define IN_CACHE(T,E,t,e) -#define CACHE(T,E,e) - -#else - -#define IN_CACHE(T,E,t,e) std::map::const_iterator it = cache.T.find(E->data().id());\ -if ( it != cache.T.end() ) { e = it->second; return true; } -#define CACHE(T,E,e) cache.T[E->data().id()] = e; - -#endif - -#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 { - protected: - std::string message; - public: - geometry_exception(const std::string& m) - : message(m) {} - virtual ~geometry_exception() throw () {} - virtual const char* what() const throw() { - return message.c_str(); - } - }; - - class IFC_GEOM_API too_many_faces_exception : public geometry_exception { - public: - too_many_faces_exception() - : geometry_exception("Too many faces for operation") {} - }; - -class IFC_GEOM_API POSTFIX_SCHEMA(Cache) { -public: -#include "IfcRegisterCreateCache.h" - std::map Shape; -}; - -class IFC_GEOM_API POSTFIX_SCHEMA(Kernel) : public IfcGeom::POSTFIX_SCHEMA(AbstractKernel) { -private: - - /* - faceset_helper traverses the forward instance references of IfcConnectedFaceSet and then provides a mapping - M of (IfcCartesianPoint, IfcCartesianPoint) -> TopoDS_Edge, where M(a, b) is a partner of M(b, a), ie share - the same underlying edge but with orientation reversed. This then later speeds op the process of creating a - manifold Shell / Solid from this set of faces. Only IfcPolyLoop instances are used. Points within the tolerance - threshiold are merged, so consider points a, b, c, distance(a, b) < eps then M(a, b) = Null, M(a, b) = M(a, c). - */ - class faceset_helper { - private: - POSTFIX_SCHEMA(Kernel)* kernel_; - std::set duplicates_; - std::map vertex_mapping_; - std::map, TopoDS_Edge> edges_; - double eps_; - bool non_manifold_; - - template - void loop_(IfcSchema::IfcCartesianPoint::list::ptr& ps, const Fn& callback) { - if (ps->size() < 3) { - return; - } - - auto a = *(ps->end() - 1); - auto A = a->data().id(); - for (auto& b : *ps) { - auto B = b->data().id(); - auto C = vertex_mapping_[A], D = vertex_mapping_[B]; - bool fwd = C < D; - if (!fwd) { - std::swap(C, D); - } - if (C != D) { - callback(C, D, fwd); - A = B; - } - } - } - public: - faceset_helper(POSTFIX_SCHEMA(Kernel)* kernel, const IfcSchema::IfcConnectedFaceSet* l); - - ~faceset_helper(); - - bool non_manifold() const { return non_manifold_; } - bool& non_manifold() { return non_manifold_; } - - bool edge(const IfcSchema::IfcCartesianPoint* a, const IfcSchema::IfcCartesianPoint* b, TopoDS_Edge& e) { - int A = vertex_mapping_[a->data().id()]; - int B = vertex_mapping_[b->data().id()]; - if (A == B) { - return false; - } - - return edge(A, B, e); - } - - bool edge(int A, int B, TopoDS_Edge& e) { - auto it = edges_.find({A, B}); - if (it == edges_.end()) { - return false; - } - e = it->second; - return true; - } - - bool wire(const IfcSchema::IfcPolyLoop* loop, TopoDS_Wire& wire) { - if (duplicates_.find(loop) != duplicates_.end()) { - return false; - } - BRep_Builder builder; - builder.MakeWire(wire); - int count = 0; - auto ps = loop->Polygon(); - loop_(ps, [this, &builder, &wire, &count](int A, int B, bool fwd) { - TopoDS_Edge e; - if (edge(A, B, e)) { - if (!fwd) { - e.Reverse(); - } - builder.Add(wire, e); - count += 1; - } - }); - if (count >= 3) { - wire.Closed(true); - - TopTools_ListOfShape results; - if (kernel_->wire_intersections(wire, results)) { - Logger::Warning("Self-intersections with " + boost::lexical_cast(results.Extent()) + " cycles detected", loop); - kernel_->select_largest(results, wire); - non_manifold_ = true; - } - - return true; - } else { - return false; - } - } - - double epsilon() const { - return eps_; - } - }; - -#ifndef NO_CACHE - POSTFIX_SCHEMA(Cache) cache; -#endif - - faceset_helper* faceset_helper_; - -public: - POSTFIX_SCHEMA(Kernel)() - : IfcGeom::POSTFIX_SCHEMA(AbstractKernel)("opencascade") - , faceset_helper_(nullptr) - {} - - POSTFIX_SCHEMA(Kernel)(const POSTFIX_SCHEMA(Kernel)& other) - : IfcGeom::POSTFIX_SCHEMA(AbstractKernel)("opencascade") - { - *this = other; - } - - POSTFIX_SCHEMA(Kernel)& operator=(const POSTFIX_SCHEMA(Kernel)& other) { - setValue(GV_DEFLECTION_TOLERANCE, other.getValue(GV_DEFLECTION_TOLERANCE)); - setValue(GV_MAX_FACES_TO_ORIENT, other.getValue(GV_MAX_FACES_TO_ORIENT)); - setValue(GV_LENGTH_UNIT, other.getValue(GV_LENGTH_UNIT)); - setValue(GV_PLANEANGLE_UNIT, other.getValue(GV_PLANEANGLE_UNIT)); - setValue(GV_PRECISION, other.getValue(GV_PRECISION)); - setValue(GV_DIMENSIONALITY, other.getValue(GV_DIMENSIONALITY)); - setValue(GV_DEFLECTION_TOLERANCE, other.getValue(GV_DEFLECTION_TOLERANCE)); - return *this; - } - - bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face); - bool convert_curve_to_wire(const Handle(Geom_Curve)& curve, TopoDS_Wire& wire); - bool convert_shapes(const IfcUtil::IfcBaseClass* L, 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::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 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&, std::vector&, std::vector&); - bool apply_layerset(const ConversionResults&, const std::vector&, const std::vector&, ConversionResults&); - bool apply_folded_layerset(const ConversionResults&, const std::vector< std::vector >&, const std::vector&, ConversionResults&); - bool fold_layers(const IfcSchema::IfcWall*, const ConversionResults&, const std::vector&, const std::vector&, std::vector< std::vector >&); - - bool split_solid_by_surface(const TopoDS_Shape&, const Handle_Geom_Surface&, TopoDS_Shape&, TopoDS_Shape&); - bool split_solid_by_shell(const TopoDS_Shape&, const TopoDS_Shape& s, TopoDS_Shape&, TopoDS_Shape&); - -#if OCC_VERSION_HEX < 0x60900 - bool boolean_operation(const TopoDS_Shape&, const TopTools_ListOfShape&, BOPAlgo_Operation, TopoDS_Shape&); - bool boolean_operation(const TopoDS_Shape&, const TopoDS_Shape&, BOPAlgo_Operation, TopoDS_Shape&); -#else - bool boolean_operation(const TopoDS_Shape&, const TopTools_ListOfShape&, BOPAlgo_Operation, TopoDS_Shape&, double fuzziness = -1.); - bool boolean_operation(const TopoDS_Shape&, const TopoDS_Shape&, BOPAlgo_Operation, TopoDS_Shape&, double fuzziness = -1.); -#endif - - bool fit_halfspace(const TopoDS_Shape& a, const TopoDS_Shape& b, TopoDS_Shape& box, double& height); - - const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const Handle_Geom_Surface&); - const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const TopoDS_Face&); - const Handle_Geom_Curve intersect(const TopoDS_Face&, const Handle_Geom_Surface&); - bool intersect(const Handle_Geom_Curve&, const Handle_Geom_Surface&, gp_Pnt&); - bool intersect(const Handle_Geom_Curve&, const TopoDS_Face&, gp_Pnt&); - bool intersect(const Handle_Geom_Curve&, const TopoDS_Shape&, std::vector&); - bool intersect(const Handle_Geom_Surface&, const TopoDS_Shape&, std::vector< std::pair >&); - bool closest(const gp_Pnt&, const std::vector&, gp_Pnt&); - bool project(const Handle_Geom_Curve&, const gp_Pnt&, gp_Pnt& p, double& u, double& d); - bool project(const Handle_Geom_Surface&, const TopoDS_Shape&, double& u1, double& v1, double& u2, double& v2, double widen=0.1); - - bool find_wall_end_points(const IfcSchema::IfcWall*, gp_Pnt& start, gp_Pnt& end); - - bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& solid); - bool create_solid_from_faces(const TopTools_ListOfShape& face_list, TopoDS_Shape& solid); - bool is_compound(const TopoDS_Shape& shape); - bool is_convex(const TopoDS_Wire& wire); - TopoDS_Shape halfspace_from_plane(const gp_Pln& pln,const gp_Pnt& cent); - gp_Pln plane_from_face(const TopoDS_Face& face); - gp_Pnt point_above_plane(const gp_Pln& pln, bool agree=true); - const TopoDS_Shape& ensure_fit_for_subtraction(const TopoDS_Shape& shape, TopoDS_Shape& solid); - bool profile_helper(int numVerts, double* verts, int numFillets, int* filletIndices, double* filletRadii, gp_Trsf2d trsf, TopoDS_Shape& face); - void apply_tolerance(TopoDS_Shape& s, double t); - bool fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape); - void remove_duplicate_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.); - void remove_collinear_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.); - bool wire_to_sequence_of_point(const TopoDS_Wire&, TColgp_SequenceOfPnt&); - void sequence_of_point_to_wire(const TColgp_SequenceOfPnt&, TopoDS_Wire&, bool closed); - bool approximate_plane_through_wire(const TopoDS_Wire&, gp_Pln&, double eps=-1.); - bool flatten_wire(TopoDS_Wire&); - /// Triangulate the set of wires. The firstmost wire is assumed to be the outer wire. - bool triangulate_wire(const std::vector&, TopTools_ListOfShape&); - bool wire_intersections(const TopoDS_Wire & wire, TopTools_ListOfShape & wires); - void select_largest(const TopTools_ListOfShape& shapes, TopoDS_Shape& largest); - - static double shape_volume(const TopoDS_Shape& s); - static double face_area(const TopoDS_Face& f); - - static TopoDS_Shape apply_transformation(const TopoDS_Shape&, const OpenCascadePlacement*); - static TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_Trsf&); - static TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_GTrsf&); - - 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 initializeUnits(IfcSchema::IfcUnitAssignment*); - - 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 = POSTFIX_SCHEMA(Cache)(); -#endif - } - -#include "IfcRegisterGeomHeader.h" - - virtual IfcGeom::NativeElement* convert( - const IteratorSettings& settings, IfcUtil::IfcBaseClass* representation, - IfcUtil::IfcBaseClass* product) - { - return create_brep_for_representation_and_product(settings, (IfcSchema::IfcRepresentation*) representation, (IfcSchema::IfcProduct*) product); - } - - virtual ConversionResults convert(IfcUtil::IfcBaseClass* item) { - ConversionResults items; - bool success = convert_shapes(item, items); - if (!success) { - throw IfcParse::IfcException("Failed to process representation item"); - } - return items; - } - - virtual bool convert_placement(IfcUtil::IfcBaseClass* item, ConversionResultPlacement*& trsf) { - if (item->as()) { - gp_Trsf occt_trsf; - if (convert(item->as(), occt_trsf)) { - trsf = new OpenCascadePlacement(occt_trsf); - return true; - } - } - return false; - } - -}; - -IfcUtil::IfcBaseClass* POSTFIX_SCHEMA(tesselate_)(const TopoDS_Shape& shape, double deflection); -IfcUtil::IfcBaseClass* POSTFIX_SCHEMA(serialise_)(const TopoDS_Shape& shape, bool advanced); - -} -#endif diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomCurves.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomCurves.cpp_ similarity index 100% rename from src/ifcgeom/kernels/opencascade/IfcGeomCurves.cpp rename to src/ifcgeom/kernels/opencascade/IfcGeomCurves.cpp_ diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomFaces.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomFaces.cpp_ similarity index 100% rename from src/ifcgeom/kernels/opencascade/IfcGeomFaces.cpp rename to src/ifcgeom/kernels/opencascade/IfcGeomFaces.cpp_ diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp_ similarity index 100% rename from src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp rename to src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp_ diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomHelpers.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomHelpers.cpp_ similarity index 100% rename from src/ifcgeom/kernels/opencascade/IfcGeomHelpers.cpp rename to src/ifcgeom/kernels/opencascade/IfcGeomHelpers.cpp_ diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomSerialisation.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomSerialisation.cpp_ similarity index 100% rename from src/ifcgeom/kernels/opencascade/IfcGeomSerialisation.cpp rename to src/ifcgeom/kernels/opencascade/IfcGeomSerialisation.cpp_ diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp index 5001639a6d..df2abbefe9 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp @@ -101,33 +101,37 @@ #include -#include "../../../ifcgeom/kernels/opencascade/IfcGeom.h" +#include "OpenCascadeKernel.h" #include -#define Kernel POSTFIX_SCHEMA(Kernel) +#include "../../../ifcparse/IfcLogger.h" -bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolid* l, TopoDS_Shape& shape) { - const double height = l->Depth() * getValue(GV_LENGTH_UNIT); - if (height < getValue(GV_PRECISION)) { - Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", l); +using namespace ifcopenshell::geometry; +using namespace ifcopenshell::geometry::kernels; + +bool OpenCascadeKernel::convert(const taxonomy::extrusion& extrusion, TopoDS_Shape& shape) { + const double& height = extrusion.depth; + + if (height < precision_) { + Logger::Error("Non-positive extrusion height encountered for:", extrusion.instance); return false; } TopoDS_Shape face; - if ( !convert_face(l->SweptArea(),face) ) return false; - - gp_Trsf trsf; - bool has_position = true; -#ifdef SCHEMA_IfcSweptAreaSolid_Position_IS_OPTIONAL - has_position = l->hasPosition(); -#endif - if (has_position) { - IfcGeom::Kernel::convert(l->Position(), trsf); + if (!convert(extrusion.basis, face)) { + return false; } + gp_Trsf trsf; + if (!convert(extrusion.matrix, trsf)) { + Logger::Error("Unable to move extrusion"); + } + gp_Dir dir; - convert(l->ExtrudedDirection(),dir); + if (!convert(extrusion.direction, dir)) { + return false; + } shape.Nullify(); @@ -157,7 +161,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolid* l, TopoDS_S shape = BRepPrimAPI_MakePrism(face, height*dir); } - if (has_position && !shape.IsNull()) { + if (!shape.IsNull()) { // IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D // and therefore has a unit scale factor shape.Move(trsf); @@ -165,1125 +169,3 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolid* l, TopoDS_S return !shape.IsNull(); } - -#ifdef SCHEMA_HAS_IfcExtrudedAreaSolidTapered -bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* l, TopoDS_Shape& shape) { - const double height = l->Depth() * getValue(GV_LENGTH_UNIT); - if (height < getValue(GV_PRECISION)) { - Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", l); - return false; - } - - TopoDS_Shape face1, face2; - if (!convert_face(l->SweptArea(), face1)) return false; - if (!convert_face(l->EndSweptArea(), face2)) return false; - - gp_Trsf trsf; - bool has_position = true; -#ifdef SCHEMA_IfcSweptAreaSolid_Position_IS_OPTIONAL - has_position = l->hasPosition(); -#endif - if (has_position) { - IfcGeom::Kernel::convert(l->Position(), trsf); - } - - gp_Dir dir; - convert(l->ExtrudedDirection(), dir); - - gp_Trsf end_profile; - end_profile.SetTranslation(height * dir); - - TopoDS_Edge spine_edge = BRepBuilderAPI_MakeEdge(gp_Pnt(), gp_Pnt((height * dir).XYZ())).Edge(); - TopoDS_Wire wire = BRepBuilderAPI_MakeWire(spine_edge).Wire(); - - shape.Nullify(); - - TopExp_Explorer exp1(face1, TopAbs_WIRE); - TopExp_Explorer exp2(face2, TopAbs_WIRE); - - TopoDS_Vertex v1, v2; - TopExp::Vertices(wire, v1, v2); - - TopoDS_Shape shell; - TopoDS_Compound compound; - BRep_Builder compound_builder; - - for (; exp1.More() && exp2.More(); exp1.Next(), exp2.Next()) { - const TopoDS_Wire& w1 = TopoDS::Wire(exp1.Current()); - const TopoDS_Wire& w2 = TopoDS::Wire(exp2.Current()); - - BRepOffsetAPI_MakePipeShell builder(wire); - builder.Add(w1, v1); - builder.Add(w2.Moved(end_profile), v2); - - TopoDS_Shape result = builder.Shape(); - - BRepOffsetAPI_Sewing sewer; - sewer.SetTolerance(getValue(GV_PRECISION)); - sewer.SetMaxTolerance(getValue(GV_PRECISION)); - sewer.SetMinTolerance(getValue(GV_PRECISION)); - - sewer.Add(result); - sewer.Add(BRepBuilderAPI_MakeFace(w1).Face()); - sewer.Add(BRepBuilderAPI_MakeFace(w2).Face().Moved(end_profile)); - - sewer.Perform(); - - result = sewer.SewedShape(); - - if (shell.IsNull()) { - shell = result; - } else if (l->SweptArea()->declaration().is(IfcSchema::IfcCircleHollowProfileDef::Class()) || - l->SweptArea()->declaration().is(IfcSchema::IfcRectangleHollowProfileDef::Class())) - { - /// @todo a bit of of a hack, should be sufficient - shell = BRepAlgoAPI_Cut(shell, result).Shape(); - break; - } else { - if (compound.IsNull()) { - compound_builder.MakeCompound(compound); - compound_builder.Add(compound, shell); - } - compound_builder.Add(compound, result); - } - } - - if (!compound.IsNull()) { - shell = compound; - } - - shape = shell; - - if (exp1.More() != exp2.More()) { - Logger::Message(Logger::LOG_ERROR, "Inconsistent profiles encountered for:", l); - } - - if (has_position && !shape.IsNull()) { - // IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D - // and therefore has a unit scale factor - shape.Move(trsf); - } - - return !shape.IsNull(); -} -#endif - -bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfLinearExtrusion* l, TopoDS_Shape& shape) { - TopoDS_Wire wire; - if ( !convert_wire(l->SweptCurve(), wire) ) { - TopoDS_Face face; - if ( !convert_face(l->SweptCurve(),face) ) return false; - TopExp_Explorer exp(face, TopAbs_WIRE); - wire = TopoDS::Wire(exp.Current()); - } - const double height = l->Depth() * getValue(GV_LENGTH_UNIT); - - gp_Trsf trsf; - bool has_position = true; -#ifdef SCHEMA_IfcSweptSurface_Position_IS_OPTIONAL - has_position = l->hasPosition(); -#endif - if (has_position) { - IfcGeom::Kernel::convert(l->Position(), trsf); - } - - gp_Dir dir; - convert(l->ExtrudedDirection(),dir); - - shape = BRepPrimAPI_MakePrism(wire, height*dir); - - if (has_position) { - // IfcSweptSurface.Position (trsf) is an IfcAxis2Placement3D - // and therefore has a unit scale factor - shape.Move(trsf); - } - - return !shape.IsNull(); -} - -bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfRevolution* l, TopoDS_Shape& shape) { - TopoDS_Wire wire; - if ( !convert_wire(l->SweptCurve(), wire) ) { - TopoDS_Face face; - if ( !convert_face(l->SweptCurve(),face) ) return false; - TopExp_Explorer exp(face, TopAbs_WIRE); - wire = TopoDS::Wire(exp.Current()); - } - - gp_Ax1 ax1; - IfcGeom::Kernel::convert(l->AxisPosition(), ax1); - - gp_Trsf trsf; - bool has_position = true; -#ifdef SCHEMA_IfcSweptSurface_Position_IS_OPTIONAL - has_position = l->hasPosition(); -#endif - if (has_position) { - IfcGeom::Kernel::convert(l->Position(), trsf); - } - - shape = BRepPrimAPI_MakeRevol(wire, ax1); - - if (has_position) { - // IfcSweptSurface.Position (trsf) is an IfcAxis2Placement3D - // and therefore has a unit scale factor - shape.Move(trsf); - } - - return !shape.IsNull(); -} - -bool IfcGeom::Kernel::convert(const IfcSchema::IfcRevolvedAreaSolid* l, TopoDS_Shape& shape) { - const double ang = l->Angle() * getValue(GV_PLANEANGLE_UNIT); - - TopoDS_Face face; - if ( ! convert_face(l->SweptArea(),face) ) return false; - - gp_Ax1 ax1; - IfcGeom::Kernel::convert(l->Axis(), ax1); - - gp_Trsf trsf; - bool has_position = true; -#ifdef SCHEMA_IfcSweptAreaSolid_Position_IS_OPTIONAL - has_position = l->hasPosition(); -#endif - if (has_position) { - IfcGeom::Kernel::convert(l->Position(), trsf); - } - - if (ang >= M_PI * 2. - ALMOST_ZERO) { - shape = BRepPrimAPI_MakeRevol(face, ax1); - } else { - shape = BRepPrimAPI_MakeRevol(face, ax1, ang); - } - - if (has_position) { - // IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D - // and therefore has a unit scale factor - shape.Move(trsf); - } - - return !shape.IsNull(); -} - -bool IfcGeom::Kernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, ConversionResults& shape) { - TopoDS_Shape s; - const SurfaceStyle* collective_style = get_style(l); - if (convert_shape(l->Outer(),s) ) { - const SurfaceStyle* indiv_style = get_style(l->Outer()); - - IfcSchema::IfcClosedShell::list::ptr voids(new IfcSchema::IfcClosedShell::list); - if (l->declaration().is(IfcSchema::IfcFacetedBrepWithVoids::Class())) { - voids = l->as()->Voids(); - } -#ifdef SCHEMA_HAS_IfcAdvancedBrepWithVoids - if (l->declaration().is(IfcSchema::IfcAdvancedBrepWithVoids::Class())) { - voids = l->as()->Voids(); - } -#endif - - for (IfcSchema::IfcClosedShell::list::it it = voids->begin(); it != voids->end(); ++it) { - TopoDS_Shape s2; - /// @todo No extensive shapefixing since shells should be disjoint. - /// @todo Awaiting generalized boolean ops module with appropriate checking - if (convert_shape(l->Outer(), s2)) { - s = BRepAlgoAPI_Cut(s, s2).Shape(); - } - } - - shape.push_back(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, 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 ) { - TopoDS_Shape s; - const SurfaceStyle* shell_style = get_style(*it); - if (convert_shape(*it,s)) { - shapes.push_back(ConversionResult(l->data().id(), new OpenCascadeShape(s), shell_style ? shell_style : collective_style)); - part_success |= true; - } - } - return part_success; -} - -bool IfcGeom::Kernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, TopoDS_Shape& shape) { - IfcSchema::IfcSurface* surface = l->BaseSurface(); - if ( ! surface->declaration().is(IfcSchema::IfcPlane::Class()) ) { - Logger::Message(Logger::LOG_ERROR, "Unsupported BaseSurface:", surface); - return false; - } - gp_Pln pln; - IfcGeom::Kernel::convert((IfcSchema::IfcPlane*)surface,pln); - const gp_Pnt pnt = pln.Location().Translated( l->AgreementFlag() ? -pln.Axis().Direction() : pln.Axis().Direction()); - shape = BRepPrimAPI_MakeHalfSpace(BRepBuilderAPI_MakeFace(pln),pnt).Solid(); - return true; -} - -bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace* l, TopoDS_Shape& shape) { - TopoDS_Shape halfspace; - if ( ! IfcGeom::Kernel::convert((IfcSchema::IfcHalfSpaceSolid*)l,halfspace) ) return false; - - TopoDS_Wire wire; - if ( ! convert_wire(l->PolygonalBoundary(),wire) || ! wire.Closed() ) return false; - - gp_Trsf trsf; - if ( ! convert(l->Position(),trsf) ) return false; - - TColgp_SequenceOfPnt points; - if (wire_to_sequence_of_point(wire, points)) { - // Boolean subtractions not very robust for narrow operands, - // increase minimal point spacing to eliminate such shapes. - const double t = getValue(GV_PRECISION) * 10.; - remove_duplicate_points_from_loop(points, wire.Closed() != 0, t); // Note: wire always closed, as per if statement above - remove_collinear_points_from_loop(points, wire.Closed() != 0, t); - if (points.Length() < 3) { - Logger::Message(Logger::LOG_ERROR, "Not enough points retained from:", l->PolygonalBoundary()); - return false; - } - sequence_of_point_to_wire(points, wire, wire.Closed() != 0); - } - - TopoDS_Shape prism = BRepPrimAPI_MakePrism(BRepBuilderAPI_MakeFace(wire),gp_Vec(0,0,200)); - gp_Trsf down; down.SetTranslation(gp_Vec(0,0,-100.0)); - - // `trsf` and `down` both have a unit scale factor - prism.Move(trsf*down); - - shape = BRepAlgoAPI_Common(halfspace,prism); - return true; -} - -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 ) { - TopoDS_Shape s; - const SurfaceStyle* shell_style = 0; - if ((*it)->declaration().is(IfcSchema::IfcRepresentationItem::Class())) { - shell_style = get_style((IfcSchema::IfcRepresentationItem*)*it); - } - if (convert_shape(*it,s)) { - shapes.push_back(ConversionResult(l->data().id(), new OpenCascadeShape(s), shell_style ? shell_style : collective_style)); - } - } - return true; -} - -bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape& shape) { - - TopoDS_Shape s1, s2; - ConversionResults items1; - TopoDS_Wire boundary_wire; - IfcSchema::IfcBooleanOperand* operand1 = l->FirstOperand(); - IfcSchema::IfcBooleanOperand* operand2 = l->SecondOperand(); - bool has_halfspace_operand = false; - - BOPAlgo_Operation occ_op; - - const IfcSchema::IfcBooleanOperator::Value op = l->Operator(); - if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) { - occ_op = BOPAlgo_CUT; - } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) { - occ_op = BOPAlgo_COMMON; - } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) { - occ_op = BOPAlgo_FUSE; - } else { - return false; - } - - std::vector second_operands; - second_operands.push_back(operand2); - - if (occ_op == BOPAlgo_CUT) { - bool process_as_list = true; - while (true) { - auto res1 = operand1->as(); - if (res1) { - if (res1->Operator() == op) { - operand1 = res1->FirstOperand(); - second_operands.push_back(res1->SecondOperand()); - } else { - process_as_list = false; - break; - } - } else { - break; - } - } - - if (!process_as_list) { - operand1 = l->FirstOperand(); - second_operands = { operand2 }; - } - } - - if ( shape_type(operand1) == ST_SHAPELIST ) { - 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; - } - { TopoDS_Solid temp_solid; - s1 = ensure_fit_for_subtraction(s1, temp_solid); } - } else { - Logger::Message(Logger::LOG_ERROR, "Invalid representation item for boolean operation", operand1); - return false; - } - - const double first_operand_volume = shape_volume(s1); - if (first_operand_volume <= ALMOST_ZERO) { - Logger::Message(Logger::LOG_WARNING, "Empty solid for:", l->FirstOperand()); - } - - TopTools_ListOfShape second_operand_shapes; - - for (auto& op2 : second_operands) { - TopoDS_Shape s2; - - bool shape2_processed = false; - - bool is_halfspace = op2->declaration().is(IfcSchema::IfcHalfSpaceSolid::Class()); - bool is_unbounded_halfspace = is_halfspace && !op2->declaration().is(IfcSchema::IfcPolygonalBoundedHalfSpace::Class()); - has_halfspace_operand |= is_halfspace; - - { - if (shape_type(op2) == ST_SHAPELIST) { - 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); - if (shape2_processed) { - TopoDS_Solid temp_solid; - s2 = ensure_fit_for_subtraction(s2, temp_solid); - } - } else { - Logger::Message(Logger::LOG_ERROR, "Invalid representation item for boolean operation", op2); - } - } - - if (is_unbounded_halfspace) { - TopoDS_Shape temp; - double d; - if (fit_halfspace(s1, s2, temp, d)) { - if (d < getValue(GV_PRECISION)) { - Logger::Message(Logger::LOG_WARNING, "Halfspace subtraction yields unchanged volume:", l); - continue; - } else { - s2 = temp; - } - } - } - - if (!shape2_processed) { - Logger::Message(Logger::LOG_ERROR, "Failed to convert SecondOperand:", op2); - continue; - } - - if (op2->declaration().is(IfcSchema::IfcHalfSpaceSolid::Class())) { - const double second_operand_volume = shape_volume(s2); - if (second_operand_volume <= ALMOST_ZERO) { - Logger::Message(Logger::LOG_WARNING, "Empty solid for:", op2); - } - } - - second_operand_shapes.Append(s2); - } - - /* - // TK: A little debugging trick to output both operands for visual inspection - - BRep_Builder builder; - TopoDS_Compound compound; - builder.MakeCompound(compound); - builder.Add(compound, s1); - for (const auto& s2 : second_operand_shapes) { - builder.Add(compound, s2); - } - shape = compound; - return true; - */ - -#if OCC_VERSION_HEX < 0x60900 - // @todo: this currently does not compile anymore, do we still need this? - bool valid_result = boolean_operation(s1, s2, occ_op, shape); -#else - bool valid_result = boolean_operation(s1, second_operand_shapes, occ_op, shape); -#endif - - if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) { - // In case of a subtraction, a check on volume is performed. - if (valid_result) { - const double volume_after_subtraction = shape_volume(shape); - if ( ALMOST_THE_SAME(first_operand_volume,volume_after_subtraction) ) - Logger::Message(Logger::LOG_WARNING,"Subtraction yields unchanged volume:",l); - } else { - Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",l); - shape = s1; - } - // NB: After issuing error the first operand is returned! - return true; - } else { - return valid_result; - } - return false; -} - -bool IfcGeom::Kernel::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Shape& shape) { - std::unique_ptr helper_scope; - helper_scope.reset(new faceset_helper(this, l)); - - IfcSchema::IfcFace::list::ptr faces = l->CfsFaces(); - - double min_face_area = faceset_helper_ - ? (faceset_helper_->epsilon() * faceset_helper_->epsilon() / 20.) - : getValue(GV_MINIMAL_FACE_AREA); - - TopTools_ListOfShape face_list; - for (IfcSchema::IfcFace::list::it it = faces->begin(); it != faces->end(); ++it) { - bool success = false; - TopoDS_Face face; - - try { - success = convert_face(*it, face); - } catch (const std::exception& e) { - Logger::Error(e); - } catch (const Standard_Failure& e) { - if (e.GetMessageString() && strlen(e.GetMessageString())) { - Logger::Error(e.GetMessageString()); - } else { - Logger::Error("Unknown error creating face"); - } - } catch (...) { - Logger::Error("Unknown error creating face"); - } - - if (!success) { - Logger::Message(Logger::LOG_WARNING, "Failed to convert face:", (*it)); - continue; - } - - if (face.ShapeType() == TopAbs_COMPOUND) { - TopoDS_Iterator face_it(face, false); - for (; face_it.More(); face_it.Next()) { - if (face_it.Value().ShapeType() == TopAbs_FACE) { - // This should really be the case. This is not asserted. - const TopoDS_Face& triangle = TopoDS::Face(face_it.Value()); - if (face_area(triangle) > min_face_area) { - face_list.Append(triangle); - } else { - Logger::Message(Logger::LOG_WARNING, "Degenerate face:", (*it)); - } - } - } - } else { - if (face_area(face) > min_face_area) { - face_list.Append(face); - } else { - Logger::Message(Logger::LOG_WARNING, "Degenerate face:", (*it)); - } - } - } - - if (face_list.Extent() == 0) { - return false; - } - - if (face_list.Extent() > getValue(GV_MAX_FACES_TO_ORIENT) || !create_solid_from_faces(face_list, shape)) { - TopoDS_Compound compound; - BRep_Builder builder; - builder.MakeCompound(compound); - - TopTools_ListIteratorOfListOfShape face_iterator; - for (face_iterator.Initialize(face_list); face_iterator.More(); face_iterator.Next()) { - builder.Add(compound, face_iterator.Value()); - } - shape = compound; - } - - return true; -} - -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()) ) { - IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator3DnonUniform*)transform,gtrsf); - } else if ( transform->declaration().is(IfcSchema::IfcCartesianTransformationOperator2DnonUniform::Class()) ) { - Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform); - return false; - } else if ( transform->declaration().is(IfcSchema::IfcCartesianTransformationOperator3D::Class()) ) { - gp_Trsf trsf; - IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,trsf); - gtrsf = trsf; - } else if ( transform->declaration().is(IfcSchema::IfcCartesianTransformationOperator2D::Class()) ) { - gp_Trsf2d trsf_2d; - IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator2D*)transform,trsf_2d); - gtrsf = (gp_Trsf) trsf_2d; - } - IfcSchema::IfcRepresentationMap* map = l->MappingSource(); - IfcSchema::IfcAxis2Placement* placement = map->MappingOrigin(); - gp_Trsf trsf; - if (placement->declaration().is(IfcSchema::IfcAxis2Placement3D::Class())) { - IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf); - } else { - gp_Trsf2d trsf_2d; - IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf_2d); - trsf = trsf_2d; - } - gtrsf.Multiply(trsf); - - 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 ) { - 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 - if (!shapes[i].hasStyle()) { - shapes[i].setStyle(mapped_item_style); - } - } - - return b; -} - -bool IfcGeom::Kernel::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 { - TopoDS_Shape s; - if (convert_shape(representation_item,s)) { - shapes.push_back(ConversionResult(representation_item->data().id(), new OpenCascadeShape(s), get_style(representation_item))); - part_succes |= true; - } - } - } - } - return part_succes; -} - -bool IfcGeom::Kernel::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; - TopoDS_Shape s; - if (convert_shape(element, s)) { - part_succes = true; - const IfcGeom::SurfaceStyle* style = 0; - if (element->declaration().is(IfcSchema::IfcPoint::Class())) { - style = get_style((IfcSchema::IfcPoint*) element); - } else if (element->declaration().is(IfcSchema::IfcCurve::Class())) { - style = get_style((IfcSchema::IfcCurve*) element); - } else if (element->declaration().is(IfcSchema::IfcSurface::Class())) { - style = get_style((IfcSchema::IfcSurface*) element); - } - shapes.push_back(ConversionResult(l->data().id(), new OpenCascadeShape(s), style ? style : parent_style)); - } - } - return part_succes; -} - -bool IfcGeom::Kernel::convert(const IfcSchema::IfcBlock* l, TopoDS_Shape& 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); - - BRepPrimAPI_MakeBox builder(dx, dy, dz); - gp_Trsf trsf; - IfcGeom::Kernel::convert(l->Position(),trsf); - - // IfcCsgPrimitive3D.Position has unit scale factor - shape = builder.Solid().Moved(trsf); - - return true; -} - -bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangularPyramid* l, TopoDS_Shape& 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); - - BRepPrimAPI_MakeWedge builder(dx, dz, dy, dx / 2., dy / 2., dx / 2., dy / 2.); - - gp_Trsf trsf1, trsf2; - trsf2.SetValues( - 1, 0, 0, 0, - 0, 0, 1, 0, - 0, 1, 0, 0 -#if OCC_VERSION_HEX < 0x60800 - , Precision::Angular(), Precision::Confusion() -#endif - ); - - IfcGeom::Kernel::convert(l->Position(), trsf1); - shape = BRepBuilderAPI_Transform(builder.Solid(), trsf1 * trsf2); - return true; -} - -bool IfcGeom::Kernel::convert(const IfcSchema::IfcRightCircularCylinder* l, TopoDS_Shape& shape) { - const double r = l->Radius() * getValue(GV_LENGTH_UNIT); - const double h = l->Height() * getValue(GV_LENGTH_UNIT); - - BRepPrimAPI_MakeCylinder builder(r, h); - gp_Trsf trsf; - IfcGeom::Kernel::convert(l->Position(),trsf); - - // IfcCsgPrimitive3D.Position has unit scale factor - shape = builder.Solid().Moved(trsf); - - return true; -} - -bool IfcGeom::Kernel::convert(const IfcSchema::IfcRightCircularCone* l, TopoDS_Shape& shape) { - const double r = l->BottomRadius() * getValue(GV_LENGTH_UNIT); - const double h = l->Height() * getValue(GV_LENGTH_UNIT); - - BRepPrimAPI_MakeCone builder(r, 0., h); - gp_Trsf trsf; - IfcGeom::Kernel::convert(l->Position(),trsf); - - // IfcCsgPrimitive3D.Position has unit scale factor - shape = builder.Solid().Moved(trsf); - - return true; -} - -bool IfcGeom::Kernel::convert(const IfcSchema::IfcSphere* l, TopoDS_Shape& shape) { - const double r = l->Radius() * getValue(GV_LENGTH_UNIT); - - BRepPrimAPI_MakeSphere builder(r); - gp_Trsf trsf; - IfcGeom::Kernel::convert(l->Position(),trsf); - - // IfcCsgPrimitive3D.Position has unit scale factor - shape = builder.Solid().Moved(trsf); - - return true; -} - -bool IfcGeom::Kernel::convert(const IfcSchema::IfcCsgSolid* l, TopoDS_Shape& shape) { - return convert_shape(l->TreeRootExpression(), shape); -} - -bool IfcGeom::Kernel::convert(const IfcSchema::IfcCurveBoundedPlane* l, TopoDS_Shape& face) { - gp_Pln pln; - if (!IfcGeom::Kernel::convert(l->BasisSurface(), pln)) { - return false; - } - - gp_Trsf trsf; - trsf.SetTransformation(pln.Position(), gp::XOY()); - - TopoDS_Wire outer; - if (!convert_wire(l->OuterBoundary(), outer)) { - return false; - } - - BRepBuilderAPI_MakeFace mf(outer); - - if (!mf.IsDone() || mf.Shape().IsNull()) { - Logger::Error("Invalid outer boundary:", l->OuterBoundary()); - return false; - } - - IfcSchema::IfcCurve::list::ptr boundaries = l->InnerBoundaries(); - - for (IfcSchema::IfcCurve::list::it it = boundaries->begin(); it != boundaries->end(); ++it) { - TopoDS_Wire inner; - if (convert_wire(*it, inner)) { - mf.Add(inner); - } - } - - ShapeFix_Shape sfs(mf.Face()); - sfs.Perform(); - - // `trsf` consitutes the placement of the plane and therefore has unit scale factor - face = TopoDS::Face(sfs.Shape()).Moved(trsf); - - return true; -} - -bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangularTrimmedSurface* l, TopoDS_Shape& face) { - if (!l->BasisSurface()->declaration().is(IfcSchema::IfcPlane::Class())) { - Logger::Message(Logger::LOG_ERROR, "Unsupported BasisSurface:", l->BasisSurface()); - return false; - } - gp_Pln pln; - IfcGeom::Kernel::convert((IfcSchema::IfcPlane*) l->BasisSurface(), pln); - - BRepBuilderAPI_MakeFace mf(pln, l->U1(), l->U2(), l->V1(), l->V2()); - - face = mf.Face(); - - return true; -} - -bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l, TopoDS_Shape& shape) { - gp_Trsf directrix; - TopoDS_Shape face; - TopoDS_Wire wire, section; - - if (!l->ReferenceSurface()->declaration().is(IfcSchema::IfcPlane::Class())) { - Logger::Message(Logger::LOG_WARNING, "Reference surface not supported", l->ReferenceSurface()); - return false; - } - - gp_Trsf trsf; - bool has_position = true; -#ifdef SCHEMA_IfcSweptAreaSolid_Position_IS_OPTIONAL - has_position = l->hasPosition(); -#endif - if (has_position) { - IfcGeom::Kernel::convert(l->Position(), trsf); - } - - if (!convert_face(l->SweptArea(), face) || - !convert_wire(l->Directrix(), wire) ) { - return false; - } - - gp_Pln pln; - gp_Pnt directrix_origin; - gp_Vec directrix_tangent; - bool directrix_on_plane = true; - IfcGeom::Kernel::convert((IfcSchema::IfcPlane*) l->ReferenceSurface(), pln); - - // As per Informal propositions 2: The Directrix shall lie on the ReferenceSurface. - // This is not always the case with the test files in the repository. I am not sure - // how to deal with this and whether my interpretation of the propositions is - // correct. However, if it has been asserted that the vertices of the directrix do - // not conform to the ReferenceSurface, the ReferenceSurface is ignored. - { - for (TopExp_Explorer exp(wire, TopAbs_VERTEX); exp.More(); exp.Next()) { - if (pln.Distance(BRep_Tool::Pnt(TopoDS::Vertex(exp.Current()))) > ALMOST_ZERO) { - directrix_on_plane = false; - Logger::Message(Logger::LOG_WARNING, "The Directrix does not lie on the ReferenceSurface", l); - break; - } - } - } - - { - TopExp_Explorer exp(wire, TopAbs_EDGE); - TopoDS_Edge edge = TopoDS::Edge(exp.Current()); - double u0, u1; - Handle(Geom_Curve) crv = BRep_Tool::Curve(edge, u0, u1); - crv->D1(u0, directrix_origin, directrix_tangent); - } - - if (pln.Axis().Direction().IsNormal(directrix_tangent, Precision::Approximation()) && directrix_on_plane) { - directrix.SetTransformation(gp_Ax3(directrix_origin, directrix_tangent, pln.Axis().Direction()), gp::XOY()); - } else { - directrix.SetTransformation(gp_Ax3(directrix_origin, directrix_tangent), gp::XOY()); - } - face = BRepBuilderAPI_Transform(face, directrix); - - // NB: Note that StartParam and EndParam param are ignored and the assumption is - // made that the parametric range over which to be swept matches the IfcCurve in - // its entirety. - BRepOffsetAPI_MakePipeShell builder(wire); - - { TopExp_Explorer exp(face, TopAbs_WIRE); - section = TopoDS::Wire(exp.Current()); } - - builder.Add(section); - builder.SetTransitionMode(BRepBuilderAPI_RightCorner); - if (directrix_on_plane) { - builder.SetMode(pln.Axis().Direction()); - } - builder.Build(); - builder.MakeSolid(); - shape = builder.Shape(); - - if (has_position) { - // IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D - // and therefore has a unit scale factor - shape.Move(trsf); - } - - return true; -} - -namespace { - bool wire_is_c1_continuous(const TopoDS_Wire& w, double tol) { - // NB Note that c0 continuity is NOT checked! - - TopTools_IndexedDataMapOfShapeListOfShape map; - TopExp::MapShapesAndAncestors(w, TopAbs_VERTEX, TopAbs_EDGE, map); - for (int i = 1; i <= map.Extent(); ++i) { - const auto& li = map.FindFromIndex(i); - if (li.Extent() == 2) { - const TopoDS_Vertex& v = TopoDS::Vertex(map.FindKey(i)); - - const TopoDS_Edge& e0 = TopoDS::Edge(li.First()); - const TopoDS_Edge& e1 = TopoDS::Edge(li.Last()); - - double u0 = BRep_Tool::Parameter(v, e0); - double u1 = BRep_Tool::Parameter(v, e1); - - double _, __; - Handle(Geom_Curve) c0 = BRep_Tool::Curve(e0, _, __); - Handle(Geom_Curve) c1 = BRep_Tool::Curve(e1, _, __); - - gp_Pnt p; - gp_Vec v0, v1; - c0->D1(u0, p, v0); - c1->D1(u1, p, v1); - - if (1. - std::abs(v0.Normalized().Dot(v1.Normalized())) > tol) { - return false; - } - } - } - return true; - } -} - -bool IfcGeom::Kernel::convert(const IfcSchema::IfcSweptDiskSolid* l, TopoDS_Shape& shape) { - TopoDS_Wire wire, section1, section2; - - bool hasInnerRadius = l->hasInnerRadius(); - - if (!convert_wire(l->Directrix(), wire)) { - return false; - } - - gp_Ax2 directrix; - { - gp_Pnt directrix_origin; - gp_Vec directrix_tangent; - - TopoDS_Edge edge; - - // Find first edge - TopoDS_Vertex v0, v1; - TopExp::Vertices(wire, v0, v1); - TopTools_IndexedDataMapOfShapeListOfShape map; - TopExp::MapShapesAndAncestors(wire, TopAbs_VERTEX, TopAbs_EDGE, map); - if (map.Contains(v0) && map.FindFromKey(v0).Extent() == 1) { - edge = TopoDS::Edge(map.FindFromKey(v0).First()); - } else { - Logger::Error("Unable to locate first edge of:", l->Directrix()); - return false; - } - - double u0, u1; - Handle(Geom_Curve) crv = BRep_Tool::Curve(edge, u0, u1); - crv->D1(u0, directrix_origin, directrix_tangent); - directrix = gp_Ax2(directrix_origin, directrix_tangent); - } - - const double r1 = l->Radius() * getValue(GV_LENGTH_UNIT); - Handle(Geom_Circle) circle = new Geom_Circle(directrix, r1); - section1 = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(circle)); - - if (hasInnerRadius) { - const double r2 = l->InnerRadius() * getValue(GV_LENGTH_UNIT); - if (r2 < getValue(GV_PRECISION)) { - // Subtraction of pipes with small radii is unstable. - hasInnerRadius = false; - } else { - Handle(Geom_Circle) circle2 = new Geom_Circle(directrix, r2); - section2 = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(circle2)); - } - } - - // This is not used anymore, BRepBuilderAPI_RightCorner is always used now. - // const bool is_continuous = wire_is_c1_continuous(wire, 1.e-3); - - // NB: Note that StartParam and EndParam param are ignored and the assumption is - // made that the parametric range over which to be swept matches the IfcCurve in - // its entirety. - { BRepOffsetAPI_MakePipeShell builder(wire); - builder.Add(section1); - builder.SetTransitionMode(BRepBuilderAPI_RightCorner); - builder.Build(); - builder.MakeSolid(); - shape = builder.Shape(); } - - if (hasInnerRadius) { - BRepOffsetAPI_MakePipeShell builder(wire); - builder.Add(section2); - builder.SetTransitionMode(BRepBuilderAPI_RightCorner); - builder.Build(); - builder.MakeSolid(); - TopoDS_Shape inner = builder.Shape(); - - BRepAlgoAPI_Cut brep_cut(shape, inner); - bool is_valid = false; - if (brep_cut.IsDone()) { - TopoDS_Shape result = brep_cut; - - ShapeFix_Shape fix(result); - fix.Perform(); - result = fix.Shape(); - - is_valid = BRepCheck_Analyzer(result).IsValid() != 0; - if (is_valid) { - shape = result; - } - } - - if (!is_valid) { - Logger::Message(Logger::LOG_WARNING, "Failed to subtract inner radius void for:", l); - } - } - - return true; -} - -#ifdef SCHEMA_HAS_IfcCylindricalSurface - -bool IfcGeom::Kernel::convert(const IfcSchema::IfcCylindricalSurface* l, TopoDS_Shape& face) { - gp_Trsf trsf; - IfcGeom::Kernel::convert(l->Position(),trsf); - - // IfcElementarySurface.Position has unit scale factor -#if OCC_VERSION_HEX < 0x60502 - face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius() * getValue(GV_LENGTH_UNIT))).Face().Moved(trsf); -#else - face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius() * getValue(GV_LENGTH_UNIT)), getValue(GV_PRECISION)).Face().Moved(trsf); -#endif - return true; -} - -#endif - -#ifdef SCHEMA_HAS_IfcAdvancedBrep - -bool IfcGeom::Kernel::convert(const IfcSchema::IfcAdvancedBrep* l, TopoDS_Shape& shape) { - return convert(l->Outer(), shape); -} - -#endif - -#ifdef SCHEMA_HAS_IfcTriangulatedFaceSet - -bool IfcGeom::Kernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, TopoDS_Shape& shape) { - IfcSchema::IfcCartesianPointList3D* point_list = l->Coordinates(); - const std::vector< std::vector > coordinates = point_list->CoordList(); - std::vector points; - points.reserve(coordinates.size()); - for (std::vector< std::vector >::const_iterator it = coordinates.begin(); it != coordinates.end(); ++it) { - const std::vector& coords = *it; - if (coords.size() != 3) { - Logger::Message(Logger::LOG_ERROR, "Invalid dimensions encountered on Coordinates", l); - return false; - } - points.push_back(gp_Pnt(coords[0] * getValue(GV_LENGTH_UNIT), - coords[1] * getValue(GV_LENGTH_UNIT), - coords[2] * getValue(GV_LENGTH_UNIT))); - } - - std::vector< std::vector > indices = l->CoordIndex(); - - std::vector faces; - faces.reserve(indices.size()); - - for(std::vector< std::vector >::const_iterator it = indices.begin(); it != indices.end(); ++ it) { - const std::vector& tri = *it; - if (tri.size() != 3) { - Logger::Message(Logger::LOG_ERROR, "Invalid dimensions encountered on CoordIndex", l); - return false; - } - - const int min_index = *std::min_element(tri.begin(), tri.end()); - const int max_index = *std::max_element(tri.begin(), tri.end()); - - if (min_index < 1 || max_index > (int) points.size()) { - Logger::Message(Logger::LOG_ERROR, "Contents of CoordIndex out of bounds", l); - return false; - } - - const gp_Pnt& a = points[tri[0] - 1]; // account for zero- vs - const gp_Pnt& b = points[tri[1] - 1]; // one-based indices in - const gp_Pnt& c = points[tri[2] - 1]; // c++ and express - - TopoDS_Wire wire = BRepBuilderAPI_MakePolygon(a, b, c, true).Wire(); - TopoDS_Face face = BRepBuilderAPI_MakeFace(wire).Face(); - - TopoDS_Iterator face_it(face, false); - const TopoDS_Wire& w = TopoDS::Wire(face_it.Value()); - const bool reversed = w.Orientation() == TopAbs_REVERSED; - if (reversed) { - face.Reverse(); - } - - if (face_area(face) > getValue(GV_MINIMAL_FACE_AREA)) { - faces.push_back(face); - } - } - - if (faces.empty()) return false; - - bool valid_shell = false; - - // @todo Do this more efficiently by creating proper half-edge pairs. - BRepOffsetAPI_Sewing sewing_builder; - sewing_builder.SetTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE)); - sewing_builder.SetMaxTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE)); - sewing_builder.SetMinTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE)); - - for (std::vector::const_iterator it = faces.begin(); it != faces.end(); ++it) { - sewing_builder.Add(*it); - } - - try { - sewing_builder.Perform(); - shape = sewing_builder.SewedShape(); - valid_shell = BRepCheck_Analyzer(shape).IsValid(); - } catch(...) {} - - if (valid_shell) { - try { - ShapeFix_Solid solid; - solid.LimitTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE)); - TopoDS_Solid solid_shape = solid.SolidFromShell(TopoDS::Shell(shape)); - if (!solid_shape.IsNull()) { - try { - BRepClass3d_SolidClassifier classifier(solid_shape); - shape = solid_shape; - } catch (...) {} - } - } catch(...) {} - } else { - Logger::Message(Logger::LOG_WARNING, "Failed to sew faceset:", l); - } - - if (!valid_shell) { - TopoDS_Compound compound; - BRep_Builder builder; - builder.MakeCompound(compound); - - for (std::vector::const_iterator it = faces.begin(); it != faces.end(); ++it) { - builder.Add(compound, *it); - } - - shape = compound; - } - - return true; -} - -#endif diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp_ b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp_ new file mode 100644 index 0000000000..5001639a6d --- /dev/null +++ b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp_ @@ -0,0 +1,1289 @@ +/******************************************************************************** + * * + * 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 . * + * * + ********************************************************************************/ + +/******************************************************************************** + * * + * Implementations of the various conversion functions defined in IfcRegister.h * + * * + ********************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include + +#include + +#include "../../../ifcgeom/kernels/opencascade/IfcGeom.h" + +#include + +#define Kernel POSTFIX_SCHEMA(Kernel) + +bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolid* l, TopoDS_Shape& shape) { + const double height = l->Depth() * getValue(GV_LENGTH_UNIT); + if (height < getValue(GV_PRECISION)) { + Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", l); + return false; + } + + TopoDS_Shape face; + if ( !convert_face(l->SweptArea(),face) ) return false; + + gp_Trsf trsf; + bool has_position = true; +#ifdef SCHEMA_IfcSweptAreaSolid_Position_IS_OPTIONAL + has_position = l->hasPosition(); +#endif + if (has_position) { + IfcGeom::Kernel::convert(l->Position(), trsf); + } + + gp_Dir dir; + convert(l->ExtrudedDirection(),dir); + + shape.Nullify(); + + if (face.ShapeType() == TopAbs_COMPOUND) { + + // For compounds (most likely the result of a IfcCompositeProfileDef) + // create a compound solid shape. + + TopExp_Explorer exp(face, TopAbs_FACE); + + TopoDS_CompSolid compound; + BRep_Builder builder; + builder.MakeCompSolid(compound); + + int num_faces_extruded = 0; + for (; exp.More(); exp.Next(), ++num_faces_extruded) { + builder.Add(compound, BRepPrimAPI_MakePrism(exp.Current(), height*dir)); + } + + if (num_faces_extruded) { + shape = compound; + } + + } + + if (shape.IsNull()) { + shape = BRepPrimAPI_MakePrism(face, height*dir); + } + + if (has_position && !shape.IsNull()) { + // IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D + // and therefore has a unit scale factor + shape.Move(trsf); + } + + return !shape.IsNull(); +} + +#ifdef SCHEMA_HAS_IfcExtrudedAreaSolidTapered +bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* l, TopoDS_Shape& shape) { + const double height = l->Depth() * getValue(GV_LENGTH_UNIT); + if (height < getValue(GV_PRECISION)) { + Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", l); + return false; + } + + TopoDS_Shape face1, face2; + if (!convert_face(l->SweptArea(), face1)) return false; + if (!convert_face(l->EndSweptArea(), face2)) return false; + + gp_Trsf trsf; + bool has_position = true; +#ifdef SCHEMA_IfcSweptAreaSolid_Position_IS_OPTIONAL + has_position = l->hasPosition(); +#endif + if (has_position) { + IfcGeom::Kernel::convert(l->Position(), trsf); + } + + gp_Dir dir; + convert(l->ExtrudedDirection(), dir); + + gp_Trsf end_profile; + end_profile.SetTranslation(height * dir); + + TopoDS_Edge spine_edge = BRepBuilderAPI_MakeEdge(gp_Pnt(), gp_Pnt((height * dir).XYZ())).Edge(); + TopoDS_Wire wire = BRepBuilderAPI_MakeWire(spine_edge).Wire(); + + shape.Nullify(); + + TopExp_Explorer exp1(face1, TopAbs_WIRE); + TopExp_Explorer exp2(face2, TopAbs_WIRE); + + TopoDS_Vertex v1, v2; + TopExp::Vertices(wire, v1, v2); + + TopoDS_Shape shell; + TopoDS_Compound compound; + BRep_Builder compound_builder; + + for (; exp1.More() && exp2.More(); exp1.Next(), exp2.Next()) { + const TopoDS_Wire& w1 = TopoDS::Wire(exp1.Current()); + const TopoDS_Wire& w2 = TopoDS::Wire(exp2.Current()); + + BRepOffsetAPI_MakePipeShell builder(wire); + builder.Add(w1, v1); + builder.Add(w2.Moved(end_profile), v2); + + TopoDS_Shape result = builder.Shape(); + + BRepOffsetAPI_Sewing sewer; + sewer.SetTolerance(getValue(GV_PRECISION)); + sewer.SetMaxTolerance(getValue(GV_PRECISION)); + sewer.SetMinTolerance(getValue(GV_PRECISION)); + + sewer.Add(result); + sewer.Add(BRepBuilderAPI_MakeFace(w1).Face()); + sewer.Add(BRepBuilderAPI_MakeFace(w2).Face().Moved(end_profile)); + + sewer.Perform(); + + result = sewer.SewedShape(); + + if (shell.IsNull()) { + shell = result; + } else if (l->SweptArea()->declaration().is(IfcSchema::IfcCircleHollowProfileDef::Class()) || + l->SweptArea()->declaration().is(IfcSchema::IfcRectangleHollowProfileDef::Class())) + { + /// @todo a bit of of a hack, should be sufficient + shell = BRepAlgoAPI_Cut(shell, result).Shape(); + break; + } else { + if (compound.IsNull()) { + compound_builder.MakeCompound(compound); + compound_builder.Add(compound, shell); + } + compound_builder.Add(compound, result); + } + } + + if (!compound.IsNull()) { + shell = compound; + } + + shape = shell; + + if (exp1.More() != exp2.More()) { + Logger::Message(Logger::LOG_ERROR, "Inconsistent profiles encountered for:", l); + } + + if (has_position && !shape.IsNull()) { + // IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D + // and therefore has a unit scale factor + shape.Move(trsf); + } + + return !shape.IsNull(); +} +#endif + +bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfLinearExtrusion* l, TopoDS_Shape& shape) { + TopoDS_Wire wire; + if ( !convert_wire(l->SweptCurve(), wire) ) { + TopoDS_Face face; + if ( !convert_face(l->SweptCurve(),face) ) return false; + TopExp_Explorer exp(face, TopAbs_WIRE); + wire = TopoDS::Wire(exp.Current()); + } + const double height = l->Depth() * getValue(GV_LENGTH_UNIT); + + gp_Trsf trsf; + bool has_position = true; +#ifdef SCHEMA_IfcSweptSurface_Position_IS_OPTIONAL + has_position = l->hasPosition(); +#endif + if (has_position) { + IfcGeom::Kernel::convert(l->Position(), trsf); + } + + gp_Dir dir; + convert(l->ExtrudedDirection(),dir); + + shape = BRepPrimAPI_MakePrism(wire, height*dir); + + if (has_position) { + // IfcSweptSurface.Position (trsf) is an IfcAxis2Placement3D + // and therefore has a unit scale factor + shape.Move(trsf); + } + + return !shape.IsNull(); +} + +bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfRevolution* l, TopoDS_Shape& shape) { + TopoDS_Wire wire; + if ( !convert_wire(l->SweptCurve(), wire) ) { + TopoDS_Face face; + if ( !convert_face(l->SweptCurve(),face) ) return false; + TopExp_Explorer exp(face, TopAbs_WIRE); + wire = TopoDS::Wire(exp.Current()); + } + + gp_Ax1 ax1; + IfcGeom::Kernel::convert(l->AxisPosition(), ax1); + + gp_Trsf trsf; + bool has_position = true; +#ifdef SCHEMA_IfcSweptSurface_Position_IS_OPTIONAL + has_position = l->hasPosition(); +#endif + if (has_position) { + IfcGeom::Kernel::convert(l->Position(), trsf); + } + + shape = BRepPrimAPI_MakeRevol(wire, ax1); + + if (has_position) { + // IfcSweptSurface.Position (trsf) is an IfcAxis2Placement3D + // and therefore has a unit scale factor + shape.Move(trsf); + } + + return !shape.IsNull(); +} + +bool IfcGeom::Kernel::convert(const IfcSchema::IfcRevolvedAreaSolid* l, TopoDS_Shape& shape) { + const double ang = l->Angle() * getValue(GV_PLANEANGLE_UNIT); + + TopoDS_Face face; + if ( ! convert_face(l->SweptArea(),face) ) return false; + + gp_Ax1 ax1; + IfcGeom::Kernel::convert(l->Axis(), ax1); + + gp_Trsf trsf; + bool has_position = true; +#ifdef SCHEMA_IfcSweptAreaSolid_Position_IS_OPTIONAL + has_position = l->hasPosition(); +#endif + if (has_position) { + IfcGeom::Kernel::convert(l->Position(), trsf); + } + + if (ang >= M_PI * 2. - ALMOST_ZERO) { + shape = BRepPrimAPI_MakeRevol(face, ax1); + } else { + shape = BRepPrimAPI_MakeRevol(face, ax1, ang); + } + + if (has_position) { + // IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D + // and therefore has a unit scale factor + shape.Move(trsf); + } + + return !shape.IsNull(); +} + +bool IfcGeom::Kernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, ConversionResults& shape) { + TopoDS_Shape s; + const SurfaceStyle* collective_style = get_style(l); + if (convert_shape(l->Outer(),s) ) { + const SurfaceStyle* indiv_style = get_style(l->Outer()); + + IfcSchema::IfcClosedShell::list::ptr voids(new IfcSchema::IfcClosedShell::list); + if (l->declaration().is(IfcSchema::IfcFacetedBrepWithVoids::Class())) { + voids = l->as()->Voids(); + } +#ifdef SCHEMA_HAS_IfcAdvancedBrepWithVoids + if (l->declaration().is(IfcSchema::IfcAdvancedBrepWithVoids::Class())) { + voids = l->as()->Voids(); + } +#endif + + for (IfcSchema::IfcClosedShell::list::it it = voids->begin(); it != voids->end(); ++it) { + TopoDS_Shape s2; + /// @todo No extensive shapefixing since shells should be disjoint. + /// @todo Awaiting generalized boolean ops module with appropriate checking + if (convert_shape(l->Outer(), s2)) { + s = BRepAlgoAPI_Cut(s, s2).Shape(); + } + } + + shape.push_back(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, 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 ) { + TopoDS_Shape s; + const SurfaceStyle* shell_style = get_style(*it); + if (convert_shape(*it,s)) { + shapes.push_back(ConversionResult(l->data().id(), new OpenCascadeShape(s), shell_style ? shell_style : collective_style)); + part_success |= true; + } + } + return part_success; +} + +bool IfcGeom::Kernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, TopoDS_Shape& shape) { + IfcSchema::IfcSurface* surface = l->BaseSurface(); + if ( ! surface->declaration().is(IfcSchema::IfcPlane::Class()) ) { + Logger::Message(Logger::LOG_ERROR, "Unsupported BaseSurface:", surface); + return false; + } + gp_Pln pln; + IfcGeom::Kernel::convert((IfcSchema::IfcPlane*)surface,pln); + const gp_Pnt pnt = pln.Location().Translated( l->AgreementFlag() ? -pln.Axis().Direction() : pln.Axis().Direction()); + shape = BRepPrimAPI_MakeHalfSpace(BRepBuilderAPI_MakeFace(pln),pnt).Solid(); + return true; +} + +bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace* l, TopoDS_Shape& shape) { + TopoDS_Shape halfspace; + if ( ! IfcGeom::Kernel::convert((IfcSchema::IfcHalfSpaceSolid*)l,halfspace) ) return false; + + TopoDS_Wire wire; + if ( ! convert_wire(l->PolygonalBoundary(),wire) || ! wire.Closed() ) return false; + + gp_Trsf trsf; + if ( ! convert(l->Position(),trsf) ) return false; + + TColgp_SequenceOfPnt points; + if (wire_to_sequence_of_point(wire, points)) { + // Boolean subtractions not very robust for narrow operands, + // increase minimal point spacing to eliminate such shapes. + const double t = getValue(GV_PRECISION) * 10.; + remove_duplicate_points_from_loop(points, wire.Closed() != 0, t); // Note: wire always closed, as per if statement above + remove_collinear_points_from_loop(points, wire.Closed() != 0, t); + if (points.Length() < 3) { + Logger::Message(Logger::LOG_ERROR, "Not enough points retained from:", l->PolygonalBoundary()); + return false; + } + sequence_of_point_to_wire(points, wire, wire.Closed() != 0); + } + + TopoDS_Shape prism = BRepPrimAPI_MakePrism(BRepBuilderAPI_MakeFace(wire),gp_Vec(0,0,200)); + gp_Trsf down; down.SetTranslation(gp_Vec(0,0,-100.0)); + + // `trsf` and `down` both have a unit scale factor + prism.Move(trsf*down); + + shape = BRepAlgoAPI_Common(halfspace,prism); + return true; +} + +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 ) { + TopoDS_Shape s; + const SurfaceStyle* shell_style = 0; + if ((*it)->declaration().is(IfcSchema::IfcRepresentationItem::Class())) { + shell_style = get_style((IfcSchema::IfcRepresentationItem*)*it); + } + if (convert_shape(*it,s)) { + shapes.push_back(ConversionResult(l->data().id(), new OpenCascadeShape(s), shell_style ? shell_style : collective_style)); + } + } + return true; +} + +bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape& shape) { + + TopoDS_Shape s1, s2; + ConversionResults items1; + TopoDS_Wire boundary_wire; + IfcSchema::IfcBooleanOperand* operand1 = l->FirstOperand(); + IfcSchema::IfcBooleanOperand* operand2 = l->SecondOperand(); + bool has_halfspace_operand = false; + + BOPAlgo_Operation occ_op; + + const IfcSchema::IfcBooleanOperator::Value op = l->Operator(); + if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) { + occ_op = BOPAlgo_CUT; + } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) { + occ_op = BOPAlgo_COMMON; + } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) { + occ_op = BOPAlgo_FUSE; + } else { + return false; + } + + std::vector second_operands; + second_operands.push_back(operand2); + + if (occ_op == BOPAlgo_CUT) { + bool process_as_list = true; + while (true) { + auto res1 = operand1->as(); + if (res1) { + if (res1->Operator() == op) { + operand1 = res1->FirstOperand(); + second_operands.push_back(res1->SecondOperand()); + } else { + process_as_list = false; + break; + } + } else { + break; + } + } + + if (!process_as_list) { + operand1 = l->FirstOperand(); + second_operands = { operand2 }; + } + } + + if ( shape_type(operand1) == ST_SHAPELIST ) { + 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; + } + { TopoDS_Solid temp_solid; + s1 = ensure_fit_for_subtraction(s1, temp_solid); } + } else { + Logger::Message(Logger::LOG_ERROR, "Invalid representation item for boolean operation", operand1); + return false; + } + + const double first_operand_volume = shape_volume(s1); + if (first_operand_volume <= ALMOST_ZERO) { + Logger::Message(Logger::LOG_WARNING, "Empty solid for:", l->FirstOperand()); + } + + TopTools_ListOfShape second_operand_shapes; + + for (auto& op2 : second_operands) { + TopoDS_Shape s2; + + bool shape2_processed = false; + + bool is_halfspace = op2->declaration().is(IfcSchema::IfcHalfSpaceSolid::Class()); + bool is_unbounded_halfspace = is_halfspace && !op2->declaration().is(IfcSchema::IfcPolygonalBoundedHalfSpace::Class()); + has_halfspace_operand |= is_halfspace; + + { + if (shape_type(op2) == ST_SHAPELIST) { + 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); + if (shape2_processed) { + TopoDS_Solid temp_solid; + s2 = ensure_fit_for_subtraction(s2, temp_solid); + } + } else { + Logger::Message(Logger::LOG_ERROR, "Invalid representation item for boolean operation", op2); + } + } + + if (is_unbounded_halfspace) { + TopoDS_Shape temp; + double d; + if (fit_halfspace(s1, s2, temp, d)) { + if (d < getValue(GV_PRECISION)) { + Logger::Message(Logger::LOG_WARNING, "Halfspace subtraction yields unchanged volume:", l); + continue; + } else { + s2 = temp; + } + } + } + + if (!shape2_processed) { + Logger::Message(Logger::LOG_ERROR, "Failed to convert SecondOperand:", op2); + continue; + } + + if (op2->declaration().is(IfcSchema::IfcHalfSpaceSolid::Class())) { + const double second_operand_volume = shape_volume(s2); + if (second_operand_volume <= ALMOST_ZERO) { + Logger::Message(Logger::LOG_WARNING, "Empty solid for:", op2); + } + } + + second_operand_shapes.Append(s2); + } + + /* + // TK: A little debugging trick to output both operands for visual inspection + + BRep_Builder builder; + TopoDS_Compound compound; + builder.MakeCompound(compound); + builder.Add(compound, s1); + for (const auto& s2 : second_operand_shapes) { + builder.Add(compound, s2); + } + shape = compound; + return true; + */ + +#if OCC_VERSION_HEX < 0x60900 + // @todo: this currently does not compile anymore, do we still need this? + bool valid_result = boolean_operation(s1, s2, occ_op, shape); +#else + bool valid_result = boolean_operation(s1, second_operand_shapes, occ_op, shape); +#endif + + if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) { + // In case of a subtraction, a check on volume is performed. + if (valid_result) { + const double volume_after_subtraction = shape_volume(shape); + if ( ALMOST_THE_SAME(first_operand_volume,volume_after_subtraction) ) + Logger::Message(Logger::LOG_WARNING,"Subtraction yields unchanged volume:",l); + } else { + Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",l); + shape = s1; + } + // NB: After issuing error the first operand is returned! + return true; + } else { + return valid_result; + } + return false; +} + +bool IfcGeom::Kernel::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Shape& shape) { + std::unique_ptr helper_scope; + helper_scope.reset(new faceset_helper(this, l)); + + IfcSchema::IfcFace::list::ptr faces = l->CfsFaces(); + + double min_face_area = faceset_helper_ + ? (faceset_helper_->epsilon() * faceset_helper_->epsilon() / 20.) + : getValue(GV_MINIMAL_FACE_AREA); + + TopTools_ListOfShape face_list; + for (IfcSchema::IfcFace::list::it it = faces->begin(); it != faces->end(); ++it) { + bool success = false; + TopoDS_Face face; + + try { + success = convert_face(*it, face); + } catch (const std::exception& e) { + Logger::Error(e); + } catch (const Standard_Failure& e) { + if (e.GetMessageString() && strlen(e.GetMessageString())) { + Logger::Error(e.GetMessageString()); + } else { + Logger::Error("Unknown error creating face"); + } + } catch (...) { + Logger::Error("Unknown error creating face"); + } + + if (!success) { + Logger::Message(Logger::LOG_WARNING, "Failed to convert face:", (*it)); + continue; + } + + if (face.ShapeType() == TopAbs_COMPOUND) { + TopoDS_Iterator face_it(face, false); + for (; face_it.More(); face_it.Next()) { + if (face_it.Value().ShapeType() == TopAbs_FACE) { + // This should really be the case. This is not asserted. + const TopoDS_Face& triangle = TopoDS::Face(face_it.Value()); + if (face_area(triangle) > min_face_area) { + face_list.Append(triangle); + } else { + Logger::Message(Logger::LOG_WARNING, "Degenerate face:", (*it)); + } + } + } + } else { + if (face_area(face) > min_face_area) { + face_list.Append(face); + } else { + Logger::Message(Logger::LOG_WARNING, "Degenerate face:", (*it)); + } + } + } + + if (face_list.Extent() == 0) { + return false; + } + + if (face_list.Extent() > getValue(GV_MAX_FACES_TO_ORIENT) || !create_solid_from_faces(face_list, shape)) { + TopoDS_Compound compound; + BRep_Builder builder; + builder.MakeCompound(compound); + + TopTools_ListIteratorOfListOfShape face_iterator; + for (face_iterator.Initialize(face_list); face_iterator.More(); face_iterator.Next()) { + builder.Add(compound, face_iterator.Value()); + } + shape = compound; + } + + return true; +} + +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()) ) { + IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator3DnonUniform*)transform,gtrsf); + } else if ( transform->declaration().is(IfcSchema::IfcCartesianTransformationOperator2DnonUniform::Class()) ) { + Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform); + return false; + } else if ( transform->declaration().is(IfcSchema::IfcCartesianTransformationOperator3D::Class()) ) { + gp_Trsf trsf; + IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,trsf); + gtrsf = trsf; + } else if ( transform->declaration().is(IfcSchema::IfcCartesianTransformationOperator2D::Class()) ) { + gp_Trsf2d trsf_2d; + IfcGeom::Kernel::convert((IfcSchema::IfcCartesianTransformationOperator2D*)transform,trsf_2d); + gtrsf = (gp_Trsf) trsf_2d; + } + IfcSchema::IfcRepresentationMap* map = l->MappingSource(); + IfcSchema::IfcAxis2Placement* placement = map->MappingOrigin(); + gp_Trsf trsf; + if (placement->declaration().is(IfcSchema::IfcAxis2Placement3D::Class())) { + IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf); + } else { + gp_Trsf2d trsf_2d; + IfcGeom::Kernel::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf_2d); + trsf = trsf_2d; + } + gtrsf.Multiply(trsf); + + 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 ) { + 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 + if (!shapes[i].hasStyle()) { + shapes[i].setStyle(mapped_item_style); + } + } + + return b; +} + +bool IfcGeom::Kernel::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 { + TopoDS_Shape s; + if (convert_shape(representation_item,s)) { + shapes.push_back(ConversionResult(representation_item->data().id(), new OpenCascadeShape(s), get_style(representation_item))); + part_succes |= true; + } + } + } + } + return part_succes; +} + +bool IfcGeom::Kernel::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; + TopoDS_Shape s; + if (convert_shape(element, s)) { + part_succes = true; + const IfcGeom::SurfaceStyle* style = 0; + if (element->declaration().is(IfcSchema::IfcPoint::Class())) { + style = get_style((IfcSchema::IfcPoint*) element); + } else if (element->declaration().is(IfcSchema::IfcCurve::Class())) { + style = get_style((IfcSchema::IfcCurve*) element); + } else if (element->declaration().is(IfcSchema::IfcSurface::Class())) { + style = get_style((IfcSchema::IfcSurface*) element); + } + shapes.push_back(ConversionResult(l->data().id(), new OpenCascadeShape(s), style ? style : parent_style)); + } + } + return part_succes; +} + +bool IfcGeom::Kernel::convert(const IfcSchema::IfcBlock* l, TopoDS_Shape& 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); + + BRepPrimAPI_MakeBox builder(dx, dy, dz); + gp_Trsf trsf; + IfcGeom::Kernel::convert(l->Position(),trsf); + + // IfcCsgPrimitive3D.Position has unit scale factor + shape = builder.Solid().Moved(trsf); + + return true; +} + +bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangularPyramid* l, TopoDS_Shape& 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); + + BRepPrimAPI_MakeWedge builder(dx, dz, dy, dx / 2., dy / 2., dx / 2., dy / 2.); + + gp_Trsf trsf1, trsf2; + trsf2.SetValues( + 1, 0, 0, 0, + 0, 0, 1, 0, + 0, 1, 0, 0 +#if OCC_VERSION_HEX < 0x60800 + , Precision::Angular(), Precision::Confusion() +#endif + ); + + IfcGeom::Kernel::convert(l->Position(), trsf1); + shape = BRepBuilderAPI_Transform(builder.Solid(), trsf1 * trsf2); + return true; +} + +bool IfcGeom::Kernel::convert(const IfcSchema::IfcRightCircularCylinder* l, TopoDS_Shape& shape) { + const double r = l->Radius() * getValue(GV_LENGTH_UNIT); + const double h = l->Height() * getValue(GV_LENGTH_UNIT); + + BRepPrimAPI_MakeCylinder builder(r, h); + gp_Trsf trsf; + IfcGeom::Kernel::convert(l->Position(),trsf); + + // IfcCsgPrimitive3D.Position has unit scale factor + shape = builder.Solid().Moved(trsf); + + return true; +} + +bool IfcGeom::Kernel::convert(const IfcSchema::IfcRightCircularCone* l, TopoDS_Shape& shape) { + const double r = l->BottomRadius() * getValue(GV_LENGTH_UNIT); + const double h = l->Height() * getValue(GV_LENGTH_UNIT); + + BRepPrimAPI_MakeCone builder(r, 0., h); + gp_Trsf trsf; + IfcGeom::Kernel::convert(l->Position(),trsf); + + // IfcCsgPrimitive3D.Position has unit scale factor + shape = builder.Solid().Moved(trsf); + + return true; +} + +bool IfcGeom::Kernel::convert(const IfcSchema::IfcSphere* l, TopoDS_Shape& shape) { + const double r = l->Radius() * getValue(GV_LENGTH_UNIT); + + BRepPrimAPI_MakeSphere builder(r); + gp_Trsf trsf; + IfcGeom::Kernel::convert(l->Position(),trsf); + + // IfcCsgPrimitive3D.Position has unit scale factor + shape = builder.Solid().Moved(trsf); + + return true; +} + +bool IfcGeom::Kernel::convert(const IfcSchema::IfcCsgSolid* l, TopoDS_Shape& shape) { + return convert_shape(l->TreeRootExpression(), shape); +} + +bool IfcGeom::Kernel::convert(const IfcSchema::IfcCurveBoundedPlane* l, TopoDS_Shape& face) { + gp_Pln pln; + if (!IfcGeom::Kernel::convert(l->BasisSurface(), pln)) { + return false; + } + + gp_Trsf trsf; + trsf.SetTransformation(pln.Position(), gp::XOY()); + + TopoDS_Wire outer; + if (!convert_wire(l->OuterBoundary(), outer)) { + return false; + } + + BRepBuilderAPI_MakeFace mf(outer); + + if (!mf.IsDone() || mf.Shape().IsNull()) { + Logger::Error("Invalid outer boundary:", l->OuterBoundary()); + return false; + } + + IfcSchema::IfcCurve::list::ptr boundaries = l->InnerBoundaries(); + + for (IfcSchema::IfcCurve::list::it it = boundaries->begin(); it != boundaries->end(); ++it) { + TopoDS_Wire inner; + if (convert_wire(*it, inner)) { + mf.Add(inner); + } + } + + ShapeFix_Shape sfs(mf.Face()); + sfs.Perform(); + + // `trsf` consitutes the placement of the plane and therefore has unit scale factor + face = TopoDS::Face(sfs.Shape()).Moved(trsf); + + return true; +} + +bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangularTrimmedSurface* l, TopoDS_Shape& face) { + if (!l->BasisSurface()->declaration().is(IfcSchema::IfcPlane::Class())) { + Logger::Message(Logger::LOG_ERROR, "Unsupported BasisSurface:", l->BasisSurface()); + return false; + } + gp_Pln pln; + IfcGeom::Kernel::convert((IfcSchema::IfcPlane*) l->BasisSurface(), pln); + + BRepBuilderAPI_MakeFace mf(pln, l->U1(), l->U2(), l->V1(), l->V2()); + + face = mf.Face(); + + return true; +} + +bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l, TopoDS_Shape& shape) { + gp_Trsf directrix; + TopoDS_Shape face; + TopoDS_Wire wire, section; + + if (!l->ReferenceSurface()->declaration().is(IfcSchema::IfcPlane::Class())) { + Logger::Message(Logger::LOG_WARNING, "Reference surface not supported", l->ReferenceSurface()); + return false; + } + + gp_Trsf trsf; + bool has_position = true; +#ifdef SCHEMA_IfcSweptAreaSolid_Position_IS_OPTIONAL + has_position = l->hasPosition(); +#endif + if (has_position) { + IfcGeom::Kernel::convert(l->Position(), trsf); + } + + if (!convert_face(l->SweptArea(), face) || + !convert_wire(l->Directrix(), wire) ) { + return false; + } + + gp_Pln pln; + gp_Pnt directrix_origin; + gp_Vec directrix_tangent; + bool directrix_on_plane = true; + IfcGeom::Kernel::convert((IfcSchema::IfcPlane*) l->ReferenceSurface(), pln); + + // As per Informal propositions 2: The Directrix shall lie on the ReferenceSurface. + // This is not always the case with the test files in the repository. I am not sure + // how to deal with this and whether my interpretation of the propositions is + // correct. However, if it has been asserted that the vertices of the directrix do + // not conform to the ReferenceSurface, the ReferenceSurface is ignored. + { + for (TopExp_Explorer exp(wire, TopAbs_VERTEX); exp.More(); exp.Next()) { + if (pln.Distance(BRep_Tool::Pnt(TopoDS::Vertex(exp.Current()))) > ALMOST_ZERO) { + directrix_on_plane = false; + Logger::Message(Logger::LOG_WARNING, "The Directrix does not lie on the ReferenceSurface", l); + break; + } + } + } + + { + TopExp_Explorer exp(wire, TopAbs_EDGE); + TopoDS_Edge edge = TopoDS::Edge(exp.Current()); + double u0, u1; + Handle(Geom_Curve) crv = BRep_Tool::Curve(edge, u0, u1); + crv->D1(u0, directrix_origin, directrix_tangent); + } + + if (pln.Axis().Direction().IsNormal(directrix_tangent, Precision::Approximation()) && directrix_on_plane) { + directrix.SetTransformation(gp_Ax3(directrix_origin, directrix_tangent, pln.Axis().Direction()), gp::XOY()); + } else { + directrix.SetTransformation(gp_Ax3(directrix_origin, directrix_tangent), gp::XOY()); + } + face = BRepBuilderAPI_Transform(face, directrix); + + // NB: Note that StartParam and EndParam param are ignored and the assumption is + // made that the parametric range over which to be swept matches the IfcCurve in + // its entirety. + BRepOffsetAPI_MakePipeShell builder(wire); + + { TopExp_Explorer exp(face, TopAbs_WIRE); + section = TopoDS::Wire(exp.Current()); } + + builder.Add(section); + builder.SetTransitionMode(BRepBuilderAPI_RightCorner); + if (directrix_on_plane) { + builder.SetMode(pln.Axis().Direction()); + } + builder.Build(); + builder.MakeSolid(); + shape = builder.Shape(); + + if (has_position) { + // IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D + // and therefore has a unit scale factor + shape.Move(trsf); + } + + return true; +} + +namespace { + bool wire_is_c1_continuous(const TopoDS_Wire& w, double tol) { + // NB Note that c0 continuity is NOT checked! + + TopTools_IndexedDataMapOfShapeListOfShape map; + TopExp::MapShapesAndAncestors(w, TopAbs_VERTEX, TopAbs_EDGE, map); + for (int i = 1; i <= map.Extent(); ++i) { + const auto& li = map.FindFromIndex(i); + if (li.Extent() == 2) { + const TopoDS_Vertex& v = TopoDS::Vertex(map.FindKey(i)); + + const TopoDS_Edge& e0 = TopoDS::Edge(li.First()); + const TopoDS_Edge& e1 = TopoDS::Edge(li.Last()); + + double u0 = BRep_Tool::Parameter(v, e0); + double u1 = BRep_Tool::Parameter(v, e1); + + double _, __; + Handle(Geom_Curve) c0 = BRep_Tool::Curve(e0, _, __); + Handle(Geom_Curve) c1 = BRep_Tool::Curve(e1, _, __); + + gp_Pnt p; + gp_Vec v0, v1; + c0->D1(u0, p, v0); + c1->D1(u1, p, v1); + + if (1. - std::abs(v0.Normalized().Dot(v1.Normalized())) > tol) { + return false; + } + } + } + return true; + } +} + +bool IfcGeom::Kernel::convert(const IfcSchema::IfcSweptDiskSolid* l, TopoDS_Shape& shape) { + TopoDS_Wire wire, section1, section2; + + bool hasInnerRadius = l->hasInnerRadius(); + + if (!convert_wire(l->Directrix(), wire)) { + return false; + } + + gp_Ax2 directrix; + { + gp_Pnt directrix_origin; + gp_Vec directrix_tangent; + + TopoDS_Edge edge; + + // Find first edge + TopoDS_Vertex v0, v1; + TopExp::Vertices(wire, v0, v1); + TopTools_IndexedDataMapOfShapeListOfShape map; + TopExp::MapShapesAndAncestors(wire, TopAbs_VERTEX, TopAbs_EDGE, map); + if (map.Contains(v0) && map.FindFromKey(v0).Extent() == 1) { + edge = TopoDS::Edge(map.FindFromKey(v0).First()); + } else { + Logger::Error("Unable to locate first edge of:", l->Directrix()); + return false; + } + + double u0, u1; + Handle(Geom_Curve) crv = BRep_Tool::Curve(edge, u0, u1); + crv->D1(u0, directrix_origin, directrix_tangent); + directrix = gp_Ax2(directrix_origin, directrix_tangent); + } + + const double r1 = l->Radius() * getValue(GV_LENGTH_UNIT); + Handle(Geom_Circle) circle = new Geom_Circle(directrix, r1); + section1 = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(circle)); + + if (hasInnerRadius) { + const double r2 = l->InnerRadius() * getValue(GV_LENGTH_UNIT); + if (r2 < getValue(GV_PRECISION)) { + // Subtraction of pipes with small radii is unstable. + hasInnerRadius = false; + } else { + Handle(Geom_Circle) circle2 = new Geom_Circle(directrix, r2); + section2 = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(circle2)); + } + } + + // This is not used anymore, BRepBuilderAPI_RightCorner is always used now. + // const bool is_continuous = wire_is_c1_continuous(wire, 1.e-3); + + // NB: Note that StartParam and EndParam param are ignored and the assumption is + // made that the parametric range over which to be swept matches the IfcCurve in + // its entirety. + { BRepOffsetAPI_MakePipeShell builder(wire); + builder.Add(section1); + builder.SetTransitionMode(BRepBuilderAPI_RightCorner); + builder.Build(); + builder.MakeSolid(); + shape = builder.Shape(); } + + if (hasInnerRadius) { + BRepOffsetAPI_MakePipeShell builder(wire); + builder.Add(section2); + builder.SetTransitionMode(BRepBuilderAPI_RightCorner); + builder.Build(); + builder.MakeSolid(); + TopoDS_Shape inner = builder.Shape(); + + BRepAlgoAPI_Cut brep_cut(shape, inner); + bool is_valid = false; + if (brep_cut.IsDone()) { + TopoDS_Shape result = brep_cut; + + ShapeFix_Shape fix(result); + fix.Perform(); + result = fix.Shape(); + + is_valid = BRepCheck_Analyzer(result).IsValid() != 0; + if (is_valid) { + shape = result; + } + } + + if (!is_valid) { + Logger::Message(Logger::LOG_WARNING, "Failed to subtract inner radius void for:", l); + } + } + + return true; +} + +#ifdef SCHEMA_HAS_IfcCylindricalSurface + +bool IfcGeom::Kernel::convert(const IfcSchema::IfcCylindricalSurface* l, TopoDS_Shape& face) { + gp_Trsf trsf; + IfcGeom::Kernel::convert(l->Position(),trsf); + + // IfcElementarySurface.Position has unit scale factor +#if OCC_VERSION_HEX < 0x60502 + face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius() * getValue(GV_LENGTH_UNIT))).Face().Moved(trsf); +#else + face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius() * getValue(GV_LENGTH_UNIT)), getValue(GV_PRECISION)).Face().Moved(trsf); +#endif + return true; +} + +#endif + +#ifdef SCHEMA_HAS_IfcAdvancedBrep + +bool IfcGeom::Kernel::convert(const IfcSchema::IfcAdvancedBrep* l, TopoDS_Shape& shape) { + return convert(l->Outer(), shape); +} + +#endif + +#ifdef SCHEMA_HAS_IfcTriangulatedFaceSet + +bool IfcGeom::Kernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, TopoDS_Shape& shape) { + IfcSchema::IfcCartesianPointList3D* point_list = l->Coordinates(); + const std::vector< std::vector > coordinates = point_list->CoordList(); + std::vector points; + points.reserve(coordinates.size()); + for (std::vector< std::vector >::const_iterator it = coordinates.begin(); it != coordinates.end(); ++it) { + const std::vector& coords = *it; + if (coords.size() != 3) { + Logger::Message(Logger::LOG_ERROR, "Invalid dimensions encountered on Coordinates", l); + return false; + } + points.push_back(gp_Pnt(coords[0] * getValue(GV_LENGTH_UNIT), + coords[1] * getValue(GV_LENGTH_UNIT), + coords[2] * getValue(GV_LENGTH_UNIT))); + } + + std::vector< std::vector > indices = l->CoordIndex(); + + std::vector faces; + faces.reserve(indices.size()); + + for(std::vector< std::vector >::const_iterator it = indices.begin(); it != indices.end(); ++ it) { + const std::vector& tri = *it; + if (tri.size() != 3) { + Logger::Message(Logger::LOG_ERROR, "Invalid dimensions encountered on CoordIndex", l); + return false; + } + + const int min_index = *std::min_element(tri.begin(), tri.end()); + const int max_index = *std::max_element(tri.begin(), tri.end()); + + if (min_index < 1 || max_index > (int) points.size()) { + Logger::Message(Logger::LOG_ERROR, "Contents of CoordIndex out of bounds", l); + return false; + } + + const gp_Pnt& a = points[tri[0] - 1]; // account for zero- vs + const gp_Pnt& b = points[tri[1] - 1]; // one-based indices in + const gp_Pnt& c = points[tri[2] - 1]; // c++ and express + + TopoDS_Wire wire = BRepBuilderAPI_MakePolygon(a, b, c, true).Wire(); + TopoDS_Face face = BRepBuilderAPI_MakeFace(wire).Face(); + + TopoDS_Iterator face_it(face, false); + const TopoDS_Wire& w = TopoDS::Wire(face_it.Value()); + const bool reversed = w.Orientation() == TopAbs_REVERSED; + if (reversed) { + face.Reverse(); + } + + if (face_area(face) > getValue(GV_MINIMAL_FACE_AREA)) { + faces.push_back(face); + } + } + + if (faces.empty()) return false; + + bool valid_shell = false; + + // @todo Do this more efficiently by creating proper half-edge pairs. + BRepOffsetAPI_Sewing sewing_builder; + sewing_builder.SetTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE)); + sewing_builder.SetMaxTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE)); + sewing_builder.SetMinTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE)); + + for (std::vector::const_iterator it = faces.begin(); it != faces.end(); ++it) { + sewing_builder.Add(*it); + } + + try { + sewing_builder.Perform(); + shape = sewing_builder.SewedShape(); + valid_shell = BRepCheck_Analyzer(shape).IsValid(); + } catch(...) {} + + if (valid_shell) { + try { + ShapeFix_Solid solid; + solid.LimitTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE)); + TopoDS_Solid solid_shape = solid.SolidFromShell(TopoDS::Shell(shape)); + if (!solid_shape.IsNull()) { + try { + BRepClass3d_SolidClassifier classifier(solid_shape); + shape = solid_shape; + } catch (...) {} + } + } catch(...) {} + } else { + Logger::Message(Logger::LOG_WARNING, "Failed to sew faceset:", l); + } + + if (!valid_shell) { + TopoDS_Compound compound; + BRep_Builder builder; + builder.MakeCompound(compound); + + for (std::vector::const_iterator it = faces.begin(); it != faces.end(); ++it) { + builder.Add(compound, *it); + } + + shape = compound; + } + + return true; +} + +#endif diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomWires.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomWires.cpp_ similarity index 100% rename from src/ifcgeom/kernels/opencascade/IfcGeomWires.cpp rename to src/ifcgeom/kernels/opencascade/IfcGeomWires.cpp_ diff --git a/src/ifcgeom/kernels/opencascade/IfcRegister.cpp b/src/ifcgeom/kernels/opencascade/IfcRegister.cpp_ similarity index 100% rename from src/ifcgeom/kernels/opencascade/IfcRegister.cpp rename to src/ifcgeom/kernels/opencascade/IfcRegister.cpp_ diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h new file mode 100644 index 0000000000..e274fe3ab5 --- /dev/null +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h @@ -0,0 +1,251 @@ +/******************************************************************************** + * * + * 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 . * + * * + ********************************************************************************/ + +#ifndef OPENCASCADEKERNEL_H +#define OPENCASCADEKERNEL_H + +#include + +static const double ALMOST_ZERO = 1.e-9; + +template +inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance=ALMOST_ZERO) { + return fabs(a-b) < tolerance; +} + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../../ifcgeom/kernel_agnostic/AbstractKernel.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 "../../../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h" + +#include "../../../ifcgeom/schema_agnostic/ifc_geom_api.h" + +#include "../../../ifcgeom/taxonomy.h" + +// Define this in case you want to conserve memory usage at all cost. This has been +// benchmarked extensively: https://github.com/IfcOpenShell/IfcOpenShell/pull/47 +// #define NO_CACHE + +#ifdef NO_CACHE + +#define IN_CACHE(T,E,t,e) +#define CACHE(T,E,e) + +#else + +#define IN_CACHE(T,E,t,e) std::map::const_iterator it = cache.T.find(E->data().id());\ +if ( it != cache.T.end() ) { e = it->second; return true; } +#define CACHE(T,E,e) cache.T[E->data().id()] = e; + +#endif + +namespace ifcopenshell { +namespace geometry { +namespace kernels { + + class IFC_GEOM_API geometry_exception : public std::exception { + protected: + std::string message; + public: + geometry_exception(const std::string& m) + : message(m) {} + virtual ~geometry_exception() throw () {} + virtual const char* what() const throw() { + return message.c_str(); + } + }; + + class IFC_GEOM_API too_many_faces_exception : public geometry_exception { + public: + too_many_faces_exception() + : geometry_exception("Too many faces for operation") {} + }; + + /* + class IFC_GEOM_API POSTFIX_SCHEMA(Cache) { + public: +#include "IfcRegisterCreateCache.h" + std::map Shape; + }; + */ + + + class IFC_GEOM_API OpenCascadeKernel : public AbstractKernel { + private: + /* + // faceset_helper traverses the forward instance references of IfcConnectedFaceSet and then provides a mapping + // M of (IfcCartesianPoint, IfcCartesianPoint) -> TopoDS_Edge, where M(a, b) is a partner of M(b, a), ie share + // the same underlying edge but with orientation reversed. This then later speeds op the process of creating a + // manifold Shell / Solid from this set of faces. Only IfcPolyLoop instances are used. Points within the tolerance + // threshiold are merged, so consider points a, b, c, distance(a, b) < eps then M(a, b) = Null, M(a, b) = M(a, c). + class faceset_helper { + private: + OpenCascadeKernel* kernel_; + std::set duplicates_; + std::map vertex_mapping_; + std::map, TopoDS_Edge> edges_; + double eps_; + bool non_manifold_; + + template + void loop_(IfcSchema::IfcCartesianPoint::list::ptr& ps, const Fn& callback) { + if (ps->size() < 3) { + return; + } + + auto a = *(ps->end() - 1); + auto A = a->data().id(); + for (auto& b : *ps) { + auto B = b->data().id(); + auto C = vertex_mapping_[A], D = vertex_mapping_[B]; + bool fwd = C < D; + if (!fwd) { + std::swap(C, D); + } + if (C != D) { + callback(C, D, fwd); + A = B; + } + } + } + public: + faceset_helper(OpenCascadeKernel* kernel, const IfcSchema::IfcConnectedFaceSet* l); + + ~faceset_helper(); + + bool non_manifold() const { return non_manifold_; } + bool& non_manifold() { return non_manifold_; } + + bool edge(const IfcSchema::IfcCartesianPoint* a, const IfcSchema::IfcCartesianPoint* b, TopoDS_Edge& e) { + int A = vertex_mapping_[a->data().id()]; + int B = vertex_mapping_[b->data().id()]; + if (A == B) { + return false; + } + + return edge(A, B, e); + } + + bool edge(int A, int B, TopoDS_Edge& e) { + auto it = edges_.find({ A, B }); + if (it == edges_.end()) { + return false; + } + e = it->second; + return true; + } + + bool wire(const IfcSchema::IfcPolyLoop* loop, TopoDS_Wire& wire) { + if (duplicates_.find(loop) != duplicates_.end()) { + return false; + } + BRep_Builder builder; + builder.MakeWire(wire); + int count = 0; + auto ps = loop->Polygon(); + loop_(ps, [this, &builder, &wire, &count](int A, int B, bool fwd) { + TopoDS_Edge e; + if (edge(A, B, e)) { + if (!fwd) { + e.Reverse(); + } + builder.Add(wire, e); + count += 1; + } + }); + if (count >= 3) { + wire.Closed(true); + + TopTools_ListOfShape results; + if (kernel_->wire_intersections(wire, results)) { + Logger::Warning("Self-intersections with " + boost::lexical_cast(results.Extent()) + " cycles detected", loop); + kernel_->select_largest(results, wire); + non_manifold_ = true; + } + + return true; + } else { + return false; + } + } + + double epsilon() const { + return eps_; + } + }; + +#ifndef NO_CACHE + POSTFIX_SCHEMA(Cache) cache; +#endif +*/ + + class faceset_helper {}; + + faceset_helper* faceset_helper_; + double precision_; + + public: + OpenCascadeKernel() + : AbstractKernel("opencascade") + , faceset_helper_(nullptr) {} + + OpenCascadeKernel(const OpenCascadeKernel& other) + : AbstractKernel("opencascade") { + *this = other; + } + + bool convert(const geometry::taxonomy::extrusion&, TopoDS_Shape&); + bool convert(const geometry::taxonomy::face&, TopoDS_Shape&); + bool convert(const geometry::taxonomy::matrix4&, gp_Trsf&); + bool convert(const geometry::taxonomy::direction3&, gp_Dir&); + }; + + /* + IfcUtil::IfcBaseClass* POSTFIX_SCHEMA(tesselate_)(const TopoDS_Shape& shape, double deflection); + IfcUtil::IfcBaseClass* POSTFIX_SCHEMA(serialise_)(const TopoDS_Shape& shape, bool advanced); + */ + +} +} +} + +#endif diff --git a/src/ifcgeom/schema/bind_convert_impl.i b/src/ifcgeom/schema/bind_convert_impl.i index abc10ab4f0..89af251420 100644 --- a/src/ifcgeom/schema/bind_convert_impl.i +++ b/src/ifcgeom/schema/bind_convert_impl.i @@ -5,7 +5,19 @@ #define BIND(T) \ if (l->declaration().is(IfcSchema::T::Class())) { \ try { \ - return map((IfcSchema::T*)l); \ + taxonomy::item* item = map((IfcSchema::T*)l); \ + item->instance = l; \ + try { \ + if (l->as()) { \ + auto style = find_style(l->as()); \ + if (style) { \ + ((taxonomy::geom_item*)item)->surface_style = as(map(style)); \ + } \ + } \ + } catch (const std::exception& e) { \ + Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l); \ + } \ + return item; \ } catch (const std::exception& e) { \ Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l); \ } \ diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index 64b3dc81e9..f21e58cf34 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -20,19 +20,69 @@ #include "mapping.h" #include "../../ifcparse/IfcLogger.h" +#include "../../ifcparse/IfcFile.h" using namespace IfcUtil; using namespace ifcopenshell::geometry; -#define mapping POSTFIX_SCHEMA(mapping) - -taxonomy::item* mapping::map(const IfcBaseClass* l) { -#include "bind_convert_impl.i" - Logger::Message(Logger::LOG_ERROR, "No operation defined for:", l); - return nullptr; +namespace { + struct POSTFIX_SCHEMA(factory_t) { + abstract_mapping* operator()(IfcParse::IfcFile* file) const { + ifcopenshell::geometry::POSTFIX_SCHEMA(mapping)* m = new ifcopenshell::geometry::POSTFIX_SCHEMA(mapping)(file); + return m; + } + }; } +void MAKE_INIT_FN(MappingImplementation)(ifcopenshell::geometry::impl::MappingFactoryImplementation* mapping) { + static const std::string schema_name = STRINGIFY(IfcSchema); + POSTFIX_SCHEMA(factory_t) factory; + mapping->bind(schema_name, factory); +} + +#define mapping POSTFIX_SCHEMA(mapping) + namespace { + // Hacks around not wanting to use if constexpr + template + class loop_to_face_upgrade { + public: + loop_to_face_upgrade(taxonomy::item*) {} + + operator bool() const { + return false; + } + + operator taxonomy::face() const { + throw taxonomy::topology_error(); + } + + operator T() const { + throw taxonomy::topology_error(); + } + }; + + template <> + class loop_to_face_upgrade { + private: + boost::optional face_; + public: + loop_to_face_upgrade(taxonomy::item* item) { + taxonomy::loop* loop = dynamic_cast(item); + if (loop) { + face_ = taxonomy::face(loop->instance, loop->matrix, *loop); + } + } + + operator bool() const { + return face_.is_initialized(); + } + + operator taxonomy::face() const { + return *face_; + } + }; + // A RAII-based mechanism to cast the conversion results // from map() into the right type expected by the higher // level typology items. An exception is thrown if the @@ -52,33 +102,601 @@ namespace { as(taxonomy::item* item) : item_(item) {} operator T() const { if (!item_) { - throw taxonomy::topology_error; + throw taxonomy::topology_error(); } T* t = dynamic_cast(item_); if (t) { return *t; } else { - if constexpr (std::is_same::value) { - topology::loop* loop = dynamic_cast(item_); - if (loop) { - return topology::face(loop.id, loop.matrix, *loop); + { + loop_to_face_upgrade upgrade(item_); + if (upgrade) { + return upgrade; } } - throw taxonomy::topology_error; + throw taxonomy::topology_error(); } } ~as() { - delete item; + delete item_; } }; }; taxonomy::item* mapping::map(const IfcSchema::IfcExtrudedAreaSolid* inst) { + // @todo length unit return new taxonomy::extrusion( - inst->data().id(), + inst, as(map(inst->Position())), as(map(inst->SweptArea())), as(map(inst->ExtrudedDirection())), inst->Depth() ); } + +taxonomy::item* mapping::map(const IfcSchema::IfcAxis2Placement3D* inst) { + // @todo length unit + return new taxonomy::matrix4(); +} + +IfcSchema::IfcProduct::list::ptr mapping::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::IfcRepresentationMap::list::ptr maps = representation->RepresentationMap(); + if (maps->size() == 1) { + IfcSchema::IfcRepresentationMap* rmap = *maps->begin(); + taxonomy::matrix4 origin = as(map(rmap->MappingOrigin())); + if (origin.components.isIdentity()) { + IfcSchema::IfcMappedItem::list::ptr items = rmap->MapUsage(); + for (IfcSchema::IfcMappedItem::list::it it = items->begin(); it != items->end(); ++it) { + IfcSchema::IfcMappedItem* item = *it; + if (item->StyledByItem()->size() != 0) continue; + + taxonomy::matrix4 target = as(map(item->MappingTarget())); + if (target.components.isIdentity()) { + continue; + } + + IfcSchema::IfcRepresentation::list::ptr reps = item->data().getInverse((&IfcSchema::IfcRepresentation::Class()), -1)->as(); + 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(); + products->push(ps); + } + } + } + } + } + + return products; +} + +namespace { + IfcSchema::IfcProduct::list::ptr filter_products(IfcSchema::IfcProduct::list::ptr unfiltered_products, std::vector& filters) { + auto ifcproducts = IfcSchema::IfcProduct::list::ptr(new IfcSchema::IfcProduct::list); + for (IfcSchema::IfcProduct::list::it jt = unfiltered_products->begin(); jt != unfiltered_products->end(); ++jt) { + IfcSchema::IfcProduct* prod = *jt; + if (boost::all(filters, [prod](const filter_t& f) { return f(prod); })) { + ifcproducts->push(prod); + } + } + return ifcproducts; + } +} + +bool mapping::reuse_ok_(settings& s, const IfcSchema::IfcProduct::list::ptr& products) { + // With world coords enabled, object transformations are directly applied to + // the BRep. There is no way to re-use the geometry for multiple products. + if (s.get(settings::USE_WORLD_COORDS)) { + return false; + } + + std::set associated_single_materials; + + for (IfcSchema::IfcProduct::list::it it = products->begin(); it != products->end(); ++it) { + IfcSchema::IfcProduct* product = *it; + + if (!s.get(settings::DISABLE_OPENING_SUBTRACTIONS) && find_openings(product)->size()) { + return false; + } + + if (s.get(settings::APPLY_LAYERSETS)) { + IfcSchema::IfcRelAssociates::list::ptr associations = product->HasAssociations(); + for (IfcSchema::IfcRelAssociates::list::it jt = associations->begin(); jt != associations->end(); ++jt) { + IfcSchema::IfcRelAssociatesMaterial* assoc = (*jt)->as(); + if (assoc) { + if (assoc->RelatingMaterial()->declaration().is(IfcSchema::IfcMaterialLayerSetUsage::Class())) { + // TODO: Check whether single layer? + return false; + } + } + } + } + + // Note that this can be a nullptr (!), but the fact that set size should be one still holds + associated_single_materials.insert(get_single_material_association(product)); + if (associated_single_materials.size() > 1) return false; + } + + return associated_single_materials.size() == 1; +} + +IfcEntityList::ptr mapping::find_openings(IfcSchema::IfcProduct* product) { + + IfcEntityList::ptr openings(new IfcEntityList); + if (product->declaration().is(IfcSchema::IfcElement::Class()) && !product->declaration().is(IfcSchema::IfcOpeningElement::Class())) { + IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)product; + openings = element->HasOpenings()->generalize(); + } + + // Is the IfcElement a decomposition of an IfcElement with any IfcOpeningElements? + IfcSchema::IfcObjectDefinition* obdef = product->as(); + for (;;) { + auto decomposes = obdef->Decomposes()->generalize(); + if (decomposes->size() != 1) break; + IfcSchema::IfcObjectDefinition* rel_obdef = (*decomposes->begin())->as()->RelatingObject(); + if (rel_obdef->declaration().is(IfcSchema::IfcElement::Class()) && !rel_obdef->declaration().is(IfcSchema::IfcOpeningElement::Class())) { + IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)rel_obdef; + openings->push(element->HasOpenings()->generalize()); + } + + obdef = rel_obdef; + } + + return openings; +} + + +void mapping::get_representations(std::vector& tasks, std::vector& filters, settings& s) { + IfcSchema::IfcRepresentation::list::ptr representations(new IfcSchema::IfcRepresentation::list); + + std::set allowed_context_types; + allowed_context_types.insert("model"); + allowed_context_types.insert("plan"); + allowed_context_types.insert("notdefined"); + + std::set context_types; + if (!s.get(settings::EXCLUDE_SOLIDS_AND_SURFACES)) { + // Really this should only be 'Model', as per + // the standard 'Design' is deprecated. So, + // just for backwards compatibility: + context_types.insert("model"); + context_types.insert("design"); + // Some earlier (?) versions DDS-CAD output their own ContextTypes + context_types.insert("model view"); + context_types.insert("detail view"); + } + if (s.get(settings::INCLUDE_CURVES)) { + context_types.insert("plan"); + } + + IfcSchema::IfcGeometricRepresentationContext::list::it it; + IfcSchema::IfcGeometricRepresentationSubContext::list::it jt; + IfcSchema::IfcGeometricRepresentationContext::list::ptr contexts = + file_->instances_by_type(); + + IfcSchema::IfcGeometricRepresentationContext::list::ptr filtered_contexts(new IfcSchema::IfcGeometricRepresentationContext::list); + + for (it = contexts->begin(); it != contexts->end(); ++it) { + IfcSchema::IfcGeometricRepresentationContext* context = *it; + if (context->declaration().is(IfcSchema::IfcGeometricRepresentationSubContext::Class())) { + // Continue, as the list of subcontexts will be considered + // by the parent's context inverse attributes. + continue; + } + try { + if (context->hasContextType()) { + std::string context_type = context->ContextType(); + boost::to_lower(context_type); + + if (allowed_context_types.find(context_type) == allowed_context_types.end()) { + Logger::Warning(std::string("ContextType '") + context->ContextType() + "' not allowed:", context); + } + if (context_types.find(context_type) != context_types.end()) { + filtered_contexts->push(context); + } + } + } catch (const std::exception& e) { + Logger::Error(e); + } + } + + // In case no contexts are identified based on their ContextType, all contexts are + // considered. Note that sub contexts are excluded as they are considered later on. + if (filtered_contexts->size() == 0) { + for (it = contexts->begin(); it != contexts->end(); ++it) { + IfcSchema::IfcGeometricRepresentationContext* context = *it; + if (!context->declaration().is(IfcSchema::IfcGeometricRepresentationSubContext::Class())) { + filtered_contexts->push(context); + } + } + } + + for (it = filtered_contexts->begin(); it != filtered_contexts->end(); ++it) { + IfcSchema::IfcGeometricRepresentationContext* context = *it; + + representations->push(context->RepresentationsInContext()); + + IfcSchema::IfcGeometricRepresentationSubContext::list::ptr sub_contexts = context->HasSubContexts(); + for (jt = sub_contexts->begin(); jt != sub_contexts->end(); ++jt) { + representations->push((*jt)->RepresentationsInContext()); + } + // There is no need for full recursion as the following is governed by the schema: + // WR31: The parent context shall not be another geometric representation sub context. + } + + if (representations->size() == 0) { + Logger::Warning("No representations encountered in relevant contexts, using all"); + representations = file_->instances_by_type(); + } + + IfcSchema::IfcRepresentation::list::ptr ok_mapped_representations; + + int task_index = 0; + + for (auto representation : *representations) { + + // Init. the list of filtered IfcProducts for this representation + + // Include only the desired products for processing. + IfcSchema::IfcProduct::list::ptr ifcproducts = filter_products(products_represented_by(representation), filters); + + if (ifcproducts->size() == 0) { + continue; + } + + auto geometry_reuse_ok_for_current_representation_ = reuse_ok_(s, ifcproducts); + + IfcSchema::IfcRepresentationMap::list::ptr maps = representation->RepresentationMap(); + + if (!geometry_reuse_ok_for_current_representation_ && maps->size() == 1) { + // unfiltered_products contains products represented by this representation by means of mapped items. + // For example because of openings applied to products, reuse might not be acceptable and then the + // products will be processed by means of their immediate representation and not the mapped representation. + + // IfcRepresentationMaps are also used for IfcTypeProducts, so an additional check is performed whether the map + // is indeed used by IfcMappedItems. + IfcSchema::IfcRepresentationMap* map = *maps->begin(); + if (map->MapUsage()->size() > 0) { + continue; + } + } + + // Check if this represenation has (or will be) processed as part its mapped representation + bool representation_processed_as_mapped_item = false; + IfcSchema::IfcRepresentation* rep_mapped_to = representation_mapped_to(representation); + if (rep_mapped_to) { + representation_processed_as_mapped_item = geometry_reuse_ok_for_current_representation_ && ( + ok_mapped_representations->contains(rep_mapped_to) || reuse_ok_(s, filter_products(products_represented_by(rep_mapped_to), filters))); + } + + if (representation_processed_as_mapped_item) { + ok_mapped_representations->push(rep_mapped_to); + continue; + } + + geometry_conversion_task task; + task.index = task_index++; + task.representation = representation; + task.products = ifcproducts->generalize(); + + tasks.emplace_back(task); + } +} + +const IfcSchema::IfcMaterial* mapping::get_single_material_association(const IfcSchema::IfcProduct* product) { + IfcSchema::IfcMaterial* single_material = 0; + IfcSchema::IfcRelAssociatesMaterial::list::ptr associated_materials = product->HasAssociations()->as(); + if (associated_materials->size() == 1) { + IfcSchema::IfcMaterialSelect* associated_material = (*associated_materials->begin())->RelatingMaterial(); + single_material = associated_material->as(); + + // 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::IfcMaterialLayerSet* layerset = associated_material->as()->ForLayerSet(); + if (layerset->MaterialLayers()->size() == 1) { + IfcSchema::IfcMaterialLayer* layer = (*layerset->MaterialLayers()->begin()); + if (layer->hasMaterial()) { + single_material = layer->Material(); + } + } + } + } + return single_material; +} + +IfcSchema::IfcRepresentation* mapping::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(); + taxonomy::matrix4 target = as(map(mapped_item->MappingTarget())); + if (target.components.isIdentity()) { + IfcSchema::IfcRepresentationMap* rmap = mapped_item->MappingSource(); + taxonomy::matrix4 origin = as(map(rmap->MappingOrigin())); + if (origin.components.isIdentity()) { + representation_mapped_to = rmap->MappedRepresentation(); + } + } + } + } + } + return representation_mapped_to; +} + +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 + std::pair 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(0, 0); + } + + const IfcSchema::IfcStyledItem* find_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()) { + return representation_item->as(); + } + + 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 *styled_items->begin(); + } + + return nullptr; + } + + 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(colour_or_factor), rgb); + } else if (colour_or_factor->declaration().is(IfcSchema::IfcNormalisedRatioMeasure::Class())) { + return process_colour(static_cast(colour_or_factor), rgb); + } else { + return false; + } + } +} + +taxonomy::item* mapping::map(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()); + } + for (IfcSchema::IfcStyledItem::list::it it = styles->begin(); it != styles->end(); ++it) { + return map(*it); + } + } + + taxonomy::style* material_style = new taxonomy::style; + return material_style; + + // @todo + // IfcGeom::SurfaceStyle material_style = IfcGeom::SurfaceStyle(material->data().id(), material->Name()); + // return &(style_cache[material->data().id()] = material_style); +} + +taxonomy::item* mapping::map(const IfcSchema::IfcStyledItem* inst) { + static taxonomy::colour white = taxonomy::colour(1., 1., 1.); + + taxonomy::style* surface_style = new taxonomy::style; + + auto style_pair = get_surface_style(inst); + + IfcSchema::IfcSurfaceStyle* style = style_pair.first; + IfcSchema::IfcSurfaceStyleShading* shading = style_pair.second; + + surface_style->instance = style; + if (style->hasName()) { + surface_style->name = style->Name(); + } + + double rgb[3]; + if (process_colour(shading->SurfaceColour(), rgb)) { + surface_style->diffuse.emplace(); + (*surface_style->diffuse).components << rgb[0], rgb[1], rgb[2]; + } + + if (auto rendering_style = shading->as()) { + if (rendering_style->hasDiffuseColour() && process_colour(rendering_style->DiffuseColour(), rgb)) { + const taxonomy::colour& old_diffuse = surface_style->diffuse.get_value_or(white); + surface_style->diffuse.reset(taxonomy::colour(old_diffuse.r() * rgb[0], old_diffuse.g() * rgb[1], old_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(taxonomy::colour(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 surface_style; +} + + +taxonomy::item* mapping::map(const IfcBaseClass* l) { +#include "bind_convert_impl.i" + Logger::Message(Logger::LOG_ERROR, "No operation defined for:", l); + return nullptr; +} + +namespace { + IfcUtil::IfcBaseEntity* get_RelatingObject(IfcSchema::IfcRelDecomposes* decompose) { +#ifdef SCHEMA_IfcRelDecomposes_HAS_RelatingObject + return decompose->RelatingObject(); +#else + IfcSchema::IfcRelAggregates* aggr = decompose->as(); + if (aggr != nullptr) { + return aggr->RelatingObject(); + } + return nullptr; +#endif + } +} + + +IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity* inst, bool include_openings) { + IfcSchema::IfcObjectDefinition* parent = 0; + auto product = inst->as(); + if (!product) { + return parent; + } + + /* In case of an opening element, parent to the RelatingBuildingElement */ + if (include_openings && product->declaration().is(IfcSchema::IfcOpeningElement::Class())) { + IfcSchema::IfcOpeningElement* opening = (IfcSchema::IfcOpeningElement*)product; + IfcSchema::IfcRelVoidsElement::list::ptr voids = opening->VoidsElements(); + if (voids->size()) { + IfcSchema::IfcRelVoidsElement* ifc_void = *voids->begin(); + parent = ifc_void->RelatingBuildingElement(); + } + } else if (product->declaration().is(IfcSchema::IfcElement::Class())) { + IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)product; + IfcSchema::IfcRelFillsElement::list::ptr fills = element->FillsVoids(); + /* In case of a RelatedBuildingElement parent to the opening element */ + if (fills->size() && include_openings) { + for (IfcSchema::IfcRelFillsElement::list::it it = fills->begin(); it != fills->end(); ++it) { + IfcSchema::IfcRelFillsElement* fill = *it; + IfcSchema::IfcObjectDefinition* ifc_objectdef = fill->RelatingOpeningElement(); + if (product == ifc_objectdef) continue; + parent = ifc_objectdef; + } + } + /* Else simply parent to the containing structure */ + if (!parent) { + IfcSchema::IfcRelContainedInSpatialStructure::list::ptr parents = element->ContainedInStructure(); + if (parents->size()) { + IfcSchema::IfcRelContainedInSpatialStructure* container = *parents->begin(); + parent = container->RelatingStructure(); + } + } + } + /* Parent decompositions to the RelatingObject */ + if (!parent) { + IfcEntityList::ptr parents = product->data().getInverse((&IfcSchema::IfcRelAggregates::Class()), -1); + parents->push(product->data().getInverse((&IfcSchema::IfcRelNests::Class()), -1)); + for (IfcEntityList::it it = parents->begin(); it != parents->end(); ++it) { + IfcSchema::IfcRelDecomposes* decompose = (IfcSchema::IfcRelDecomposes*)*it; + IfcUtil::IfcBaseEntity* ifc_objectdef; + ifc_objectdef = get_RelatingObject(decompose); + if (product == ifc_objectdef) continue; + parent = ifc_objectdef->as(); + } + } + + return parent; +} diff --git a/src/ifcgeom/schema/mapping.h b/src/ifcgeom/schema/mapping.h index 99d97be600..ff63308389 100644 --- a/src/ifcgeom/schema/mapping.h +++ b/src/ifcgeom/schema/mapping.h @@ -1,5 +1,6 @@ #include "../abstract_mapping.h" #include "../../ifcparse/macros.h" +#include "../../ifcparse/IfcFile.h" #define INCLUDE_SCHEMA(x) STRINGIFY(../../ifcparse/x.h) #include INCLUDE_SCHEMA(IfcSchema) @@ -13,7 +14,20 @@ namespace ifcopenshell { namespace geometry { class POSTFIX_SCHEMA(mapping) : public abstract_mapping { + private: + IfcParse::IfcFile* file_; + public: + POSTFIX_SCHEMA(mapping)(IfcParse::IfcFile* file) : file_(file) {} virtual ifcopenshell::geometry::taxonomy::item* map(const IfcUtil::IfcBaseClass*); + virtual void get_representations(std::vector& tasks, std::vector& filters, settings& s); + + const IfcSchema::IfcMaterial* get_single_material_association(const IfcSchema::IfcProduct* product); + IfcSchema::IfcRepresentation* representation_mapped_to(const IfcSchema::IfcRepresentation* representation); + IfcSchema::IfcProduct::list::ptr products_represented_by(const IfcSchema::IfcRepresentation* representation); + bool reuse_ok_(settings& s, const IfcSchema::IfcProduct::list::ptr& products); + IfcEntityList::ptr find_openings(IfcSchema::IfcProduct* product); + IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity* product, bool include_openings); + #include "bind_convert_decl.i" }; diff --git a/src/ifcgeom/schema/mapping.i b/src/ifcgeom/schema/mapping.i index b6a863d353..1c86d47634 100644 --- a/src/ifcgeom/schema/mapping.i +++ b/src/ifcgeom/schema/mapping.i @@ -126,4 +126,8 @@ BIND(IfcCartesianTransformationOperator2D); BIND(IfcCartesianTransformationOperator3D); BIND(IfcObjectPlacement); BIND(IfcVector); -BIND(IfcPlane); \ No newline at end of file +BIND(IfcPlane); + +BIND(IfcColourRgb); +BIND(IfcMaterial); +BIND(IfcStyledItem); diff --git a/src/ifcgeom/schema_agnostic/ConversionResult.h b/src/ifcgeom/schema_agnostic/ConversionResult.h index b7b9301e2e..ec88055893 100644 --- a/src/ifcgeom/schema_agnostic/ConversionResult.h +++ b/src/ifcgeom/schema_agnostic/ConversionResult.h @@ -21,12 +21,12 @@ #define IFCSHAPELIST_H #include "../../ifcgeom/schema_agnostic/IfcGeomRenderStyles.h" -#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h" +#include "../../ifcgeom/settings.h" +#include "../../ifcgeom/taxonomy.h" -namespace IfcGeom { +namespace ifcopenshell { namespace geometry { namespace Representation { - template class IFC_GEOM_API Triangulation; } @@ -44,8 +44,8 @@ namespace IfcGeom { class IFC_GEOM_API ConversionResultShape { public: - virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement* place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const = 0; - virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement* place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const = 0; + virtual void Triangulate(const ifcopenshell::geometry::settings & settings, const ifcopenshell::geometry::ConversionResultPlacement* place, ifcopenshell::geometry::Representation::Triangulation* 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; @@ -57,16 +57,16 @@ namespace IfcGeom { int id; ConversionResultPlacement* placement; ConversionResultShape* shape; - const SurfaceStyle* style; + ifcopenshell::geometry::taxonomy::style style; public: - ConversionResult(int id, const ConversionResultPlacement* placement, const ConversionResultShape* shape, const SurfaceStyle* style) + ConversionResult(int id, const ConversionResultPlacement* placement, const ConversionResultShape* shape, const ifcopenshell::geometry::taxonomy::style& style) : id(id), placement(placement->clone()), shape(shape->clone()), style(style) {} ConversionResult(int id, const ConversionResultPlacement* placement, const ConversionResultShape* shape) - : id(id), placement(placement->clone()), shape(shape->clone()), style(0) {} - ConversionResult(int id, const ConversionResultShape* shape, const SurfaceStyle* style) + : id(id), placement(placement->clone()), shape(shape->clone()) {} + ConversionResult(int id, const ConversionResultShape* shape, const ifcopenshell::geometry::taxonomy::style& 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) {} + : id(id), placement(0), shape(shape->clone()) {} void append(const ConversionResultPlacement* trsf) { if (placement == 0) { placement = trsf->clone(); @@ -83,12 +83,13 @@ namespace IfcGeom { } 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; } + // @todo + bool hasStyle() const { return style.diffuse.is_initialized(); } + const ifcopenshell::geometry::taxonomy::style& Style() const { return style; } + void setStyle(const ifcopenshell::geometry::taxonomy::style& newStyle) { style = newStyle; } int ItemId() const { return id; } }; typedef std::vector ConversionResults; -} +}} #endif diff --git a/src/ifcgeom/schema_agnostic/Converter.cpp b/src/ifcgeom/schema_agnostic/Converter.cpp new file mode 100644 index 0000000000..cee8ad501f --- /dev/null +++ b/src/ifcgeom/schema_agnostic/Converter.cpp @@ -0,0 +1,413 @@ +#include "Converter.h" + +#include "../../ifcgeom/schema_agnostic/IfcGeomElement.h" + +ifcopenshell::geometry::Converter::Converter(const std::string& geometry_library, IfcParse::IfcFile* file) { + kernel_ = kernels::impl::kernel_implementations().construct(geometry_library, file); + mapping_ = impl::mapping_implementations().construct(file); +} + +ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create_brep_for_representation_and_product( + const ifcopenshell::geometry::settings& settings, IfcUtil::IfcBaseEntity* representation, IfcUtil::IfcBaseEntity* product) { + + std::stringstream representation_id_builder; + + const std::string product_type = product->declaration().name(); + // @todo + element_settings s(settings, 1.0 /*getValue(GV_LENGTH_UNIT) */, product_type); + + int parent_id = -1; + try { + IfcUtil::IfcBaseEntity* parent_object = mapping_->get_decomposing_entity(product); + if (parent_object) { + parent_id = parent_object->data().id(); + } + } catch (const std::exception& e) { + Logger::Error(e); + } + + ConversionResultPlacement* trsf = nullptr; + try { + convert_placement(product, trsf); + } catch (const std::exception& e) { + Logger::Error(e); + } catch (...) { + Logger::Error("Failed to construct placement"); + } + + const std::string guid = product->get_value("GlobalId"); + const std::string name = product->get_value_or("Name", ""); + + representation_id_builder << representation->data().id(); + + ifcopenshell::geometry::Representation::BRep* shape; + ifcopenshell::geometry::ConversionResults shapes; + + auto rep_item = mapping_->map(representation); + auto placement = mapping_->map(product); + kernel_->convert(rep_item, shapes); + + shape = new ifcopenshell::geometry::Representation::BRep(s, representation_id_builder.str(), shapes); + + return new NativeElement( + product->data().id(), + parent_id, + name, + product_type, + guid, + // @todo + "", + trsf, + boost::shared_ptr(shape), + product + ); + + /* + std::stringstream representation_id_builder; + + representation_id_builder << representation->data().id(); + + ifcopenshell::geometry::kernels::Representation::BRep* shape; + ifcopenshell::geometry::kernels::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(); + 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 ifcopenshell::geometry::kernels::SurfaceStyle* s = get_style(single_material); + for (ifcopenshell::geometry::kernels::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 (ifcopenshell::geometry::kernels::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(); + } + + 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(); + + const std::string product_type = product->declaration().name(); + ElementSettings element_settings(settings, getValue(GV_LENGTH_UNIT), product_type); + + if (!settings.get(ifcopenshell::geometry::kernels::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(); + } + + ifcopenshell::geometry::kernels::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 (ifcopenshell::geometry::kernels::ConversionResults::iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++it) { + it->prepend(trsf); + } + trsf = nullptr; + representation_id_builder << "-world-coords"; + } + shape = new ifcopenshell::geometry::kernels::Representation::BRep(element_settings, representation_id_builder.str(), opened_shapes); + } else if (settings.get(IteratorSettings::USE_WORLD_COORDS)) { + for (ifcopenshell::geometry::kernels::ConversionResults::iterator it = shapes.begin(); it != shapes.end(); ++it) { + it->prepend(trsf); + } + trsf = nullptr; + representation_id_builder << "-world-coords"; + shape = new ifcopenshell::geometry::kernels::Representation::BRep(element_settings, representation_id_builder.str(), shapes); + } else { + shape = new ifcopenshell::geometry::kernels::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( + product->data().id(), + parent_id, + name, + product_type, + guid, + context_string, + trsf, + boost::shared_ptr(shape), + product + ); + + if (settings.get(IteratorSettings::VALIDATE_QUANTITIES)) { + validate_quantities(product, elem->geometry()); + } + + return elem; + + */ +} + +/* +template +ifcopenshell::geometry::kernels::NativeElement* ifcopenshell::geometry::kernels::AbstractKernel::create_brep_for_processed_representation( + const IteratorSettings& //* settings /, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, + ifcopenshell::geometry::kernels::NativeElement* brep) { + int parent_id = -1; + try { + IfcUtil::IfcBaseEntity* parent_object = get_decomposing_entity(product); + if (parent_object && parent_object->as()) { + 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( + product->data().id(), + parent_id, + name, + product_type, + guid, + context_string, + trsf, + brep->geometry_pointer(), + product + ); +} +*/ +//#include "../../ifcparse/Ifc2x3.h" +//#include "../../ifcparse/Ifc4.h" +// +//// @todo remove +//#include "../../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h" +// +//#include +//#include +//#include +//#include +// +//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, geometry_library, file); +// } +//} +// +//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); +// return map.Extent(); +// } else { +// int i = 0; +// TopExp_Explorer exp(s, t); +// for (; exp.More(); exp.Next()) { +// ++i; +// } +// return i; +// } +//} +// +// +//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; +// +// return genus; +//} +// +//IfcGeom::impl::KernelFactoryImplementation& IfcGeom::impl::kernel_implementations() { +// static KernelFactoryImplementation impl; +// return impl; +//} +// +//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_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, 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(std::make_pair(schema_name_lower, geometry_library), fn)); +//} +// +//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, 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); +// } +// return it->second(file); +//} +// +// +//IfcUtil::IfcBaseEntity* IfcGeom::Kernel::get_decomposing_entity(IfcUtil::IfcBaseEntity* inst, bool include_openings) { +// if (inst->as()) { +// return get_decomposing_entity_impl(inst->as(), include_openings); +// } else if (inst->as()) { +// return get_decomposing_entity_impl(inst->as(), include_openings); +// } else if (inst->declaration().name() == "IfcProject") { +// return nullptr; +// } else { +// throw IfcParse::IfcException("Unexpected entity " + inst->declaration().name()); +// } +//} +// +//namespace { +// template +// static std::map get_layers_impl(typename Schema::IfcProduct* prod) { +// std::map layers; +// if (prod->hasRepresentation()) { +// IfcEntityList::ptr r = IfcParse::traverse(prod->Representation()); +// typename Schema::IfcRepresentation::list::ptr representations = r->template as(); +// for (typename Schema::IfcRepresentation::list::it it = representations->begin(); it != representations->end(); ++it) { +// typename Schema::IfcPresentationLayerAssignment::list::ptr a = (*it)->LayerAssignments(); +// for (typename Schema::IfcPresentationLayerAssignment::list::it jt = a->begin(); jt != a->end(); ++jt) { +// layers[(*jt)->Name()] = *jt; +// } +// } +// } +// return layers; +// } +//} +// +//std::map IfcGeom::Kernel::get_layers(IfcUtil::IfcBaseEntity* inst) { +// if (inst->as()) { +// return get_layers_impl(inst->as()); +// } else if (inst->as()) { +// return get_layers_impl(inst->as()); +// } else { +// throw IfcParse::IfcException("Unexpected entity " + inst->declaration().name()); +// } +//} +// +//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()) { +// OpenCascadeShape s(it.Value()); +// if (!is_manifold(&s)) { +// return false; +// } +// } +// return true; +// } else { +// TopTools_IndexedDataMapOfShapeListOfShape map; +// TopExp::MapShapesAndAncestors(a, TopAbs_EDGE, TopAbs_FACE, map); +// +// for (int i = 1; i <= map.Extent(); ++i) { +// if (map.FindFromIndex(i).Extent() != 2) { +// return false; +// } +// } +// +// return true; +// } +//} diff --git a/src/ifcgeom/schema_agnostic/Kernel.h b/src/ifcgeom/schema_agnostic/Converter.h similarity index 58% rename from src/ifcgeom/schema_agnostic/Kernel.h rename to src/ifcgeom/schema_agnostic/Converter.h index abb484189b..06cd31ad3b 100644 --- a/src/ifcgeom/schema_agnostic/Kernel.h +++ b/src/ifcgeom/schema_agnostic/Converter.h @@ -2,19 +2,21 @@ #define ITERATOR_KERNEL_H #include "../../ifcparse/IfcFile.h" -#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h" +#include "../../ifcgeom/settings.h" #include "../../ifcgeom/schema_agnostic/ConversionResult.h" +#include "../../ifcgeom/abstract_mapping.h" +#include "../../ifcgeom/kernel_agnostic/AbstractKernel.h" #include -namespace IfcGeom { +namespace ifcopenshell { namespace geometry { - template class NativeElement; - class Kernel { + class Converter { private: - Kernel* implementation_; + abstract_mapping* mapping_; + kernels::AbstractKernel* kernel_; public: // Tolerances and settings for various geometrical operations: @@ -47,10 +49,13 @@ namespace IfcGeom { GV_DIMENSIONALITY }; - Kernel(const std::string& geometry_library, IfcParse::IfcFile* file_ = 0); + Converter(const std::string& geometry_library, IfcParse::IfcFile* file); - virtual ~Kernel() {} + ~Converter() {} + abstract_mapping* mapping() const { return mapping_; } + + /* virtual void setValue(GeomValue var, double value) { implementation_->setValue(var, value); } @@ -58,43 +63,42 @@ namespace IfcGeom { virtual double getValue(GeomValue var) const { return implementation_->getValue(var); } + */ + /* virtual NativeElement* convert( const IteratorSettings& settings, IfcUtil::IfcBaseClass* representation, IfcUtil::IfcBaseClass* product) { return implementation_->convert(settings, representation, product); } + */ - virtual ConversionResults convert(IfcUtil::IfcBaseClass* item) { - return implementation_->convert(item); + ifcopenshell::geometry::ConversionResults convert(IfcUtil::IfcBaseClass* item) { + auto geom_item = mapping_->map(item); + ifcopenshell::geometry::ConversionResults results; + kernel_->convert(geom_item, results); + return results; } - virtual bool convert_placement(IfcUtil::IfcBaseClass* item, ConversionResultPlacement*& trsf) { - return implementation_->convert_placement(item, trsf); + bool convert_placement(IfcUtil::IfcBaseClass* item, ifcopenshell::geometry::ConversionResultPlacement*& trsf) { + throw std::runtime_error("not implemented"); + // return implementation_->convert_placement(item, trsf); } - static int count(const ConversionResultShape*, int, bool unique=false); - static int surface_genus(const ConversionResultShape*); + ifcopenshell::geometry::NativeElement* create_brep_for_representation_and_product(const ifcopenshell::geometry::settings& settings, IfcUtil::IfcBaseEntity* representation, IfcUtil::IfcBaseEntity* product); + ifcopenshell::geometry::NativeElement* create_brep_for_processed_representation(const ifcopenshell::geometry::settings& settings, IfcUtil::IfcBaseEntity* representation, IfcUtil::IfcBaseEntity* product, ifcopenshell::geometry::NativeElement* brep); - static bool is_manifold(const ConversionResultShape*); + /* + static int count(const ifcopenshell::geometry::ConversionResultShape*, int, bool unique=false); + static int surface_genus(const ifcopenshell::geometry::ConversionResultShape*); + + static bool is_manifold(const ifcopenshell::geometry::ConversionResultShape*); static IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity*, bool include_openings=true); static std::map get_layers(IfcUtil::IfcBaseEntity*); static IfcEntityList::ptr find_openings(IfcUtil::IfcBaseEntity* product); + */ }; - - namespace impl { - typedef boost::function1 kernel_fn; - - class KernelFactoryImplementation : public std::map, kernel_fn> { - public: - KernelFactoryImplementation(); - 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(); - } -} +}} #endif \ No newline at end of file diff --git a/src/ifcgeom/schema_agnostic/IfcGeomElement.h b/src/ifcgeom/schema_agnostic/IfcGeomElement.h index 0cefed19de..d51329a342 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomElement.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomElement.h @@ -27,18 +27,17 @@ #include "../../ifcparse/Argument.h" #include "../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h" -#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h" +#include "../../ifcgeom/settings.h" #include "ifc_geom_api.h" -namespace IfcGeom { +namespace ifcopenshell { namespace geometry { - template class Matrix { private: - std::vector

_data; + std::vector _data; public: - Matrix(const ElementSettings& settings, const IfcGeom::ConversionResultPlacement* trsf) { + Matrix(const element_settings& settings, const 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 @@ -49,30 +48,29 @@ namespace IfcGeom { 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)) + const double matrix_value = (i == 4 && settings.get(settings::CONVERT_BACK_UNITS)) ? trsf_value / settings.unit_magnitude() : trsf_value; - _data.push_back(static_cast

(matrix_value)); + _data.push_back(static_cast(matrix_value)); } } } - const std::vector

& data() const { return _data; } + const std::vector& data() const { return _data; } }; - template class Transformation { private: - ElementSettings settings_; + element_settings settings_; ConversionResultPlacement* trsf_; - Matrix

matrix_; + Matrix matrix_; public: - Transformation(const ElementSettings& settings, const IfcGeom::ConversionResultPlacement* trsf) + Transformation(const element_settings& settings, const ConversionResultPlacement* trsf) : settings_(settings) , trsf_(trsf ? trsf->clone() : nullptr) , matrix_(settings, trsf) {} - const IfcGeom::ConversionResultPlacement* data() const { return trsf_; } - const Matrix

& matrix() const { return matrix_; } + const ConversionResultPlacement* data() const { return trsf_; } + const Matrix& matrix() const { return matrix_; } Transformation inverted() const { return Transformation(settings_, trsf_->inverted()); @@ -83,7 +81,6 @@ namespace IfcGeom { } }; - template class Element { private: int _id; @@ -93,17 +90,17 @@ namespace IfcGeom { std::string _guid; std::string _context; std::string _unique_id; - Transformation _transformation; + Transformation _transformation; IfcUtil::IfcBaseEntity* product_; - std::vector*> _parents; + std::vector _parents; public: - friend bool operator == (const Element & element1, const Element & element2) { + friend bool operator == (const Element & element1, const Element & element2) { return element1.id() == element2.id(); } // Use the id to compare, or the elevation is the elements are IfcBuildingStoreys and the elevation is set - friend bool operator < (const Element & element1, const Element & element2) { + friend bool operator < (const Element & element1, const Element & element2) { if (element1.type() == "IfcBuildingStorey" && element2.type() == "IfcBuildingStorey") { size_t attr_index = element1.product()->declaration().attribute_index("Elevation"); Argument* elev_attr1 = element1.product()->data().getArgument(attr_index); @@ -127,13 +124,13 @@ namespace IfcGeom { const std::string& guid() const { return _guid; } const std::string& context() const { return _context; } const std::string& unique_id() const { return _unique_id; } - const Transformation& transformation() const { return _transformation; } + const Transformation& transformation() const { return _transformation; } IfcUtil::IfcBaseEntity* product() const { return product_; } - const std::vector*> parents() const { return _parents; } - void SetParents(std::vector*> newparents) { _parents = newparents; } + const std::vector parents() const { return _parents; } + void SetParents(std::vector 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 IfcGeom::ConversionResultPlacement* trsf, IfcUtil::IfcBaseEntity* product) + Element(const element_settings& settings, int id, int parent_id, const std::string& name, const std::string& type, + const std::string& guid, const std::string& context, const ConversionResultPlacement* trsf, IfcUtil::IfcBaseEntity* product) : _id(id), _parent_id(parent_id), _name(name), _type(type), _guid(guid), _context(context), _transformation(settings, trsf) , product_(product) { @@ -162,17 +159,16 @@ namespace IfcGeom { virtual ~Element() {} }; - template - class NativeElement : public Element { + class NativeElement : public Element { private: boost::shared_ptr _geometry; public: const boost::shared_ptr& geometry_pointer() const { return _geometry; } const Representation::BRep& geometry() const { return *_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& geometry, + const std::string& context, const ConversionResultPlacement* trsf, const boost::shared_ptr& geometry, IfcUtil::IfcBaseEntity* product) - : Element(geometry->settings() ,id, parent_id, name, type, guid, context, trsf, product) + : Element(geometry->settings() ,id, parent_id, name, type, guid, context, trsf, product) , _geometry(geometry) {} @@ -184,19 +180,18 @@ namespace IfcGeom { NativeElement& operator=(const NativeElement& other); }; - template - class TriangulationElement : public Element { + class TriangulationElement : public Element { private: - boost::shared_ptr< Representation::Triangulation

> _geometry; + boost::shared_ptr _geometry; public: - const Representation::Triangulation

& geometry() const { return *_geometry; } - const boost::shared_ptr< Representation::Triangulation

>& geometry_pointer() const { return _geometry; } - TriangulationElement(const NativeElement& shape_model) - : Element(shape_model) - , _geometry(boost::shared_ptr >(new Representation::Triangulation

(shape_model.geometry()))) + const Representation::Triangulation& geometry() const { return *_geometry; } + const boost::shared_ptr< Representation::Triangulation >& geometry_pointer() const { return _geometry; } + TriangulationElement(const NativeElement& shape_model) + : Element(shape_model) + , _geometry(boost::shared_ptr(new Representation::Triangulation(shape_model.geometry()))) {} - TriangulationElement(const Element& element, const boost::shared_ptr >& geometry) - : Element(element) + TriangulationElement(const Element& element, const boost::shared_ptr& geometry) + : Element(element) , _geometry(geometry) {} private: @@ -204,14 +199,13 @@ namespace IfcGeom { TriangulationElement& operator=(const TriangulationElement& other); }; - template - class SerializedElement : public Element { + class SerializedElement : public Element { private: Representation::Serialization* _geometry; public: const Representation::Serialization& geometry() const { return *_geometry; } - SerializedElement(const NativeElement& shape_model) - : Element(shape_model) + SerializedElement(const NativeElement& shape_model) + : Element(shape_model) , _geometry(new Representation::Serialization(shape_model.geometry())) {} virtual ~SerializedElement() { @@ -221,6 +215,6 @@ namespace IfcGeom { SerializedElement(const SerializedElement& other); SerializedElement& operator=(const SerializedElement& other); }; -} +}} #endif diff --git a/src/ifcgeom/schema_agnostic/IfcGeomFilter.h b/src/ifcgeom/schema_agnostic/IfcGeomFilter.h index 1d457abeb1..523cc0b8f0 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomFilter.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomFilter.h @@ -23,8 +23,9 @@ #ifndef IFCGEOMFILTER_H #define IFCGEOMFILTER_H -#include "../../ifcgeom/schema_agnostic/Kernel.h" +#include "../../ifcgeom/kernel_agnostic/AbstractKernel.h" #include "../../ifcparse/IfcFile.h" +#include "../../ifcgeom/abstract_mapping.h" #include #include @@ -65,7 +66,11 @@ namespace IfcGeom { bool traverse_match(IfcUtil::IfcBaseEntity* prod, const filter_t& pred) const { IfcUtil::IfcBaseEntity* parent, *current = prod; - while ((parent = IfcGeom::Kernel::get_decomposing_entity(current, traverse_openings)) != nullptr) { + // @todo examine if this can indeed be static. For now usage is only + // in IfcConvert so invocation is bound to a single file with a single + // schema. + static auto mapping = ifcopenshell::geometry::impl::mapping_implementations().construct(prod->data().file); + while ((parent = mapping->get_decomposing_entity(current, traverse_openings)) != nullptr) { if (pred(parent)) { return true; } @@ -170,7 +175,8 @@ namespace IfcGeom { : wildcard_filter(include, traverse, patterns) {} bool match(IfcUtil::IfcBaseEntity* prod) const { - layer_map_t layers = IfcGeom::Kernel::get_layers(prod); + static auto mapping = ifcopenshell::geometry::impl::mapping_implementations().construct(prod->data().file); + layer_map_t layers = mapping->get_layers(prod); return std::find_if(layers.begin(), layers.end(), wildcards_match(values)) != layers.end(); } diff --git a/src/ifcgeom/schema_agnostic/IfcGeomIterator.h b/src/ifcgeom/schema_agnostic/IfcGeomIterator.h deleted file mode 100644 index 4b4fe95f2e..0000000000 --- a/src/ifcgeom/schema_agnostic/IfcGeomIterator.h +++ /dev/null @@ -1,130 +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 . * - * * - ********************************************************************************/ - -/******************************************************************************** - * * - * Geometrical data in an IFC file consists of shapes (IfcShapeRepresentation) * - * and instances (SUBTYPE OF IfcBuildingElement e.g. IfcWindow). * - * * - * IfcGeom::Representation::Triangulation is a class that represents a * - * triangulated IfcShapeRepresentation. * - * Triangulation.verts is a 1 dimensional vector of float defining the * - * cartesian coordinates of the vertices of the triangulated shape in the * - * format of [x1,y1,z1,..,xn,yn,zn] * - * Triangulation.faces is a 1 dimensional vector of int containing the * - * indices of the triangles referencing positions in Triangulation.verts * - * Triangulation.edges is a 1 dimensional vector of int in {0,1} that dictates* - * the visibility of the edges that span the faces in Triangulation.faces * - * * - * IfcGeom::Element represents the actual IfcBuildingElements. * - * IfcGeomObject.name is the GUID of the element * - * IfcGeomObject.type is the datatype of the element e.g. IfcWindow * - * IfcGeomObject.mesh is a pointer to an IfcMesh * - * IfcGeomObject.transformation.matrix is a 4x3 matrix that defines the * - * orientation and translation of the mesh in relation to the world origin * - * * - * IfcGeom::Iterator::initialize() * - * finds the most suitable representation contexts. Returns true iff * - * at least a single representation will process successfully * - * * - * IfcGeom::Iterator::get() * - * returns a pointer to the current IfcGeom::Element * - * * - * IfcGeom::Iterator::next() * - * returns true iff a following entity is available for a successive call to * - * IfcGeom::Iterator::get() * - * * - * IfcGeom::Iterator::progress() * - * returns an int in [0..100] that indicates the overall progress * - * * - ********************************************************************************/ - -#ifndef IFCGEOMITERATOR_H -#define IFCGEOMITERATOR_H - -#include "../../ifcgeom/schema_agnostic/IteratorImplementation.h" - -// The infamous min & max Win32 #defines can leak here from OCE depending on the build configuration -#ifdef min -#undef min -#endif -#ifdef max -#undef max -#endif - -namespace IfcGeom { - - template - class Iterator { - private: - Iterator(const Iterator&); // N/I - Iterator& operator=(const Iterator&); // N/I - - IfcParse::IfcFile* file_; - IfcGeom::IteratorSettings settings_; - std::vector filters_; - - IteratorImplementation* implementation_; - - public: - 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().construct(file_->schema()->name(), geometry_library, settings, file, filters_, num_threads); - } - - Iterator(const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector& filters, const std::string& geometry_library = "opencascade", int num_threads = 1) - : file_(file) - , settings_(settings) - , filters_(filters) - { - implementation_ = iterator_implementations().construct(file_->schema()->name(), geometry_library, settings, file, filters_, num_threads); - } - - bool initialize() { - return implementation_->initialize(); - } - - int progress() const { return implementation_->progress(); } - - void compute_bounds() { implementation_->compute_bounds(); } - - const gp_XYZ& bounds_min() const { return implementation_->bounds_min(); } - const gp_XYZ& bounds_max() const { return implementation_->bounds_max(); } - - const std::string& unit_name() const { return implementation_->getUnitName(); } - - double unit_magnitude() const { return implementation_->getUnitMagnitude(); } - - IfcParse::IfcFile* file() const { return implementation_->file(); } - - IfcUtil::IfcBaseClass* next() const { return implementation_->next(); } - - Element* get() { return implementation_->get(); } - - NativeElement* get_native() { return implementation_->get_native(); } - - const Element* get_object(int id) { return implementation_->get_object(id); } - - IfcUtil::IfcBaseClass* create() { return implementation_->create(); } - }; -} - -#endif diff --git a/src/ifcgeom/schema_agnostic/IfcGeomIteratorImplementation.cpp b/src/ifcgeom/schema_agnostic/IfcGeomIteratorImplementation.cpp new file mode 100644 index 0000000000..6340b79d04 --- /dev/null +++ b/src/ifcgeom/schema_agnostic/IfcGeomIteratorImplementation.cpp @@ -0,0 +1 @@ +#include "IfcGeomIteratorImplementation.h" diff --git a/src/ifcgeom/schema_agnostic/IfcGeomIteratorImplementation.h b/src/ifcgeom/schema_agnostic/IfcGeomIteratorImplementation.h new file mode 100644 index 0000000000..85d436644b --- /dev/null +++ b/src/ifcgeom/schema_agnostic/IfcGeomIteratorImplementation.h @@ -0,0 +1,617 @@ +/******************************************************************************** + * * + * 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 . * + * * + ********************************************************************************/ + +/******************************************************************************** + * * + * Geometrical data in an IFC file consists of shapes (IfcShapeRepresentation) * + * and instances (SUBTYPE OF IfcBuildingElement e.g. IfcWindow). * + * * + * ifcopenshell::geometry::Representation::Triangulation is a class that represents a * + * triangulated IfcShapeRepresentation. * + * Triangulation.verts is a 1 dimensional vector of float defining the * + * cartesian coordinates of the vertices of the triangulated shape in the * + * format of [x1,y1,z1,..,xn,yn,zn] * + * Triangulation.faces is a 1 dimensional vector of int containing the * + * indices of the triangles referencing positions in Triangulation.verts * + * Triangulation.edges is a 1 dimensional vector of int in {0,1} that dictates* + * the visibility of the edges that span the faces in Triangulation.faces * + * * + * ifcopenshell::geometry::Element represents the actual IfcBuildingElements. * + * IfcGeomObject.name is the GUID of the element * + * IfcGeomObject.type is the datatype of the element e.g. IfcWindow * + * IfcGeomObject.mesh is a pointer to an IfcMesh * + * IfcGeomObject.transformation.matrix is a 4x3 matrix that defines the * + * orientation and translation of the mesh in relation to the world origin * + * * + * ifcopenshell::geometry::Iterator::initialize() * + * finds the most suitable representation contexts. Returns true iff * + * at least a single representation will process successfully * + * * + * ifcopenshell::geometry::Iterator::get() * + * returns a pointer to the current ifcopenshell::geometry::Element * + * * + * ifcopenshell::geometry::Iterator::next() * + * returns true iff a following entity is available for a successive call to * + * ifcopenshell::geometry::Iterator::get() * + * * + * ifcopenshell::geometry::Iterator::progress() * + * returns an int in [0..100] that indicates the overall progress * + * * + ********************************************************************************/ + +#ifndef IFCGEOMITERATOR_H +#define IFCGEOMITERATOR_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "../../ifcparse/macros.h" +#include "../../ifcparse/IfcFile.h" + +#include "../../ifcgeom/schema_agnostic/IfcGeomElement.h" +#include "../../ifcgeom/settings.h" +#include "../../ifcgeom/schema_agnostic/ConversionResult.h" + +#include "../../ifcgeom/schema_agnostic/IfcGeomFilter.h" + +#include "../../ifcgeom/kernel_agnostic/AbstractKernel.h" + +#include "../../ifcgeom/schema_agnostic/Converter.h" + +#define INCLUDE_SCHEMA(x) STRINGIFY(../../ifcparse/x.h) +#include INCLUDE_SCHEMA(IfcSchema) +#undef INCLUDE_SCHEMA + +#include + +// The infamous min & max Win32 #defines can leak here from OCE depending on the build configuration +#ifdef min +#undef min +#endif +#ifdef max +#undef max +#endif + +namespace { + ifcopenshell::geometry::Element* process_based_on_settings( + const ifcopenshell::geometry::settings& settings, + ifcopenshell::geometry::NativeElement* elem, + ifcopenshell::geometry::TriangulationElement* previous=nullptr) + { + if (settings.get(ifcopenshell::geometry::settings::USE_BREP_DATA)) { + try { + return new ifcopenshell::geometry::SerializedElement(*elem); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Getting a serialized element from model failed."); + return nullptr; + } + } else if (!settings.get(ifcopenshell::geometry::settings::DISABLE_TRIANGULATION)) { + try { + if (!previous) { + return new ifcopenshell::geometry::TriangulationElement(*elem); + } else { + return new ifcopenshell::geometry::TriangulationElement(*elem, previous->geometry_pointer()); + } + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Getting a triangulation element from model failed."); + return nullptr; + } + } else { + return elem; + } + } + + void create_element( + ifcopenshell::geometry::Converter* converter, + const ifcopenshell::geometry::settings& settings, + ifcopenshell::geometry::geometry_conversion_task* rep) + { + IfcUtil::IfcBaseEntity* representation = rep->representation; + IfcUtil::IfcBaseEntity* product = (IfcUtil::IfcBaseEntity*) *rep->products->begin(); + auto brep = converter->create_brep_for_representation_and_product(settings, representation, product); + if (!brep) { + return; + } + + auto elem = process_based_on_settings(settings, brep); + if (!elem) { + return; + } + + rep->breps = { brep }; + rep->elements = { elem }; + + for (auto it = rep->products->begin() + 1; it != rep->products->end(); ++it) { + auto brep2 = converter->create_brep_for_processed_representation(settings, representation, (IfcUtil::IfcBaseEntity*) *it, brep); + if (brep2) { + auto elem2 = process_based_on_settings(settings, brep, dynamic_cast(elem)); + if (elem2) { + rep->breps.push_back(brep2); + rep->elements.push_back(elem2); + } + } + } + } +} + +namespace ifcopenshell { namespace geometry { + + class Iterator { + private: + + int num_threads_; + std::atomic progress_; + std::vector tasks_; + std::vector::iterator task_iterator_; + + std::vector all_processed_elements_; + std::vector all_processed_native_elements_; + size_t task_result_index_; + + std::string geometry_library_; + + Iterator(const Iterator&); // N/I + Iterator& operator=(const Iterator&); // N/I + + Converter* converter_; + settings settings_; + + IfcParse::IfcFile* ifc_file; + + int done; + int total; + + std::string unit_name; + double unit_magnitude; + + gp_XYZ bounds_min_; + gp_XYZ bounds_max_; + + std::vector filters_; + + /// @todo public/private sections all over the place: move all public to the beginning of the class + public: + + bool initialize() { + converter_->mapping()->get_representations(tasks_, filters_, settings_); + + if (tasks_.size() == 0) { + Logger::Warning("No representations encountered, aborting"); + return false; + } + + task_iterator_ = tasks_.begin(); + + done = 0; + total = tasks_.size(); + + if (num_threads_ != 1) { + process_concurrently(); + } else { + if (!create()) { + return false; + } + } + + return true; + } + + void process_concurrently() { + size_t conc_threads = num_threads_; + if (conc_threads > tasks_.size()) { + conc_threads = tasks_.size(); + } + + std::vector kernel_pool; + kernel_pool.reserve(conc_threads); + for (unsigned i = 0; i < conc_threads; ++i) { + kernel_pool.push_back(new Converter(geometry_library_, ifc_file)); + } + + std::vector> threadpool; + + int old_progress = -1; + int processed = 0; + + Logger::ProgressBar(0); + + for (auto& rep : tasks_) { + Converter* K = nullptr; + if (threadpool.size() < kernel_pool.size()) { + K = kernel_pool[threadpool.size()]; + } + + while (threadpool.size() == conc_threads) { + for (int i = 0; i < (int)threadpool.size(); i++) { + std::future &fu = threadpool[i]; + std::future_status status; + status = fu.wait_for(std::chrono::seconds(0)); + if (status == std::future_status::ready) { + fu.get(); + + processed += 1; + progress_ = processed * 50 / tasks_.size(); + if (progress_ != old_progress) { + Logger::ProgressBar(progress_); + old_progress = progress_; + } + + std::swap(threadpool[i], threadpool.back()); + threadpool.pop_back(); + std::swap(kernel_pool[i], kernel_pool.back()); + K = kernel_pool.back(); + break; + } // if + } // for + } // while + + std::future fu = std::async(std::launch::async, create_element, K, std::ref(settings_), &rep); + threadpool.emplace_back(std::move(fu)); + } + + for (std::future &fu : threadpool) { + fu.get(); + + processed += 1; + progress_ = processed * 50 / tasks_.size(); + if (progress_ != old_progress) { + Logger::ProgressBar(progress_); + old_progress = progress_; + } + } + + for (auto& rep : tasks_) { + all_processed_elements_.insert(all_processed_elements_.end(), rep.elements.begin(), rep.elements.end()); + all_processed_native_elements_.insert(all_processed_native_elements_.end(), rep.breps.begin(), rep.breps.end()); + } + + task_result_index_ = 0; + + Logger::Status("\rDone creating geometry (" + boost::lexical_cast(all_processed_elements_.size()) + + " objects) "); + } + + /// Computes model's bounding box (bounds_min and bounds_max). + /// @note Can take several minutes for large files. + void compute_bounds() + { + // @todo + + /* + for (int i = 1; i < 4; ++i) { + bounds_min_.SetCoord(i, std::numeric_limits::infinity()); + bounds_max_.SetCoord(i, -std::numeric_limits::infinity()); + } + + IfcSchema::IfcProduct::list::ptr products = ifc_file->instances_by_type(); + for (IfcSchema::IfcProduct::list::it iter = products->begin(); iter != products->end(); ++iter) { + IfcSchema::IfcProduct* product = *iter; + if (product->hasObjectPlacement()) { + // Use a fresh trsf every time in order to prevent the result to be concatenated + ConversionResultPlacement* trsf; + bool success = false; + + try { + success = kernel->convert_placement(product->ObjectPlacement(), trsf); + } catch (const std::exception& e) { + Logger::Error(e); + } catch (...) { + Logger::Error("Failed to construct placement"); + } + + if (!success) { + continue; + } + + 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)); + } + } + */ + } + + int progress() const { + if (num_threads_ == 1) { + return 100 * done / total; + } else { + return progress_; + } + } + + const std::string& getUnitName() const { return unit_name; } + + /// @note Double always as per IFC specification. + double getUnitMagnitude() const { return unit_magnitude; } + + std::string getLog() const { return Logger::GetLog(); } + + IfcParse::IfcFile* file() const { return ifc_file; } + + const std::vector& filters() const { return filters_; } + std::vector& filters() { return filters_; } + + const gp_XYZ& bounds_min() const { return bounds_min_; } + const gp_XYZ& bounds_max() const { return bounds_max_; } + + private: + // Move to the next IfcRepresentation + void _nextShape() { + ++task_iterator_; + ++done; + } + + IfcUtil::IfcBaseClass* create_shape_model_for_next_entity() { + geometry_conversion_task* task = nullptr; + while (task_iterator_ != tasks_.end()) { + task = &*task_iterator_++; + create_element(converter_, settings_, task); + if (task->elements.empty()) { + task = nullptr; + } else { + break; + } + } + if (task) { + all_processed_elements_.insert(all_processed_elements_.end(), task->elements.begin(), task->elements.end()); + all_processed_native_elements_.insert(all_processed_native_elements_.end(), task->breps.begin(), task->breps.end()); + return (*task->products)[0]; + } else { + return nullptr; + } + } + + public: + + /// Moves to the next shape representation, create its geometry, and returns the associated product. + /// Use get() to retrieve the created geometry. + IfcUtil::IfcBaseClass* next() { + if (num_threads_ != 1) { + task_result_index_++; + if (task_result_index_ == all_processed_elements_.size()) { + return nullptr; + } else { + return all_processed_elements_[task_result_index_]->product(); + } + } else { + // Increment the iterator over the list of products using the current + // shape representation + ++task_result_index_; + if (task_result_index_ == all_processed_elements_.size()) { + return create(); + } + } + } + + /// Gets the representation of the current geometrical entity. + Element* get() + { + // TODO: Test settings and throw + Element* ret = 0; + + ret = all_processed_elements_[task_result_index_]; + + // If we want to organize the element considering their hierarchy + if (settings_.get(settings::SEARCH_FLOOR)) + { + // We are going to build a vector with the element parents. + // First, create the parent vector + std::vector parents; + + // if the element has a parent + if (ret->parent_id() != -1) + { + const ifcopenshell::geometry::Element* parent_object = NULL; + bool hasParent = true; + + // get the parent + try { + parent_object = get_object(ret->parent_id()); + } catch (const std::exception& e) { + Logger::Error(e); + hasParent = false; + } + + // Add the previously found parent to the vector + if (hasParent) parents.insert(parents.begin(), parent_object); + + // We need to find all the parents + while (parent_object != NULL && hasParent && parent_object->parent_id() != -1) + { + // Find the next parent + try { + parent_object = get_object(parent_object->parent_id()); + } catch (const std::exception& e) { + Logger::Error(e); + hasParent = false; + } + + // Add the previously found parent to the vector + if (hasParent) parents.insert(parents.begin(), parent_object); + + hasParent = hasParent && parent_object->parent_id() != -1; + } + + // when done push the parent list in the Element object + ret->SetParents(parents); + } + } + + return ret; + } + + /// Gets the native (Open Cascade) representation of the current geometrical entity. + NativeElement* get_native() + { + return all_processed_native_elements_[task_result_index_]; + } + + const Element* get_object(int id) { + // @todo + return nullptr; + /* + ConversionResultPlacement* trsf; + int parent_id = -1; + std::string instance_type, product_name, product_guid; + IfcSchema::IfcProduct* ifc_product = 0; + + try { + IfcUtil::IfcBaseClass* ifc_entity = ifc_file->instance_by_id(id); + instance_type = ifc_entity->declaration().name(); + + if (ifc_entity->declaration().is(IfcSchema::IfcRoot::Class())) { + IfcSchema::IfcRoot* ifc_root = ifc_entity->as(); + product_guid = ifc_root->GlobalId(); + product_name = ifc_root->hasName() ? ifc_root->Name() : ""; + } + + if (ifc_entity->declaration().is(IfcSchema::IfcProduct::Class())) { + ifc_product = ifc_entity->as(); + parent_id = -1; + try { + IfcSchema::IfcObjectDefinition* parent_object = kernel->get_decomposing_entity(ifc_product)->template as(); + if (parent_object) { + parent_id = parent_object->data().id(); + } + } catch (const std::exception& e) { + Logger::Error(e); + } catch (...) { + Logger::Error("Failed to find decomposing entity"); + } + + try { + kernel->convert_placement(ifc_product->ObjectPlacement(), trsf); + } catch (const std::exception& e) { + Logger::Error(e); + } catch (...) { + Logger::Error("Failed to construct placement"); + } + } + } catch (const std::exception& e) { + Logger::Error(e); + } catch (const Standard_Failure& e) { + if (e.GetMessageString() && strlen(e.GetMessageString())) { + Logger::Error(e.GetMessageString()); + } else { + Logger::Error("Unknown error returning product"); + } + } catch (...) { + Logger::Error("Unknown error returning product"); + } + + ElementSettings element_settings(settings, unit_magnitude, instance_type); + + Element* ifc_object = new Element(element_settings, id, parent_id, product_name, instance_type, product_guid, "", trsf, ifc_product); + return ifc_object; + */ + } + + IfcUtil::IfcBaseClass* create() { + IfcUtil::IfcBaseClass* product = nullptr; + try { + product = create_shape_model_for_next_entity(); + } catch (const std::exception& e) { + Logger::Error(e); + } catch (const Standard_Failure& e) { + if (e.GetMessageString() && strlen(e.GetMessageString())) { + Logger::Error(e.GetMessageString()); + } else { + Logger::Error("Unknown error creating geometry"); + } + } catch (...) { + Logger::Error("Unknown error creating geometry"); + } + return product; + } + private: + void _initialize() { + unit_name = "METER"; + unit_magnitude = 1.f; + + // @todo + + /* + kernel->setValue(ifcopenshell::geometry::Kernel::GV_MAX_FACES_TO_ORIENT, settings.get(settings::SEW_SHELLS) ? std::numeric_limits::infinity() : -1); + kernel->setValue(ifcopenshell::geometry::Kernel::GV_DIMENSIONALITY, (settings.get(settings::INCLUDE_CURVES) + ? (settings.get(settings::EXCLUDE_SOLIDS_AND_SURFACES) ? -1. : 0.) : +1.)); + if (settings.get(settings::BUILDING_LOCAL_PLACEMENT)) { + if (settings.get(settings::SITE_LOCAL_PLACEMENT)) { + Logger::Message(Logger::LOG_WARNING, "building-local-placement takes precedence over site-local-placement"); + } + kernel->set_conversion_placement_rel_to(&IfcSchema::IfcBuilding::Class()); + } else if (settings.get(settings::SITE_LOCAL_PLACEMENT)) { + kernel->set_conversion_placement_rel_to(&IfcSchema::IfcSite::Class()); + } + */ + } + + bool owns_ifc_file; + public: + Iterator(const std::string& geometry_library, const settings& settings, IfcParse::IfcFile* file, const std::vector& filters, int num_threads) + : settings_(settings) + , ifc_file(file) + , filters_(filters) + , owns_ifc_file(false) + , num_threads_(num_threads) + , geometry_library_(geometry_library) + { + _initialize(); + } + + ~Iterator() { + if (owns_ifc_file) { + delete ifc_file; + } + + if (settings_.get(settings::DISABLE_TRIANGULATION)) { + for (auto& p : all_processed_native_elements_) { + delete p; + } + } + + for (auto& p : all_processed_elements_) { + delete p; + } + } + }; +}} + +#endif diff --git a/src/ifcgeom/schema_agnostic/IfcGeomMaterial.cpp b/src/ifcgeom/schema_agnostic/IfcGeomMaterial.cpp deleted file mode 100644 index 3593ed7673..0000000000 --- a/src/ifcgeom/schema_agnostic/IfcGeomMaterial.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/******************************************************************************** - * * - * This file is part of IfcOpenShell. * - * * - * IfcOpenShell is free software: you can redistribute it and/or modify * - * it under the terms of the Lesser GNU General Public License as published by * - * the Free Software Foundation, either version 3.0 of the License, or * - * (at your option) any later version. * - * * - * IfcOpenShell is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * Lesser GNU General Public License for more details. * - * * - * You should have received a copy of the Lesser GNU General Public License * - * along with this program. If not, see . * - * * - ********************************************************************************/ - -#include "IfcGeomMaterial.h" - -static double black[3] = {0.,0.,0.}; - -IfcGeom::Material::Material(const IfcGeom::SurfaceStyle* style) : style(style) {} -bool IfcGeom::Material::hasDiffuse() const { return style->Diffuse() ? true : false; } -bool IfcGeom::Material::hasSpecular() const { return style->Specular() ? true : false; } -bool IfcGeom::Material::hasTransparency() const { return style->Transparency() ? true : false; } -bool IfcGeom::Material::hasSpecularity() const { return style->Specularity() ? true : false; } -const double* IfcGeom::Material::diffuse() const { if (hasDiffuse()) return &((*style->Diffuse()).R()); else return black; } -const double* IfcGeom::Material::specular() const { if (hasSpecular()) return &((*style->Specular()).R()); else return black; } -double IfcGeom::Material::transparency() const { if (hasTransparency()) return *style->Transparency(); else return 0; } -double IfcGeom::Material::specularity() const { if (hasSpecularity()) return *style->Specularity(); else return 0; } -const std::string &IfcGeom::Material::name() const { return style->Name(); } -const std::string &IfcGeom::Material::original_name() const { return style->original_name(); } -bool IfcGeom::Material::operator==(const IfcGeom::Material& other) const { return style == other.style; } diff --git a/src/ifcgeom/schema_agnostic/IfcGeomMaterial.h b/src/ifcgeom/schema_agnostic/IfcGeomMaterial.h deleted file mode 100644 index c700aa7760..0000000000 --- a/src/ifcgeom/schema_agnostic/IfcGeomMaterial.h +++ /dev/null @@ -1,51 +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 . * - * * - ********************************************************************************/ - -#ifndef IFCGEOMMATERIAL_H -#define IFCGEOMMATERIAL_H - -#include - -#include "../../ifcgeom/schema_agnostic/IfcGeomRenderStyles.h" - -namespace IfcGeom { - - class IFC_GEOM_API Material { - private: - const IfcGeom::SurfaceStyle* style; - public: - explicit Material(const IfcGeom::SurfaceStyle* style = 0); // TODO default constructor for vector? - // Material(const Material& other); - // Material& operator=(const Material& other); - bool hasDiffuse() const; - bool hasSpecular() const; - bool hasTransparency() const; - bool hasSpecularity() const; - const double* diffuse() const; - const double* specular() const; - double transparency() const; - double specularity() const; - const std::string &name() const; - const std::string &original_name() const; - bool operator==(const Material& other) const; - }; - -} - -#endif diff --git a/src/ifcgeom/schema_agnostic/IfcGeomRenderStyles.h b/src/ifcgeom/schema_agnostic/IfcGeomRenderStyles.h index 5c98a70469..76b9b56924 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomRenderStyles.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomRenderStyles.h @@ -21,6 +21,7 @@ #define IFCGEOMRENDERSTYLES_H #include "../../ifcgeom/schema_agnostic/ifc_geom_api.h" +#include "../../ifcgeom/taxonomy.h" #include #include @@ -29,72 +30,7 @@ #include namespace IfcGeom { - class IFC_GEOM_API SurfaceStyle { - public: - class ColorComponent { - private: - double data[3]; - public: - ColorComponent(double r, double g, double b) { - data[0] = r; data[1] = g; data[2] = b; - } - const double& R() const { return data[0]; } - const double& G() const { return data[1]; } - const double& B() const { return data[2]; } - double& R() { return data[0]; } - double& G() { return data[1]; } - double& B() { return data[2]; } - }; - private: - std::string name; - std::string original_name_; - boost::optional id; - boost::optional diffuse, specular; - boost::optional transparency; - boost::optional specularity; - public: - SurfaceStyle() : name("surface-style") {} - SurfaceStyle(int id) : id(id) { - std::stringstream sstr; - sstr << "surface-style-" << id; - this->name = sstr.str(); - } - SurfaceStyle(const std::string& name) : name(name), original_name_(name) {} - SurfaceStyle(int id, const std::string& name) : original_name_(name), id(id) - { - std::stringstream sstr; - std::string sanitized = name; - boost::to_lower(sanitized); - boost::replace_all(sanitized, " ", "-"); - sstr << "surface-style-" << id << "-" << sanitized; - this->name = sstr.str(); - } - - // Not used at this point. In fact, equality testing in the current - // architecture can just as easily be accomplished by comparing the - // pointer addresses of the styles, as they are always referenced - // from out of a global map of some sort. - bool operator==(const SurfaceStyle& other) { - return name == other.name; - } - - /// ID name, e.g. "surface-style-66675-metal---aluminium" - const std::string& Name() const { return name; } - - /// Original name, if available, e.g. "Metal - Aluminium" - const std::string& original_name() const { return original_name_; } - - const boost::optional& Diffuse() const { return diffuse; } - const boost::optional& Specular() const { return specular; } - const boost::optional& Transparency() const { return transparency; } - const boost::optional& Specularity() const { return specularity; } - boost::optional& Diffuse() { return diffuse; } - boost::optional& Specular() { return specular; } - boost::optional& Transparency() { return transparency; } - boost::optional& Specularity() { return specularity; } - }; - - IFC_GEOM_API const SurfaceStyle* get_default_style(const std::string& ifc_type); + IFC_GEOM_API const ifcopenshell::geometry::taxonomy::style& get_default_style(const std::string& ifc_type); IFC_GEOM_API void set_default_style_file(const std::string& json_file); } diff --git a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.h b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.h index a2886803fc..2f354acc3d 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.h @@ -20,13 +20,12 @@ #ifndef IFCGEOMREPRESENTATION_H #define IFCGEOMREPRESENTATION_H -#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h" -#include "../../ifcgeom/schema_agnostic/IfcGeomMaterial.h" +#include "../../ifcgeom/settings.h" #include "../../ifcgeom/schema_agnostic/ConversionResult.h" #include -namespace IfcGeom { +namespace ifcopenshell { namespace geometry { namespace Representation { @@ -34,37 +33,37 @@ namespace IfcGeom { Representation(const Representation&); //N/A Representation& operator =(const Representation&); //N/A protected: - const ElementSettings settings_; + const element_settings settings_; public: - explicit Representation(const ElementSettings& settings) + explicit Representation(const element_settings& settings) : settings_(settings) {} - const ElementSettings& settings() const { return settings_; } + const element_settings& settings() const { return settings_; } virtual ~Representation() {} }; class IFC_GEOM_API BRep : public Representation { private: std::string id_; - const IfcGeom::ConversionResults shapes_; + const ifcopenshell::geometry::ConversionResults shapes_; BRep(const BRep& other); BRep& operator=(const BRep& other); public: - BRep(const ElementSettings& settings, const std::string& id, const IfcGeom::ConversionResults& shapes) + BRep(const element_settings& settings, const std::string& id, const ifcopenshell::geometry::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_; } + ifcopenshell::geometry::ConversionResults::const_iterator begin() const { return shapes_.begin(); } + ifcopenshell::geometry::ConversionResults::const_iterator end() const { return shapes_.end(); } + const ifcopenshell::geometry::ConversionResults& shapes() const { return shapes_; } const std::string& id() const { return id_; } - IfcGeom::ConversionResultShape* as_compound(bool force_meters = false) const; + ifcopenshell::geometry::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; + bool calculate_projected_surface_area(const ifcopenshell::geometry::ConversionResultPlacement* ax, double& along_x, double& along_y, double& along_z) const; }; class IFC_GEOM_API Serialization : public Representation { @@ -84,57 +83,55 @@ namespace IfcGeom { Serialization& operator=(const Serialization&); }; - template 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 > Coordinate; + typedef typename std::pair > Coordinate; typedef typename std::pair VertexKey; typedef std::map VertexKeyMap; typedef std::pair Edge; std::string id_; - std::vector

_verts; + std::vector _verts; std::vector _faces; std::vector _edges; - std::vector

_normals; - std::vector

uvs_; + std::vector _normals; + std::vector uvs_; std::vector _material_ids; - std::vector _materials; + std::vector _materials; VertexKeyMap welds; public: const std::string& id() const { return id_; } - const std::vector

& verts() const { return _verts; } + const std::vector& verts() const { return _verts; } const std::vector& faces() const { return _faces; } const std::vector& edges() const { return _edges; } - const std::vector

& normals() const { return _normals; } - const std::vector

& uvs() const { return uvs_; } + const std::vector& normals() const { return _normals; } + const std::vector& uvs() const { return uvs_; } const std::vector& material_ids() const { return _material_ids; } - const std::vector& materials() const { return _materials; } + const std::vector& 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 ) { + for ( ifcopenshell::geometry::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::const_iterator jt = std::find(_materials.begin(), _materials.end(), adapter); + std::vector::const_iterator jt = std::find(_materials.begin(), _materials.end(), iit->Style()); if (jt == _materials.end()) { surface_style_id = (int)_materials.size(); - _materials.push_back(adapter); + _materials.push_back(iit->Style()); } 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::const_iterator mit = std::find(_materials.begin(), _materials.end(), material); + if (settings().get(ifcopenshell::geometry::settings::APPLY_DEFAULT_MATERIALS) && surface_style_id == -1) { + const ifcopenshell::geometry::taxonomy::style& material = IfcGeom::get_default_style(settings().element_type()); + std::vector::const_iterator mit = std::find(_materials.begin(), _materials.end(), material); if (mit == _materials.end()) { surface_style_id = (int)_materials.size(); _materials.push_back(material); @@ -150,16 +147,16 @@ namespace IfcGeom { /// 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

box_project_uvs(const std::vector

&vertices, const std::vector

&normals) + static std::vector box_project_uvs(const std::vector &vertices, const std::vector &normals) { - std::vector

uvs; + std::vector 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]; + double n_x = normals[v_idx], n_y = normals[v_idx + 1], n_z = normals[v_idx + 2]; + double 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; @@ -181,13 +178,13 @@ namespace IfcGeom { 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

(convert ? (X / settings().unit_magnitude()) : X); - Y = static_cast

(convert ? (Y / settings().unit_magnitude()) : Y); - Z = static_cast

(convert ? (Z / settings().unit_magnitude()) : Z); + int addVertex(int material_index, double X, double Y, double Z) { + const bool convert = settings().get(ifcopenshell::geometry::settings::CONVERT_BACK_UNITS); + X = static_cast(convert ? (X / settings().unit_magnitude()) : X); + Y = static_cast(convert ? (Y / settings().unit_magnitude()) : Y); + Z = static_cast(convert ? (Z / settings().unit_magnitude()) : Z); int i = (int) _verts.size() / 3; - if (settings().get(IteratorSettings::WELD_VERTICES)) { + if (settings().get(ifcopenshell::geometry::settings::WELD_VERTICES)) { const VertexKey key = std::make_pair(material_index, std::make_pair(X, std::make_pair(Y, Z))); typename VertexKeyMap::const_iterator it = welds.find(key); if ( it != welds.end() ) return it->second; @@ -207,7 +204,7 @@ namespace IfcGeom { edges_temp.push_back(e); } - inline void addNormal(P X, P Y, P Z) { + inline void addNormal(double X, double Y, double Z) { _normals.push_back(X); _normals.push_back(Y); _normals.push_back(Z); @@ -233,6 +230,6 @@ namespace IfcGeom { }; } -} +}} #endif diff --git a/src/ifcgeom/schema_agnostic/IteratorImplementation.cpp b/src/ifcgeom/schema_agnostic/IteratorImplementation.cpp deleted file mode 100644 index 10fde43794..0000000000 --- a/src/ifcgeom/schema_agnostic/IteratorImplementation.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "IteratorImplementation.h" - -#include - -template -IteratorFactoryImplementation& iterator_implementations() { - static IteratorFactoryImplementation impl; - return impl; -} - -template IteratorFactoryImplementation& iterator_implementations(); -template IteratorFactoryImplementation& iterator_implementations(); -template IteratorFactoryImplementation& iterator_implementations(); - -template -extern void init_IteratorImplementation_Ifc2x3(IteratorFactoryImplementation*); - -template -extern void init_IteratorImplementation_Ifc4(IteratorFactoryImplementation*); - -template -IteratorFactoryImplementation::IteratorFactoryImplementation() { - init_IteratorImplementation_Ifc2x3(this); - init_IteratorImplementation_Ifc4(this); -} - -template -void IteratorFactoryImplementation::bind(const std::string& schema_name, typename get_factory_type::type fn) { - const std::string schema_name_lower = boost::to_lower_copy(schema_name); - this->insert(std::make_pair(schema_name_lower, fn)); -} - -template -IfcGeom::IteratorImplementation* IteratorFactoryImplementation::construct(const std::string& schema_name, const std::string& geometry_library, const IfcGeom::IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector& filters, int num_threads) { - const std::string schema_name_lower = boost::to_lower_copy(schema_name); - typename std::map::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(geometry_library, settings, file, filters, num_threads); -} - - -template class IteratorFactoryImplementation; -template class IteratorFactoryImplementation; -template class IteratorFactoryImplementation; diff --git a/src/ifcgeom/schema_agnostic/IteratorImplementation.h b/src/ifcgeom/schema_agnostic/IteratorImplementation.h deleted file mode 100644 index fc9b9e1754..0000000000 --- a/src/ifcgeom/schema_agnostic/IteratorImplementation.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef ITERATOR_IMPLEMENTATION_H -#define ITERATOR_IMPLEMENTATION_H - -#include "../../ifcparse/IfcFile.h" -#include "../../ifcgeom/schema_agnostic/IfcGeomFilter.h" -#include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h" - -#include - -#include - -#include -#include - -namespace IfcGeom { - template - class IteratorImplementation; - - template - class Element; - - template - class NativeElement; -} - -typedef boost::function5*, const std::string&, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector&, int> iterator_float_float_fn; -typedef boost::function5*, const std::string&, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector&, int> iterator_float_double_fn; -typedef boost::function5*, const std::string&, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector&, int> iterator_double_double_fn; - -template -struct get_factory_type {}; - -template <> -struct get_factory_type { - typedef iterator_float_float_fn type; -}; - -template <> -struct get_factory_type { - typedef iterator_float_double_fn type; -}; - -template <> -struct get_factory_type { - typedef iterator_double_double_fn type; -}; - -template -class IteratorFactoryImplementation : public std::map::type> { -public: - IteratorFactoryImplementation(); - void bind(const std::string& schema_name, typename get_factory_type::type fn); - IfcGeom::IteratorImplementation* construct(const std::string& schema_name, const std::string& geometry_library, const IfcGeom::IteratorSettings&, IfcParse::IfcFile*, const std::vector&, int); -}; - -template -IteratorFactoryImplementation& iterator_implementations(); - -namespace IfcGeom { - - template - class IteratorImplementation { - public: - virtual bool initialize() = 0; - virtual void compute_bounds() = 0; - virtual const gp_XYZ& bounds_min() const = 0; - virtual const gp_XYZ& bounds_max() const = 0; - virtual int progress() const = 0; - virtual const std::string& getUnitName() const = 0; - virtual double getUnitMagnitude() const = 0; - virtual IfcParse::IfcFile* file() const = 0; - virtual IfcUtil::IfcBaseClass* next() = 0; - virtual Element* get() = 0; - virtual NativeElement* get_native() = 0; - virtual const Element* get_object(int id) = 0; - virtual IfcUtil::IfcBaseClass* create() = 0; - }; - -} - -#endif \ No newline at end of file diff --git a/src/ifcgeom/schema_agnostic/Kernel.cpp b/src/ifcgeom/schema_agnostic/Kernel.cpp deleted file mode 100644 index 0f897f3b68..0000000000 --- a/src/ifcgeom/schema_agnostic/Kernel.cpp +++ /dev/null @@ -1,268 +0,0 @@ -#include "Kernel.h" - -#include "../../ifcparse/Ifc2x3.h" -#include "../../ifcparse/Ifc4.h" - -// @todo remove -#include "../../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h" - -#include -#include -#include -#include - -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, geometry_library, file); - } -} - -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); - return map.Extent(); - } else { - int i = 0; - TopExp_Explorer exp(s, t); - for (; exp.More(); exp.Next()) { - ++i; - } - return i; - } -} - - -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; - - return genus; -} - -IfcGeom::impl::KernelFactoryImplementation& IfcGeom::impl::kernel_implementations() { - static KernelFactoryImplementation impl; - return impl; -} - -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_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, 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(std::make_pair(schema_name_lower, geometry_library), fn)); -} - -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, 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); - } - return it->second(file); -} - -#define CREATE_GET_DECOMPOSING_ENTITY(IfcSchema) \ - \ -IfcSchema::IfcObjectDefinition* get_decomposing_entity_impl(IfcSchema::IfcProduct* product, bool include_openings) {\ - IfcSchema::IfcObjectDefinition* parent = 0; \ - \ - /* In case of an opening element, parent to the RelatingBuildingElement */ \ - if (include_openings && product->declaration().is(IfcSchema::IfcOpeningElement::Class())) { \ - IfcSchema::IfcOpeningElement* opening = (IfcSchema::IfcOpeningElement*)product; \ - IfcSchema::IfcRelVoidsElement::list::ptr voids = opening->VoidsElements(); \ - if (voids->size()) { \ - IfcSchema::IfcRelVoidsElement* ifc_void = *voids->begin(); \ - parent = ifc_void->RelatingBuildingElement(); \ - } \ - } else if (product->declaration().is(IfcSchema::IfcElement::Class())) { \ - IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)product; \ - IfcSchema::IfcRelFillsElement::list::ptr fills = element->FillsVoids(); \ - /* In case of a RelatedBuildingElement parent to the opening element */ \ - if (fills->size() && include_openings) { \ - for (IfcSchema::IfcRelFillsElement::list::it it = fills->begin(); it != fills->end(); ++it) { \ - IfcSchema::IfcRelFillsElement* fill = *it; \ - IfcSchema::IfcObjectDefinition* ifc_objectdef = fill->RelatingOpeningElement(); \ - if (product == ifc_objectdef) continue; \ - parent = ifc_objectdef; \ - } \ - } \ - /* Else simply parent to the containing structure */ \ - if (!parent) { \ - IfcSchema::IfcRelContainedInSpatialStructure::list::ptr parents = element->ContainedInStructure(); \ - if (parents->size()) { \ - IfcSchema::IfcRelContainedInSpatialStructure* container = *parents->begin(); \ - parent = container->RelatingStructure(); \ - } \ - } \ - } \ - \ - /* Parent decompositions to the RelatingObject */ \ - if (!parent) { \ - IfcEntityList::ptr parents = product->data().getInverse((&IfcSchema::IfcRelAggregates::Class()), -1); \ - parents->push(product->data().getInverse((&IfcSchema::IfcRelNests::Class()), -1)); \ - for (IfcEntityList::it it = parents->begin(); it != parents->end(); ++it) { \ - IfcSchema::IfcRelDecomposes* decompose = (IfcSchema::IfcRelDecomposes*)*it; \ - IfcUtil::IfcBaseEntity* ifc_objectdef; \ - \ - ifc_objectdef = get_RelatingObject(decompose); \ - \ - if (product == ifc_objectdef) continue; \ - parent = ifc_objectdef->as(); \ - } \ - } \ - return parent; \ -} - -namespace { - IfcUtil::IfcBaseEntity* get_RelatingObject(Ifc4::IfcRelDecomposes* decompose) { - Ifc4::IfcRelAggregates* aggr = decompose->as(); - if (aggr != nullptr) { - return aggr->RelatingObject(); - } - return nullptr; - } - - IfcUtil::IfcBaseEntity* get_RelatingObject(Ifc2x3::IfcRelDecomposes* decompose) { - return decompose->RelatingObject(); - } - - CREATE_GET_DECOMPOSING_ENTITY(Ifc2x3); - CREATE_GET_DECOMPOSING_ENTITY(Ifc4); -} - -IfcUtil::IfcBaseEntity* IfcGeom::Kernel::get_decomposing_entity(IfcUtil::IfcBaseEntity* inst, bool include_openings) { - if (inst->as()) { - return get_decomposing_entity_impl(inst->as(), include_openings); - } else if (inst->as()) { - return get_decomposing_entity_impl(inst->as(), include_openings); - } else if (inst->declaration().name() == "IfcProject") { - return nullptr; - } else { - throw IfcParse::IfcException("Unexpected entity " + inst->declaration().name()); - } -} - -namespace { - template - static std::map get_layers_impl(typename Schema::IfcProduct* prod) { - std::map layers; - if (prod->hasRepresentation()) { - IfcEntityList::ptr r = IfcParse::traverse(prod->Representation()); - typename Schema::IfcRepresentation::list::ptr representations = r->template as(); - for (typename Schema::IfcRepresentation::list::it it = representations->begin(); it != representations->end(); ++it) { - typename Schema::IfcPresentationLayerAssignment::list::ptr a = (*it)->LayerAssignments(); - for (typename Schema::IfcPresentationLayerAssignment::list::it jt = a->begin(); jt != a->end(); ++jt) { - layers[(*jt)->Name()] = *jt; - } - } - } - return layers; - } -} - -std::map IfcGeom::Kernel::get_layers(IfcUtil::IfcBaseEntity* inst) { - if (inst->as()) { - return get_layers_impl(inst->as()); - } else if (inst->as()) { - return get_layers_impl(inst->as()); - } else { - throw IfcParse::IfcException("Unexpected entity " + inst->declaration().name()); - } -} - -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()) { - OpenCascadeShape s(it.Value()); - if (!is_manifold(&s)) { - return false; - } - } - return true; - } else { - TopTools_IndexedDataMapOfShapeListOfShape map; - TopExp::MapShapesAndAncestors(a, TopAbs_EDGE, TopAbs_FACE, map); - - for (int i = 1; i <= map.Extent(); ++i) { - if (map.FindFromIndex(i).Extent() != 2) { - return false; - } - } - - return true; - } -} - -namespace { - template - 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(); - for (;;) { - auto decomposes = obdef->Decomposes()->generalize(); - if (decomposes->size() != 1) break; - typename Schema::IfcObjectDefinition* rel_obdef = (*decomposes->begin())->template as()->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()) { - return find_openings_helper(inst->as()); - } else if (inst->as()) { - return find_openings_helper(inst->as()); - } else { - throw IfcParse::IfcException("Unexpected entity " + inst->declaration().name()); - } -} diff --git a/src/ifcgeom/schema_agnostic/SurfaceStyle.cpp b/src/ifcgeom/schema_agnostic/SurfaceStyle.cpp index 6368cd9514..a936e30e19 100644 --- a/src/ifcgeom/schema_agnostic/SurfaceStyle.cpp +++ b/src/ifcgeom/schema_agnostic/SurfaceStyle.cpp @@ -7,49 +7,49 @@ namespace pt = boost::property_tree; -static std::map default_materials; -static IfcGeom::SurfaceStyle default_material; +static std::map default_materials; +static ifcopenshell::geometry::taxonomy::style default_material; static bool default_materials_initialized = false; void InitDefaultMaterials() { - default_materials.insert(std::make_pair("IfcSite", IfcGeom::SurfaceStyle("IfcSite"))); - default_materials["IfcSite"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.75, 0.8, 0.65)); + default_materials.insert(std::make_pair("IfcSite", ifcopenshell::geometry::taxonomy::style("IfcSite"))); + default_materials["IfcSite"].diffuse.reset(ifcopenshell::geometry::taxonomy::colour(0.75, 0.8, 0.65)); - default_materials.insert(std::make_pair("IfcSlab", IfcGeom::SurfaceStyle("IfcSlab"))); - default_materials["IfcSlab"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.4, 0.4, 0.4)); + default_materials.insert(std::make_pair("IfcSlab", ifcopenshell::geometry::taxonomy::style("IfcSlab"))); + default_materials["IfcSlab"].diffuse.reset(ifcopenshell::geometry::taxonomy::colour(0.4, 0.4, 0.4)); - default_materials.insert(std::make_pair("IfcWallStandardCase", IfcGeom::SurfaceStyle("IfcWallStandardCase"))); - default_materials["IfcWallStandardCase"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.9, 0.9, 0.9)); + default_materials.insert(std::make_pair("IfcWallStandardCase", ifcopenshell::geometry::taxonomy::style("IfcWallStandardCase"))); + default_materials["IfcWallStandardCase"].diffuse.reset(ifcopenshell::geometry::taxonomy::colour(0.9, 0.9, 0.9)); - default_materials.insert(std::make_pair("IfcWall", IfcGeom::SurfaceStyle("IfcWall"))); - default_materials["IfcWall"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.9, 0.9, 0.9)); + default_materials.insert(std::make_pair("IfcWall", ifcopenshell::geometry::taxonomy::style("IfcWall"))); + default_materials["IfcWall"].diffuse.reset(ifcopenshell::geometry::taxonomy::colour(0.9, 0.9, 0.9)); - default_materials.insert(std::make_pair("IfcWindow", IfcGeom::SurfaceStyle("IfcWindow"))); - default_materials["IfcWindow"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.75, 0.8, 0.75)); - default_materials["IfcWindow"].Transparency().reset(0.3); + default_materials.insert(std::make_pair("IfcWindow", ifcopenshell::geometry::taxonomy::style("IfcWindow"))); + default_materials["IfcWindow"].diffuse.reset(ifcopenshell::geometry::taxonomy::colour(0.75, 0.8, 0.75)); + default_materials["IfcWindow"].transparency.reset(0.3); - default_materials.insert(std::make_pair("IfcDoor", IfcGeom::SurfaceStyle("IfcDoor"))); - default_materials["IfcDoor"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.55, 0.3, 0.15)); + default_materials.insert(std::make_pair("IfcDoor", ifcopenshell::geometry::taxonomy::style("IfcDoor"))); + default_materials["IfcDoor"].diffuse.reset(ifcopenshell::geometry::taxonomy::colour(0.55, 0.3, 0.15)); - default_materials.insert(std::make_pair("IfcBeam", IfcGeom::SurfaceStyle("IfcBeam"))); - default_materials["IfcBeam"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.75, 0.7, 0.7)); + default_materials.insert(std::make_pair("IfcBeam", ifcopenshell::geometry::taxonomy::style("IfcBeam"))); + default_materials["IfcBeam"].diffuse.reset(ifcopenshell::geometry::taxonomy::colour(0.75, 0.7, 0.7)); - default_materials.insert(std::make_pair("IfcRailing", IfcGeom::SurfaceStyle("IfcRailing"))); - default_materials["IfcRailing"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.65, 0.6, 0.6)); + default_materials.insert(std::make_pair("IfcRailing", ifcopenshell::geometry::taxonomy::style("IfcRailing"))); + default_materials["IfcRailing"].diffuse.reset(ifcopenshell::geometry::taxonomy::colour(0.65, 0.6, 0.6)); - default_materials.insert(std::make_pair("IfcMember", IfcGeom::SurfaceStyle("IfcMember"))); - default_materials["IfcMember"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.65, 0.6, 0.6)); + default_materials.insert(std::make_pair("IfcMember", ifcopenshell::geometry::taxonomy::style("IfcMember"))); + default_materials["IfcMember"].diffuse.reset(ifcopenshell::geometry::taxonomy::colour(0.65, 0.6, 0.6)); - default_materials.insert(std::make_pair("IfcPlate", IfcGeom::SurfaceStyle("IfcPlate"))); - default_materials["IfcPlate"].Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.8, 0.8, 0.8)); + default_materials.insert(std::make_pair("IfcPlate", ifcopenshell::geometry::taxonomy::style("IfcPlate"))); + default_materials["IfcPlate"].diffuse.reset(ifcopenshell::geometry::taxonomy::colour(0.8, 0.8, 0.8)); - default_material = IfcGeom::SurfaceStyle("DefaultMaterial"); - default_material.Diffuse().reset(IfcGeom::SurfaceStyle::ColorComponent(0.7, 0.7, 0.7)); + default_material = ifcopenshell::geometry::taxonomy::style("DefaultMaterial"); + default_material.diffuse.reset(ifcopenshell::geometry::taxonomy::colour(0.7, 0.7, 0.7)); default_materials_initialized = true; } -boost::optional read_colour_component(const boost::optional list) { +boost::optional read_colour_component(const boost::optional list) { if (!list) { return boost::none; } @@ -65,7 +65,7 @@ boost::optional read_colour_component(con if (i != 3) { throw std::runtime_error("rgb array less than 3 elements large (was " + std::to_string(i) + ")"); } - return IfcGeom::SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]); + return ifcopenshell::geometry::taxonomy::colour(rgb[0], rgb[1], rgb[2]); } void IfcGeom::set_default_style_file(const std::string& json_file) { @@ -78,46 +78,45 @@ void IfcGeom::set_default_style_file(const std::string& json_file) { for (pt::ptree::value_type &material_pair : root) { std::string name = material_pair.first; - default_materials.insert(std::make_pair(name, IfcGeom::SurfaceStyle(name))); + default_materials.insert(std::make_pair(name, ifcopenshell::geometry::taxonomy::style(name))); pt::ptree material = material_pair.second; boost::optional diffuse = material.get_child_optional("diffuse"); - default_materials[name].Diffuse() = read_colour_component(diffuse); + default_materials[name].diffuse = read_colour_component(diffuse); boost::optional specular = material.get_child_optional("specular"); - default_materials[name].Specular() = read_colour_component(specular); + default_materials[name].specular = read_colour_component(specular); if (material.get_child_optional("specular-roughness")) { - default_materials[name].Specularity().reset(1.0 / material.get("specular-roughness")); + default_materials[name].specularity.reset(1.0 / material.get("specular-roughness")); } if (material.get_child_optional("transparency")) { - default_materials[name].Transparency() = material.get("transparency"); + default_materials[name].transparency = material.get("transparency"); } } // Is "*" present? If yes, remove it and make it the default style. - std::map::const_iterator it = default_materials.find("*"); + std::map::const_iterator it = default_materials.find("*"); if (it != default_materials.end()) { - IfcGeom::SurfaceStyle star = it->second; - default_material.Diffuse() = star.Diffuse(); - default_material.Specular() = star.Specular(); - default_material.Specularity() = star.Specularity(); - default_material.Transparency() = star.Transparency(); + ifcopenshell::geometry::taxonomy::style star = it->second; + default_material.diffuse = star.diffuse; + default_material.specular = star.specular; + default_material.specularity = star.specularity; + default_material.transparency = star.transparency; default_materials.erase(it); } } -const IfcGeom::SurfaceStyle* IfcGeom::get_default_style(const std::string& s) { +const ifcopenshell::geometry::taxonomy::style& IfcGeom::get_default_style(const std::string& s) { if (!default_materials_initialized) InitDefaultMaterials(); - std::map::const_iterator it = default_materials.find(s); + std::map::const_iterator it = default_materials.find(s); if (it == default_materials.end()) { - default_materials.insert(std::make_pair(s, IfcGeom::SurfaceStyle(s))); - default_materials[s].Diffuse() = default_material.Diffuse(); - default_materials[s].Specular() = default_material.Specular(); - default_materials[s].Specularity() = default_material.Specularity(); - default_materials[s].Transparency() = default_material.Transparency(); + default_materials.insert(std::make_pair(s, ifcopenshell::geometry::taxonomy::style(s))); + default_materials[s].diffuse = default_material.diffuse; + default_materials[s].specular = default_material.specular; + default_materials[s].specularity = default_material.specularity; + default_materials[s].transparency = default_material.transparency; it = default_materials.find(s); } - const IfcGeom::SurfaceStyle& surface_style = it->second; - return &surface_style; + return it->second; } diff --git a/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h b/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h index 75a41dd1b1..51680f645d 100644 --- a/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h +++ b/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h @@ -36,75 +36,76 @@ #include "../../../ifcgeom/schema_agnostic/ConversionResult.h" -namespace IfcGeom { +namespace ifcopenshell { + namespace geometry { - class OpenCascadePlacement : public ConversionResultPlacement { - public: - OpenCascadePlacement(const gp_GTrsf& trsf) - : trsf_(trsf) {} + 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_; } + 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 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 Multiply(const ConversionResultPlacement* other) { + trsf_.Multiply(((OpenCascadePlacement*)other)->trsf_); + } - virtual void PreMultiply(const ConversionResultPlacement* other) { - trsf_.PreMultiply(((OpenCascadePlacement*)other)->trsf_); - } + virtual void PreMultiply(const ConversionResultPlacement* other) { + trsf_.PreMultiply(((OpenCascadePlacement*)other)->trsf_); + } - virtual ConversionResultPlacement* clone() const { - return new OpenCascadePlacement(trsf_); - } + virtual ConversionResultPlacement* clone() const { + return new OpenCascadePlacement(trsf_); + } - virtual ConversionResultPlacement* inverted() const { - return new OpenCascadePlacement(trsf_.Inverted()); - } + 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 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) - {} + 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_; + }; - const TopoDS_Shape& shape() const { return shape_; } - operator const TopoDS_Shape& () { return shape_; } + class OpenCascadeShape : public ConversionResultShape { + public: + OpenCascadeShape(const TopoDS_Shape& shape) + : shape_(shape) {} - virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const; + 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* t, int surface_style_id) const; + virtual void Triangulate(const settings & settings, const ConversionResultPlacement * place, Representation::Triangulation* t, int surface_style_id) const; - virtual void Serialize(std::string&) const { - throw std::runtime_error("Not implemented"); - } + virtual void Triangulate(const settings & settings, const ConversionResultPlacement * place, Representation::Triangulation* t, int surface_style_id) const; - virtual ConversionResultShape* clone() const { - return new OpenCascadeShape(shape_); - } + virtual void Serialize(std::string&) const { + throw std::runtime_error("Not implemented"); + } - virtual int surface_genus() const; - private: - TopoDS_Shape shape_; - }; - + virtual ConversionResultShape* clone() const { + return new OpenCascadeShape(shape_); + } + + virtual int surface_genus() const; + private: + TopoDS_Shape shape_; + }; + + } } #endif \ No newline at end of file diff --git a/src/ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h b/src/ifcgeom/settings.h similarity index 94% rename from src/ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h rename to src/ifcgeom/settings.h index 1ad0850423..63032e9187 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h +++ b/src/ifcgeom/settings.h @@ -20,14 +20,17 @@ #ifndef IFCGEOMITERATORSETTINGS_H #define IFCGEOMITERATORSETTINGS_H -#include "ifc_geom_api.h" -#include "../../ifcparse/IfcException.h" -#include "../../ifcparse/IfcBaseClass.h" -#include "../../ifcparse/IfcLogger.h" +// #include "ifc_geom_api.h" -namespace IfcGeom -{ - class IFC_GEOM_API IteratorSettings +#define IFC_GEOM_API + +#include "../ifcparse/IfcException.h" +#include "../ifcparse/IfcBaseClass.h" +#include "../ifcparse/IfcLogger.h" + +namespace ifcopenshell { namespace geometry { + + class IFC_GEOM_API settings { public: /// Enumeration of setting identifiers. These settings define the @@ -93,7 +96,7 @@ namespace IfcGeom /// Used to store logical OR combination of setting flags. typedef unsigned SettingField; - IteratorSettings() + settings() : settings_(WELD_VERTICES) // OR options that default to true here , deflection_tolerance_(1.e-3) { @@ -136,13 +139,13 @@ namespace IfcGeom double deflection_tolerance_; }; - class IFC_GEOM_API ElementSettings : public IteratorSettings + class IFC_GEOM_API element_settings : public settings { public: - ElementSettings(const IteratorSettings& settings, + element_settings(const settings& s, double unit_magnitude, const std::string& element_type) - : IteratorSettings(settings) + : settings(s) , unit_magnitude_(unit_magnitude) , element_type_(element_type) { @@ -155,6 +158,7 @@ namespace IfcGeom double unit_magnitude_; std::string element_type_; }; -} + +}} #endif diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index 90ed25b764..4f32f05bb6 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -1,6 +1,17 @@ +#ifndef TAXONOMY_H +#define TAXONOMY_H + +#include "../ifcparse/IfcBaseClass.h" + #include +#include + +#include +#include +#include #include +#include namespace ifcopenshell { @@ -8,11 +19,16 @@ namespace geometry { namespace taxonomy { -struct item { - int instance_id; - virtual item* clone() const = 0; +enum kinds { MATRIX4, POINT3, DIRECTION3, LINE, CIRCLE, ELLIPSE, BSPLINE, EDGE, LOOP, FACE, EXTRUSION, NODE, COLOUR, STYLE }; - item(int id) : instance_id(id) {} +struct item { + const IfcUtil::IfcBaseClass* instance; + virtual item* clone() const = 0; + virtual kinds kind() const = 0; + + item(const IfcUtil::IfcBaseClass* instance = nullptr) : instance(instance) {} + + EIGEN_MAKE_ALIGNED_OPERATOR_NEW }; struct matrix4 : public item { @@ -20,53 +36,94 @@ struct matrix4 : public item { IDENTITY, AFFINE_WO_SCALE, AFFINE_W_UNIFORM_SCALE, AFFINE_W_NONUNIFORM_SCALE, OTHER }; tag_t tag; - std::array components; - matrix4() : components({1. ,0., 0., 0., 0., 1., 0., 0., 0., 0., 1. ,0., 0., 0., 0., 1.}), tag(IDENTITY) {} + + Eigen::Matrix4d components; + + matrix4() : components(Eigen::Matrix4d::Identity()), tag(IDENTITY) {} virtual item* clone() const { return new matrix4(*this); } + virtual kinds kind() const { return MATRIX4; } +}; + +struct colour : public item { + Eigen::Vector3d components; + + virtual item* clone() const { return new colour(*this); } + virtual kinds kind() const { return COLOUR; } + + colour() : components(Eigen::Vector3d::Zero()) {} + colour(double r, double g, double b) { components << r, g, b; } + + const double& r() const { return components[0]; } + const double& g() const { return components[1]; } + const double& b() const { return components[2]; } +}; + +struct style : public item { + // @todo this is not very efficient wrt alignment + boost::optional name; + boost::optional diffuse; + boost::optional specular; + boost::optional specularity, transparency; + + virtual item* clone() const { return new style(*this); } + virtual kinds kind() const { return STYLE; } + + // @todo equality implementation based on values? + bool operator==(const style& other) const { return instance == other.instance; } + + style() {} + style(const std::string& name) : name(name) {} }; struct geom_item : public item { - // geometry::style surface_style; + style surface_style; matrix4 matrix; - geom_item(int id) : item(id) {} - geom_item(int id, matrix4 m) : item(id), matrix(m) {} + geom_item(const IfcUtil::IfcBaseClass* instance = nullptr) : item(instance) {} + geom_item(const IfcUtil::IfcBaseClass* instance, matrix4 m) : item(instance), matrix(m) {} }; template struct cartesian_base : public geom_item { - std::array components; + Eigen::Vector3d components; - cartesian_base(double x, double y, double z = 0.) : components{ {x, y, z} } {} + cartesian_base() : components(Eigen::Vector3d::Zero()) {} + cartesian_base(double x, double y, double z = 0.) { components << x, y, z; } }; struct point3 : public cartesian_base<3> { virtual item* clone() const { return new point3(*this); } + virtual kinds kind() const { return POINT3; } point3(double x, double y, double z = 0.) : cartesian_base(x, y, z) {} }; struct direction3 : public cartesian_base<3> { virtual item* clone() const { return new direction3(*this); } + virtual kinds kind() const { return DIRECTION3; } direction3(double x, double y, double z = 0.) : cartesian_base(x, y, z) {} }; struct line : public geom_item { virtual item* clone() const { return new line(*this); } + virtual kinds kind() const { return LINE; } }; struct circle : public geom_item { virtual item* clone() const { return new circle(*this); } + virtual kinds kind() const { return CIRCLE; } }; struct ellipse : public geom_item { virtual item* clone() const { return new ellipse(*this); } + virtual kinds kind() const { return ELLIPSE; } }; struct bspline : public geom_item { virtual item* clone() const { return new bspline(*this); } + virtual kinds kind() const { return BSPLINE; } }; typedef boost::variant curve; @@ -76,12 +133,14 @@ struct edge : public geom_item { boost::optional basis; virtual item* clone() const { return new edge(*this); } + virtual kinds kind() const { return EDGE; } }; struct loop : public geom_item { std::vector edges; virtual item* clone() const { return new loop(*this); } + virtual kinds kind() const { return LOOP; } }; struct face : public geom_item { @@ -89,18 +148,19 @@ struct face : public geom_item { std::vector inner; virtual item* clone() const { return new face(*this); } + virtual kinds kind() const { return FACE; } - face(int id, loop o) : geom_item(id), outer(o) {} - face(int id, loop o, std::vector i) : geom_item(id), outer(o), inner(i) {} - face(int id, matrix4 m, loop o) : geom_item(id, m), outer(o) {} - face(int id, matrix4 m, loop o, std::vector i) : geom_item(id, m), outer(o), inner(i) {} + face(const IfcUtil::IfcBaseClass* instance, loop o) : geom_item(instance), outer(o) {} + face(const IfcUtil::IfcBaseClass* instance, loop o, std::vector i) : geom_item(instance), outer(o), inner(i) {} + face(const IfcUtil::IfcBaseClass* instance, matrix4 m, loop o) : geom_item(instance, m), outer(o) {} + face(const IfcUtil::IfcBaseClass* instance, matrix4 m, loop o, std::vector i) : geom_item(instance, m), outer(o), inner(i) {} }; struct sweep : public geom_item { face basis; - sweep(int id, face b) : geom_item(id), basis(b) {} - sweep(int id, matrix4 m, face b) : geom_item(id, m), basis(b) {} + sweep(const IfcUtil::IfcBaseClass* instance, face b) : geom_item(instance), basis(b) {} + sweep(const IfcUtil::IfcBaseClass* instance, matrix4 m, face b) : geom_item(instance, m), basis(b) {} }; struct extrusion : public sweep { @@ -108,11 +168,36 @@ struct extrusion : public sweep { double depth; virtual item* clone() const { return new extrusion(*this); } - extrusion(int id, matrix4 m, face basis, direction3 dir, double d) : sweep(id, m, basis), direction(dir), depth(d) {} + virtual kinds kind() const { return EXTRUSION; } + + extrusion(const IfcUtil::IfcBaseClass* instance, matrix4 m, face basis, direction3 dir, double d) : sweep(instance, m, basis), direction(dir), depth(d) {} +}; + +struct node : public geom_item { + std::map representations; + std::vector children; + + virtual item* clone() const { return new node(*this); } + virtual kinds kind() const { return NODE; } + + node(const IfcUtil::IfcBaseClass* instance, matrix4 m, const std::map& representations, const std::vector& children) : geom_item(instance, m), representations(representations), children(children) {} +}; + +namespace impl { + // enum kinds { MATRIX4, POINT3, DIRECTION3, LINE, CIRCLE, ELLIPSE, BSPLINE, EDGE, LOOP, FACE, EXTRUSION, NODE }; + typedef std::tuple KindsTuple; +} + +struct type_by_kind { + template + using type = typename std::tuple_element::type; + + static const size_t max = std::tuple_size< impl::KindsTuple>::value; }; class topology_error : public std::runtime_error { - +public: + topology_error() : std::runtime_error("Generic topology error") {} }; } @@ -122,3 +207,5 @@ class topology_error : public std::runtime_error { } } + +#endif \ No newline at end of file diff --git a/src/ifcparse/IfcBaseClass.h b/src/ifcparse/IfcBaseClass.h index 3caa6534fd..81395e972d 100644 --- a/src/ifcparse/IfcBaseClass.h +++ b/src/ifcparse/IfcBaseClass.h @@ -78,6 +78,21 @@ namespace IfcUtil { virtual const IfcParse::entity& declaration() const = 0; Argument* get(const std::string& name) const; + + template + T get_value_or(const std::string& name, const T& if_null) const { + auto arg = get(name); + if (arg->isNull()) { + return if_null; + } else { + return *arg; + } + } + + template + T get_value(const std::string& name) const { + return *get(name); + } }; // TODO: Investigate whether these should be template classes instead diff --git a/src/ifcparse/macros.h b/src/ifcparse/macros.h index 9552139bf5..ce3132b2a1 100644 --- a/src/ifcparse/macros.h +++ b/src/ifcparse/macros.h @@ -27,7 +27,7 @@ #define STRINGIFY_(x) #x #define STRINGIFY(x) STRINGIFY_(x) -#define MAKE_INIT_FN__(a, b) init_ ## a ## b +#define MAKE_INIT_FN__(a, b) init_ ## a ## _ ## b #define MAKE_INIT_FN_(a, b) MAKE_INIT_FN__(a, b) #define MAKE_INIT_FN(t) MAKE_INIT_FN_(t, IfcSchema) diff --git a/src/serializers/ColladaSerializer.cpp b/src/serializers/ColladaSerializer.cpp index 4a4ae6934b..d5434c92da 100644 --- a/src/serializers/ColladaSerializer.cpp +++ b/src/serializers/ColladaSerializer.cpp @@ -66,7 +66,7 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write( const std::string &mesh_id, const std::string &/**<@todo 'default_material_name' unused, remove? */, const std::vector& positions, const std::vector& normals, const std::vector& faces, const std::vector& edges, - const std::vector& material_ids, const std::vector& /**<@todo 'materials' unused, remove? */, + const std::vector& material_ids, const std::vector& /**<@todo 'materials' unused, remove? */, const std::vector& uvs, const std::vector& material_references) { openMesh(mesh_id); @@ -179,7 +179,7 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::close() { void ColladaSerializer::ColladaExporter::ColladaScene::add( const std::string& node_id, const std::string& node_name, const std::string& geom_name, - const std::vector& material_ids, const IfcGeom::Transformation& transformation) + const std::vector& material_ids, const ifcopenshell::geometry::Transformation& transformation) { if (!scene_opened) { openVisualScene(scene_id); @@ -194,13 +194,13 @@ void ColladaSerializer::ColladaExporter::ColladaScene::add( // The matrix attribute of an entity is basically a 4x3 representation of its ObjectPlacement. // Note that this placement is absolute, ie it is multiplied with all parent placements. - IfcGeom::Transformation* relative_trsf = 0; - const IfcGeom::Transformation* transformation_towrite = &transformation; + ifcopenshell::geometry::Transformation* relative_trsf = 0; + const ifcopenshell::geometry::Transformation* transformation_towrite = &transformation; // If this is not the first parent, get the relative placement if (parentNodes.size() > 0) { - relative_trsf = new IfcGeom::Transformation(matrixStack.top().multiplied(transformation)); + relative_trsf = new ifcopenshell::geometry::Transformation(matrixStack.top().multiplied(transformation)); transformation_towrite = relative_trsf; } @@ -236,22 +236,22 @@ void ColladaSerializer::ColladaExporter::ColladaScene::add( node.end(); } -void ColladaSerializer::ColladaExporter::ColladaScene::addParent(const IfcGeom::Element& parent){ +void ColladaSerializer::ColladaExporter::ColladaScene::addParent(const ifcopenshell::geometry::Element& parent){ //we open the visual scene tag if it's not. if (!scene_opened) { openVisualScene(scene_id); scene_opened = true; } - const IfcGeom::Transformation& parent_trsf = parent.transformation(); + const ifcopenshell::geometry::Transformation& parent_trsf = parent.transformation(); - IfcGeom::Transformation* relative_trsf = 0; - const IfcGeom::Transformation* transformation_towrite = &parent_trsf; + ifcopenshell::geometry::Transformation* relative_trsf = 0; + const ifcopenshell::geometry::Transformation* transformation_towrite = &parent_trsf; // If this is not the first parent, get the relative placement if (parentNodes.size() > 0) { - relative_trsf = new IfcGeom::Transformation(matrixStack.top().multiplied(parent_trsf)); + relative_trsf = new ifcopenshell::geometry::Transformation(matrixStack.top().multiplied(parent_trsf)); transformation_towrite = relative_trsf; } @@ -311,24 +311,24 @@ void ColladaSerializer::ColladaExporter::ColladaScene::write() { } void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write( - const IfcGeom::Material &material, const std::string &material_uri) + const ifcopenshell::geometry::taxonomy::style &material, const std::string &material_uri) { openEffect(material_uri + "-fx"); COLLADASW::EffectProfile effect(mSW); effect.setShaderType(COLLADASW::EffectProfile::LAMBERT); - if (material.hasDiffuse()) { - const double* diffuse = material.diffuse(); + if (material.diffuse) { + auto diffuse = material.diffuse.get().components; effect.setDiffuse(COLLADASW::ColorOrTexture(COLLADASW::Color(diffuse[0],diffuse[1],diffuse[2]))); } - if (material.hasSpecular()) { - const double* specular = material.specular(); + if (material.specular) { + auto specular = material.specular.get().components; effect.setSpecular(COLLADASW::ColorOrTexture(COLLADASW::Color(specular[0],specular[1],specular[2]))); } - if (material.hasSpecularity()) { - effect.setShininess(material.specularity()); + if (material.specularity) { + effect.setShininess(*material.specularity); } - if (material.hasTransparency()) { - const double transparency = material.transparency(); + if (material.transparency) { + const double transparency = *material.transparency; if (transparency > 0) { // The default opacity mode for Collada is A_ONE, which apparently indicates a // transparency value of 1 to be fully opaque. Hence transparency is inverted. @@ -343,13 +343,14 @@ void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::close closeLibrary(); } -void ColladaSerializer::ColladaExporter::ColladaMaterials::add(const IfcGeom::Material& material) { +void ColladaSerializer::ColladaExporter::ColladaMaterials::add(const ifcopenshell::geometry::taxonomy::style& material) { if (!contains(material)) { - std::string material_name = (serializer->settings().get(SerializerSettings::USE_MATERIAL_NAMES) - ? material.original_name() : material.name()); + // @todo original_name + std::string material_name = *(serializer->settings().get(SerializerSettings::USE_MATERIAL_NAMES) + ? material.name : material.name); if (material_name.empty()) { - material_name = "missing-material-" + material.name(); + material_name = "missing-material-" + *material.name; } collada_id(material_name); @@ -360,19 +361,19 @@ void ColladaSerializer::ColladaExporter::ColladaMaterials::add(const IfcGeom::Ma } } -std::string ColladaSerializer::ColladaExporter::ColladaMaterials::getMaterialUri(const IfcGeom::Material& material) { - std::vector::iterator it = std::find(materials.begin(), materials.end(), material); +std::string ColladaSerializer::ColladaExporter::ColladaMaterials::getMaterialUri(const ifcopenshell::geometry::taxonomy::style& material) { + std::vector::iterator it = std::find(materials.begin(), materials.end(), material); ptrdiff_t index = std::distance(materials.begin(), it); return material_uris.at(index); } -bool ColladaSerializer::ColladaExporter::ColladaMaterials::contains(const IfcGeom::Material& material) { +bool ColladaSerializer::ColladaExporter::ColladaMaterials::contains(const ifcopenshell::geometry::taxonomy::style& material) { return std::find(materials.begin(), materials.end(), material) != materials.end(); } void ColladaSerializer::ColladaExporter::ColladaMaterials::write() { effects.close(); - BOOST_FOREACH(const IfcGeom::Material& material, materials) { + BOOST_FOREACH(const ifcopenshell::geometry::taxonomy::style& material, materials) { std::string material_name = getMaterialUri(material); openMaterial(material_name); @@ -395,9 +396,9 @@ void ColladaSerializer::ColladaExporter::startDocument(const std::string& unit_n asset.add(); } -void ColladaSerializer::ColladaExporter::write(const IfcGeom::TriangulationElement* o) +void ColladaSerializer::ColladaExporter::write(const ifcopenshell::geometry::TriangulationElement* o) { - const IfcGeom::Representation::Triangulation& mesh = o->geometry(); + const ifcopenshell::geometry::Representation::Triangulation& mesh = o->geometry(); std::string name = serializer->object_id(o); collada_id(name); @@ -406,7 +407,7 @@ void ColladaSerializer::ColladaExporter::write(const IfcGeom::TriangulationEleme collada_id(representation_id); std::vector material_references; - BOOST_FOREACH(const IfcGeom::Material& material, mesh.materials()) { + BOOST_FOREACH(const ifcopenshell::geometry::taxonomy::style& material, mesh.materials()) { materials.add(material); std::string material_name = materials.getMaterialUri(material); @@ -456,7 +457,7 @@ std::string ColladaSerializer::differentiateSlabTypes(const IfcUtil::IfcBaseEnti return result; } -std::string ColladaSerializer::object_id(const IfcGeom::Element* o) /*override*/ +std::string ColladaSerializer::object_id(const ifcopenshell::geometry::Element* o) /*override*/ { if (settings_.get(SerializerSettings::USE_ELEMENT_TYPES)) { const std::string slabSuffix = (o->product() && o->product()->declaration().name() == "IfcSlab") @@ -549,7 +550,7 @@ void ColladaSerializer::writeHeader() { exporter.startDocument(unit_name, unit_magnitude); } -void ColladaSerializer::write(const IfcGeom::TriangulationElement* o) { +void ColladaSerializer::write(const ifcopenshell::geometry::TriangulationElement* o) { exporter.write(o); } diff --git a/src/serializers/ColladaSerializer.h b/src/serializers/ColladaSerializer.h index 3236dc3e69..849612e81e 100644 --- a/src/serializers/ColladaSerializer.h +++ b/src/serializers/ColladaSerializer.h @@ -41,8 +41,6 @@ #pragma GCC diagnostic pop #endif -#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h" - #include "../serializers/GeometrySerializer.h" #include @@ -68,14 +66,14 @@ private: , serializer(_serializer) {} void addFloatSource(const std::string& mesh_id, const std::string& suffix, - const std::vector& floats, const char* coords = "XYZ"); + const std::vector& floats, const char* coords = "XYZ"); /// @todo pass simply DeferredObject? void write( const std::string &mesh_id, const std::string &default_material_name, - const std::vector& positions, const std::vector& normals, + const std::vector& positions, const std::vector& normals, const std::vector& faces, const std::vector& edges, - const std::vector& material_ids, const std::vector& materials, - const std::vector& uvs, const std::vector& material_references); + const std::vector& material_ids, const std::vector& materials, + const std::vector& uvs, const std::vector& material_references); void close(); ColladaSerializer *serializer; }; @@ -88,7 +86,7 @@ private: const std::string scene_id; bool scene_opened; std::stack parentNodes; - std::stack > matrixStack; + std::stack matrixStack; public: ColladaScene(const std::string& scene_id, COLLADASW::StreamWriter& stream, ColladaSerializer *_serializer) : COLLADASW::LibraryVisualScenes(&stream) @@ -97,8 +95,8 @@ private: , serializer(_serializer) {} void add(const std::string& node_id, const std::string& node_name, const std::string& geom_name, - const std::vector& material_ids, const IfcGeom::Transformation& matrix); - void addParent(const IfcGeom::Element& parent); + const std::vector& material_ids, const ifcopenshell::geometry::Transformation& matrix); + void addParent(const ifcopenshell::geometry::Element& parent); void closeParent(); COLLADASW::Node* GetDirectParent(); void write(); @@ -117,11 +115,11 @@ private: explicit ColladaEffects(COLLADASW::StreamWriter& stream) : COLLADASW::LibraryEffects(&stream) {} - void write(const IfcGeom::Material &material, const std::string &material_uri); + void write(const ifcopenshell::geometry::taxonomy::style &material, const std::string &material_uri); void close(); ColladaSerializer *serializer; }; - std::vector materials; + std::vector materials; std::vector material_uris; public: explicit ColladaMaterials(COLLADASW::StreamWriter& stream, ColladaSerializer *_serializer) @@ -129,9 +127,9 @@ private: , serializer(_serializer) , effects(stream) {} - void add(const IfcGeom::Material& material); - std::string getMaterialUri(const IfcGeom::Material& material); - bool contains(const IfcGeom::Material& material); + void add(const ifcopenshell::geometry::taxonomy::style& material); + std::string getMaterialUri(const ifcopenshell::geometry::taxonomy::style& material); + bool contains(const ifcopenshell::geometry::taxonomy::style& material); void write(); ColladaSerializer *serializer; ColladaEffects effects; @@ -158,21 +156,21 @@ private: public: std::string unique_id, representation_id, type; - IfcGeom::Transformation transformation; - std::vector vertices; - std::vector normals; + ifcopenshell::geometry::Transformation transformation; + std::vector vertices; + std::vector normals; std::vector faces; std::vector edges; std::vector material_ids; - std::vector materials; + std::vector materials; std::vector material_references; - std::vector uvs; - std::vector*> parents_; + std::vector uvs; + std::vector parents_; - DeferredObject(const std::string& unique_id, const std::string& representation_id, const std::string& type, const IfcGeom::Transformation& transformation, - const std::vector& vertices, const std::vector& normals, const std::vector& faces, - const std::vector& edges, const std::vector& material_ids, const std::vector& materials, - const std::vector& material_references, const std::vector& uvs) + DeferredObject(const std::string& unique_id, const std::string& representation_id, const std::string& type, const ifcopenshell::geometry::Transformation& transformation, + const std::vector& vertices, const std::vector& normals, const std::vector& faces, + const std::vector& edges, const std::vector& material_ids, const std::vector& materials, + const std::vector& material_references, const std::vector& uvs) : unique_id(unique_id) , representation_id(representation_id) , type(type) @@ -187,8 +185,8 @@ private: , uvs(uvs) {} - std::vector*>& parents() { return parents_; } - const std::vector*>& parents() const { return parents_; } + std::vector& parents() { return parents_; } + const std::vector& parents() const { return parents_; } }; COLLADABU::NativeString filename; COLLADASW::StreamWriter stream; @@ -211,7 +209,7 @@ private: std::vector deferreds; virtual ~ColladaExporter() {} void startDocument(const std::string& unit_name, float unit_magnitude); - void write(const IfcGeom::TriangulationElement* o); + void write(const ifcopenshell::geometry::TriangulationElement* o); void endDocument(); }; ColladaExporter exporter; @@ -229,8 +227,8 @@ public: } bool ready(); void writeHeader(); - void write(const IfcGeom::TriangulationElement* o); - void write(const IfcGeom::NativeElement* /*o*/) {} + void write(const ifcopenshell::geometry::TriangulationElement* o); + void write(const ifcopenshell::geometry::NativeElement* /*o*/) {} void finalize(); bool isTesselated() const { return true; } void setUnitNameAndMagnitude(const std::string& name, float magnitude) { @@ -239,7 +237,7 @@ public: } void setFile(IfcParse::IfcFile*) {} - std::string object_id(const IfcGeom::Element* o) /*override*/; + std::string object_id(const ifcopenshell::geometry::Element* o) /*override*/; private: static std::string differentiateSlabTypes(const IfcUtil::IfcBaseEntity* slab); diff --git a/src/serializers/GeometrySerializer.h b/src/serializers/GeometrySerializer.h index ff50154f29..3eec952cc7 100644 --- a/src/serializers/GeometrySerializer.h +++ b/src/serializers/GeometrySerializer.h @@ -27,29 +27,29 @@ typedef float real_t; #endif #include "../serializers/Serializer.h" -#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h" #include "../ifcgeom/schema_agnostic/IfcGeomElement.h" +#include "../ifcgeom/settings.h" -class SerializerSettings : public IfcGeom::IteratorSettings +class SerializerSettings : public ifcopenshell::geometry::settings { public: enum Setting { /// Use entity names instead of unique IDs for naming elements. /// Applicable for OBJ, DAE, and SVG output. - USE_ELEMENT_NAMES = 1 << (IfcGeom::IteratorSettings::NUM_SETTINGS + 1), + USE_ELEMENT_NAMES = 1 << (ifcopenshell::geometry::settings::NUM_SETTINGS + 1), /// Use entity GUIDs instead of unique IDs for naming elements. /// Applicable for OBJ, DAE, and SVG output. - USE_ELEMENT_GUIDS = 1 << (IfcGeom::IteratorSettings::NUM_SETTINGS + 2), + USE_ELEMENT_GUIDS = 1 << (ifcopenshell::geometry::settings::NUM_SETTINGS + 2), /// Use material names instead of unique IDs for naming materials. /// Applicable for OBJ and DAE output. - USE_MATERIAL_NAMES = 1 << (IfcGeom::IteratorSettings::NUM_SETTINGS + 3), + USE_MATERIAL_NAMES = 1 << (ifcopenshell::geometry::settings::NUM_SETTINGS + 3), /// Use element types instead of unique IDs for naming elements. /// Applicable for DAE output. - USE_ELEMENT_TYPES = 1 << (IfcGeom::IteratorSettings::NUM_SETTINGS + 4), + USE_ELEMENT_TYPES = 1 << (ifcopenshell::geometry::settings::NUM_SETTINGS + 4), /// Order the elements using their IfcBuildingStorey parent /// Applicable for DAE output - USE_ELEMENT_HIERARCHY = 1 << (IfcGeom::IteratorSettings::NUM_SETTINGS + 5), + USE_ELEMENT_HIERARCHY = 1 << (ifcopenshell::geometry::settings::NUM_SETTINGS + 5), /// Number of different setting flags. NUM_SETTINGS = 5 }; @@ -76,15 +76,15 @@ public: virtual ~GeometrySerializer() {} virtual bool isTesselated() const = 0; - virtual void write(const IfcGeom::TriangulationElement* o) = 0; - virtual void write(const IfcGeom::NativeElement* o) = 0; + virtual void write(const ifcopenshell::geometry::TriangulationElement* o) = 0; + virtual void write(const ifcopenshell::geometry::NativeElement* o) = 0; virtual void setUnitNameAndMagnitude(const std::string& name, float magnitude) = 0; const SerializerSettings& settings() const { return settings_; } SerializerSettings& settings() { return settings_; } /// Returns ID for the object depending on the used setting. - virtual std::string object_id(const IfcGeom::Element* o) + virtual std::string object_id(const ifcopenshell::geometry::Element* o) { if (settings_.get(SerializerSettings::USE_ELEMENT_GUIDS)) return o->guid(); if (settings_.get(SerializerSettings::USE_ELEMENT_NAMES)) return o->name(); diff --git a/src/serializers/OpenCascadeBasedSerializer.h b/src/serializers/OpenCascadeBasedSerializer.h index bb92b4fd1c..81b8bbd126 100644 --- a/src/serializers/OpenCascadeBasedSerializer.h +++ b/src/serializers/OpenCascadeBasedSerializer.h @@ -20,7 +20,6 @@ #ifndef OPENCASCADEBASEDSERIALIZER_H #define OPENCASCADEBASEDSERIALIZER_H -#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h" #include "../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h" #include "../serializers/GeometrySerializer.h" diff --git a/src/serializers/schema_dependent/XmlSerializer.cpp b/src/serializers/schema_dependent/XmlSerializer.cpp index d47c184555..dbe310d538 100644 --- a/src/serializers/schema_dependent/XmlSerializer.cpp +++ b/src/serializers/schema_dependent/XmlSerializer.cpp @@ -28,7 +28,7 @@ #include "../../ifcparse/IfcSIPrefix.h" #include "../../ifcparse/utils.h" -#include "../../ifcgeom/kernels/opencascade/IfcGeom.h" +#include "../../ifcgeom/abstract_mapping.h" using boost::property_tree::ptree; @@ -57,7 +57,7 @@ std::map POSTFIX_SCHEMA(argument_name_map); // Format an IFC attribute and maybe returns as string. Only literal scalar // values are converted. Things like entity instances and lists are omitted. -boost::optional format_attribute(const Argument* argument, IfcUtil::ArgumentType argument_type, const std::string& argument_name) { +boost::optional format_attribute(ifcopenshell::geometry::abstract_mapping* mapping, const Argument* argument, IfcUtil::ArgumentType argument_type, const std::string& argument_name) { boost::optional value; // Hard-code lat-lon as it represents an array @@ -106,7 +106,7 @@ boost::optional format_attribute(const Argument* argument, IfcUtil: IfcUtil::IfcBaseClass* e = *argument; if (!e->declaration().as_entity()) { IfcUtil::IfcBaseType* f = (IfcUtil::IfcBaseType*) e; - value = format_attribute(f->data().getArgument(0), f->data().getArgument(0)->type(), argument_name); + value = format_attribute(mapping, f->data().getArgument(0), f->data().getArgument(0)->type(), argument_name); } else if (e->declaration().is(IfcSchema::IfcSIUnit::Class()) || e->declaration().is(IfcSchema::IfcConversionBasedUnit::Class())) { // Some string concatenation to have a unit name as a XML attribute. @@ -125,21 +125,21 @@ boost::optional format_attribute(const Argument* argument, IfcUtil: value = unit_name; } else if (e->declaration().is(IfcSchema::IfcLocalPlacement::Class())) { - IfcSchema::IfcLocalPlacement* placement = e->as(); - gp_Trsf trsf; - IfcGeom::POSTFIX_SCHEMA(Kernel) kernel; - - if (kernel.convert(placement, trsf)) { - std::stringstream stream; - for (int i = 1; i < 5; ++i) { - for (int j = 1; j < 4; ++j) { - const double trsf_value = trsf.Value(j, i); - stream << trsf_value << " "; - } - stream << ((i == 4) ? "1" : "0 "); + auto placement = mapping->map(e); + auto matrix = (ifcopenshell::geometry::taxonomy::matrix4*) placement; + + std::stringstream stream; + for (int i = 0; i < 16; ++i) { + const double trsf_value = matrix->components[i]; + stream << trsf_value; + if (i != 15) { + stream << " "; } - value = stream.str(); - } + } + value = stream.str(); + + delete mapping; + delete placement; } break; } default: @@ -149,7 +149,7 @@ boost::optional format_attribute(const Argument* argument, IfcUtil: } // Appends to a node with possibly existing attributes -ptree& format_entity_instance(IfcUtil::IfcBaseEntity* instance, ptree& child, ptree& tree, bool as_link = false) { +ptree& format_entity_instance(ifcopenshell::geometry::abstract_mapping* mapping, IfcUtil::IfcBaseEntity* instance, ptree& child, ptree& tree, bool as_link = false) { const unsigned n = instance->declaration().attribute_count(); for (unsigned i = 0; i < n; ++i) { try { @@ -172,11 +172,9 @@ ptree& format_entity_instance(IfcUtil::IfcBaseEntity* instance, ptree& child, pt const std::string qualified_name = instance->declaration().name() + "." + argument_name; boost::optional value; try { - value = format_attribute(argument, argument_type, qualified_name); + value = format_attribute(mapping, argument, argument_type, qualified_name); } catch (const std::exception& e) { Logger::Error(e); - } catch (const Standard_ConstructionError& e) { - Logger::Error(e.GetMessageString(), instance); } if (value) { @@ -196,9 +194,9 @@ ptree& format_entity_instance(IfcUtil::IfcBaseEntity* instance, ptree& child, pt // Formats an entity instances as a ptree node, and insert into the DOM. Recurses // over the entity attributes and writes them as xml attributes of the node. -ptree& format_entity_instance(IfcUtil::IfcBaseEntity* instance, ptree& tree, bool as_link = false) { +ptree& format_entity_instance(ifcopenshell::geometry::abstract_mapping* mapping, IfcUtil::IfcBaseEntity* instance, ptree& tree, bool as_link = false) { ptree child; - return format_entity_instance(instance, child, tree, as_link); + return format_entity_instance(mapping, instance, child, tree, as_link); } std::string qualify_unrooted_instance(IfcUtil::IfcBaseClass* inst) { @@ -208,11 +206,11 @@ std::string qualify_unrooted_instance(IfcUtil::IfcBaseClass* inst) { // A function to be called recursively. Template specialization is used // to descend into decomposition, containment and property relationships. template -ptree& descend(A* instance, ptree& tree) { +ptree& descend(ifcopenshell::geometry::abstract_mapping* mapping, A* instance, ptree& tree) { if (instance->declaration().is(IfcSchema::IfcObjectDefinition::Class())) { - return descend(instance->template as(), tree); + return descend(mapping, instance->template as(), tree); } else { - return format_entity_instance(instance, tree); + return format_entity_instance(mapping, instance, tree); } } @@ -232,8 +230,8 @@ typename V::list::ptr get_related(T* t, F f, G g) { // Descends into the tree by recursing into IfcRelContainedInSpatialStructure, // IfcRelDecomposes, IfcRelDefinesByType, IfcRelDefinesByProperties relations. template <> -ptree& descend(IfcSchema::IfcObjectDefinition* product, ptree& tree) { - ptree& child = format_entity_instance(product, tree); +ptree& descend(ifcopenshell::geometry::abstract_mapping* mapping, IfcSchema::IfcObjectDefinition* product, ptree& tree) { + ptree& child = format_entity_instance(mapping, product, tree); if (product->declaration().is(IfcSchema::IfcSpatialStructureElement::Class())) { IfcSchema::IfcSpatialStructureElement* structure = (IfcSchema::IfcSpatialStructureElement*) product; @@ -243,7 +241,7 @@ ptree& descend(IfcSchema::IfcObjectDefinition* product, ptree& tree) { (structure, &IfcSchema::IfcSpatialStructureElement::ContainsElements, &IfcSchema::IfcRelContainedInSpatialStructure::RelatedElements); for (IfcSchema::IfcObjectDefinition::list::it it = elements->begin(); it != elements->end(); ++it) { - descend(*it, child); + descend(mapping, *it, child); } } @@ -253,7 +251,7 @@ ptree& descend(IfcSchema::IfcObjectDefinition* product, ptree& tree) { element, &IfcSchema::IfcElement::HasOpenings, &IfcSchema::IfcRelVoidsElement::RelatedOpeningElement); for (IfcSchema::IfcOpeningElement::list::it it = openings->begin(); it != openings->end(); ++it) { - descend(*it, child); + descend(mapping, *it, child); } } @@ -269,7 +267,7 @@ ptree& descend(IfcSchema::IfcObjectDefinition* product, ptree& tree) { for (IfcSchema::IfcObjectDefinition::list::it it = structures->begin(); it != structures->end(); ++it) { IfcSchema::IfcObjectDefinition* ob = *it; - descend(ob, child); + descend(mapping, ob, child); } if (product->declaration().is(IfcSchema::IfcObject::Class())) { @@ -282,13 +280,13 @@ ptree& descend(IfcSchema::IfcObjectDefinition* product, ptree& tree) { for (IfcSchema::IfcPropertySetDefinition::list::it it = property_sets->begin(); it != property_sets->end(); ++it) { IfcSchema::IfcPropertySetDefinition* pset = *it; if (pset->declaration().is(IfcSchema::IfcPropertySet::Class())) { - format_entity_instance(pset, child, true); + format_entity_instance(mapping, pset, child, true); } if (pset->declaration().is(IfcSchema::IfcElementQuantity::Class())) { - format_entity_instance(pset, child, true); + format_entity_instance(mapping, pset, child, true); } if (pset->declaration().is(IfcSchema::IfcElementQuantity::Class())) { - format_entity_instance(pset, child, true); + format_entity_instance(mapping, pset, child, true); } } @@ -304,19 +302,19 @@ ptree& descend(IfcSchema::IfcObjectDefinition* product, ptree& tree) { for (IfcSchema::IfcTypeObject::list::it it = types->begin(); it != types->end(); ++it) { IfcSchema::IfcTypeObject* type = *it; - format_entity_instance(type, child, true); + format_entity_instance(mapping, type, child, true); } } if (product->declaration().is(IfcSchema::IfcProduct::Class())) { - std::map layers = IfcGeom::Kernel::get_layers(product); + std::map layers = mapping->get_layers(product); for (std::map::const_iterator it = layers.begin(); it != layers.end(); ++it) { // IfcPresentationLayerAssignments don't have GUIDs (only optional Identifier) so use name as the ID. // Note that the IfcPresentationLayerAssignment passed here doesn't really matter as as_link is true // for the format_entity_instance() call. ptree node; node.put(".xlink:href", "#" + it->first); - format_entity_instance(it->second, node, child, true); + format_entity_instance(mapping, it->second, node, child, true); } IfcSchema::IfcRelAssociates::list::ptr associations = product->HasAssociations(); @@ -325,7 +323,7 @@ ptree& descend(IfcSchema::IfcObjectDefinition* product, ptree& tree) { IfcSchema::IfcMaterialSelect* mat = (*it)->as()->RelatingMaterial(); ptree node; node.put(".xlink:href", "#" + qualify_unrooted_instance(mat)); - format_entity_instance((IfcUtil::IfcBaseEntity*) mat, node, child, true); + format_entity_instance(mapping, (IfcUtil::IfcBaseEntity*) mat, node, child, true); } } } @@ -334,26 +332,26 @@ ptree& descend(IfcSchema::IfcObjectDefinition* product, ptree& tree) { } // Format IfcProperty instances and insert into the DOM. IfcComplexProperties are flattened out. -void format_properties(IfcSchema::IfcProperty::list::ptr properties, ptree& node) { +void format_properties(ifcopenshell::geometry::abstract_mapping* mapping, IfcSchema::IfcProperty::list::ptr properties, ptree& node) { for (IfcSchema::IfcProperty::list::it it = properties->begin(); it != properties->end(); ++it) { IfcSchema::IfcProperty* p = *it; if (p->declaration().is(IfcSchema::IfcComplexProperty::Class())) { IfcSchema::IfcComplexProperty* complex = (IfcSchema::IfcComplexProperty*) p; - format_properties(complex->HasProperties(), node); + format_properties(mapping, complex->HasProperties(), node); } else { - format_entity_instance(p, node); + format_entity_instance(mapping, p, node); } } } // Format IfcElementQuantity instances and insert into the DOM. -void format_quantities(IfcSchema::IfcPhysicalQuantity::list::ptr quantities, ptree& node) { +void format_quantities(ifcopenshell::geometry::abstract_mapping* mapping, IfcSchema::IfcPhysicalQuantity::list::ptr quantities, ptree& node) { for (IfcSchema::IfcPhysicalQuantity::list::it it = quantities->begin(); it != quantities->end(); ++it) { IfcSchema::IfcPhysicalQuantity* p = *it; - ptree& node2 = format_entity_instance(p, node); + ptree& node2 = format_entity_instance(mapping, p, node); if (p->declaration().is(IfcSchema::IfcPhysicalComplexQuantity::Class())) { IfcSchema::IfcPhysicalComplexQuantity* complex = (IfcSchema::IfcPhysicalComplexQuantity*)p; - format_quantities(complex->HasQuantities(), node2); + format_quantities(mapping, complex->HasQuantities(), node2); } } } @@ -435,22 +433,22 @@ void POSTFIX_SCHEMA(XmlSerializer)::finalize() { } // Descend into the decomposition structure of the IFC file. - descend(project, decomposition); + descend(mapping_, project, decomposition); // Write all property sets and values as XML nodes. IfcSchema::IfcPropertySet::list::ptr psets = file->instances_by_type(); for (IfcSchema::IfcPropertySet::list::it it = psets->begin(); it != psets->end(); ++it) { IfcSchema::IfcPropertySet* pset = *it; - ptree& node = format_entity_instance(pset, properties); - format_properties(pset->HasProperties(), node); + ptree& node = format_entity_instance(mapping_, pset, properties); + format_properties(mapping_, pset->HasProperties(), node); } // Write all quantities and values as XML nodes. IfcSchema::IfcElementQuantity::list::ptr qtosets = file->instances_by_type(); for (IfcSchema::IfcElementQuantity::list::it it = qtosets->begin(); it != qtosets->end(); ++it) { IfcSchema::IfcElementQuantity* qto = *it; - ptree& node = format_entity_instance(qto, quantities); - format_quantities(qto->Quantities(), node); + ptree& node = format_entity_instance(mapping_, qto, quantities); + format_quantities(mapping_, qto->Quantities(), node); } @@ -458,7 +456,7 @@ void POSTFIX_SCHEMA(XmlSerializer)::finalize() { IfcSchema::IfcTypeObject::list::ptr type_objects = file->instances_by_type(); for (IfcSchema::IfcTypeObject::list::it it = type_objects->begin(); it != type_objects->end(); ++it) { IfcSchema::IfcTypeObject* type_object = *it; - ptree& node = descend(type_object, types); + ptree& node = descend(mapping_, type_object, types); // ptree& node = format_entity_instance(type_object, types); if (type_object->hasHasPropertySets()) { @@ -466,7 +464,7 @@ void POSTFIX_SCHEMA(XmlSerializer)::finalize() { for (IfcSchema::IfcPropertySetDefinition::list::it jt = property_sets->begin(); jt != property_sets->end(); ++jt) { IfcSchema::IfcPropertySetDefinition* pset = *jt; if (pset->declaration().is(IfcSchema::IfcPropertySet::Class())) { - format_entity_instance(pset, node, true); + format_entity_instance(mapping_, pset, node, true); } } } @@ -477,10 +475,10 @@ void POSTFIX_SCHEMA(XmlSerializer)::finalize() { for (IfcEntityList::it it = unit_assignments->begin(); it != unit_assignments->end(); ++it) { if ((*it)->declaration().is(IfcSchema::IfcNamedUnit::Class())) { IfcSchema::IfcNamedUnit* named_unit = (*it)->as(); - ptree& node = format_entity_instance(named_unit, units); + ptree& node = format_entity_instance(mapping, named_unit, units); node.put(".SI_equivalent", IfcParse::get_SI_equivalent(named_unit)); } else if ((*it)->declaration().is(IfcSchema::IfcMonetaryUnit::Class())) { - format_entity_instance((*it)->as(), units); + format_entity_instance(mapping_, (*it)->as(), units); } } @@ -495,7 +493,7 @@ void POSTFIX_SCHEMA(XmlSerializer)::finalize() { layer_names.insert(name); ptree node; node.put(".id", name); - format_entity_instance(*it, node, layers); + format_entity_instance(mapping_, *it, node, layers); } } @@ -521,16 +519,16 @@ void POSTFIX_SCHEMA(XmlSerializer)::finalize() { if ((*jt)->hasMaterial()) { subnode.put(".Name", (*jt)->Material()->Name()); } - format_entity_instance(*jt, subnode, node); + format_entity_instance(mapping_, *jt, subnode, node); } } else if (mat->as()) { IfcSchema::IfcMaterial::list::ptr mats = mat->as()->Materials(); for (IfcSchema::IfcMaterial::list::it jt = mats->begin(); jt != mats->end(); ++jt) { ptree subnode; - format_entity_instance(*jt, subnode, node); + format_entity_instance(mapping_, *jt, subnode, node); } } - format_entity_instance((IfcUtil::IfcBaseEntity*) mat, node, materials); + format_entity_instance(mapping_, (IfcUtil::IfcBaseEntity*) mat, node, materials); } } diff --git a/src/serializers/schema_dependent/XmlSerializer.h b/src/serializers/schema_dependent/XmlSerializer.h index 9e55d7f1f6..2141576e41 100644 --- a/src/serializers/schema_dependent/XmlSerializer.h +++ b/src/serializers/schema_dependent/XmlSerializer.h @@ -20,6 +20,7 @@ #ifndef XMLSERIALIZERIMPL_H #define XMLSERIALIZERIMPL_H +#include "../../ifcgeom/abstract_mapping.h" #include "../../ifcparse/macros.h" #include "../../serializers/XmlSerializer.h" @@ -29,10 +30,12 @@ class POSTFIX_SCHEMA(XmlSerializer) : public XmlSerializer { private: IfcParse::IfcFile* file; + ifcopenshell::geometry::abstract_mapping* mapping_; public: POSTFIX_SCHEMA(XmlSerializer)(IfcParse::IfcFile* file, const std::string& xml_filename) : XmlSerializer(0, "") + , mapping_(ifcopenshell::geometry::impl::mapping_implementations().construct(file)) { this->file = file; this->xml_filename = xml_filename; diff --git a/win/build-deps.cmd b/win/build-deps.cmd index b09ed33d47..1805fb5180 100644 --- a/win/build-deps.cmd +++ b/win/build-deps.cmd @@ -157,6 +157,8 @@ set OCE_VERSION=OCE-0.18 set PYTHON_VERSION=3.4.3 set SWIG_VERSION=3.0.12 +goto :Eigen + :: Note all of the dependencies have appropriate label so that user can easily skip something if wanted :: by modifying this file and using goto. :Boost @@ -459,6 +461,15 @@ IF NOT %ERRORLEVEL%==0 GOTO :Error call :InstallCMakeProject "%DEPENDENCY_DIR%\%BUILD_DIR%" %BUILD_CFG% IF NOT %ERRORLEVEL%==0 GOTO :Error +:Eigen +set DEPENDENCY_NAME=eigen +call :DownloadFile http://bitbucket.org/eigen/eigen/get/3.3.7.zip "%DEPS_DIR%" eigen-eigen-323c052e1731.zip +IF NOT %ERRORLEVEL%==0 GOTO :Error +call :ExtractArchive eigen-eigen-323c052e1731.zip "%DEPS_DIR%" "%DEPS_DIR%\eigen" +IF NOT %ERRORLEVEL%==0 GOTO :Error +IF NOT EXIST "%INSTALL_DIR%\Eigen\Eigen". mkdir "%INSTALL_DIR%\Eigen\Eigen" +robocopy /MIR "%DEPS_DIR%\eigen-eigen-323c052e1731\Eigen" "%INSTALL_DIR%\Eigen\Eigen" + :Successful echo. call "%~dp0\utils\cecho.cmd" 0 10 "%PROJECT_NAME% dependencies built." diff --git a/win/run-cmake.bat b/win/run-cmake.bat index 058aa3498a..f091990988 100755 --- a/win/run-cmake.bat +++ b/win/run-cmake.bat @@ -86,6 +86,7 @@ set MPFR_INCLUDE_DIR=%INSTALL_DIR%\mpfr set MPFR_LIBRARY_DIR=%INSTALL_DIR%\mpfr set VOXEL_INCLUDE_DIR=%INSTALL_DIR%\voxel\include set VOXEL_LIBRARY_DIR=%INSTALL_DIR%\voxel\lib +set EIGEN_DIR=%INSTALL_DIR%\Eigen echo. call cecho.cmd 0 10 "Script configuration:" @@ -115,6 +116,7 @@ echo MPFR_INCLUDE_DIR = %MPFR_INCLUDE_DIR% echo MPFR_LIBRARY_DIR = %MPFR_LIBRARY_DIR% echo VOXEL_INCLUDE_DIR = %VOXEL_INCLUDE_DIR% echo VOXEL_LIBRARY_DIR = %VOXEL_LIBRARY_DIR% +echo EIGEN_DIR = %EIGEN_DIR% echo. echo CMAKE_INSTALL_PREFIX = %CMAKE_INSTALL_PREFIX% echo. From 585b89be87d74442e148c12e328dbf1e6aafc3ff Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sat, 17 Aug 2019 09:47:07 +0200 Subject: [PATCH 157/235] Fix compilation of serializers and convert --- src/ifcconvert/IfcConvert.cpp | 62 +++++++++---------- .../schema_agnostic/ConversionResult.h | 3 + ...atorImplementation.h => IfcGeomIterator.h} | 31 +++++++--- .../IfcGeomIteratorImplementation.cpp | 1 - .../opencascade/OpenCascadeConversionResult.h | 4 +- src/serializers/IgesSerializer.h | 4 +- .../OpenCascadeBasedSerializer.cpp | 8 +-- src/serializers/OpenCascadeBasedSerializer.h | 6 +- src/serializers/StepSerializer.h | 6 +- src/serializers/SvgSerializer.cpp | 22 +++---- src/serializers/SvgSerializer.h | 8 ++- src/serializers/WavefrontObjSerializer.cpp | 41 ++++++------ src/serializers/WavefrontObjSerializer.h | 6 +- .../schema_dependent/XmlSerializer.cpp | 14 +++-- 14 files changed, 119 insertions(+), 97 deletions(-) rename src/ifcgeom/schema_agnostic/{IfcGeomIteratorImplementation.h => IfcGeomIterator.h} (96%) delete mode 100644 src/ifcgeom/schema_agnostic/IfcGeomIteratorImplementation.cpp diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 3b045f04f3..271f5c0794 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -633,24 +633,24 @@ int main(int argc, char** argv) { SerializerSettings settings; /// @todo Make APPLY_DEFAULT_MATERIALS configurable? Quickly tested setting this to false and using obj exporter caused the program to crash and burn. - settings.set(IfcGeom::IteratorSettings::APPLY_DEFAULT_MATERIALS, true); - settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, use_world_coords || output_extension == SVG || output_extension == OBJ); - settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, weld_vertices); - settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, orient_shells); - settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, convert_back_units); + settings.set(ifcopenshell::geometry::settings::APPLY_DEFAULT_MATERIALS, true); + settings.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, use_world_coords || output_extension == SVG || output_extension == OBJ); + settings.set(ifcopenshell::geometry::settings::WELD_VERTICES, weld_vertices); + settings.set(ifcopenshell::geometry::settings::SEW_SHELLS, orient_shells); + settings.set(ifcopenshell::geometry::settings::CONVERT_BACK_UNITS, convert_back_units); #if OCC_VERSION_HEX < 0x60900 - settings.set(IfcGeom::IteratorSettings::FASTER_BOOLEANS, merge_boolean_operands); + settings.set(ifcopenshell::geometry::settings::FASTER_BOOLEANS, merge_boolean_operands); #endif - settings.set(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS, disable_opening_subtractions); - settings.set(IfcGeom::IteratorSettings::INCLUDE_CURVES, include_plan); - settings.set(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES, !include_model); - settings.set(IfcGeom::IteratorSettings::APPLY_LAYERSETS, enable_layerset_slicing); - settings.set(IfcGeom::IteratorSettings::NO_NORMALS, no_normals); - settings.set(IfcGeom::IteratorSettings::GENERATE_UVS, generate_uvs); - settings.set(IfcGeom::IteratorSettings::SEARCH_FLOOR, use_element_hierarchy || output_extension == SVG); - settings.set(IfcGeom::IteratorSettings::SITE_LOCAL_PLACEMENT, site_local_placement); - settings.set(IfcGeom::IteratorSettings::BUILDING_LOCAL_PLACEMENT, building_local_placement); - settings.set(IfcGeom::IteratorSettings::VALIDATE_QUANTITIES, validate); + settings.set(ifcopenshell::geometry::settings::DISABLE_OPENING_SUBTRACTIONS, disable_opening_subtractions); + settings.set(ifcopenshell::geometry::settings::INCLUDE_CURVES, include_plan); + settings.set(ifcopenshell::geometry::settings::EXCLUDE_SOLIDS_AND_SURFACES, !include_model); + settings.set(ifcopenshell::geometry::settings::APPLY_LAYERSETS, enable_layerset_slicing); + settings.set(ifcopenshell::geometry::settings::NO_NORMALS, no_normals); + settings.set(ifcopenshell::geometry::settings::GENERATE_UVS, generate_uvs); + settings.set(ifcopenshell::geometry::settings::SEARCH_FLOOR, use_element_hierarchy || output_extension == SVG); + settings.set(ifcopenshell::geometry::settings::SITE_LOCAL_PLACEMENT, site_local_placement); + settings.set(ifcopenshell::geometry::settings::BUILDING_LOCAL_PLACEMENT, building_local_placement); + settings.set(ifcopenshell::geometry::settings::VALIDATE_QUANTITIES, validate); settings.set(SerializerSettings::USE_ELEMENT_NAMES, use_element_names); settings.set(SerializerSettings::USE_ELEMENT_GUIDS, use_element_guids); @@ -682,7 +682,7 @@ int main(int argc, char** argv) { #endif serializer = boost::make_shared(IfcUtil::path::to_utf8(output_temp_filename), settings); } else if (output_extension == SVG) { - settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true); + settings.set(ifcopenshell::geometry::settings::DISABLE_TRIANGULATION, true); serializer = boost::make_shared(IfcUtil::path::to_utf8(output_temp_filename), settings); if (vmap.count("section-height") != 0) { Logger::Notice("Overriding section height"); @@ -719,7 +719,7 @@ int main(int argc, char** argv) { Logger::Notice("Centering/offsetting model setting ignored when writing non-tesselated output"); } - settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true); + settings.set(ifcopenshell::geometry::settings::DISABLE_TRIANGULATION, true); } if (!serializer->ready()) { @@ -749,7 +749,7 @@ int main(int argc, char** argv) { Logger::SetOutput(quiet ? nullptr : &cout_, &log_stream); - IfcGeom::Iterator context_iterator(settings, ifc_file, filter_funcs, geometry_kernel, num_threads); + ifcopenshell::geometry::Iterator context_iterator(geometry_kernel, settings, ifc_file, filter_funcs, 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. @@ -823,15 +823,15 @@ int main(int argc, char** argv) { size_t num_created = 0; do { - IfcGeom::Element *geom_object = context_iterator.get(); + ifcopenshell::geometry::Element* geom_object = context_iterator.get(); if (is_tesselated) { - serializer->write(static_cast*>(geom_object)); + serializer->write(static_cast(geom_object)); } else { - serializer->write(static_cast*>(geom_object)); + serializer->write(static_cast(geom_object)); } if (!no_progress) { @@ -1219,14 +1219,14 @@ void fix_quantities(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool std } } - IfcGeom::IteratorSettings settings; - settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, false); - settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, false); - settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, true); - settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, true); - settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true); + ifcopenshell::geometry::settings settings; + settings.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, false); + settings.set(ifcopenshell::geometry::settings::WELD_VERTICES, false); + settings.set(ifcopenshell::geometry::settings::SEW_SHELLS, true); + settings.set(ifcopenshell::geometry::settings::CONVERT_BACK_UNITS, true); + settings.set(ifcopenshell::geometry::settings::DISABLE_TRIANGULATION, true); - IfcGeom::Iterator context_iterator(settings, &f); + ifcopenshell::geometry::Iterator context_iterator(settings, &f); if (!context_iterator.initialize()) { return; @@ -1260,14 +1260,14 @@ void fix_quantities(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool std IfcUtil::IfcBaseClass* quantity = nullptr; IfcEntityList::ptr objects; - boost::shared_ptr previous_geometry_pointer; + boost::shared_ptr previous_geometry_pointer; for (;; ++num_created) { bool has_more = true; if (num_created) { has_more = context_iterator.next(); } - IfcGeom::NativeElement* geom_object = nullptr; + ifcopenshell::geometry::NativeElement* geom_object = nullptr; if (has_more) { geom_object = context_iterator.get_native(); } diff --git a/src/ifcgeom/schema_agnostic/ConversionResult.h b/src/ifcgeom/schema_agnostic/ConversionResult.h index ec88055893..cd967a6eee 100644 --- a/src/ifcgeom/schema_agnostic/ConversionResult.h +++ b/src/ifcgeom/schema_agnostic/ConversionResult.h @@ -30,6 +30,9 @@ namespace ifcopenshell { namespace geometry { class IFC_GEOM_API Triangulation; } + // @todo, this class is no longer necessary, we can directly use + // taxonomy::matrix4, which does not need to be implemented specifically + // in the respective kernels class IFC_GEOM_API ConversionResultPlacement { public: virtual void Multiply(const ConversionResultPlacement*) = 0; diff --git a/src/ifcgeom/schema_agnostic/IfcGeomIteratorImplementation.h b/src/ifcgeom/schema_agnostic/IfcGeomIterator.h similarity index 96% rename from src/ifcgeom/schema_agnostic/IfcGeomIteratorImplementation.h rename to src/ifcgeom/schema_agnostic/IfcGeomIterator.h index 85d436644b..c6febd30e1 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomIteratorImplementation.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomIterator.h @@ -194,8 +194,8 @@ namespace ifcopenshell { namespace geometry { int done; int total; - std::string unit_name; - double unit_magnitude; + std::string unit_name_; + double unit_magnitude_; gp_XYZ bounds_min_; gp_XYZ bounds_max_; @@ -205,6 +205,9 @@ namespace ifcopenshell { namespace geometry { /// @todo public/private sections all over the place: move all public to the beginning of the class public: + const std::string& unit_name() const { return unit_name_; } + const double unit_magnitude() const { return unit_magnitude_; } + bool initialize() { converter_->mapping()->get_representations(tasks_, filters_, settings_); @@ -357,10 +360,10 @@ namespace ifcopenshell { namespace geometry { } } - const std::string& getUnitName() const { return unit_name; } + const std::string& getUnitName() const { return unit_name_; } /// @note Double always as per IFC specification. - double getUnitMagnitude() const { return unit_magnitude; } + double getUnitMagnitude() const { return unit_magnitude_; } std::string getLog() const { return Logger::GetLog(); } @@ -418,6 +421,10 @@ namespace ifcopenshell { namespace geometry { if (task_result_index_ == all_processed_elements_.size()) { return create(); } + if (task_result_index_ == all_processed_elements_.size()) { + return nullptr; + } + return all_processed_elements_[task_result_index_]->product(); } } @@ -563,8 +570,8 @@ namespace ifcopenshell { namespace geometry { } private: void _initialize() { - unit_name = "METER"; - unit_magnitude = 1.f; + unit_name_ = "METER"; + unit_magnitude_ = 1.f; // @todo @@ -585,7 +592,7 @@ namespace ifcopenshell { namespace geometry { bool owns_ifc_file; public: - Iterator(const std::string& geometry_library, const settings& settings, IfcParse::IfcFile* file, const std::vector& filters, int num_threads) + Iterator(const std::string& geometry_library, const settings& settings, IfcParse::IfcFile* file, const std::vector& filters, int num_threads = 1) : settings_(settings) , ifc_file(file) , filters_(filters) @@ -596,6 +603,16 @@ namespace ifcopenshell { namespace geometry { _initialize(); } + Iterator(const settings& settings, IfcParse::IfcFile* file, int num_threads = 1) + : settings_(settings) + , ifc_file(file) + , owns_ifc_file(false) + , num_threads_(num_threads) + , geometry_library_("opencascade") + { + _initialize(); + } + ~Iterator() { if (owns_ifc_file) { delete ifc_file; diff --git a/src/ifcgeom/schema_agnostic/IfcGeomIteratorImplementation.cpp b/src/ifcgeom/schema_agnostic/IfcGeomIteratorImplementation.cpp deleted file mode 100644 index 6340b79d04..0000000000 --- a/src/ifcgeom/schema_agnostic/IfcGeomIteratorImplementation.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "IfcGeomIteratorImplementation.h" diff --git a/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h b/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h index 51680f645d..25d26150f9 100644 --- a/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h +++ b/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h @@ -88,9 +88,7 @@ namespace ifcopenshell { const TopoDS_Shape& shape() const { return shape_; } operator const TopoDS_Shape& () { return shape_; } - virtual void Triangulate(const settings & settings, const ConversionResultPlacement * place, Representation::Triangulation* t, int surface_style_id) const; - - virtual void Triangulate(const settings & settings, const ConversionResultPlacement * place, Representation::Triangulation* t, int surface_style_id) const; + virtual void Triangulate(const settings & settings, const ConversionResultPlacement * place, Representation::Triangulation* t, int surface_style_id) const; virtual void Serialize(std::string&) const { throw std::runtime_error("Not implemented"); diff --git a/src/serializers/IgesSerializer.h b/src/serializers/IgesSerializer.h index 77845d0116..9455f34e7f 100644 --- a/src/serializers/IgesSerializer.h +++ b/src/serializers/IgesSerializer.h @@ -42,8 +42,8 @@ public: : OpenCascadeBasedSerializer(out_filename, settings) {} virtual ~IgesSerializer() {} - void writeShape(const IfcGeom::ConversionResultShape* shape) { - writer.AddShape(*(IfcGeom::OpenCascadeShape*)shape); + void writeShape(const ifcopenshell::geometry::ConversionResultShape* shape) { + writer.AddShape(*(ifcopenshell::geometry::OpenCascadeShape*)shape); } void finalize() { writer.Write(out_filename.c_str()); diff --git a/src/serializers/OpenCascadeBasedSerializer.cpp b/src/serializers/OpenCascadeBasedSerializer.cpp index d5790a1134..89ad2dc1c6 100644 --- a/src/serializers/OpenCascadeBasedSerializer.cpp +++ b/src/serializers/OpenCascadeBasedSerializer.cpp @@ -36,19 +36,19 @@ bool OpenCascadeBasedSerializer::ready() { return succeeded; } -void OpenCascadeBasedSerializer::write(const IfcGeom::NativeElement* o) { - IfcGeom::OpenCascadeShape* occt_shape = ((IfcGeom::OpenCascadeShape*) o->geometry().as_compound()); +void OpenCascadeBasedSerializer::write(const ifcopenshell::geometry::NativeElement* o) { + ifcopenshell::geometry::OpenCascadeShape* occt_shape = ((ifcopenshell::geometry::OpenCascadeShape*) o->geometry().as_compound()); TopoDS_Shape compound = occt_shape->shape(); delete occt_shape; - if (o->geometry().settings().get(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS)) { + if (o->geometry().settings().get(ifcopenshell::geometry::settings::CONVERT_BACK_UNITS)) { gp_Trsf scale; scale.SetScaleFactor(1.0 / o->geometry().settings().unit_magnitude()); compound = BRepBuilderAPI_Transform(compound, scale, true).Shape(); } - IfcGeom::OpenCascadeShape s(compound); + ifcopenshell::geometry::OpenCascadeShape s(compound); writeShape(&s); } diff --git a/src/serializers/OpenCascadeBasedSerializer.h b/src/serializers/OpenCascadeBasedSerializer.h index 81b8bbd126..a8e72feddd 100644 --- a/src/serializers/OpenCascadeBasedSerializer.h +++ b/src/serializers/OpenCascadeBasedSerializer.h @@ -37,9 +37,9 @@ public: virtual ~OpenCascadeBasedSerializer() {} void writeHeader() {} bool ready(); - virtual void writeShape(const IfcGeom::ConversionResultShape* shape) = 0; - void write(const IfcGeom::TriangulationElement* /*o*/) {} - void write(const IfcGeom::NativeElement* o); + virtual void writeShape(const ifcopenshell::geometry::ConversionResultShape* shape) = 0; + void write(const ifcopenshell::geometry::TriangulationElement* /*o*/) {} + void write(const ifcopenshell::geometry::NativeElement* o); bool isTesselated() const { return false; } void setFile(IfcParse::IfcFile*) {} }; diff --git a/src/serializers/StepSerializer.h b/src/serializers/StepSerializer.h index 5152c5d362..b742397717 100644 --- a/src/serializers/StepSerializer.h +++ b/src/serializers/StepSerializer.h @@ -23,8 +23,6 @@ #include #include -#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h" - #include "../serializers/OpenCascadeBasedSerializer.h" class StepSerializer : public OpenCascadeBasedSerializer @@ -36,10 +34,10 @@ public: : OpenCascadeBasedSerializer(out_filename, settings) {} virtual ~StepSerializer() {} - void writeShape(const IfcGeom::ConversionResultShape* shape) { + void writeShape(const ifcopenshell::geometry::ConversionResultShape* shape) { std::stringstream ss; std::streambuf *sb = std::cout.rdbuf(ss.rdbuf()); - writer.Transfer(((IfcGeom::OpenCascadeShape*)shape)->shape(), STEPControl_AsIs); + writer.Transfer(((ifcopenshell::geometry::OpenCascadeShape*)shape)->shape(), STEPControl_AsIs); std::cout.rdbuf(sb); } void finalize() { diff --git a/src/serializers/SvgSerializer.cpp b/src/serializers/SvgSerializer.cpp index 7c821dfbda..846a9bac14 100644 --- a/src/serializers/SvgSerializer.cpp +++ b/src/serializers/SvgSerializer.cpp @@ -285,7 +285,7 @@ SvgSerializer::path_object& SvgSerializer::start_path(IfcUtil::IfcBaseEntity* st return p; } -void SvgSerializer::write(const IfcGeom::NativeElement* o) +void SvgSerializer::write(const ifcopenshell::geometry::NativeElement* o) { IfcUtil::IfcBaseEntity* storey = storey_; boost::optional storey_elevation = boost::none; @@ -293,7 +293,7 @@ void SvgSerializer::write(const IfcGeom::NativeElement* o) for (const auto& p : o->parents()) { if (p->type() == "IfcBuildingStorey") { try { - const IfcGeom::ElementSettings& settings = o->geometry().settings(); + const ifcopenshell::geometry::element_settings& settings = o->geometry().settings(); double e = *p->product()->get("Elevation"); storey_elevation = e * settings.unit_magnitude(); } catch (...) { @@ -312,7 +312,8 @@ void SvgSerializer::write(const IfcGeom::NativeElement* o) path_object& p = start_path(storey, nameElement(o)); - IfcGeom::OpenCascadeShape* occt_shape = ((IfcGeom::OpenCascadeShape*) o->geometry().as_compound()); + // @todo check whether correct kernel is used + ifcopenshell::geometry::OpenCascadeShape* occt_shape = ((ifcopenshell::geometry::OpenCascadeShape*) o->geometry().as_compound()); TopoDS_Shape compound = occt_shape->shape(); delete occt_shape; @@ -443,7 +444,7 @@ void SvgSerializer::writeHeader() { svg_file << "\n"; } -std::string SvgSerializer::nameElement(const IfcGeom::Element* elem) +std::string SvgSerializer::nameElement(const ifcopenshell::geometry::Element* elem) { std::ostringstream oss; const std::string type = "product"; @@ -471,11 +472,10 @@ std::string SvgSerializer::nameElement(const IfcUtil::IfcBaseEntity* elem) { void SvgSerializer::setFile(IfcParse::IfcFile* f) { file = f; + mapping_ = ifcopenshell::geometry::impl::mapping_implementations().construct(f); + auto storeys = f->instances_by_type("IfcBuildingStorey"); if (!storeys || storeys->size() == 0) { - - IfcGeom::Kernel kernel("opencascade", f); - std::vector to_derive_from; to_derive_from.push_back(f->schema()->declaration_by_name("IfcBuilding")); to_derive_from.push_back(f->schema()->declaration_by_name("IfcSite")); @@ -485,10 +485,10 @@ 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()) { - IfcGeom::ConversionResultPlacement* trsf; - if (kernel.convert_placement(*product->get("ObjectPlacement"), trsf)) { - double X, Y, Z; - trsf->TranslationPart(X, Y, Z); + auto item = mapping_->map(*product->get("ObjectPlacement")); + if (item) { + auto matrix = (ifcopenshell::geometry::taxonomy::matrix4*) item; + const double& Z = matrix->components(3, 2); setSectionHeight(Z + 1.); Logger::Warning("No building storeys encountered, used for reference:", product); return; diff --git a/src/serializers/SvgSerializer.h b/src/serializers/SvgSerializer.h index 2f739996a6..0bacb0437a 100644 --- a/src/serializers/SvgSerializer.h +++ b/src/serializers/SvgSerializer.h @@ -26,6 +26,7 @@ #include "../serializers/util.h" #include "../ifcparse/utils.h" +#include "../ifcgeom/abstract_mapping.h" #include #include @@ -45,6 +46,7 @@ protected: std::vector< boost::shared_ptr > radii; IfcParse::IfcFile* file; IfcUtil::IfcBaseEntity* storey_; + ifcopenshell::geometry::abstract_mapping* mapping_; public: SvgSerializer(const std::string& out_filename, const SerializerSettings& settings) : GeometrySerializer(settings) @@ -63,8 +65,8 @@ public: void growBoundingBox(double x, double y) { if (x < xmin) xmin = x; if (x > xmax) xmax = x; if (y < ymin) ymin = y; if (y > ymax) ymax = y; } void writeHeader(); bool ready(); - void write(const IfcGeom::TriangulationElement* /*o*/) {} - void write(const IfcGeom::NativeElement* o); + void write(const ifcopenshell::geometry::TriangulationElement* /*o*/) {} + void write(const ifcopenshell::geometry::NativeElement* 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; } @@ -73,7 +75,7 @@ public: void setFile(IfcParse::IfcFile* f); void setBoundingRectangle(double width, double height); void setSectionHeight(double h, IfcUtil::IfcBaseEntity* storey = 0) { section_height = h; storey_ = storey; } - std::string nameElement(const IfcGeom::Element* elem); + std::string nameElement(const ifcopenshell::geometry::Element* elem); std::string nameElement(const IfcUtil::IfcBaseEntity* elem); }; diff --git a/src/serializers/WavefrontObjSerializer.cpp b/src/serializers/WavefrontObjSerializer.cpp index 102acab022..1297e37353 100644 --- a/src/serializers/WavefrontObjSerializer.cpp +++ b/src/serializers/WavefrontObjSerializer.cpp @@ -58,38 +58,39 @@ void WaveFrontOBJSerializer::writeHeader() { mtl_stream << "# File generated by IfcOpenShell " << IFCOPENSHELL_VERSION << "\n"; } -void WaveFrontOBJSerializer::writeMaterial(const IfcGeom::Material& style) +void WaveFrontOBJSerializer::writeMaterial(const ifcopenshell::geometry::taxonomy::style& style) { - std::string material_name = (settings().get(SerializerSettings::USE_MATERIAL_NAMES) - ? style.original_name() : style.name()); + // @todo original_name + std::string material_name = *(settings().get(SerializerSettings::USE_MATERIAL_NAMES) + ? style.name : style.name); IfcUtil::sanitate_material_name(material_name); mtl_stream << "newmtl " << material_name << "\n"; - if (style.hasDiffuse()) { - const double* diffuse = style.diffuse(); + if (style.diffuse) { + auto diffuse = style.diffuse->components; mtl_stream << "Kd " << diffuse[0] << " " << diffuse[1] << " " << diffuse[2] << "\n"; } - if (style.hasSpecular()) { - const double* specular = style.specular(); + if (style.specular) { + auto specular = style.specular->components; mtl_stream << "Ks " << specular[0] << " " << specular[1] << " " << specular[2] << "\n"; } - if (style.hasSpecularity()) { - mtl_stream << "Ns " << style.specularity() << "\n"; + if (style.specularity) { + mtl_stream << "Ns " << *style.specularity << "\n"; } - if (style.hasTransparency()) { - const double transparency = 1.0 - style.transparency(); + if (style.transparency) { + const double transparency = 1.0 - *style.transparency; if (transparency < 1) { mtl_stream << "d " << transparency << "\n"; } } } -void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement* o) +void WaveFrontOBJSerializer::write(const ifcopenshell::geometry::TriangulationElement* o) { obj_stream << "g " << object_id(o) << "\n"; obj_stream << "s 1" << "\n"; - const IfcGeom::Representation::Triangulation& mesh = o->geometry(); + const ifcopenshell::geometry::Representation::Triangulation& mesh = o->geometry(); const int vcount = (int)mesh.verts().size() / 3; for ( std::vector::const_iterator it = mesh.verts().begin(); it != mesh.verts().end(); ) { @@ -121,9 +122,10 @@ void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement* const int material_id = *(material_it++); if (material_id != previous_material_id) { - const IfcGeom::Material& material = mesh.materials()[material_id]; - std::string material_name = (settings().get(SerializerSettings::USE_MATERIAL_NAMES) - ? material.original_name() : material.name()); + const ifcopenshell::geometry::taxonomy::style& material = mesh.materials()[material_id]; + // @todo original_name + std::string material_name = *(settings().get(SerializerSettings::USE_MATERIAL_NAMES) + ? material.name : material.name); IfcUtil::sanitate_material_name(material_name); obj_stream << "usemtl " << material_name << "\n"; if (materials.find(material_name) == materials.end()) { @@ -165,9 +167,10 @@ void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement* const int material_id = *(material_it++); if (material_id != previous_material_id) { - const IfcGeom::Material& material = mesh.materials()[material_id]; - std::string material_name = (settings().get(SerializerSettings::USE_MATERIAL_NAMES) - ? material.original_name() : material.name()); + const ifcopenshell::geometry::taxonomy::style& material = mesh.materials()[material_id]; + // @todo original_name + std::string material_name = *(settings().get(SerializerSettings::USE_MATERIAL_NAMES) + ? material.name : material.name); IfcUtil::sanitate_material_name(material_name); obj_stream << "usemtl " << material_name << "\n"; if (materials.find(material_name) == materials.end()) { diff --git a/src/serializers/WavefrontObjSerializer.h b/src/serializers/WavefrontObjSerializer.h index 8bce643d74..48ee1588da 100644 --- a/src/serializers/WavefrontObjSerializer.h +++ b/src/serializers/WavefrontObjSerializer.h @@ -39,9 +39,9 @@ public: virtual ~WaveFrontOBJSerializer() {} bool ready(); void writeHeader(); - void writeMaterial(const IfcGeom::Material& style); - void write(const IfcGeom::TriangulationElement* o); - void write(const IfcGeom::NativeElement* /*o*/) {} + void writeMaterial(const ifcopenshell::geometry::taxonomy::style& style); + void write(const ifcopenshell::geometry::TriangulationElement* o); + void write(const ifcopenshell::geometry::NativeElement* /*o*/) {} void finalize() {} bool isTesselated() const { return true; } void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {} diff --git a/src/serializers/schema_dependent/XmlSerializer.cpp b/src/serializers/schema_dependent/XmlSerializer.cpp index dbe310d538..ddc174b027 100644 --- a/src/serializers/schema_dependent/XmlSerializer.cpp +++ b/src/serializers/schema_dependent/XmlSerializer.cpp @@ -129,11 +129,13 @@ boost::optional format_attribute(ifcopenshell::geometry::abstract_m auto matrix = (ifcopenshell::geometry::taxonomy::matrix4*) placement; std::stringstream stream; - for (int i = 0; i < 16; ++i) { - const double trsf_value = matrix->components[i]; - stream << trsf_value; - if (i != 15) { - stream << " "; + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + const double trsf_value = matrix->components(j, i); + stream << trsf_value; + if (i < 3 && j < 3) { + stream << " "; + } } } value = stream.str(); @@ -475,7 +477,7 @@ void POSTFIX_SCHEMA(XmlSerializer)::finalize() { for (IfcEntityList::it it = unit_assignments->begin(); it != unit_assignments->end(); ++it) { if ((*it)->declaration().is(IfcSchema::IfcNamedUnit::Class())) { IfcSchema::IfcNamedUnit* named_unit = (*it)->as(); - ptree& node = format_entity_instance(mapping, named_unit, units); + ptree& node = format_entity_instance(mapping_, named_unit, units); node.put(".SI_equivalent", IfcParse::get_SI_equivalent(named_unit)); } else if ((*it)->declaration().is(IfcSchema::IfcMonetaryUnit::Class())) { format_entity_instance(mapping_, (*it)->as(), units); From 85171bb5df3895e3ec2e68ee0ecc040b80ea0661 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 18 Aug 2019 08:37:59 +0200 Subject: [PATCH 158/235] Remove ConversionResultPlacement, fix some errors --- cmake/CMakeLists.txt | 2 +- src/ifcgeom/schema/mapping.cpp | 3 +- .../schema_agnostic/ConversionResult.h | 45 +++++++------- src/ifcgeom/schema_agnostic/IfcGeomElement.h | 53 +++++----------- .../schema_agnostic/IfcGeomRepresentation.cpp | 62 +++++++++++-------- .../schema_agnostic/IfcGeomRepresentation.h | 2 +- .../opencascade/OpenCascadeConversionResult.h | 45 +------------- 7 files changed, 77 insertions(+), 135 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index a77db1cddf..88191a7f5b 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -610,7 +610,7 @@ if (BUILD_IFCGEOM) foreach(s ${SCHEMA_VERSIONS}) set(IFCGEOM_SCHEMA_LIBRARIES ${IFCGEOM_SCHEMA_LIBRARIES} geometry_mapping_ifc${s}) endforeach() - set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} IfcGeom geometry_mapping ${IFCGEOM_SCHEMA_LIBRARIES}) + set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} IfcGeom geometry_mappings ${IFCGEOM_SCHEMA_LIBRARIES}) endif() if (BUILD_CONVERT) foreach(s ${SCHEMA_VERSIONS}) diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index f21e58cf34..c2c74fcb27 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -648,8 +648,7 @@ namespace { } } - -IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity* inst, bool include_openings) { +IfcUtil::IfcBaseEntity* mapping::get_decomposing_entity(IfcUtil::IfcBaseEntity* inst, bool include_openings) { IfcSchema::IfcObjectDefinition* parent = 0; auto product = inst->as(); if (!product) { diff --git a/src/ifcgeom/schema_agnostic/ConversionResult.h b/src/ifcgeom/schema_agnostic/ConversionResult.h index cd967a6eee..0ccae1ccf0 100644 --- a/src/ifcgeom/schema_agnostic/ConversionResult.h +++ b/src/ifcgeom/schema_agnostic/ConversionResult.h @@ -33,59 +33,56 @@ namespace ifcopenshell { namespace geometry { // @todo, this class is no longer necessary, we can directly use // taxonomy::matrix4, which does not need to be implemented specifically // in the respective kernels + /* class IFC_GEOM_API ConversionResultPlacement { public: - virtual void Multiply(const ConversionResultPlacement*) = 0; - virtual void PreMultiply(const ConversionResultPlacement*) = 0; + virtual void Multiply(const ifcopenshell::geometry::taxonomy::matrix4&) = 0; + virtual void PreMultiply(const ifcopenshell::geometry::taxonomy::matrix4&) = 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 ConversionResultPlacement* multiplied(const ifcopenshell::geometry::taxonomy::matrix4&) 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 ifcopenshell::geometry::settings & settings, const ifcopenshell::geometry::ConversionResultPlacement* place, ifcopenshell::geometry::Representation::Triangulation* t, int surface_style_id) const = 0; + virtual void Triangulate(const ifcopenshell::geometry::settings & settings, const ifcopenshell::geometry::taxonomy::matrix4& place, ifcopenshell::geometry::Representation::Triangulation* 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 bool is_manifold() const = 0; virtual ~ConversionResultShape() {} }; class IFC_GEOM_API ConversionResult { private: int id; - ConversionResultPlacement* placement; + ifcopenshell::geometry::taxonomy::matrix4 placement; ConversionResultShape* shape; ifcopenshell::geometry::taxonomy::style style; public: - ConversionResult(int id, const ConversionResultPlacement* placement, const ConversionResultShape* shape, const ifcopenshell::geometry::taxonomy::style& style) - : id(id), placement(placement->clone()), shape(shape->clone()), style(style) {} - ConversionResult(int id, const ConversionResultPlacement* placement, const ConversionResultShape* shape) - : id(id), placement(placement->clone()), shape(shape->clone()) {} + ConversionResult(int id, const ifcopenshell::geometry::taxonomy::matrix4& placement, const ConversionResultShape* shape, const ifcopenshell::geometry::taxonomy::style& style) + : id(id), placement(placement), shape(shape->clone()), style(style) {} + ConversionResult(int id, const ifcopenshell::geometry::taxonomy::matrix4& placement, const ConversionResultShape* shape) + : id(id), placement(placement), shape(shape->clone()) {} ConversionResult(int id, const ConversionResultShape* shape, const ifcopenshell::geometry::taxonomy::style& style) - : id(id), placement(0), shape(shape->clone()), style(style) {} + : id(id), shape(shape->clone()), style(style) {} ConversionResult(int id, const ConversionResultShape* shape) - : id(id), placement(0), shape(shape->clone()) {} - void append(const ConversionResultPlacement* trsf) { - if (placement == 0) { - placement = trsf->clone(); - } else { - placement->Multiply(trsf); - } + : id(id), shape(shape->clone()) {} + void append(const ifcopenshell::geometry::taxonomy::matrix4& trsf) { + // @todo verify order + placement.components = placement.components * trsf.components; } - void prepend(const ConversionResultPlacement* trsf) { - if (placement == 0) { - placement = trsf->clone(); - } else { - placement->PreMultiply(trsf); - } + void prepend(const ifcopenshell::geometry::taxonomy::matrix4& trsf) { + // @todo verify order + placement.components = trsf.components * placement.components; } const ConversionResultShape* Shape() const { return shape; } - const ConversionResultPlacement* Placement() const { return placement; } + const ifcopenshell::geometry::taxonomy::matrix4& Placement() const { return placement; } // @todo bool hasStyle() const { return style.diffuse.is_initialized(); } const ifcopenshell::geometry::taxonomy::style& Style() const { return style; } diff --git a/src/ifcgeom/schema_agnostic/IfcGeomElement.h b/src/ifcgeom/schema_agnostic/IfcGeomElement.h index d51329a342..cc8544be5f 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomElement.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomElement.h @@ -28,57 +28,32 @@ #include "../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h" #include "../../ifcgeom/settings.h" +#include "../../ifcgeom/taxonomy.h" #include "ifc_geom_api.h" namespace ifcopenshell { namespace geometry { - class Matrix { + class Transformation { private: - std::vector _data; + element_settings settings_; + ifcopenshell::geometry::taxonomy::matrix4 matrix_; public: - Matrix(const element_settings& settings, const ConversionResultPlacement* trsf) { - // Convert the gp_Trsf into a 4x3 Matrix + Transformation(const element_settings& settings, const ifcopenshell::geometry::taxonomy::matrix4& trsf) + : settings_(settings) + , matrix_(trsf) + { // Note that in case the CONVERT_BACK_UNITS setting is enabled // the translation component of the matrix needs to be divided // by the magnitude of the IFC model length unit because // 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 == nullptr) - ? (i == j ? 1. : 0.) - : trsf->Value(j,i); - const double matrix_value = (i == 4 && settings.get(settings::CONVERT_BACK_UNITS)) - ? trsf_value / settings.unit_magnitude() - : trsf_value; - _data.push_back(static_cast(matrix_value)); + if (settings.get(settings::CONVERT_BACK_UNITS)) { + for (int i = 0; i <= 2; ++i) { + matrix_.components(3, i) /= settings.unit_magnitude(); } } } - const std::vector& data() const { return _data; } - }; - - class Transformation { - private: - element_settings settings_; - ConversionResultPlacement* trsf_; - Matrix matrix_; - public: - Transformation(const element_settings& settings, const ConversionResultPlacement* trsf) - : settings_(settings) - , trsf_(trsf ? trsf->clone() : nullptr) - , matrix_(settings, trsf) - {} - const ConversionResultPlacement* data() const { return trsf_; } - const Matrix& matrix() const { return matrix_; } - - Transformation inverted() const { - return Transformation(settings_, trsf_->inverted()); - } - - Transformation multiplied(const Transformation& other) const { - return Transformation(settings_, trsf_->multiplied(other.data())); - } + const ifcopenshell::geometry::taxonomy::matrix4& data() const { return matrix_; } }; class Element { @@ -130,7 +105,7 @@ namespace ifcopenshell { namespace geometry { void SetParents(std::vector newparents) { _parents = newparents; } Element(const element_settings& settings, int id, int parent_id, const std::string& name, const std::string& type, - const std::string& guid, const std::string& context, const ConversionResultPlacement* trsf, IfcUtil::IfcBaseEntity* product) + const std::string& guid, const std::string& context, const ifcopenshell::geometry::taxonomy::matrix4& trsf, IfcUtil::IfcBaseEntity* product) : _id(id), _parent_id(parent_id), _name(name), _type(type), _guid(guid), _context(context), _transformation(settings, trsf) , product_(product) { @@ -166,7 +141,7 @@ namespace ifcopenshell { namespace geometry { const boost::shared_ptr& geometry_pointer() const { return _geometry; } const Representation::BRep& geometry() const { return *_geometry; } NativeElement(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, - const std::string& context, const ConversionResultPlacement* trsf, const boost::shared_ptr& geometry, + const std::string& context, const ifcopenshell::geometry::taxonomy::matrix4& trsf, const boost::shared_ptr& geometry, IfcUtil::IfcBaseEntity* product) : Element(geometry->settings() ,id, parent_id, name, type, guid, context, trsf, product) , _geometry(geometry) diff --git a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp index 92ce22ae93..e71ef2fad0 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp +++ b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp @@ -29,29 +29,28 @@ #include "IfcGeomRepresentation.h" #include "../../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h" -#include "../../ifcgeom/schema_agnostic/Kernel.h" -IfcGeom::Representation::Serialization::Serialization(const BRep& brep) +ifcopenshell::geometry::Representation::Serialization::Serialization(const BRep& brep) : Representation(brep.settings()) , id_(brep.id()) { - IfcGeom::ConversionResultShape* shape = brep.as_compound(); + ifcopenshell::geometry::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()); - surface_styles_.push_back(clr.G()); - surface_styles_.push_back(clr.B()); + for (ifcopenshell::geometry::ConversionResults::const_iterator it = brep.begin(); it != brep.end(); ++ it) { + if (it->hasStyle() && it->Style().diffuse) { + auto clr = it->Style().diffuse.get().components; + surface_styles_.push_back(clr[0]); + surface_styles_.push_back(clr[1]); + surface_styles_.push_back(clr[2]); } else { surface_styles_.push_back(-1.); surface_styles_.push_back(-1.); surface_styles_.push_back(-1.); } - if (it->hasStyle() && it->Style().Transparency()) { - surface_styles_.push_back(1. - *it->Style().Transparency()); + if (it->hasStyle() && it->Style().transparency) { + surface_styles_.push_back(1. - *it->Style().transparency); } else { surface_styles_.push_back(1.); } @@ -86,19 +85,23 @@ TopoDS_Shape apply_transformation(const TopoDS_Shape& s, const gp_GTrsf& t) { } } -IfcGeom::ConversionResultShape* IfcGeom::Representation::BRep::as_compound(bool force_meters) const { +ifcopenshell::geometry::ConversionResultShape* ifcopenshell::geometry::Representation::BRep::as_compound(bool force_meters) const { TopoDS_Compound compound; BRep_Builder builder; builder.MakeCompound(compound); - for (IfcGeom::ConversionResults::const_iterator it = begin(); it != end(); ++it) { + for (ifcopenshell::geometry::ConversionResults::const_iterator it = begin(); it != end(); ++it) { const TopoDS_Shape& s = *(OpenCascadeShape*) it->Shape(); + + // @todo, check gp_GTrsf trsf; - if (it->Placement()) { - trsf = ((OpenCascadePlacement*)it->Placement())->trsf(); + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < j; ++i) { + trsf.SetValue(i + 1, j + 1, it->Placement().components(i, j)); + } } - if (!force_meters && settings().get(IteratorSettings::CONVERT_BACK_UNITS)) { + if (!force_meters && settings().get(ifcopenshell::geometry::settings::CONVERT_BACK_UNITS)) { gp_Trsf scale; scale.SetScaleFactor(1.0 / settings().unit_magnitude()); trsf.PreMultiply(scale); @@ -195,11 +198,11 @@ namespace { } } -bool IfcGeom::Representation::BRep::calculate_surface_area(double& area) const { +bool ifcopenshell::geometry::Representation::BRep::calculate_surface_area(double& area) const { try { area = 0.; - for (IfcGeom::ConversionResults::const_iterator it = begin(); it != end(); ++it) { + for (ifcopenshell::geometry::ConversionResults::const_iterator it = begin(); it != end(); ++it) { GProp_GProps prop; BRepGProp::SurfaceProperties(*(OpenCascadeShape*)it->Shape(), prop); area += prop.Mass(); @@ -212,12 +215,12 @@ bool IfcGeom::Representation::BRep::calculate_surface_area(double& area) const { } } -bool IfcGeom::Representation::BRep::calculate_volume(double& volume) const { +bool ifcopenshell::geometry::Representation::BRep::calculate_volume(double& volume) const { try { volume = 0.; - for (IfcGeom::ConversionResults::const_iterator it = begin(); it != end(); ++it) { - if (Kernel::is_manifold(it->Shape())) { + for (ifcopenshell::geometry::ConversionResults::const_iterator it = begin(); it != end(); ++it) { + if (it->Shape()->is_manifold()) { GProp_GProps prop; BRepGProp::VolumeProperties(*(OpenCascadeShape*)it->Shape(), prop); volume += prop.Mass(); @@ -233,19 +236,26 @@ bool IfcGeom::Representation::BRep::calculate_volume(double& volume) const { } } -bool IfcGeom::Representation::BRep::calculate_projected_surface_area(const ConversionResultPlacement* place, double & along_x, double & along_y, double & along_z) const { +bool ifcopenshell::geometry::Representation::BRep::calculate_projected_surface_area(const ifcopenshell::geometry::taxonomy::matrix4& place, double & along_x, double & along_y, double & along_z) const { try { - gp_Trsf trsf = ((OpenCascadePlacement*)place)->trsf().Trsf(); - gp_Mat mat = trsf.HVectorialPart(); + // @todo check + gp_GTrsf trsf; + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < j; ++i) { + trsf.SetValue(i + 1, j + 1, place.components(i, j)); + } + } + + gp_Mat mat = trsf.Trsf().HVectorialPart(); gp_Ax3 ax(trsf.TranslationPart(), mat.Column(3), mat.Column(1)); along_x = along_y = along_z = 0.; - for (IfcGeom::ConversionResults::const_iterator it = begin(); it != end(); ++it) { + for (ifcopenshell::geometry::ConversionResults::const_iterator it = begin(); it != end(); ++it) { double x, y, z; surface_area_along_direction(settings().deflection_tolerance(), *(OpenCascadeShape*)it->Shape(), ax, x, y, z); - if (Kernel::is_manifold(it->Shape())) { + if (it->Shape()->is_manifold()) { x /= 2.; y /= 2.; z /= 2.; diff --git a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.h b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.h index 2f354acc3d..62194b0749 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.h @@ -63,7 +63,7 @@ namespace ifcopenshell { namespace geometry { bool calculate_volume(double&) const; bool calculate_surface_area(double&) const; - bool calculate_projected_surface_area(const ifcopenshell::geometry::ConversionResultPlacement* ax, double& along_x, double& along_y, double& along_z) const; + bool calculate_projected_surface_area(const ifcopenshell::geometry::taxonomy::matrix4& ax, double& along_x, double& along_y, double& along_z) const; }; class IFC_GEOM_API Serialization : public Representation { diff --git a/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h b/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h index 25d26150f9..864e7f68fe 100644 --- a/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h +++ b/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h @@ -39,47 +39,6 @@ namespace ifcopenshell { namespace geometry { - 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) @@ -88,7 +47,7 @@ namespace ifcopenshell { const TopoDS_Shape& shape() const { return shape_; } operator const TopoDS_Shape& () { return shape_; } - virtual void Triangulate(const settings & settings, const ConversionResultPlacement * place, Representation::Triangulation* t, int surface_style_id) const; + virtual void Triangulate(const settings & settings, const ifcopenshell::geometry::taxonomy::matrix4& place, Representation::Triangulation* t, int surface_style_id) const; virtual void Serialize(std::string&) const { throw std::runtime_error("Not implemented"); @@ -98,6 +57,8 @@ namespace ifcopenshell { return new OpenCascadeShape(shape_); } + virtual bool is_manifold() const; + virtual int surface_genus() const; private: TopoDS_Shape shape_; From 8f88c601c6bccbcaa4b8bbf587cd25935696e922 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 18 Aug 2019 14:31:22 +0200 Subject: [PATCH 159/235] IfcConvert links on windows --- src/ifcgeom/abstract_mapping.h | 2 +- .../kernel_agnostic/AbstractKernel.cpp | 10 ++ src/ifcgeom/kernel_agnostic/AbstractKernel.h | 13 +- src/ifcgeom/kernels/opencascade/IfcGeomTree.h | 2 +- .../OpenCascadeConversionResult.cpp | 37 ++--- .../opencascade/OpenCascadeConversionResult.h | 2 +- .../kernels/opencascade/OpenCascadeKernel.h | 2 +- src/ifcgeom/schema/mapping.cpp | 16 ++ src/ifcgeom/schema/mapping.h | 1 + src/ifcgeom/schema/mapping.i | 148 +++++++++--------- src/ifcgeom/schema_agnostic/Converter.cpp | 116 +++----------- src/ifcgeom/schema_agnostic/Converter.h | 6 - src/ifcgeom/schema_agnostic/IfcGeomElement.h | 6 + .../schema_agnostic/IfcGeomRepresentation.cpp | 2 +- src/ifcgeom/taxonomy.h | 1 + src/ifcgeomserver/IfcGeomServer.cpp | 2 +- src/serializers/ColladaSerializer.cpp | 19 ++- src/serializers/OpenCascadeBasedSerializer.h | 2 +- src/serializers/SvgSerializer.cpp | 2 +- src/serializers/XmlSerializer.cpp | 12 +- 20 files changed, 173 insertions(+), 228 deletions(-) rename src/ifcgeom/{schema_agnostic => kernels}/opencascade/OpenCascadeConversionResult.cpp (81%) rename src/ifcgeom/{schema_agnostic => kernels}/opencascade/OpenCascadeConversionResult.h (93%) diff --git a/src/ifcgeom/abstract_mapping.h b/src/ifcgeom/abstract_mapping.h index 7dbb4d413e..5ff2e575bc 100644 --- a/src/ifcgeom/abstract_mapping.h +++ b/src/ifcgeom/abstract_mapping.h @@ -33,7 +33,7 @@ namespace geometry { virtual ifcopenshell::geometry::taxonomy::item* map(const IfcUtil::IfcBaseClass*) = 0; virtual void get_representations(std::vector& tasks, std::vector& filters, settings& s) = 0; virtual IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity* product, bool include_openings = true) = 0; - virtual std::map get_layers(IfcUtil::IfcBaseEntity*); + virtual std::map get_layers(IfcUtil::IfcBaseEntity*) = 0; }; namespace impl { diff --git a/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp index 18f5d0c53d..4c1d7dcce1 100644 --- a/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp +++ b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp @@ -1,6 +1,7 @@ #include "AbstractKernel.h" #include "../../ifcgeom/schema_agnostic/IfcGeomElement.h" +#include "../../ifcgeom/kernels/opencascade/OpenCascadeKernel.h" namespace { /* A compile-time for loop over the taxonomy kinds */ @@ -28,6 +29,15 @@ bool ifcopenshell::geometry::kernels::AbstractKernel::convert(const taxonomy::it return dispatch_conversion<0>::dispatch(this, item, results); } +ifcopenshell::geometry::kernels::AbstractKernel* ifcopenshell::geometry::kernels::construct(const std::string& geometry_library, IfcParse::IfcFile* file) { + const std::string geometry_library_lower = boost::to_lower_copy(geometry_library); + if (geometry_library_lower == "opencascade") { + return new OpenCascadeKernel; + } else { + throw IfcParse::IfcException("No geometry kernel registered for " + geometry_library); + } +} + //void ifcopenshell::geometry::kernels::AbstractKernel::set_conversion_placement_rel_to(const IfcParse::declaration* type) { // placement_rel_to = type; //} diff --git a/src/ifcgeom/kernel_agnostic/AbstractKernel.h b/src/ifcgeom/kernel_agnostic/AbstractKernel.h index dcff03cebc..51673a6143 100644 --- a/src/ifcgeom/kernel_agnostic/AbstractKernel.h +++ b/src/ifcgeom/kernel_agnostic/AbstractKernel.h @@ -53,18 +53,7 @@ namespace ifcopenshell { namespace geometry { namespace kernels { virtual bool convert_impl(const taxonomy::node*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } }; - namespace impl { - typedef boost::function1 < AbstractKernel*, const std::string&> kernel_fn; - - class KernelFactoryImplementation : public std::map { - public: - KernelFactoryImplementation(); - void bind(const std::string& geometry_library, kernel_fn); - AbstractKernel* construct(const std::string& geometry_library, IfcParse::IfcFile*); - }; - - KernelFactoryImplementation& kernel_implementations(); - } + AbstractKernel* construct(const std::string& geometry_library, IfcParse::IfcFile*); } } diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomTree.h b/src/ifcgeom/kernels/opencascade/IfcGeomTree.h index c5c657a370..73869ae50c 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomTree.h +++ b/src/ifcgeom/kernels/opencascade/IfcGeomTree.h @@ -24,7 +24,7 @@ #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 "../../../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h" #include #include diff --git a/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.cpp b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp similarity index 81% rename from src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.cpp rename to src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp index b113ba45ce..9478a64c15 100644 --- a/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.cpp +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp @@ -7,17 +7,19 @@ #include -template -void triangulate_helper(const TopoDS_Shape& s, const IfcGeom::IteratorSettings& settings, const IfcGeom::ConversionResultPlacement* place, IfcGeom::Representation::Triangulation* t, int surface_style_id) { +void ifcopenshell::geometry::OpenCascadeShape::Triangulate(const settings& settings, const ifcopenshell::geometry::taxonomy::matrix4& place, Representation::Triangulation* t, int surface_style_id) const { + // @todo check gp_GTrsf trsf; - if (place) { - trsf = dynamic_cast(place)->trsf(); + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < j; ++i) { + trsf.SetValue(i + 1, j + 1, place.components(i, j)); + } } // Triangulate the shape try { - BRepMesh_IncrementalMesh(s, settings.deflection_tolerance()); + BRepMesh_IncrementalMesh(shape_, settings.deflection_tolerance()); } catch (...) { // TODO: Catch outside @@ -29,7 +31,7 @@ void triangulate_helper(const TopoDS_Shape& s, const IfcGeom::IteratorSettings& // Iterates over the faces of the shape int num_faces = 0; TopExp_Explorer exp; - for (exp.Init(s, TopAbs_FACE); exp.More(); exp.Next(), ++num_faces) { + for (exp.Init(shape_, 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); @@ -51,8 +53,8 @@ void triangulate_helper(const TopoDS_Shape& s, const IfcGeom::IteratorSettings& std::map 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); + const bool calculate_normals = !settings.get(ifcopenshell::geometry::settings::WELD_VERTICES) && + !settings.get(ifcopenshell::geometry::settings::NO_NORMALS); for (int i = 1; i <= nodes.Length(); ++i) { coords.push_back(nodes(i).Transformed(loc).XYZ()); @@ -114,7 +116,7 @@ void triangulate_helper(const TopoDS_Shape& s, const IfcGeom::IteratorSettings& 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 @@ -184,18 +186,13 @@ void triangulate_helper(const TopoDS_Shape& s, const IfcGeom::IteratorSettings& */ - BRepTools::Clean(s); + BRepTools::Clean(shape_); } -void IfcGeom::OpenCascadeShape::Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation* 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* t, int surface_style_id) const { - triangulate_helper(shape_, settings, place, t, surface_style_id); -} - -int IfcGeom::OpenCascadeShape::surface_genus() const { +int ifcopenshell::geometry::OpenCascadeShape::surface_genus() const { + throw std::runtime_error("Not implemented"); +} + +bool ifcopenshell::geometry::OpenCascadeShape::is_manifold() const { throw std::runtime_error("Not implemented"); - // return IfcGeom::Kernel::surface_genus(shape_); } \ No newline at end of file diff --git a/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h similarity index 93% rename from src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h rename to src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h index 864e7f68fe..8083e33fed 100644 --- a/src/ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h @@ -47,7 +47,7 @@ namespace ifcopenshell { const TopoDS_Shape& shape() const { return shape_; } operator const TopoDS_Shape& () { return shape_; } - virtual void Triangulate(const settings & settings, const ifcopenshell::geometry::taxonomy::matrix4& place, Representation::Triangulation* t, int surface_style_id) const; + virtual void Triangulate(const settings& settings, const ifcopenshell::geometry::taxonomy::matrix4& place, Representation::Triangulation* t, int surface_style_id) const; virtual void Serialize(std::string&) const { throw std::runtime_error("Not implemented"); diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h index e274fe3ab5..0d5b37dfe6 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h @@ -55,7 +55,7 @@ inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance=ALMO #include "../../../ifcgeom/schema_agnostic/ConversionResult.h" #include "../../../ifcgeom/kernels/opencascade/IfcGeomShapeType.h" -#include "../../../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h" +#include "../../../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h" #include "../../../ifcgeom/schema_agnostic/ifc_geom_api.h" diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index c2c74fcb27..a7b8a46871 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -699,3 +699,19 @@ IfcUtil::IfcBaseEntity* mapping::get_decomposing_entity(IfcUtil::IfcBaseEntity* return parent; } + +std::map mapping::get_layers(IfcUtil::IfcBaseEntity* inst) { + auto prod = inst->as(); + std::map layers; + if (prod->hasRepresentation()) { + IfcEntityList::ptr r = IfcParse::traverse(prod->Representation()); + IfcSchema::IfcRepresentation::list::ptr representations = r->as(); + for (IfcSchema::IfcRepresentation::list::it it = representations->begin(); it != representations->end(); ++it) { + IfcSchema::IfcPresentationLayerAssignment::list::ptr a = (*it)->LayerAssignments(); + for (IfcSchema::IfcPresentationLayerAssignment::list::it jt = a->begin(); jt != a->end(); ++jt) { + layers[(*jt)->Name()] = *jt; + } + } + } + return layers; +} diff --git a/src/ifcgeom/schema/mapping.h b/src/ifcgeom/schema/mapping.h index ff63308389..4083966f0d 100644 --- a/src/ifcgeom/schema/mapping.h +++ b/src/ifcgeom/schema/mapping.h @@ -20,6 +20,7 @@ namespace geometry { POSTFIX_SCHEMA(mapping)(IfcParse::IfcFile* file) : file_(file) {} virtual ifcopenshell::geometry::taxonomy::item* map(const IfcUtil::IfcBaseClass*); virtual void get_representations(std::vector& tasks, std::vector& filters, settings& s); + virtual std::map get_layers(IfcUtil::IfcBaseEntity*); const IfcSchema::IfcMaterial* get_single_material_association(const IfcSchema::IfcProduct* product); IfcSchema::IfcRepresentation* representation_mapped_to(const IfcSchema::IfcRepresentation* representation); diff --git a/src/ifcgeom/schema/mapping.i b/src/ifcgeom/schema/mapping.i index 1c86d47634..2875100592 100644 --- a/src/ifcgeom/schema/mapping.i +++ b/src/ifcgeom/schema/mapping.i @@ -24,110 +24,110 @@ * * ********************************************************************************/ -BIND(IfcShellBasedSurfaceModel); -BIND(IfcFaceBasedSurfaceModel); -BIND(IfcRepresentation); -BIND(IfcMappedItem); +// BIND(IfcShellBasedSurfaceModel); +// BIND(IfcFaceBasedSurfaceModel); +// BIND(IfcRepresentation); +// BIND(IfcMappedItem); // IfcFacetedBrep included // IfcAdvancedBrep included // IfcFacetedBrepWithVoids included // IfcAdvancedBrepWithVoids included -BIND(IfcManifoldSolidBrep); -BIND(IfcGeometricSet); +// BIND(IfcManifoldSolidBrep); +// BIND(IfcGeometricSet); #ifdef SCHEMA_HAS_IfcCylindricalSurface -BIND(IfcCylindricalSurface); +// BIND(IfcCylindricalSurface); #endif #ifdef SCHEMA_HAS_IfcAdvancedBrep -BIND(IfcAdvancedBrep); +// BIND(IfcAdvancedBrep); #endif // FIXME: Surfaces should have a shape type of their own #ifdef SCHEMA_HAS_IfcBSplineSurfaceWithKnots -BIND(IfcBSplineSurfaceWithKnots); +// BIND(IfcBSplineSurfaceWithKnots); #endif #ifdef SCHEMA_HAS_IfcTriangulatedFaceSet -BIND(IfcTriangulatedFaceSet); +// BIND(IfcTriangulatedFaceSet); #endif #ifdef SCHEMA_HAS_IfcExtrudedAreaSolidTapered -BIND(IfcExtrudedAreaSolidTapered); +// BIND(IfcExtrudedAreaSolidTapered); #endif BIND(IfcExtrudedAreaSolid); -BIND(IfcRevolvedAreaSolid); -BIND(IfcConnectedFaceSet); -BIND(IfcBooleanResult); -BIND(IfcPolygonalBoundedHalfSpace); -BIND(IfcHalfSpaceSolid); -BIND(IfcSurfaceOfLinearExtrusion); -BIND(IfcSurfaceOfRevolution); -BIND(IfcBlock); -BIND(IfcRectangularPyramid); -BIND(IfcRightCircularCylinder); -BIND(IfcRightCircularCone); -BIND(IfcSphere); -BIND(IfcCsgSolid); -BIND(IfcCurveBoundedPlane); -BIND(IfcRectangularTrimmedSurface); -BIND(IfcSurfaceCurveSweptAreaSolid); -BIND(IfcSweptDiskSolid); +// BIND(IfcRevolvedAreaSolid); +// BIND(IfcConnectedFaceSet); +// BIND(IfcBooleanResult); +// BIND(IfcPolygonalBoundedHalfSpace); +// BIND(IfcHalfSpaceSolid); +// BIND(IfcSurfaceOfLinearExtrusion); +// BIND(IfcSurfaceOfRevolution); +// BIND(IfcBlock); +// BIND(IfcRectangularPyramid); +// BIND(IfcRightCircularCylinder); +// BIND(IfcRightCircularCone); +// BIND(IfcSphere); +// BIND(IfcCsgSolid); +// BIND(IfcCurveBoundedPlane); +// BIND(IfcRectangularTrimmedSurface); +// BIND(IfcSurfaceCurveSweptAreaSolid); +// BIND(IfcSweptDiskSolid); -BIND(IfcArbitraryProfileDefWithVoids); -BIND(IfcArbitraryClosedProfileDef); -BIND(IfcRoundedRectangleProfileDef); -BIND(IfcRectangleHollowProfileDef); -BIND(IfcRectangleProfileDef); -BIND(IfcTrapeziumProfileDef) -BIND(IfcCShapeProfileDef); +// BIND(IfcArbitraryProfileDefWithVoids); +// BIND(IfcArbitraryClosedProfileDef); +// BIND(IfcRoundedRectangleProfileDef); +// BIND(IfcRectangleHollowProfileDef); +// BIND(IfcRectangleProfileDef); +// BIND(IfcTrapeziumProfileDef) +// BIND(IfcCShapeProfileDef); // IfcAsymmetricIShapeProfileDef included -BIND(IfcIShapeProfileDef); -BIND(IfcLShapeProfileDef); -BIND(IfcTShapeProfileDef); -BIND(IfcUShapeProfileDef); -BIND(IfcZShapeProfileDef); -BIND(IfcCircleHollowProfileDef); -BIND(IfcCircleProfileDef); -BIND(IfcEllipseProfileDef); -BIND(IfcCenterLineProfileDef); -BIND(IfcCompositeProfileDef); -BIND(IfcDerivedProfileDef); +// BIND(IfcIShapeProfileDef); +// BIND(IfcLShapeProfileDef); +// BIND(IfcTShapeProfileDef); +// BIND(IfcUShapeProfileDef); +// BIND(IfcZShapeProfileDef); +// BIND(IfcCircleHollowProfileDef); +// BIND(IfcCircleProfileDef); +// BIND(IfcEllipseProfileDef); +// BIND(IfcCenterLineProfileDef); +// BIND(IfcCompositeProfileDef); +// BIND(IfcDerivedProfileDef); // IfcFaceSurface included // IfcAdvancedFace included in case of IFC4 -BIND(IfcFace); +// BIND(IfcFace); -BIND(IfcEdgeCurve); -BIND(IfcSubedge); -BIND(IfcOrientedEdge); -BIND(IfcEdge); -BIND(IfcEdgeLoop); -BIND(IfcPolyline); -BIND(IfcPolyLoop); -BIND(IfcCompositeCurve); -BIND(IfcTrimmedCurve); -BIND(IfcArbitraryOpenProfileDef); +// BIND(IfcEdgeCurve); +// BIND(IfcSubedge); +// BIND(IfcOrientedEdge); +// BIND(IfcEdge); +// BIND(IfcEdgeLoop); +// BIND(IfcPolyline); +// BIND(IfcPolyLoop); +// BIND(IfcCompositeCurve); +// BIND(IfcTrimmedCurve); +// BIND(IfcArbitraryOpenProfileDef); #ifdef SCHEMA_HAS_IfcIndexedPolyCurve -BIND(IfcIndexedPolyCurve) +// BIND(IfcIndexedPolyCurve) #endif -BIND(IfcCircle); -BIND(IfcEllipse); -BIND(IfcLine); +// BIND(IfcCircle); +// BIND(IfcEllipse); +// BIND(IfcLine); #ifdef SCHEMA_HAS_IfcBSplineCurveWithKnots // IfcRationalBSplineCurveWithKnots included -BIND(IfcBSplineCurveWithKnots); +// BIND(IfcBSplineCurveWithKnots); #endif -BIND(IfcCartesianPoint); -BIND(IfcDirection); -BIND(IfcAxis2Placement2D); +// BIND(IfcCartesianPoint); +// BIND(IfcDirection); +// BIND(IfcAxis2Placement2D); BIND(IfcAxis2Placement3D); -BIND(IfcAxis1Placement); -BIND(IfcCartesianTransformationOperator2DnonUniform); -BIND(IfcCartesianTransformationOperator3DnonUniform); -BIND(IfcCartesianTransformationOperator2D); -BIND(IfcCartesianTransformationOperator3D); -BIND(IfcObjectPlacement); -BIND(IfcVector); -BIND(IfcPlane); +// BIND(IfcAxis1Placement); +// BIND(IfcCartesianTransformationOperator2DnonUniform); +// BIND(IfcCartesianTransformationOperator3DnonUniform); +// BIND(IfcCartesianTransformationOperator2D); +// BIND(IfcCartesianTransformationOperator3D); +// BIND(IfcObjectPlacement); +// BIND(IfcVector); +// BIND(IfcPlane); -BIND(IfcColourRgb); +// BIND(IfcColourRgb); BIND(IfcMaterial); BIND(IfcStyledItem); diff --git a/src/ifcgeom/schema_agnostic/Converter.cpp b/src/ifcgeom/schema_agnostic/Converter.cpp index cee8ad501f..751b68ec8f 100644 --- a/src/ifcgeom/schema_agnostic/Converter.cpp +++ b/src/ifcgeom/schema_agnostic/Converter.cpp @@ -3,7 +3,7 @@ #include "../../ifcgeom/schema_agnostic/IfcGeomElement.h" ifcopenshell::geometry::Converter::Converter(const std::string& geometry_library, IfcParse::IfcFile* file) { - kernel_ = kernels::impl::kernel_implementations().construct(geometry_library, file); + kernel_ = kernels::construct(geometry_library, file); mapping_ = impl::mapping_implementations().construct(file); } @@ -26,15 +26,6 @@ ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create Logger::Error(e); } - ConversionResultPlacement* trsf = nullptr; - try { - convert_placement(product, trsf); - } catch (const std::exception& e) { - Logger::Error(e); - } catch (...) { - Logger::Error("Failed to construct placement"); - } - const std::string guid = product->get_value("GlobalId"); const std::string name = product->get_value_or("Name", ""); @@ -44,7 +35,8 @@ ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create ifcopenshell::geometry::ConversionResults shapes; auto rep_item = mapping_->map(representation); - auto placement = mapping_->map(product); + // @todo decide how to get placement from product + auto placement = (taxonomy::geom_item*) mapping_->map(product); kernel_->convert(rep_item, shapes); shape = new ifcopenshell::geometry::Representation::BRep(s, representation_id_builder.str(), shapes); @@ -57,7 +49,7 @@ ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create guid, // @todo "", - trsf, + placement->matrix, boost::shared_ptr(shape), product ); @@ -202,55 +194,50 @@ ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create */ } -/* -template -ifcopenshell::geometry::kernels::NativeElement* ifcopenshell::geometry::kernels::AbstractKernel::create_brep_for_processed_representation( - const IteratorSettings& //* settings /, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product, - ifcopenshell::geometry::kernels::NativeElement* brep) { +ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create_brep_for_processed_representation( + const ifcopenshell::geometry::settings& /* settings */, IfcUtil::IfcBaseEntity* /* representation */, IfcUtil::IfcBaseEntity* product, + ifcopenshell::geometry::NativeElement* brep) +{ int parent_id = -1; try { - IfcUtil::IfcBaseEntity* parent_object = get_decomposing_entity(product); - if (parent_object && parent_object->as()) { + IfcUtil::IfcBaseEntity* parent_object = mapping_->get_decomposing_entity(product); + if (parent_object) { 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(); + const std::string guid = product->get_value("GlobalId"); + const std::string name = product->get_value_or("Name", ""); - ConversionResultPlacement* trsf = nullptr; - try { - convert_placement(product->ObjectPlacement(), trsf); - } catch (const std::exception& e) { - Logger::Error(e); - } catch (...) { - Logger::Error("Failed to construct placement"); - } + auto placement = (taxonomy::geom_item*) mapping_->map(product); + /* 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( + return new NativeElement( product->data().id(), parent_id, name, product_type, guid, - context_string, - trsf, + // @todo + "", + placement->matrix, brep->geometry_pointer(), product ); } -*/ + //#include "../../ifcparse/Ifc2x3.h" //#include "../../ifcparse/Ifc4.h" // @@ -308,42 +295,6 @@ ifcopenshell::geometry::kernels::NativeElement* ifcopenshell::geometry::k // return genus; //} // -//IfcGeom::impl::KernelFactoryImplementation& IfcGeom::impl::kernel_implementations() { -// static KernelFactoryImplementation impl; -// return impl; -//} -// -//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_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, 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(std::make_pair(schema_name_lower, geometry_library), fn)); -//} -// -//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, 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); -// } -// return it->second(file); -//} -// // //IfcUtil::IfcBaseEntity* IfcGeom::Kernel::get_decomposing_entity(IfcUtil::IfcBaseEntity* inst, bool include_openings) { // if (inst->as()) { @@ -357,33 +308,6 @@ ifcopenshell::geometry::kernels::NativeElement* ifcopenshell::geometry::k // } //} // -//namespace { -// template -// static std::map get_layers_impl(typename Schema::IfcProduct* prod) { -// std::map layers; -// if (prod->hasRepresentation()) { -// IfcEntityList::ptr r = IfcParse::traverse(prod->Representation()); -// typename Schema::IfcRepresentation::list::ptr representations = r->template as(); -// for (typename Schema::IfcRepresentation::list::it it = representations->begin(); it != representations->end(); ++it) { -// typename Schema::IfcPresentationLayerAssignment::list::ptr a = (*it)->LayerAssignments(); -// for (typename Schema::IfcPresentationLayerAssignment::list::it jt = a->begin(); jt != a->end(); ++jt) { -// layers[(*jt)->Name()] = *jt; -// } -// } -// } -// return layers; -// } -//} -// -//std::map IfcGeom::Kernel::get_layers(IfcUtil::IfcBaseEntity* inst) { -// if (inst->as()) { -// return get_layers_impl(inst->as()); -// } else if (inst->as()) { -// return get_layers_impl(inst->as()); -// } else { -// throw IfcParse::IfcException("Unexpected entity " + inst->declaration().name()); -// } -//} // //bool IfcGeom::Kernel::is_manifold(const ConversionResultShape* s_) { // // @todo make kernel agnostic diff --git a/src/ifcgeom/schema_agnostic/Converter.h b/src/ifcgeom/schema_agnostic/Converter.h index 06cd31ad3b..598123f360 100644 --- a/src/ifcgeom/schema_agnostic/Converter.h +++ b/src/ifcgeom/schema_agnostic/Converter.h @@ -81,11 +81,6 @@ namespace ifcopenshell { namespace geometry { return results; } - bool convert_placement(IfcUtil::IfcBaseClass* item, ifcopenshell::geometry::ConversionResultPlacement*& trsf) { - throw std::runtime_error("not implemented"); - // return implementation_->convert_placement(item, trsf); - } - ifcopenshell::geometry::NativeElement* create_brep_for_representation_and_product(const ifcopenshell::geometry::settings& settings, IfcUtil::IfcBaseEntity* representation, IfcUtil::IfcBaseEntity* product); ifcopenshell::geometry::NativeElement* create_brep_for_processed_representation(const ifcopenshell::geometry::settings& settings, IfcUtil::IfcBaseEntity* representation, IfcUtil::IfcBaseEntity* product, ifcopenshell::geometry::NativeElement* brep); @@ -95,7 +90,6 @@ namespace ifcopenshell { namespace geometry { static bool is_manifold(const ifcopenshell::geometry::ConversionResultShape*); static IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity*, bool include_openings=true); - static std::map get_layers(IfcUtil::IfcBaseEntity*); static IfcEntityList::ptr find_openings(IfcUtil::IfcBaseEntity* product); */ }; diff --git a/src/ifcgeom/schema_agnostic/IfcGeomElement.h b/src/ifcgeom/schema_agnostic/IfcGeomElement.h index cc8544be5f..a21db0ede1 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomElement.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomElement.h @@ -54,6 +54,9 @@ namespace ifcopenshell { namespace geometry { } } const ifcopenshell::geometry::taxonomy::matrix4& data() const { return matrix_; } + const element_settings& settings() const { return settings_; } + + EIGEN_MAKE_ALIGNED_OPERATOR_NEW }; class Element { @@ -131,7 +134,10 @@ namespace ifcopenshell { namespace geometry { _unique_id = oss.str(); } + virtual ~Element() {} + + EIGEN_MAKE_ALIGNED_OPERATOR_NEW }; class NativeElement : public Element { diff --git a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp index e71ef2fad0..fcca0ad6be 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp +++ b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp @@ -28,7 +28,7 @@ #include #include "IfcGeomRepresentation.h" -#include "../../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h" +#include "../../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h" ifcopenshell::geometry::Representation::Serialization::Serialization(const BRep& brep) : Representation(brep.settings()) diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index 4f32f05bb6..725ce46722 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -39,6 +39,7 @@ struct matrix4 : public item { Eigen::Matrix4d components; + matrix4(const Eigen::Matrix4d& c) : components(c), tag(OTHER) {} matrix4() : components(Eigen::Matrix4d::Identity()), tag(IDENTITY) {} virtual item* clone() const { return new matrix4(*this); } diff --git a/src/ifcgeomserver/IfcGeomServer.cpp b/src/ifcgeomserver/IfcGeomServer.cpp index 1acef29553..9dfcd12519 100644 --- a/src/ifcgeomserver/IfcGeomServer.cpp +++ b/src/ifcgeomserver/IfcGeomServer.cpp @@ -47,7 +47,7 @@ #include #endif -#include "../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h" +#include "../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h" #include #include diff --git a/src/serializers/ColladaSerializer.cpp b/src/serializers/ColladaSerializer.cpp index d5434c92da..b9ca3a6786 100644 --- a/src/serializers/ColladaSerializer.cpp +++ b/src/serializers/ColladaSerializer.cpp @@ -191,20 +191,20 @@ void ColladaSerializer::ColladaExporter::ColladaScene::add( node.setNodeName(node_name); node.setType(COLLADASW::Node::NODE); - // The matrix attribute of an entity is basically a 4x3 representation of its ObjectPlacement. - // Note that this placement is absolute, ie it is multiplied with all parent placements. - ifcopenshell::geometry::Transformation* relative_trsf = 0; const ifcopenshell::geometry::Transformation* transformation_towrite = &transformation; // If this is not the first parent, get the relative placement if (parentNodes.size() > 0) { - relative_trsf = new ifcopenshell::geometry::Transformation(matrixStack.top().multiplied(transformation)); + auto m4 = ifcopenshell::geometry::taxonomy::matrix4(matrixStack.top().data().components * transformation.data().components); + relative_trsf = new ifcopenshell::geometry::Transformation(transformation.settings(), m4); transformation_towrite = relative_trsf; } - const std::vector& posmatrix = transformation_towrite->matrix().data(); + // @todo verify + + const double* posmatrix = transformation_towrite->data().components.data(); double matrix_array[4][4] = { { (double)posmatrix[0], (double)posmatrix[3], (double)posmatrix[6], (double)posmatrix[9] }, @@ -251,11 +251,14 @@ void ColladaSerializer::ColladaExporter::ColladaScene::addParent(const ifcopensh // If this is not the first parent, get the relative placement if (parentNodes.size() > 0) { - relative_trsf = new ifcopenshell::geometry::Transformation(matrixStack.top().multiplied(parent_trsf)); + auto m4 = ifcopenshell::geometry::taxonomy::matrix4(matrixStack.top().data().components * parent_trsf.data().components); + relative_trsf = new ifcopenshell::geometry::Transformation(parent_trsf.settings(), m4); transformation_towrite = relative_trsf; } - const std::vector& parentMatrix = transformation_towrite->matrix().data(); + // @todo verify + + const double* parentMatrix = transformation_towrite->data().components.data(); double matrix_array[4][4] = { { (double)parentMatrix[0], (double)parentMatrix[3], (double)parentMatrix[6], (double)parentMatrix[9] }, @@ -277,7 +280,7 @@ void ColladaSerializer::ColladaExporter::ColladaScene::addParent(const ifcopensh current_node->addMatrix(matrix_array); // Add the node to the parent stack - matrixStack.push(parent_trsf.inverted()); + matrixStack.push(ifcopenshell::geometry::Transformation(parent_trsf.settings(), ifcopenshell::geometry::taxonomy::matrix4(parent_trsf.data().components.inverse()))); parentNodes.push(current_node); serializer->parentStackId.push(parent.id()); } diff --git a/src/serializers/OpenCascadeBasedSerializer.h b/src/serializers/OpenCascadeBasedSerializer.h index a8e72feddd..185945d6d0 100644 --- a/src/serializers/OpenCascadeBasedSerializer.h +++ b/src/serializers/OpenCascadeBasedSerializer.h @@ -20,7 +20,7 @@ #ifndef OPENCASCADEBASEDSERIALIZER_H #define OPENCASCADEBASEDSERIALIZER_H -#include "../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h" +#include "../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h" #include "../serializers/GeometrySerializer.h" class OpenCascadeBasedSerializer : public GeometrySerializer { diff --git a/src/serializers/SvgSerializer.cpp b/src/serializers/SvgSerializer.cpp index 846a9bac14..323351010b 100644 --- a/src/serializers/SvgSerializer.cpp +++ b/src/serializers/SvgSerializer.cpp @@ -19,7 +19,7 @@ * * ********************************************************************************/ -#include "../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h" +#include "../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h" #include #include diff --git a/src/serializers/XmlSerializer.cpp b/src/serializers/XmlSerializer.cpp index c9e0ae06f8..66ab4c879c 100644 --- a/src/serializers/XmlSerializer.cpp +++ b/src/serializers/XmlSerializer.cpp @@ -1,11 +1,15 @@ #include "XmlSerializer.h" -extern void init_XmlSerializerIfc2x3(XmlSerializerFactory::Factory*); -extern void init_XmlSerializerIfc4(XmlSerializerFactory::Factory*); +extern void init_XmlSerializer_Ifc2x3(XmlSerializerFactory::Factory*); +extern void init_XmlSerializer_Ifc4(XmlSerializerFactory::Factory*); +extern void init_XmlSerializer_Ifc4x1(XmlSerializerFactory::Factory*); +extern void init_XmlSerializer_Ifc4x2(XmlSerializerFactory::Factory*); XmlSerializerFactory::Factory::Factory() { - init_XmlSerializerIfc2x3(this); - init_XmlSerializerIfc4(this); + init_XmlSerializer_Ifc2x3(this); + init_XmlSerializer_Ifc4(this); + init_XmlSerializer_Ifc4x1(this); + init_XmlSerializer_Ifc4x2(this); } void XmlSerializerFactory::Factory::bind(const std::string& schema_name, fn f) { From 94aa7dfab4f16395eafb9304ae3b7b2a7da429bb Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 18 Aug 2019 15:53:26 +0200 Subject: [PATCH 160/235] Close to working executable --- src/ifcgeom/kernel_agnostic/AbstractKernel.h | 2 ++ src/ifcgeom/schema/bind_convert_impl.i | 18 ++++++++++-------- src/ifcgeom/schema/mapping.cpp | 18 +++++++++++++++++- src/ifcgeom/schema/mapping.i | 2 +- src/ifcgeom/schema_agnostic/Converter.cpp | 5 +++++ src/ifcgeom/schema_agnostic/IfcGeomIterator.h | 1 + src/ifcgeom/taxonomy.h | 19 +++++++++++++------ 7 files changed, 49 insertions(+), 16 deletions(-) diff --git a/src/ifcgeom/kernel_agnostic/AbstractKernel.h b/src/ifcgeom/kernel_agnostic/AbstractKernel.h index 51673a6143..062b6d2a05 100644 --- a/src/ifcgeom/kernel_agnostic/AbstractKernel.h +++ b/src/ifcgeom/kernel_agnostic/AbstractKernel.h @@ -51,6 +51,8 @@ namespace ifcopenshell { namespace geometry { namespace kernels { virtual bool convert_impl(const taxonomy::face*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } virtual bool convert_impl(const taxonomy::extrusion*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } virtual bool convert_impl(const taxonomy::node*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } + virtual bool convert_impl(const taxonomy::colour*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } + virtual bool convert_impl(const taxonomy::collection*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } }; AbstractKernel* construct(const std::string& geometry_library, IfcParse::IfcFile*); diff --git a/src/ifcgeom/schema/bind_convert_impl.i b/src/ifcgeom/schema/bind_convert_impl.i index 89af251420..5914425f88 100644 --- a/src/ifcgeom/schema/bind_convert_impl.i +++ b/src/ifcgeom/schema/bind_convert_impl.i @@ -6,16 +6,18 @@ if (l->declaration().is(IfcSchema::T::Class())) { \ try { \ taxonomy::item* item = map((IfcSchema::T*)l); \ - item->instance = l; \ - try { \ - if (l->as()) { \ - auto style = find_style(l->as()); \ - if (style) { \ - ((taxonomy::geom_item*)item)->surface_style = as(map(style)); \ + if (item != nullptr) { \ + item->instance = l; \ + try { \ + if (l->as()) { \ + auto style = find_style(l->as()); \ + if (style) { \ + ((taxonomy::geom_item*)item)->surface_style = as(map(style)); \ + } \ } \ + } catch (const std::exception& e) { \ + Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l); \ } \ - } catch (const std::exception& e) { \ - Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l); \ } \ return item; \ } catch (const std::exception& e) { \ diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index a7b8a46871..d904f9e5d9 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -126,7 +126,6 @@ namespace { taxonomy::item* mapping::map(const IfcSchema::IfcExtrudedAreaSolid* inst) { // @todo length unit return new taxonomy::extrusion( - inst, as(map(inst->Position())), as(map(inst->SweptArea())), as(map(inst->ExtrudedDirection())), @@ -134,6 +133,23 @@ taxonomy::item* mapping::map(const IfcSchema::IfcExtrudedAreaSolid* inst) { ); } +taxonomy::item* mapping::map(const IfcSchema::IfcRepresentation* inst) { + auto c = new taxonomy::collection(); + IfcSchema::IfcRepresentationItem::list::ptr items = inst->Items(); + if (items->size()) { + for (IfcSchema::IfcRepresentationItem::list::it it = items->begin(); it != items->end(); ++it) { + if (auto r = map(*it)) { + c->children.push_back(r); + } + } + } + if (c->children.empty()) { + delete c; + return nullptr; + } + return c; +} + taxonomy::item* mapping::map(const IfcSchema::IfcAxis2Placement3D* inst) { // @todo length unit return new taxonomy::matrix4(); diff --git a/src/ifcgeom/schema/mapping.i b/src/ifcgeom/schema/mapping.i index 2875100592..4fb8a158a7 100644 --- a/src/ifcgeom/schema/mapping.i +++ b/src/ifcgeom/schema/mapping.i @@ -26,7 +26,7 @@ // BIND(IfcShellBasedSurfaceModel); // BIND(IfcFaceBasedSurfaceModel); -// BIND(IfcRepresentation); +BIND(IfcRepresentation); // BIND(IfcMappedItem); // IfcFacetedBrep included // IfcAdvancedBrep included diff --git a/src/ifcgeom/schema_agnostic/Converter.cpp b/src/ifcgeom/schema_agnostic/Converter.cpp index 751b68ec8f..19843b11a8 100644 --- a/src/ifcgeom/schema_agnostic/Converter.cpp +++ b/src/ifcgeom/schema_agnostic/Converter.cpp @@ -35,6 +35,11 @@ ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create ifcopenshell::geometry::ConversionResults shapes; auto rep_item = mapping_->map(representation); + // @todo should map() throw an exception instead? + if (rep_item == nullptr) { + return nullptr; + } + // @todo decide how to get placement from product auto placement = (taxonomy::geom_item*) mapping_->map(product); kernel_->convert(rep_item, shapes); diff --git a/src/ifcgeom/schema_agnostic/IfcGeomIterator.h b/src/ifcgeom/schema_agnostic/IfcGeomIterator.h index c6febd30e1..cc6bc32823 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomIterator.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomIterator.h @@ -209,6 +209,7 @@ namespace ifcopenshell { namespace geometry { const double unit_magnitude() const { return unit_magnitude_; } bool initialize() { + converter_ = new Converter(geometry_library_, ifc_file); converter_->mapping()->get_representations(tasks_, filters_, settings_); if (tasks_.size() == 0) { diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index 725ce46722..65bc958071 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -19,7 +19,7 @@ namespace geometry { namespace taxonomy { -enum kinds { MATRIX4, POINT3, DIRECTION3, LINE, CIRCLE, ELLIPSE, BSPLINE, EDGE, LOOP, FACE, EXTRUSION, NODE, COLOUR, STYLE }; +enum kinds { MATRIX4, POINT3, DIRECTION3, LINE, CIRCLE, ELLIPSE, BSPLINE, EDGE, LOOP, FACE, EXTRUSION, NODE, COLOUR, STYLE, COLLECTION }; struct item { const IfcUtil::IfcBaseClass* instance; @@ -83,6 +83,7 @@ struct geom_item : public item { geom_item(const IfcUtil::IfcBaseClass* instance = nullptr) : item(instance) {} geom_item(const IfcUtil::IfcBaseClass* instance, matrix4 m) : item(instance), matrix(m) {} + geom_item(matrix4 m) : matrix(m) {} }; template @@ -160,8 +161,8 @@ struct face : public geom_item { struct sweep : public geom_item { face basis; - sweep(const IfcUtil::IfcBaseClass* instance, face b) : geom_item(instance), basis(b) {} - sweep(const IfcUtil::IfcBaseClass* instance, matrix4 m, face b) : geom_item(instance, m), basis(b) {} + sweep(face b) : basis(b) {} + sweep(matrix4 m, face b) : geom_item(m), basis(b) {} }; struct extrusion : public sweep { @@ -171,7 +172,14 @@ struct extrusion : public sweep { virtual item* clone() const { return new extrusion(*this); } virtual kinds kind() const { return EXTRUSION; } - extrusion(const IfcUtil::IfcBaseClass* instance, matrix4 m, face basis, direction3 dir, double d) : sweep(instance, m, basis), direction(dir), depth(d) {} + extrusion(matrix4 m, face basis, direction3 dir, double d) : sweep(m, basis), direction(dir), depth(d) {} +}; + +struct collection : public geom_item { + std::vector children; + + virtual item* clone() const { return new collection(*this); } + virtual kinds kind() const { return COLLECTION; } }; struct node : public geom_item { @@ -185,8 +193,7 @@ struct node : public geom_item { }; namespace impl { - // enum kinds { MATRIX4, POINT3, DIRECTION3, LINE, CIRCLE, ELLIPSE, BSPLINE, EDGE, LOOP, FACE, EXTRUSION, NODE }; - typedef std::tuple KindsTuple; + typedef std::tuple KindsTuple; } struct type_by_kind { From 2f1861db7b9c2905436658435711f4ce09622b0d Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sat, 24 Aug 2019 17:36:17 +0200 Subject: [PATCH 161/235] Declare conversions for reuse detection --- src/ifcgeom/schema/mapping.cpp | 22 +++++++++++++++++++++- src/ifcgeom/schema/mapping.i | 8 ++++---- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index d904f9e5d9..748339388f 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -155,6 +155,26 @@ taxonomy::item* mapping::map(const IfcSchema::IfcAxis2Placement3D* inst) { return new taxonomy::matrix4(); } +taxonomy::item* mapping::map(const IfcSchema::IfcCartesianTransformationOperator2DnonUniform* inst) { + // @todo length unit + return new taxonomy::matrix4(); +} + +taxonomy::item* mapping::map(const IfcSchema::IfcCartesianTransformationOperator3DnonUniform* inst) { + // @todo length unit + return new taxonomy::matrix4(); +} + +taxonomy::item* mapping::map(const IfcSchema::IfcCartesianTransformationOperator2D* inst) { + // @todo length unit + return new taxonomy::matrix4(); +} + +taxonomy::item* mapping::map(const IfcSchema::IfcCartesianTransformationOperator3D* inst) { + // @todo length unit + return new taxonomy::matrix4(); +} + IfcSchema::IfcProduct::list::ptr mapping::products_represented_by(const IfcSchema::IfcRepresentation* representation) { IfcSchema::IfcProduct::list::ptr products(new IfcSchema::IfcProduct::list); @@ -361,7 +381,7 @@ void mapping::get_representations(std::vector& tasks, representations = file_->instances_by_type(); } - IfcSchema::IfcRepresentation::list::ptr ok_mapped_representations; + IfcSchema::IfcRepresentation::list::ptr ok_mapped_representations(new IfcSchema::IfcRepresentation::list); int task_index = 0; diff --git a/src/ifcgeom/schema/mapping.i b/src/ifcgeom/schema/mapping.i index 4fb8a158a7..eb6bf0b4f0 100644 --- a/src/ifcgeom/schema/mapping.i +++ b/src/ifcgeom/schema/mapping.i @@ -120,10 +120,10 @@ BIND(IfcExtrudedAreaSolid); // BIND(IfcAxis2Placement2D); BIND(IfcAxis2Placement3D); // BIND(IfcAxis1Placement); -// BIND(IfcCartesianTransformationOperator2DnonUniform); -// BIND(IfcCartesianTransformationOperator3DnonUniform); -// BIND(IfcCartesianTransformationOperator2D); -// BIND(IfcCartesianTransformationOperator3D); +BIND(IfcCartesianTransformationOperator2DnonUniform); +BIND(IfcCartesianTransformationOperator3DnonUniform); +BIND(IfcCartesianTransformationOperator2D); +BIND(IfcCartesianTransformationOperator3D); // BIND(IfcObjectPlacement); // BIND(IfcVector); // BIND(IfcPlane); From 26d7af1450bafd3aa13834a36445d199e252890c Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sat, 24 Aug 2019 18:32:30 +0200 Subject: [PATCH 162/235] Implement additional mappings --- src/ifcgeom/schema/mapping.cpp | 110 +++++++++++++++++++++++++++++---- src/ifcgeom/schema/mapping.i | 14 +++-- src/ifcgeom/taxonomy.h | 101 ++++++++++++++++-------------- 3 files changed, 161 insertions(+), 64 deletions(-) diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index 748339388f..3218e4355b 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -70,7 +70,11 @@ namespace { loop_to_face_upgrade(taxonomy::item* item) { taxonomy::loop* loop = dynamic_cast(item); if (loop) { - face_ = taxonomy::face(loop->instance, loop->matrix, *loop); + face_ = taxonomy::face(); + face_->instance = loop->instance; + face_->matrix = loop->matrix; + // @todo make sure loop is not freed + face_->children = { loop }; } } @@ -121,6 +125,23 @@ namespace { delete item_; } }; + + template + U* map_to_collection(mapping* m, const T& ts) { + auto c = new U; + if (ts->size()) { + for (auto it = ts->begin(); it != ts->end(); ++it) { + if (auto r = m->map(*it)) { + c->children.push_back(r); + } + } + } + if (c->children.empty()) { + delete c; + return nullptr; + } + return c; + } }; taxonomy::item* mapping::map(const IfcSchema::IfcExtrudedAreaSolid* inst) { @@ -134,20 +155,82 @@ taxonomy::item* mapping::map(const IfcSchema::IfcExtrudedAreaSolid* inst) { } taxonomy::item* mapping::map(const IfcSchema::IfcRepresentation* inst) { - auto c = new taxonomy::collection(); - IfcSchema::IfcRepresentationItem::list::ptr items = inst->Items(); - if (items->size()) { - for (IfcSchema::IfcRepresentationItem::list::it it = items->begin(); it != items->end(); ++it) { - if (auto r = map(*it)) { - c->children.push_back(r); + return map_to_collection(this, inst->Items()); +} + +taxonomy::item* mapping::map(const IfcSchema::IfcFaceBasedSurfaceModel* inst) { + return map_to_collection(this, inst->FbsmFaces()); +} + +taxonomy::item* mapping::map(const IfcSchema::IfcConnectedFaceSet* inst) { + return map_to_collection(this, inst->CfsFaces()); +} + +taxonomy::item* mapping::map(const IfcSchema::IfcFace* inst) { + taxonomy::face* face = new taxonomy::face; + auto bounds = inst->Bounds(); + for (auto& bound : *bounds) { + if (auto r = map(bound->Bound())) { + if (!bound->Orientation()) { + r->reverse(); } - } + face->children.push_back(r); + } } - if (c->children.empty()) { - delete c; + if (face->children.empty()) { + delete face; return nullptr; } - return c; + return face; +} + +taxonomy::item* mapping::map(const IfcSchema::IfcPolyLoop* inst) { + taxonomy::loop* loop = new taxonomy::loop; + + taxonomy::point3 first, previous; + bool is_first = true; + + auto points = inst->Polygon(); + for (auto& point : *points) { + auto p = as(map(point)); + if (is_first) { + previous = first = p; + is_first = false; + } else { + auto edge = new taxonomy::edge; + edge->start = previous; + edge->end = p; + loop->children.push_back(edge); + previous = p; + } + } + + auto edge = new taxonomy::edge; + edge->start = previous; + edge->end = first; + loop->children.push_back(edge); + + if (loop->children.size() < 3) { + Logger::Warning("Not enough edges for", inst); + delete loop; + return nullptr; + } + return loop; +} + +taxonomy::item* mapping::map(const IfcSchema::IfcCartesianPoint* inst) { + auto coords = inst->Coordinates(); + return new taxonomy::point3( + coords.size() >= 1 ? coords[0] : 0., + coords.size() >= 2 ? coords[1] : 0., + coords.size() >= 3 ? coords[2] : 0. + ); +} + +taxonomy::item* mapping::map(const IfcSchema::IfcProduct* inst) { + auto n = new taxonomy::node; + n->matrix = as(map(inst->ObjectPlacement())); + return n; } taxonomy::item* mapping::map(const IfcSchema::IfcAxis2Placement3D* inst) { @@ -175,6 +258,11 @@ taxonomy::item* mapping::map(const IfcSchema::IfcCartesianTransformationOperator return new taxonomy::matrix4(); } +taxonomy::item* mapping::map(const IfcSchema::IfcLocalPlacement* inst) { + // @todo length unit + return new taxonomy::matrix4(); +} + IfcSchema::IfcProduct::list::ptr mapping::products_represented_by(const IfcSchema::IfcRepresentation* representation) { IfcSchema::IfcProduct::list::ptr products(new IfcSchema::IfcProduct::list); diff --git a/src/ifcgeom/schema/mapping.i b/src/ifcgeom/schema/mapping.i index eb6bf0b4f0..c794c6f447 100644 --- a/src/ifcgeom/schema/mapping.i +++ b/src/ifcgeom/schema/mapping.i @@ -24,8 +24,10 @@ * * ********************************************************************************/ +BIND(IfcProduct); + // BIND(IfcShellBasedSurfaceModel); -// BIND(IfcFaceBasedSurfaceModel); +BIND(IfcFaceBasedSurfaceModel); BIND(IfcRepresentation); // BIND(IfcMappedItem); // IfcFacetedBrep included @@ -53,7 +55,7 @@ BIND(IfcRepresentation); #endif BIND(IfcExtrudedAreaSolid); // BIND(IfcRevolvedAreaSolid); -// BIND(IfcConnectedFaceSet); +BIND(IfcConnectedFaceSet); // BIND(IfcBooleanResult); // BIND(IfcPolygonalBoundedHalfSpace); // BIND(IfcHalfSpaceSolid); @@ -91,7 +93,7 @@ BIND(IfcExtrudedAreaSolid); // BIND(IfcDerivedProfileDef); // IfcFaceSurface included // IfcAdvancedFace included in case of IFC4 -// BIND(IfcFace); +BIND(IfcFace); // BIND(IfcEdgeCurve); // BIND(IfcSubedge); @@ -99,7 +101,7 @@ BIND(IfcExtrudedAreaSolid); // BIND(IfcEdge); // BIND(IfcEdgeLoop); // BIND(IfcPolyline); -// BIND(IfcPolyLoop); +BIND(IfcPolyLoop); // BIND(IfcCompositeCurve); // BIND(IfcTrimmedCurve); // BIND(IfcArbitraryOpenProfileDef); @@ -115,7 +117,7 @@ BIND(IfcExtrudedAreaSolid); // BIND(IfcBSplineCurveWithKnots); #endif -// BIND(IfcCartesianPoint); +BIND(IfcCartesianPoint); // BIND(IfcDirection); // BIND(IfcAxis2Placement2D); BIND(IfcAxis2Placement3D); @@ -124,7 +126,7 @@ BIND(IfcCartesianTransformationOperator2DnonUniform); BIND(IfcCartesianTransformationOperator3DnonUniform); BIND(IfcCartesianTransformationOperator2D); BIND(IfcCartesianTransformationOperator3D); -// BIND(IfcObjectPlacement); +BIND(IfcLocalPlacement); // BIND(IfcVector); // BIND(IfcPlane); diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index 65bc958071..21a187fc4b 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -19,12 +19,18 @@ namespace geometry { namespace taxonomy { -enum kinds { MATRIX4, POINT3, DIRECTION3, LINE, CIRCLE, ELLIPSE, BSPLINE, EDGE, LOOP, FACE, EXTRUSION, NODE, COLOUR, STYLE, COLLECTION }; +class topology_error : public std::runtime_error { +public: + topology_error() : std::runtime_error("Generic topology error") {} +}; + +enum kinds { MATRIX4, POINT3, DIRECTION3, LINE, CIRCLE, ELLIPSE, BSPLINE, EDGE, LOOP, FACE, SHELL, EXTRUSION, NODE, COLOUR, STYLE, COLLECTION }; struct item { const IfcUtil::IfcBaseClass* instance; virtual item* clone() const = 0; virtual kinds kind() const = 0; + virtual void reverse() { throw taxonomy::topology_error(); } item(const IfcUtil::IfcBaseClass* instance = nullptr) : instance(instance) {} @@ -98,14 +104,14 @@ struct point3 : public cartesian_base<3> { virtual item* clone() const { return new point3(*this); } virtual kinds kind() const { return POINT3; } - point3(double x, double y, double z = 0.) : cartesian_base(x, y, z) {} + point3(double x = 0., double y = 0., double z = 0.) : cartesian_base(x, y, z) {} }; struct direction3 : public cartesian_base<3> { virtual item* clone() const { return new direction3(*this); } virtual kinds kind() const { return DIRECTION3; } - direction3(double x, double y, double z = 0.) : cartesian_base(x, y, z) {} + direction3(double x = 0., double y = 0., double z = 0.) : cartesian_base(x, y, z) {} }; struct line : public geom_item { @@ -133,46 +139,16 @@ typedef boost::variant curve; struct edge : public geom_item { boost::variant start, end; boost::optional basis; + bool orientation; + edge() : orientation(true) {} virtual item* clone() const { return new edge(*this); } virtual kinds kind() const { return EDGE; } -}; -struct loop : public geom_item { - std::vector edges; - - virtual item* clone() const { return new loop(*this); } - virtual kinds kind() const { return LOOP; } -}; - -struct face : public geom_item { - loop outer; - std::vector inner; - - virtual item* clone() const { return new face(*this); } - virtual kinds kind() const { return FACE; } - - face(const IfcUtil::IfcBaseClass* instance, loop o) : geom_item(instance), outer(o) {} - face(const IfcUtil::IfcBaseClass* instance, loop o, std::vector i) : geom_item(instance), outer(o), inner(i) {} - face(const IfcUtil::IfcBaseClass* instance, matrix4 m, loop o) : geom_item(instance, m), outer(o) {} - face(const IfcUtil::IfcBaseClass* instance, matrix4 m, loop o, std::vector i) : geom_item(instance, m), outer(o), inner(i) {} -}; - -struct sweep : public geom_item { - face basis; - - sweep(face b) : basis(b) {} - sweep(matrix4 m, face b) : geom_item(m), basis(b) {} -}; - -struct extrusion : public sweep { - direction3 direction; - double depth; - - virtual item* clone() const { return new extrusion(*this); } - virtual kinds kind() const { return EXTRUSION; } - - extrusion(matrix4 m, face basis, direction3 dir, double d) : sweep(m, basis), direction(dir), depth(d) {} + virtual void reverse() { + std::swap(start, end); + orientation = !orientation; + } }; struct collection : public geom_item { @@ -180,6 +156,44 @@ struct collection : public geom_item { virtual item* clone() const { return new collection(*this); } virtual kinds kind() const { return COLLECTION; } + virtual void reverse() { + std::reverse(children.begin(), children.end()); + for (auto& child : children) { + child->reverse(); + } + } +}; + +struct shell : public collection { + virtual item* clone() const { return new shell(*this); } + virtual kinds kind() const { return SHELL; } +}; + +struct face : public collection { + virtual item* clone() const { return new face(*this); } + virtual kinds kind() const { return FACE; } +}; + +struct loop : public collection { + virtual item* clone() const { return new loop(*this); } + virtual kinds kind() const { return LOOP; } +}; + +struct sweep : public geom_item { + face basis; + + sweep(face b) : basis(b) {} + sweep(matrix4 m, face b) : geom_item(m), basis(b) {} +}; + +struct extrusion : public sweep { + direction3 direction; + double depth; + + virtual item* clone() const { return new extrusion(*this); } + virtual kinds kind() const { return EXTRUSION; } + + extrusion(matrix4 m, face basis, direction3 dir, double d) : sweep(m, basis), direction(dir), depth(d) {} }; struct node : public geom_item { @@ -188,12 +202,10 @@ struct node : public geom_item { virtual item* clone() const { return new node(*this); } virtual kinds kind() const { return NODE; } - - node(const IfcUtil::IfcBaseClass* instance, matrix4 m, const std::map& representations, const std::vector& children) : geom_item(instance, m), representations(representations), children(children) {} }; namespace impl { - typedef std::tuple KindsTuple; + typedef std::tuple KindsTuple; } struct type_by_kind { @@ -203,11 +215,6 @@ struct type_by_kind { static const size_t max = std::tuple_size< impl::KindsTuple>::value; }; -class topology_error : public std::runtime_error { -public: - topology_error() : std::runtime_error("Generic topology error") {} -}; - } From 8ec201900393ebfee3e27c3bcd2cb3bfd0227eff Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 25 Aug 2019 11:50:40 +0200 Subject: [PATCH 163/235] Fix enumeration order --- src/ifcgeom/kernel_agnostic/AbstractKernel.cpp | 3 ++- src/ifcgeom/taxonomy.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp index 4c1d7dcce1..ac6db16dfd 100644 --- a/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp +++ b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp @@ -19,7 +19,8 @@ namespace { template <> struct dispatch_conversion { - static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel*, const ifcopenshell::geometry::taxonomy::item*, ifcopenshell::geometry::ConversionResults&) { + static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel*, const ifcopenshell::geometry::taxonomy::item* item, ifcopenshell::geometry::ConversionResults&) { + Logger::Error("No conversion for " + std::to_string(item->kind())); return false; } }; diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index 21a187fc4b..122f5a0fef 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -24,7 +24,7 @@ public: topology_error() : std::runtime_error("Generic topology error") {} }; -enum kinds { MATRIX4, POINT3, DIRECTION3, LINE, CIRCLE, ELLIPSE, BSPLINE, EDGE, LOOP, FACE, SHELL, EXTRUSION, NODE, COLOUR, STYLE, COLLECTION }; +enum kinds { MATRIX4, POINT3, DIRECTION3, LINE, CIRCLE, ELLIPSE, BSPLINE, EDGE, LOOP, FACE, SHELL, EXTRUSION, NODE, COLLECTION, COLOUR, STYLE }; struct item { const IfcUtil::IfcBaseClass* instance; From 41d7fb32da295abb987f7260b09b4158caea546e Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 25 Aug 2019 12:00:04 +0200 Subject: [PATCH 164/235] Provide collection implementation in abstract_kernel --- src/ifcgeom/kernel_agnostic/AbstractKernel.cpp | 8 ++++++++ src/ifcgeom/kernel_agnostic/AbstractKernel.h | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp index ac6db16dfd..10168dfaa8 100644 --- a/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp +++ b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp @@ -39,6 +39,14 @@ ifcopenshell::geometry::kernels::AbstractKernel* ifcopenshell::geometry::kernels } } +bool ifcopenshell::geometry::kernels::AbstractKernel::convert_impl(const taxonomy::collection* collection, ifcopenshell::geometry::ConversionResults& r) { + auto s = r.size(); + for (auto& c : collection->children) { + convert(c, r); + } + return r.size() > s; +} + //void ifcopenshell::geometry::kernels::AbstractKernel::set_conversion_placement_rel_to(const IfcParse::declaration* type) { // placement_rel_to = type; //} diff --git a/src/ifcgeom/kernel_agnostic/AbstractKernel.h b/src/ifcgeom/kernel_agnostic/AbstractKernel.h index 062b6d2a05..0985b23745 100644 --- a/src/ifcgeom/kernel_agnostic/AbstractKernel.h +++ b/src/ifcgeom/kernel_agnostic/AbstractKernel.h @@ -52,7 +52,7 @@ namespace ifcopenshell { namespace geometry { namespace kernels { virtual bool convert_impl(const taxonomy::extrusion*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } virtual bool convert_impl(const taxonomy::node*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } virtual bool convert_impl(const taxonomy::colour*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } - virtual bool convert_impl(const taxonomy::collection*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } + virtual bool convert_impl(const taxonomy::collection*, ifcopenshell::geometry::ConversionResults&); }; AbstractKernel* construct(const std::string& geometry_library, IfcParse::IfcFile*); From 8b4900b0e183527cc2e629b5a296cdf872c0d1c6 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 25 Aug 2019 16:07:10 +0200 Subject: [PATCH 165/235] Work on shell conversino --- src/ifcgeom/kernel_agnostic/AbstractKernel.h | 1 + .../kernels/opencascade/IfcGeomShapes.cpp | 46 ++++++++++++++----- .../OpenCascadeConversionResult.cpp | 2 +- .../kernels/opencascade/OpenCascadeKernel.h | 44 +++++++++--------- .../schema_agnostic/IfcGeomRepresentation.cpp | 4 +- 5 files changed, 62 insertions(+), 35 deletions(-) diff --git a/src/ifcgeom/kernel_agnostic/AbstractKernel.h b/src/ifcgeom/kernel_agnostic/AbstractKernel.h index 0985b23745..3b3021b42f 100644 --- a/src/ifcgeom/kernel_agnostic/AbstractKernel.h +++ b/src/ifcgeom/kernel_agnostic/AbstractKernel.h @@ -48,6 +48,7 @@ namespace ifcopenshell { namespace geometry { namespace kernels { virtual bool convert_impl(const taxonomy::bspline*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } virtual bool convert_impl(const taxonomy::edge*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } virtual bool convert_impl(const taxonomy::loop*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } + virtual bool convert_impl(const taxonomy::shell*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } virtual bool convert_impl(const taxonomy::face*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } virtual bool convert_impl(const taxonomy::extrusion*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } virtual bool convert_impl(const taxonomy::node*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp index df2abbefe9..672789fc41 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp @@ -106,33 +106,33 @@ #include #include "../../../ifcparse/IfcLogger.h" +#include "../../../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h" using namespace ifcopenshell::geometry; using namespace ifcopenshell::geometry::kernels; -bool OpenCascadeKernel::convert(const taxonomy::extrusion& extrusion, TopoDS_Shape& shape) { - const double& height = extrusion.depth; +bool OpenCascadeKernel::convert(const taxonomy::extrusion* extrusion, TopoDS_Shape& shape) { + const double& height = extrusion->depth; if (height < precision_) { - Logger::Error("Non-positive extrusion height encountered for:", extrusion.instance); + Logger::Error("Non-positive extrusion height encountered for:", extrusion->instance); return false; } TopoDS_Shape face; - if (!convert(extrusion.basis, face)) { + if (!convert(&extrusion->basis, face)) { return false; } - gp_Trsf trsf; - if (!convert(extrusion.matrix, trsf)) { + gp_GTrsf gtrsf; + if (!convert(&extrusion->matrix, gtrsf)) { Logger::Error("Unable to move extrusion"); } + auto trsf = gtrsf.Trsf(); + + auto fs = extrusion->direction.components.data(); + gp_Dir dir(fs[0], fs[1], fs[2]); - gp_Dir dir; - if (!convert(extrusion.direction, dir)) { - return false; - } - shape.Nullify(); if (face.ShapeType() == TopAbs_COMPOUND) { @@ -169,3 +169,27 @@ bool OpenCascadeKernel::convert(const taxonomy::extrusion& extrusion, TopoDS_Sha return !shape.IsNull(); } + +bool OpenCascadeKernel::convert_impl(const taxonomy::extrusion* extrusion, ifcopenshell::geometry::ConversionResults& results) { + TopoDS_Shape shape; + if (!convert(extrusion, shape)) { + return false; + } + results.emplace_back(ConversionResult( + extrusion->instance->data().id(), + extrusion->matrix, + new OpenCascadeShape(shape), + extrusion->surface_style + )); + return true; +} + +bool OpenCascadeKernel::convert(const taxonomy::matrix4* matrix, gp_GTrsf& trsf) { + // @todo check + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 4; ++i) { + trsf.SetValue(i + 1, j + 1, matrix->components(i, j)); + } + } + return true; +} \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp index 9478a64c15..6e45b00859 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp @@ -12,7 +12,7 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(const settings& setti // @todo check gp_GTrsf trsf; for (int i = 0; i < 3; ++i) { - for (int j = 0; j < j; ++i) { + for (int j = 0; j < 4; ++i) { trsf.SetValue(i + 1, j + 1, place.components(i, j)); } } diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h index 0d5b37dfe6..ffce0fa956 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h @@ -111,7 +111,6 @@ namespace kernels { class IFC_GEOM_API OpenCascadeKernel : public AbstractKernel { private: - /* // faceset_helper traverses the forward instance references of IfcConnectedFaceSet and then provides a mapping // M of (IfcCartesianPoint, IfcCartesianPoint) -> TopoDS_Edge, where M(a, b) is a partner of M(b, a), ie share // the same underlying edge but with orientation reversed. This then later speeds op the process of creating a @@ -120,22 +119,22 @@ namespace kernels { class faceset_helper { private: OpenCascadeKernel* kernel_; - std::set duplicates_; + std::set duplicates_; std::map vertex_mapping_; std::map, TopoDS_Edge> edges_; double eps_; bool non_manifold_; template - void loop_(IfcSchema::IfcCartesianPoint::list::ptr& ps, const Fn& callback) { - if (ps->size() < 3) { + void loop_(const taxonomy::loop* ps, const Fn& callback) { + if (ps->children.size() < 3) { return; } - auto a = *(ps->end() - 1); + auto a = boost::get(((taxonomy::edge*) ps->children.back())->start).instance; auto A = a->data().id(); - for (auto& b : *ps) { - auto B = b->data().id(); + for (auto& b : ps->children) { + auto B = boost::get(((taxonomy::edge*) b)->start).instance->data().id(); auto C = vertex_mapping_[A], D = vertex_mapping_[B]; bool fwd = C < D; if (!fwd) { @@ -148,16 +147,16 @@ namespace kernels { } } public: - faceset_helper(OpenCascadeKernel* kernel, const IfcSchema::IfcConnectedFaceSet* l); + faceset_helper(OpenCascadeKernel* kernel, const taxonomy::shell* l); ~faceset_helper(); bool non_manifold() const { return non_manifold_; } bool& non_manifold() { return non_manifold_; } - bool edge(const IfcSchema::IfcCartesianPoint* a, const IfcSchema::IfcCartesianPoint* b, TopoDS_Edge& e) { - int A = vertex_mapping_[a->data().id()]; - int B = vertex_mapping_[b->data().id()]; + bool edge(const taxonomy::point3& a, const taxonomy::point3& b, TopoDS_Edge& e) { + int A = vertex_mapping_[a.instance->data().id()]; + int B = vertex_mapping_[b.instance->data().id()]; if (A == B) { return false; } @@ -174,15 +173,14 @@ namespace kernels { return true; } - bool wire(const IfcSchema::IfcPolyLoop* loop, TopoDS_Wire& wire) { - if (duplicates_.find(loop) != duplicates_.end()) { + bool wire(const taxonomy::loop* loop, TopoDS_Wire& wire) { + if (duplicates_.find(loop->instance->data().id()) != duplicates_.end()) { return false; } BRep_Builder builder; builder.MakeWire(wire); int count = 0; - auto ps = loop->Polygon(); - loop_(ps, [this, &builder, &wire, &count](int A, int B, bool fwd) { + loop_(loop, [this, &builder, &wire, &count](int A, int B, bool fwd) { TopoDS_Edge e; if (edge(A, B, e)) { if (!fwd) { @@ -195,12 +193,15 @@ namespace kernels { if (count >= 3) { wire.Closed(true); + /* + @todo TopTools_ListOfShape results; if (kernel_->wire_intersections(wire, results)) { Logger::Warning("Self-intersections with " + boost::lexical_cast(results.Extent()) + " cycles detected", loop); kernel_->select_largest(results, wire); non_manifold_ = true; } + */ return true; } else { @@ -213,13 +214,12 @@ namespace kernels { } }; +/* #ifndef NO_CACHE POSTFIX_SCHEMA(Cache) cache; #endif */ - class faceset_helper {}; - faceset_helper* faceset_helper_; double precision_; @@ -233,10 +233,12 @@ namespace kernels { *this = other; } - bool convert(const geometry::taxonomy::extrusion&, TopoDS_Shape&); - bool convert(const geometry::taxonomy::face&, TopoDS_Shape&); - bool convert(const geometry::taxonomy::matrix4&, gp_Trsf&); - bool convert(const geometry::taxonomy::direction3&, gp_Dir&); + bool convert(const taxonomy::extrusion*, TopoDS_Shape&); + bool convert(const taxonomy::face*, TopoDS_Shape&); + bool convert(const taxonomy::matrix4*, gp_GTrsf&); + + virtual bool convert_impl(const taxonomy::shell*, ifcopenshell::geometry::ConversionResults&); + virtual bool convert_impl(const taxonomy::extrusion*, ifcopenshell::geometry::ConversionResults&); }; /* diff --git a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp index fcca0ad6be..28605992df 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp +++ b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp @@ -96,7 +96,7 @@ ifcopenshell::geometry::ConversionResultShape* ifcopenshell::geometry::Represent // @todo, check gp_GTrsf trsf; for (int i = 0; i < 3; ++i) { - for (int j = 0; j < j; ++i) { + for (int j = 0; j < 4; ++i) { trsf.SetValue(i + 1, j + 1, it->Placement().components(i, j)); } } @@ -241,7 +241,7 @@ bool ifcopenshell::geometry::Representation::BRep::calculate_projected_surface_a // @todo check gp_GTrsf trsf; for (int i = 0; i < 3; ++i) { - for (int j = 0; j < j; ++i) { + for (int j = 0; j < 4; ++i) { trsf.SetValue(i + 1, j + 1, place.components(i, j)); } } From f17036313d365580fa19572a0c0ab9ea8849e5f6 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Mon, 26 Aug 2019 17:19:06 +0200 Subject: [PATCH 166/235] Work on face boundaries --- src/ifcgeom/kernel_agnostic/AbstractKernel.h | 2 +- .../kernels/opencascade/IfcGeomShapes.cpp | 914 +++++++++++++++++- .../kernels/opencascade/OpenCascadeKernel.h | 4 + src/ifcgeom/taxonomy.h | 71 +- 4 files changed, 973 insertions(+), 18 deletions(-) diff --git a/src/ifcgeom/kernel_agnostic/AbstractKernel.h b/src/ifcgeom/kernel_agnostic/AbstractKernel.h index 3b3021b42f..45c3ed5bf5 100644 --- a/src/ifcgeom/kernel_agnostic/AbstractKernel.h +++ b/src/ifcgeom/kernel_agnostic/AbstractKernel.h @@ -45,7 +45,7 @@ namespace ifcopenshell { namespace geometry { namespace kernels { virtual bool convert_impl(const taxonomy::line*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } virtual bool convert_impl(const taxonomy::circle*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } virtual bool convert_impl(const taxonomy::ellipse*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } - virtual bool convert_impl(const taxonomy::bspline*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } + virtual bool convert_impl(const taxonomy::bspline_curve*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } virtual bool convert_impl(const taxonomy::edge*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } virtual bool convert_impl(const taxonomy::loop*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } virtual bool convert_impl(const taxonomy::shell*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp index 672789fc41..71c382b5c2 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp @@ -170,6 +170,646 @@ bool OpenCascadeKernel::convert(const taxonomy::extrusion* extrusion, TopoDS_Sha return !shape.IsNull(); } +namespace { + /* Returns whether wire conforms to a polyhedron, i.e. only edges with linear curves*/ + bool is_polyhedron(const TopoDS_Wire& wire) { + double a, b; + TopLoc_Location l; + + TopoDS_Iterator it(wire, false, false); + for (; it.More(); it.Next()) { + auto crv = BRep_Tool::Curve(TopoDS::Edge(it.Value()), l, a, b); + if (!crv || crv->DynamicType() != STANDARD_TYPE(Geom_Line)) { + return false; + } + } + + return true; + } + + /* Returns whether wire conforms to a polyhedron, i.e. only edges with linear curves*/ + bool is_polyhedron(const taxonomy::loop* wire) { + for (auto& edge : wire->children_as()) { + if (edge->basis) { + if (edge->basis->kind() != taxonomy::LINE) { + return false; + } + } + } + return true; + } + + /* A temporary structure to store the intermediate data for the face conversion */ + class face_definition { + private: + Handle(Geom_Surface) surface_; + std::vector wires_; + bool all_outer_; + public: + face_definition() : surface_(), all_outer_(false) {} + + typedef std::vector::const_iterator wire_it; + + bool& all_outer() { + return all_outer_; + } + + bool all_outer() const { + return all_outer_; + } + + Handle(Geom_Surface)& surface() { + return surface_; + } + + const Handle(Geom_Surface)& surface() const { + return surface_; + } + + std::vector& wires() { + return wires_; + } + + const TopoDS_Wire& outer_wire() const { + return wires_.front(); + } + + std::pair inner_wires() const { + return { wires_.begin() + 1, wires_.end() }; + } + }; +} + +#include +#include +#include +#include + +bool OpenCascadeKernel::convert(const taxonomy::face* face, TopoDS_Shape& result) { + std::vector bounds; + std::transform(face->children.begin(), face->children.end(), std::back_inserter(bounds), [](auto item){ + return static_cast(item); + }); + + face_definition fd; + + const bool is_face_surface = false; /* todo */ + + /* + if (is_face_surface) { + IfcSchema::IfcFaceSurface* fs = (IfcSchema::IfcFaceSurface*) l; + fs->FaceSurface(); + // FIXME: Surfaces are interpreted as a TopoDS_Shape + TopoDS_Shape surface_shape; + if (!convert_shape(fs->FaceSurface(), surface_shape)) return false; + + // FIXME: Assert this obtaines the only face + TopExp_Explorer exp(surface_shape, TopAbs_FACE); + if (!exp.More()) return false; + + TopoDS_Face surface = TopoDS::Face(exp.Current()); + fd.surface() = BRep_Tool::Surface(surface); + } + */ + + const int num_bounds = bounds.size(); + int num_outer_bounds = 0; + + for (auto& bound: bounds) { + if (bound->external.get_value_or(false)) { + num_outer_bounds++; + } + } + + // The number of outer bounds should be one according to the schema. Also Open Cascade + // expects this, but it is not strictly checked. Regardless, if the number is greater, + // the face will still be processed as long as there are no holes. A compound of faces + // is returned in that case. + if (num_bounds > 1 && num_outer_bounds > 1 && num_bounds != num_outer_bounds) { + Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", face->instance); + return false; + } + + if (num_outer_bounds > 1) { + Logger::Message(Logger::LOG_WARNING, "Multiple outer boundaries for:", face->instance); + fd.all_outer() = true; + } + + TopTools_DataMapOfShapeInteger wire_senses; + + for (int process_interior = 0; process_interior <= 1; ++process_interior) { + for (auto& bound : bounds) { + bool same_sense = true; /* todo bound->Orientation(); */ + + const bool is_interior = + !bound->external.get_value_or(false) && + (num_bounds > 1) && + (num_outer_bounds < num_bounds); + + // The exterior face boundary is processed first + if (is_interior == !process_interior) continue; + + TopoDS_Wire wire; + if (faceset_helper_ && is_polyhedron(bound)) { + if (!faceset_helper_->wire(bound, wire)) { + Logger::Message(Logger::LOG_WARNING, "Face boundary loop not included", bound->instance); + continue; + } + } else if (!convert(bound, wire)) { + Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", bound->instance); + return false; + } + + if (!same_sense) { + wire.Reverse(); + } + + wire_senses.Bind(wire.Oriented(TopAbs_FORWARD), same_sense ? TopAbs_FORWARD : TopAbs_REVERSED); + + fd.wires().emplace_back(wire); + } + } + + if (fd.wires().empty()) { + Logger::Warning("Face with no boundaries", face->instance); + return false; + } + + if (fd.surface().IsNull()) { + // Use the first wire to find a plane manually for polygonal wires + const TopoDS_Wire& wire = fd.wires().front(); + if (is_polyhedron(wire)) { + TopExp_Explorer exp(wire, TopAbs_EDGE); + int count = 0; + TopoDS_Edge edges[2]; + for (; exp.More(); exp.Next(), count++) { + if (count < 2) { + edges[count] = TopoDS::Edge(exp.Current()); + } + } + + if (count == 3) { + // Help Open Cascade by finding the plane more efficiently + double _, __; + Handle(Geom_Line) c1 = Handle(Geom_Line)::DownCast(BRep_Tool::Curve(edges[0], _, __)); + Handle(Geom_Line) c2 = Handle(Geom_Line)::DownCast(BRep_Tool::Curve(edges[1], _, __)); + + const gp_Vec ab = c1->Position().Direction(); + const gp_Vec ac = c2->Position().Direction(); + const gp_Vec cross = ab.Crossed(ac); + + if (cross.SquareMagnitude() > ALMOST_ZERO) { + const gp_Dir n = cross; + fd.surface() = new Geom_Plane(c1->Position().Location(), n); + } + } else { + gp_Pln pln; + if (approximate_plane_through_wire(wire, pln)) { + fd.surface() = new Geom_Plane(pln); + } + } + } + } + + if (fd.surface().IsNull()) { + // BRepLib_FindSurface is used in case no surface is found or provided + + const TopoDS_Wire& wire = fd.wires().front(); + + BRepLib_FindSurface fs(wire, precision_, true, true); + if (fs.Found()) { + fd.surface() = fs.Surface(); + ShapeFix_ShapeTolerance ftol; + ftol.SetTolerance(wire, fs.ToleranceReached(), TopAbs_WIRE); + } + } + + TopTools_ListOfShape face_list; + + if (fd.surface().IsNull()) { + // The set of wires is triangulated in case no surface can be found + Logger::Message(Logger::LOG_WARNING, "Triangulating face boundaries for face", face->instance); + + if (fd.all_outer()) { + for (const auto& w : fd.wires()) { + TopTools_ListOfShape fl; + triangulate_wire({ w }, fl); + face_list.Append(fl); + } + } else { + triangulate_wire(fd.wires(), face_list); + } + } else if (!fd.all_outer()) { + BRepBuilderAPI_MakeFace mf(fd.surface(), fd.outer_wire()); + + if (mf.IsDone()) { + // Is this necessary + TopoDS_Face f = mf.Face(); + mf.Init(f); + + for (auto it = fd.inner_wires().first; it != fd.inner_wires().second; ++it) { + mf.Add(*it); + } + + face_list.Append(mf.Face()); + } + } else { + for (const auto& w : fd.wires()) { + BRepBuilderAPI_MakeFace mf(fd.surface(), w); + if (mf.IsDone()) { + face_list.Append(mf.Face()); + } + } + } + + if (!fd.surface().IsNull()) { + // Some fixes for orientation and p-curves. If we have no surface, it + // means the face has been triangulated in which case none of these + // fixes are necessary. + + if (fd.surface()->DynamicType() != STANDARD_TYPE(Geom_Plane)) { + // In case of (non-planar) face surface, p-curves need to be computed. + // For planar faces, Open Cascade generates p-curves on the fly. + + for (TopTools_ListIteratorOfListOfShape it(face_list); it.More(); it.Next()) { + // Small chance there are multiple faces + const TopoDS_Face& occ_face = TopoDS::Face(it.Value()); + for (TopExp_Explorer exp2(occ_face, TopAbs_EDGE); exp2.More(); exp2.Next()) { + const TopoDS_Edge& edge = TopoDS::Edge(exp2.Current()); + ShapeFix_Edge fix_edge; + fix_edge.FixAddPCurve(edge, occ_face, false, precision_); + } + } + } + + for (TopTools_ListIteratorOfListOfShape it(face_list); it.More(); it.Next()) { + const TopoDS_Face& occ_face = TopoDS::Face(it.Value()); + + ShapeFix_Face sfs(TopoDS::Face(occ_face)); + TopTools_DataMapOfShapeListOfShape wire_map; + sfs.FixOrientation(wire_map); + + TopoDS_Iterator jt(occ_face, false); + for (; jt.More(); jt.Next()) { + const TopoDS_Wire& w = TopoDS::Wire(jt.Value()); + // tfk: @todo if wire_map contains w, I would assume wire_senses also contains w, + // this is not the case in github issue #405. + if (wire_map.IsBound(w) && wire_senses.IsBound(w)) { + const TopTools_ListOfShape& shapes = wire_map.Find(w); + TopTools_ListIteratorOfListOfShape kt(shapes); + for (; kt.More(); kt.Next()) { + // Apparently the wire got reversed, so register it with opposite orientation in the map + wire_senses.Bind(kt.Value(), wire_senses.Find(w) == TopAbs_FORWARD ? TopAbs_REVERSED : TopAbs_FORWARD); + } + } + } + + it.Value() = sfs.Face(); + } + + for (TopTools_ListIteratorOfListOfShape it(face_list); it.More(); it.Next()) { + TopoDS_Face& occ_face = TopoDS::Face(it.Value()); + + bool all_reversed = true; + TopoDS_Iterator jt(occ_face, false); + for (; jt.More(); jt.Next()) { + const TopoDS_Wire& w = TopoDS::Wire(jt.Value()); + if (!wire_senses.IsBound(w.Oriented(TopAbs_FORWARD)) || (w.Orientation() == wire_senses.Find(w.Oriented(TopAbs_FORWARD)))) { + all_reversed = false; + } + } + + if (all_reversed) { + occ_face.Reverse(); + } + } + } + + if (face_list.Extent() > 1) { + TopoDS_Compound compound; + BRep_Builder builder; + builder.MakeCompound(compound); + for (TopTools_ListIteratorOfListOfShape it(face_list); it.More(); it.Next()) { + TopoDS_Face& occ_face = TopoDS::Face(it.Value()); + builder.Add(compound, occ_face); + } + result = compound; + } else { + result = face_list.First(); + } + + return true; +} + +#include +#include + +namespace { + /* A compile-time for loop over the curve kinds */ + template + struct dispatch_curve_creation { + static bool dispatch(const ifcopenshell::geometry::taxonomy::item* item, T visitor) { + // @todo it should be possible to eliminate this dynamic_cast when there is a static equivalent to kind() + const ifcopenshell::geometry::taxonomy::curves::type* v = dynamic_cast*>(item); + if (v) { + visitor(*v); + return true; + } else { + return dispatch_curve_creation::dispatch(item, visitor); + } + } + }; + + template + struct dispatch_curve_creation { + static bool dispatch(const ifcopenshell::geometry::taxonomy::item* item, T visitor) { + Logger::Error("No conversion for " + std::to_string(item->kind())); + return false; + } + }; + + template + T convert_xyz(const U& u) { + const double* vs = u.components.data(); + return T(vs[0], vs[1], vs[2]); + } + + struct curve_creation_visitor { + typedef boost::variant result_type; + result_type result; + + result_type operator()(const taxonomy::bspline_curve&) { + throw std::runtime_error("Not implemented"); + } + + result_type operator()(const taxonomy::line& l) { + return result = Handle(Geom_Curve)(new Geom_Line(convert_xyz(l.origin), convert_xyz(l.direction))); + } + + result_type operator()(const taxonomy::circle& c) { + return result = Handle(Geom_Curve)(new Geom_Circle(gp_Ax2(convert_xyz(c.origin), convert_xyz(c.z), convert_xyz(c.x)), c.radius)); + } + + result_type operator()(const taxonomy::ellipse& e) { + return result = Handle(Geom_Curve)(new Geom_Ellipse(gp_Ax2(convert_xyz(e.origin), convert_xyz(e.z), convert_xyz(e.x)), e.radius, e.radius2)); + } + }; + + curve_creation_visitor::result_type convert_curve(const taxonomy::item* curve) { + curve_creation_visitor v; + if (dispatch_curve_creation::dispatch(curve, v)) { + return v.result; + } else { + throw std::runtime_error("No curve created"); + } + } +} + +#include +#include + +namespace { + // Returns the other vertex of an edge + TopoDS_Vertex other(const TopoDS_Edge& e, const TopoDS_Vertex& v) { + TopoDS_Vertex a, b; + TopExp::Vertices(e, a, b); + return v.IsSame(b) ? a : b; + } + + TopoDS_Edge first_edge(const TopoDS_Wire& w) { + TopoDS_Vertex v1, v2; + TopExp::Vertices(w, v1, v2); + TopTools_IndexedDataMapOfShapeListOfShape wm; + TopExp::MapShapesAndAncestors(w, TopAbs_VERTEX, TopAbs_EDGE, wm); + return TopoDS::Edge(wm.FindFromKey(v1).First()); + } + + // Returns new wire with the edge replaced by a linear edge with the vertex v moved to p + TopoDS_Wire adjust(const TopoDS_Wire& w, const TopoDS_Vertex& v, const gp_Pnt& p) { + TopTools_IndexedDataMapOfShapeListOfShape map; + TopExp::MapShapesAndAncestors(w, TopAbs_VERTEX, TopAbs_EDGE, map); + + bool all_linear = true, single_circle = false, first = true; + + const TopTools_ListOfShape& edges = map.FindFromKey(v); + TopTools_ListIteratorOfListOfShape it(edges); + for (; it.More(); it.Next()) { + const TopoDS_Edge& e = TopoDS::Edge(it.Value()); + double _, __; + Handle(Geom_Curve) crv = BRep_Tool::Curve(e, _, __); + const bool is_line = crv->DynamicType() == STANDARD_TYPE(Geom_Line); + const bool is_circle = crv->DynamicType() == STANDARD_TYPE(Geom_Circle); + all_linear = all_linear && is_line; + single_circle = first && is_circle; + } + + if (all_linear) { + BRep_Builder b; + TopoDS_Vertex v2; + b.MakeVertex(v2, p, BRep_Tool::Tolerance(v)); + + ShapeBuild_ReShape reshape; + reshape.Replace(v.Oriented(TopAbs_FORWARD), v2); + + return TopoDS::Wire(reshape.Apply(w)); + } else if (single_circle) { + TopoDS_Vertex v1, v2; + TopExp::Vertices(w, v1, v2); + + gp_Pnt p1, p2, p3; + p1 = v.IsEqual(v1) ? p : BRep_Tool::Pnt(v1); + p3 = v.IsEqual(v2) ? p : BRep_Tool::Pnt(v2); + + double a, b; + Handle(Geom_Curve) crv = BRep_Tool::Curve(TopoDS::Edge(edges.First()), a, b); + crv->D0((a + b) / 2., p2); + + GC_MakeCircle mc(p1, p2, p3); + if (!mc.IsDone()) { + throw std::runtime_error("Failed to adjust circle"); + } + + TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(mc.Value(), p1, p3).Edge(); + BRepBuilderAPI_MakeWire builder; + builder.Add(edge); + return builder.Wire(); + } else { + throw std::runtime_error("Unexpected wire to adjust"); + } + } + + // A wrapper around BRepBuilderAPI_MakeWire that makes sure segments are connected either by moving end points or by adding intermediate segments + class wire_builder { + private: + BRepBuilderAPI_MakeWire mw_; + double p_; + bool override_next_; + gp_Pnt next_override_; + const IfcUtil::IfcBaseClass* inst_; + + public: + wire_builder(double p, const IfcUtil::IfcBaseClass* inst = 0) : p_(p), override_next_(false), inst_(inst) {} + + void operator()(const TopoDS_Shape& a) { + const TopoDS_Wire& w = TopoDS::Wire(a); + if (override_next_) { + override_next_ = false; + TopoDS_Edge e = first_edge(w); + mw_.Add(adjust(w, TopExp::FirstVertex(e, true), next_override_)); + } else { + mw_.Add(w); + } + } + + void operator()(const TopoDS_Shape& a, const TopoDS_Shape& b, bool last) { + TopoDS_Wire w1 = TopoDS::Wire(a); + const TopoDS_Wire& w2 = TopoDS::Wire(b); + + if (override_next_) { + override_next_ = false; + TopoDS_Edge e = first_edge(w1); + w1 = adjust(w1, TopExp::FirstVertex(e, true), next_override_); + } + + TopoDS_Vertex w11, w12, w21, w22; + TopExp::Vertices(w1, w11, w12); + TopExp::Vertices(w2, w21, w22); + + gp_Pnt p1 = BRep_Tool::Pnt(w12); + gp_Pnt p2 = BRep_Tool::Pnt(w21); + + double dist = p1.Distance(p2); + + // Distance is within tolerance, this is fine + if (dist < p_) { + mw_.Add(w1); + goto check; + } + + // Distance is too large for attempting to move end points, add intermediate edge + if (dist > 1000. * p_) { + mw_.Add(w1); + mw_.Add(BRepBuilderAPI_MakeEdge(p1, p2)); + Logger::Warning("Added additional segment to close gap with length " + boost::lexical_cast(dist) + " to:", inst_); + goto check; + } + + { + TopTools_IndexedDataMapOfShapeListOfShape wmap1, wmap2; + + // Find edges connected to end- and begin vertex + TopExp::MapShapesAndAncestors(w1, TopAbs_VERTEX, TopAbs_EDGE, wmap1); + TopExp::MapShapesAndAncestors(w2, TopAbs_VERTEX, TopAbs_EDGE, wmap2); + + const TopTools_ListOfShape& last_edges = wmap1.FindFromKey(w12); + const TopTools_ListOfShape& first_edges = wmap2.FindFromKey(w21); + + double _, __; + if (last_edges.Extent() == 1 && first_edges.Extent() == 1) { + Handle(Geom_Curve) c1 = BRep_Tool::Curve(TopoDS::Edge(last_edges.First()), _, __); + Handle(Geom_Curve) c2 = BRep_Tool::Curve(TopoDS::Edge(first_edges.First()), _, __); + + const bool is_line1 = c1->DynamicType() == STANDARD_TYPE(Geom_Line); + const bool is_line2 = c2->DynamicType() == STANDARD_TYPE(Geom_Line); + + const bool is_circle1 = c1->DynamicType() == STANDARD_TYPE(Geom_Circle); + const bool is_circle2 = c2->DynamicType() == STANDARD_TYPE(Geom_Circle); + + // Preferably adjust the segment that is linear + if (is_line1 || (is_circle1 && !is_line2)) { + mw_.Add(adjust(w1, w12, p2)); + Logger::Notice("Adjusted edge end-point with distance " + boost::lexical_cast(dist) + " on:", inst_); + } else if ((is_line2 || is_circle2) && !last) { + mw_.Add(w1); + override_next_ = true; + next_override_ = p1; + Logger::Notice("Adjusted edge end-point with distance " + boost::lexical_cast(dist) + " on:", inst_); + } else { + // In all other cases an edge is added + mw_.Add(w1); + mw_.Add(BRepBuilderAPI_MakeEdge(p1, p2)); + Logger::Warning("Added additional segment to close gap with length " + boost::lexical_cast(dist) + " to:", inst_); + } + } else { + Logger::Error("Internal error, inconsistent wire segments", inst_); + mw_.Add(w1); + } + } + + check: + if (mw_.Error() == BRepBuilderAPI_NonManifoldWire) { + Logger::Error("Non-manifold curve segments:", inst_); + } else if (mw_.Error() == BRepBuilderAPI_DisconnectedWire) { + Logger::Error("Failed to join curve segments:", inst_); + } + } + + const TopoDS_Wire& wire() { return mw_.Wire(); } + }; + + template + void shape_pair_enumerate(TopTools_ListIteratorOfListOfShape& it, Fn& fn, bool closed) { + bool is_first = true; + TopoDS_Shape first, previous, current; + for (; it.More(); it.Next(), is_first = false) { + current = it.Value(); + if (is_first) { + first = current; + } else { + fn(previous, current, false); + } + previous = current; + } + if (closed) { + fn(current, first, true); + } else { + fn(current); + } + } +} + +bool OpenCascadeKernel::convert(const taxonomy::loop* loop, TopoDS_Wire& wire) { + auto segments = loop->children_as(); + + TopTools_ListOfShape converted_segments; + + for (auto& segment : segments) { + TopoDS_Wire segment_wire = boost::get(convert_curve(segment)); + + if (!segment->orientation) { + segment_wire.Reverse(); + } + + ShapeFix_ShapeTolerance FTol; + FTol.SetTolerance(segment_wire, precision_, TopAbs_WIRE); + + converted_segments.Append(segment_wire); + } + + if (converted_segments.Extent() == 0) { + Logger::Message(Logger::LOG_ERROR, "No segment succesfully converted:", loop->instance); + return false; + } + + BRepBuilderAPI_MakeWire w; + TopoDS_Vertex wire_first_vertex, wire_last_vertex, edge_first_vertex, edge_last_vertex; + + TopTools_ListIteratorOfListOfShape it(converted_segments); + + /* + @todo + IfcEntityList::ptr profile = l->data().getInverse(&IfcSchema::IfcProfileDef::Class(), -1); + const bool force_close = profile && profile->size() > 0; + */ + const bool force_close = false; + + wire_builder bld(precision_, loop->instance); + shape_pair_enumerate(it, bld, force_close); + wire = bld.wire(); + + return true; +} + bool OpenCascadeKernel::convert_impl(const taxonomy::extrusion* extrusion, ifcopenshell::geometry::ConversionResults& results) { TopoDS_Shape shape; if (!convert(extrusion, shape)) { @@ -192,4 +832,276 @@ bool OpenCascadeKernel::convert(const taxonomy::matrix4* matrix, gp_GTrsf& trsf) } } return true; -} \ No newline at end of file +} + +#include + +bool OpenCascadeKernel::approximate_plane_through_wire(const TopoDS_Wire& wire, gp_Pln& plane, double eps) { + // Newell's Method is used for the normal calculation + // as a simple edge cross product can give opposite results + // for a concave face boundary. + // Reference: Graphics Gems III p. 231 + + const double eps_ = eps < 1. ? precision_ : eps; + const double eps2 = eps_ * eps_; + + double x = 0, y = 0, z = 0; + gp_Pnt current, previous, first; + gp_XYZ center; + int n = 0; + + BRepTools_WireExplorer exp(wire); + + for (;; exp.Next()) { + const bool has_more = exp.More() != 0; + if (has_more) { + const TopoDS_Vertex& v = exp.CurrentVertex(); + current = BRep_Tool::Pnt(v); + center += current.XYZ(); + } else { + current = first; + } + if (n) { + const double& xn = previous.X(); + const double& yn = previous.Y(); + const double& zn = previous.Z(); + const double& xn1 = current.X(); + const double& yn1 = current.Y(); + const double& zn1 = current.Z(); + x += (yn - yn1)*(zn + zn1); + y += (xn + xn1)*(zn - zn1); + z += (xn - xn1)*(yn + yn1); + } else { + first = current; + } + if (!has_more) { + break; + } + previous = current; + ++n; + } + + if (n < 3) { + return false; + } + + plane = gp_Pln(center / n, gp_Dir(x, y, z)); + + exp.Init(wire); + for (; exp.More(); exp.Next()) { + const TopoDS_Vertex& v = exp.CurrentVertex(); + current = BRep_Tool::Pnt(v); + if (plane.SquareDistance(current) > eps2) { + return false; + } + } + + return true; +} + + +bool OpenCascadeKernel::triangulate_wire(const std::vector& wires, TopTools_ListOfShape& faces) { + // This is a bit of a precarious approach, but seems to work for the + // versions of OCCT tested for. OCCT has a Delaunay triangulation function + // BRepMesh_Delaun, but it is notoriously hard to interpret the results + // (due to the Bowyer-Watson super triangle perhaps?). Therefore + // alternatively we use the regular OCCT incremental mesher on a new face + // created from the UV coordinates of the original wire. Pray to our gods + // that the vertex coordinates are unaffected by the meshing algorithm and + // map them back to 3d coordinates when iterating over the mesh triangles. + + // In addition, to maintain a manifold shell, we need to make sure that + // every edge from the input wire is used exactly once in the list of + // resulting faces. And that other internal edges are used twice. + + typedef std::pair uv_node; + + gp_Pln pln; + if (!approximate_plane_through_wire(wires.front(), pln, std::numeric_limits::infinity())) { + return false; + } + + const gp_XYZ& udir = pln.Position().XDirection().XYZ(); + const gp_XYZ& vdir = pln.Position().YDirection().XYZ(); + const gp_XYZ& pnt = pln.Position().Location().XYZ(); + + std::map mapping; + std::map, TopoDS_Edge> existing_edges, new_edges; + + std::unique_ptr mf; + + for (auto it = wires.begin(); it != wires.end(); ++it) { + const TopoDS_Wire& wire = *it; + BRepTools_WireExplorer exp(wire); + BRepBuilderAPI_MakePolygon mp; + + // Add UV coordinates to a newly created polygon + for (; exp.More(); exp.Next()) { + // Project onto plane + const TopoDS_Vertex& V = exp.CurrentVertex(); + gp_Pnt p = BRep_Tool::Pnt(V); + double u = (p.XYZ() - pnt).Dot(udir); + double v = (p.XYZ() - pnt).Dot(vdir); + mp.Add(gp_Pnt(u, v, 0.)); + + mapping.insert(std::make_pair(std::make_pair(u, v), V)); + + // Store existing edges in a map so that triangles can + // actually reference the preexisting edges. + const TopoDS_Edge& e = exp.Current(); + TopoDS_Vertex V0, V1; + TopExp::Vertices(e, V0, V1, true); + gp_Pnt p0 = BRep_Tool::Pnt(V0); + gp_Pnt p1 = BRep_Tool::Pnt(V1); + double u0 = (p0.XYZ() - pnt).Dot(udir); + double v0 = (p0.XYZ() - pnt).Dot(vdir); + double u1 = (p1.XYZ() - pnt).Dot(udir); + double v1 = (p1.XYZ() - pnt).Dot(vdir); + uv_node uv0 = std::make_pair(u0, v0); + uv_node uv1 = std::make_pair(u1, v1); + existing_edges.insert(std::make_pair(std::make_pair(uv0, uv1), e)); + existing_edges.insert(std::make_pair(std::make_pair(uv1, uv0), TopoDS::Edge(e.Reversed()))); + } + + // Not closed by default + mp.Close(); + + if (mf) { + if (it - 1 == wires.begin()) { + // @todo is this necessary? + TopoDS_Face f = mf->Face(); + mf->Init(f); + } + mf->Add(mp.Wire()); + } else { + mf.reset(new BRepBuilderAPI_MakeFace(mp.Wire())); + } + } + + const TopoDS_Face& face = mf->Face(); + + // Create a triangular mesh from the face + BRepMesh_IncrementalMesh(face, Precision::Confusion()); + + int n123[3]; + TopLoc_Location loc; + Handle_Poly_Triangulation tri = BRep_Tool::Triangulation(face, loc); + + if (!tri.IsNull()) { + const TColgp_Array1OfPnt& nodes = tri->Nodes(); + + const Poly_Array1OfTriangle& triangles = tri->Triangles(); + for (int i = 1; i <= triangles.Length(); ++i) { + if (face.Orientation() == TopAbs_REVERSED) + triangles(i).Get(n123[2], n123[1], n123[0]); + else triangles(i).Get(n123[0], n123[1], n123[2]); + + // Create polygons from the mesh vertices + BRepBuilderAPI_MakeWire mp2; + for (int j = 0; j < 3; ++j) { + + uv_node uvnodes[2]; + TopoDS_Vertex vs[2]; + + for (int k = 0; k < 2; ++k) { + const gp_Pnt& uv = nodes.Value(n123[(j + k) % 3]); + uvnodes[k] = std::make_pair(uv.X(), uv.Y()); + + auto it = mapping.find(uvnodes[k]); + if (it == mapping.end()) { + Logger::Error("Internal error: unable to unproject uv-mesh"); + return false; + } + + vs[k] = it->second; + } + + auto it = existing_edges.find(std::make_pair(uvnodes[0], uvnodes[1])); + if (it != existing_edges.end()) { + // This is a boundary edge, reuse existing edge from wire + mp2.Add(it->second); + } else { + auto jt = new_edges.find(std::make_pair(uvnodes[0], uvnodes[1])); + if (jt != new_edges.end()) { + // We have already added the reverse as part of another + // triangle, reuse this edge. + mp2.Add(TopoDS::Edge(jt->second)); + } else { + // This is a new internal edge. Register the reverse + // for reuse later. We need to be sure to reuse vertices + // for the edge construction because otherwise the wire + // builder will use geometrical proximity for vertex + // connections in which case the edge will be copied + // and no longer partner with other edges from the shell. + TopoDS_Edge ne = BRepBuilderAPI_MakeEdge(vs[0], vs[1]); + mp2.Add(ne); + // Store the reverse to be picked up later. + new_edges.insert(std::make_pair(std::make_pair(uvnodes[1], uvnodes[0]), TopoDS::Edge(ne.Reversed()))); + } + } + } + + BRepBuilderAPI_MakeFace mft(mp2.Wire()); + if (mft.IsDone()) { + TopoDS_Face triangle_face = mft.Face(); + TopoDS_Iterator jt(triangle_face, false); + for (; jt.More(); jt.Next()) { + const TopoDS_Wire& w = TopoDS::Wire(jt.Value()); + if (w.Orientation() != wires.front().Orientation()) { + triangle_face.Reverse(); + } + } + faces.Append(triangle_face); + } else { + Logger::Error("Internal error: missing face"); + return false; + } + } + } + + TopTools_IndexedDataMapOfShapeListOfShape mape, mapn; + for (auto& wire : wires) { + TopExp::MapShapesAndAncestors(wire, TopAbs_EDGE, TopAbs_WIRE, mape); + } + TopTools_ListIteratorOfListOfShape it(faces); + for (; it.More(); it.Next()) { + TopExp::MapShapesAndAncestors(it.Value(), TopAbs_EDGE, TopAbs_WIRE, mapn); + } + + // Validation + + for (int i = 1; i <= mape.Extent(); ++i) { +#if OCC_VERSION_HEX >= 0x70000 + TopTools_ListOfShape val; + if (!mapn.FindFromKey(mape.FindKey(i), val)) { +#else + bool contains = false; + try { + TopTools_ListOfShape val = mapn.FindFromKey(mape.FindKey(i)); + contains = true; + } catch (Standard_NoSuchObject&) {} + if (!contains) { +#endif + // All existing edges need to exist in the new faces + Logger::Error("Internal error, missing edge from triangulation"); + if (faceset_helper_ != nullptr) { + faceset_helper_->non_manifold() = true; + } + } + } + + for (int i = 1; i <= mapn.Extent(); ++i) { + const TopoDS_Shape& v = mapn.FindKey(i); + int n = mapn.FindFromIndex(i).Extent(); + // Existing edges are boundaries with use 1 + // New edges are internal with use 2 + if (n != (mape.Contains(v) ? 1 : 2)) { + Logger::Error("Internal error, non-manifold result from triangulation"); + if (faceset_helper_ != nullptr) { + faceset_helper_->non_manifold() = true; + } + } + } + + return true; + } \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h index ffce0fa956..101c6643c2 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h @@ -235,8 +235,12 @@ namespace kernels { bool convert(const taxonomy::extrusion*, TopoDS_Shape&); bool convert(const taxonomy::face*, TopoDS_Shape&); + bool convert(const taxonomy::loop*, TopoDS_Wire&); bool convert(const taxonomy::matrix4*, gp_GTrsf&); + bool approximate_plane_through_wire(const TopoDS_Wire& wire, gp_Pln& plane, double eps = -1.); + bool triangulate_wire(const std::vector& wires, TopTools_ListOfShape& faces); + virtual bool convert_impl(const taxonomy::shell*, ifcopenshell::geometry::ConversionResults&); virtual bool convert_impl(const taxonomy::extrusion*, ifcopenshell::geometry::ConversionResults&); }; diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index 122f5a0fef..3be8ec2f6d 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -24,7 +24,7 @@ public: topology_error() : std::runtime_error("Generic topology error") {} }; -enum kinds { MATRIX4, POINT3, DIRECTION3, LINE, CIRCLE, ELLIPSE, BSPLINE, EDGE, LOOP, FACE, SHELL, EXTRUSION, NODE, COLLECTION, COLOUR, STYLE }; +enum kinds { MATRIX4, POINT3, DIRECTION3, LINE, CIRCLE, ELLIPSE, BSPLINE_CURVE, EDGE, LOOP, FACE, SHELL, EXTRUSION, NODE, COLLECTION, COLOUR, STYLE }; struct item { const IfcUtil::IfcBaseClass* instance; @@ -114,46 +114,74 @@ struct direction3 : public cartesian_base<3> { direction3(double x = 0., double y = 0., double z = 0.) : cartesian_base(x, y, z) {} }; -struct line : public geom_item { +struct curve : public geom_item {}; + +struct line : public curve { + point3 origin; + direction3 direction; + virtual item* clone() const { return new line(*this); } virtual kinds kind() const { return LINE; } }; -struct circle : public geom_item { +struct circle : public curve { + point3 origin; + direction3 x; + direction3 z; + double radius; + virtual item* clone() const { return new circle(*this); } virtual kinds kind() const { return CIRCLE; } }; -struct ellipse : public geom_item { +struct ellipse : public circle { + double radius2; + virtual item* clone() const { return new ellipse(*this); } virtual kinds kind() const { return ELLIPSE; } }; -struct bspline : public geom_item { - virtual item* clone() const { return new bspline(*this); } - virtual kinds kind() const { return BSPLINE; } +struct bspline_curve : public curve { + virtual item* clone() const { return new bspline_curve(*this); } + virtual kinds kind() const { return BSPLINE_CURVE; } }; -typedef boost::variant curve; - -struct edge : public geom_item { +struct trimmed_curve : public curve { boost::variant start, end; - boost::optional basis; + // @todo somehow account for the fact that curve in IFC can be trimmed curve, polyline and composite curve as well. + curve* basis; bool orientation; - edge() : orientation(true) {} - virtual item* clone() const { return new edge(*this); } - virtual kinds kind() const { return EDGE; } - + trimmed_curve() : basis(nullptr), orientation(true) {} + virtual void reverse() { std::swap(start, end); orientation = !orientation; } }; +struct edge : public trimmed_curve { + // @todo how to express similarity between trimmed_curve and edge? + virtual item* clone() const { return new edge(*this); } + virtual kinds kind() const { return EDGE; } +}; + struct collection : public geom_item { std::vector children; + template + std::vector children_as() const { + std::vector ts; + ts.reserve(children.size()); + std::for_each(children.begin(), children.end(), [&ts](item* i){ + auto v = dynamic_cast(i); + if (v) { + ts.push_back(v); + } + }); + return ts; + } + virtual item* clone() const { return new collection(*this); } virtual kinds kind() const { return COLLECTION; } virtual void reverse() { @@ -175,6 +203,8 @@ struct face : public collection { }; struct loop : public collection { + boost::optional external; + virtual item* clone() const { return new loop(*this); } virtual kinds kind() const { return LOOP; } }; @@ -205,7 +235,8 @@ struct node : public geom_item { }; namespace impl { - typedef std::tuple KindsTuple; + typedef std::tuple KindsTuple; + typedef std::tuple CurvesTuple; } struct type_by_kind { @@ -215,6 +246,14 @@ struct type_by_kind { static const size_t max = std::tuple_size< impl::KindsTuple>::value; }; +struct curves { + template + using type = typename std::tuple_element::type; + + static const size_t max = std::tuple_size< impl::CurvesTuple>::value; +}; + + } From 640b08159fd9e18e361cf525cfec87d6300a87a2 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Tue, 27 Aug 2019 18:59:19 +0200 Subject: [PATCH 167/235] Work on shells --- .../kernels/opencascade/IfcGeomShapes.cpp | 469 +++++++++++++++++- .../kernels/opencascade/OpenCascadeKernel.h | 8 + 2 files changed, 476 insertions(+), 1 deletion(-) diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp index 71c382b5c2..08d1d6a09e 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp @@ -824,6 +824,20 @@ bool OpenCascadeKernel::convert_impl(const taxonomy::extrusion* extrusion, ifcop return true; } +bool OpenCascadeKernel::convert_impl(const taxonomy::shell *extrusion, ifcopenshell::geometry::ConversionResults& results) { + TopoDS_Shape shape; + if (!convert(extrusion, shape)) { + return false; + } + results.emplace_back(ConversionResult( + extrusion->instance->data().id(), + extrusion->matrix, + new OpenCascadeShape(shape), + extrusion->surface_style + )); + return true; +} + bool OpenCascadeKernel::convert(const taxonomy::matrix4* matrix, gp_GTrsf& trsf) { // @todo check for (int i = 0; i < 3; ++i) { @@ -1104,4 +1118,457 @@ bool OpenCascadeKernel::triangulate_wire(const std::vector& wires, } return true; - } \ No newline at end of file +} + +bool OpenCascadeKernel::convert(const taxonomy::shell* l, TopoDS_Shape& shape) { + std::unique_ptr helper_scope; + helper_scope.reset(new faceset_helper(this, l)); + + auto faces = l->children_as(); + double minimal_face_area = precision_ * precision_ * 0.5; + + double min_face_area = faceset_helper_ + ? (faceset_helper_->epsilon() * faceset_helper_->epsilon() / 20.) + : minimal_face_area; + + TopTools_ListOfShape face_list; + for (auto& face : faces) { + bool success = false; + TopoDS_Face occ_face; + + try { + success = convert(face, occ_face); + } catch (const std::exception& e) { + Logger::Error(e); + } catch (const Standard_Failure& e) { + if (e.GetMessageString() && strlen(e.GetMessageString())) { + Logger::Error(e.GetMessageString()); + } else { + Logger::Error("Unknown error creating face"); + } + } catch (...) { + Logger::Error("Unknown error creating face"); + } + + if (!success) { + Logger::Message(Logger::LOG_WARNING, "Failed to convert face:", face->instance); + continue; + } + + if (occ_face.ShapeType() == TopAbs_COMPOUND) { + TopoDS_Iterator face_it(occ_face, false); + for (; face_it.More(); face_it.Next()) { + if (face_it.Value().ShapeType() == TopAbs_FACE) { + // This should really be the case. This is not asserted. + const TopoDS_Face& triangle = TopoDS::Face(face_it.Value()); + if (face_area(triangle) > min_face_area) { + face_list.Append(triangle); + } else { + Logger::Message(Logger::LOG_WARNING, "Degenerate face:", face->instance); + } + } + } + } else { + if (face_area(occ_face) > min_face_area) { + face_list.Append(occ_face); + } else { + Logger::Message(Logger::LOG_WARNING, "Degenerate face:", face->instance); + } + } + } + + if (face_list.Extent() == 0) { + return false; + } + + // @todo + /* face_list.Extent() > getValue(GV_MAX_FACES_TO_ORIENT) || */ + + if (!create_solid_from_faces(face_list, shape)) { + TopoDS_Compound compound; + BRep_Builder builder; + builder.MakeCompound(compound); + + TopTools_ListIteratorOfListOfShape face_iterator; + for (face_iterator.Initialize(face_list); face_iterator.More(); face_iterator.Next()) { + builder.Add(compound, face_iterator.Value()); + } + shape = compound; + } + + return true; +} + +#include +#include + +double OpenCascadeKernel::shape_volume(const TopoDS_Shape& s) { + GProp_GProps prop; + BRepGProp::VolumeProperties(s, prop); + return prop.Mass(); +} + +double OpenCascadeKernel::face_area(const TopoDS_Face& f) { + GProp_GProps prop; + BRepGProp::SurfaceProperties(f, prop); + return prop.Mass(); +} + +bool OpenCascadeKernel::create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& shape) { + TopTools_ListOfShape face_list; + TopExp_Explorer exp(compound, TopAbs_FACE); + for (; exp.More(); exp.Next()) { + TopoDS_Face face = TopoDS::Face(exp.Current()); + face_list.Append(face); + } + + if (face_list.Extent() == 0) { + return false; + } + + return create_solid_from_faces(face_list, shape); +} + +bool OpenCascadeKernel::create_solid_from_faces(const TopTools_ListOfShape& face_list, TopoDS_Shape& shape) { + bool valid_shell = false; + + if (face_list.Extent() == 1) { + shape = face_list.First(); + // A bit dubious what to return here. + return true; + } else if (face_list.Extent() == 0) { + return false; + } + + TopTools_ListIteratorOfListOfShape face_iterator; + + bool has_shared_edges = false; + TopTools_MapOfShape edge_set; + + // In case there are wire interesections or failures in non-planar wire triangulations + // the idea is to let occt do an exhaustive search of edge partners. But we have not + // found a case where this actually improves boolean ops later on. + // if (!faceset_helper_ || !faceset_helper_->non_manifold()) { + + for (face_iterator.Initialize(face_list); face_iterator.More(); face_iterator.Next()) { + // As soon as is detected one of the edges is shared, the assumption is made no + // additional sewing is necessary. + if (!has_shared_edges) { + TopExp_Explorer exp(face_iterator.Value(), TopAbs_EDGE); + for (; exp.More(); exp.Next()) { + if (edge_set.Contains(exp.Current())) { + has_shared_edges = true; + break; + } + edge_set.Add(exp.Current()); + } + } + } + + BRepOffsetAPI_Sewing sewing_builder; + sewing_builder.SetTolerance(precision_); + sewing_builder.SetMaxTolerance(precision_); + sewing_builder.SetMinTolerance(precision_); + + BRep_Builder builder; + TopoDS_Shell shell; + builder.MakeShell(shell); + + for (face_iterator.Initialize(face_list); face_iterator.More(); face_iterator.Next()) { + if (has_shared_edges) { + builder.Add(shell, face_iterator.Value()); + } else { + sewing_builder.Add(face_iterator.Value()); + } + } + + try { + if (has_shared_edges) { + ShapeFix_Shell fix; + fix.FixFaceOrientation(shell); + shape = fix.Shape(); + } else { + sewing_builder.Perform(); + shape = sewing_builder.SewedShape(); + } + + BRepCheck_Analyzer ana(shape); + valid_shell = ana.IsValid(); + + if (!valid_shell) { + ShapeFix_Shape sfs(shape); + sfs.Perform(); + shape = sfs.Shape(); + + BRepCheck_Analyzer reana(shape); + valid_shell = reana.IsValid(); + } + + valid_shell &= count(shape, TopAbs_SHELL) > 0; + } catch (const Standard_Failure& e) { + if (e.GetMessageString() && strlen(e.GetMessageString())) { + Logger::Error(e.GetMessageString()); + } else { + Logger::Error("Unknown error sewing shell"); + } + } catch (...) { + Logger::Error("Unknown error sewing shell"); + } + + if (valid_shell) { + + TopoDS_Shape complete_shape; + TopExp_Explorer exp(shape, TopAbs_SHELL); + + for (; exp.More(); exp.Next()) { + TopoDS_Shape result_shape = exp.Current(); + + try { + ShapeFix_Solid solid; + solid.SetMaxTolerance(precision_); + TopoDS_Solid solid_shape = solid.SolidFromShell(TopoDS::Shell(exp.Current())); + // @todo: BRepClass3d_SolidClassifier::PerformInfinitePoint() is done by SolidFromShell + // and this is done again, to be able to catch errors during this process. + // This is double work that should be avoided. + if (!solid_shape.IsNull()) { + try { + BRepClass3d_SolidClassifier classifier(solid_shape); + result_shape = solid_shape; + classifier.PerformInfinitePoint(precision_); + if (classifier.State() == TopAbs_IN) { + shape.Reverse(); + } + } catch (const Standard_Failure& e) { + if (e.GetMessageString() && strlen(e.GetMessageString())) { + Logger::Error(e.GetMessageString()); + } else { + Logger::Error("Unknown error classifying solid"); + } + } catch (...) { + Logger::Error("Unknown error classifying solid"); + } + } + } catch (const Standard_Failure& e) { + if (e.GetMessageString() && strlen(e.GetMessageString())) { + Logger::Error(e.GetMessageString()); + } else { + Logger::Error("Unknown error creating solid"); + } + } catch (...) { + Logger::Error("Unknown error creating solid"); + } + + if (complete_shape.IsNull()) { + complete_shape = result_shape; + } else { + BRep_Builder B; + if (complete_shape.ShapeType() != TopAbs_COMPOUND) { + TopoDS_Compound C; + B.MakeCompound(C); + B.Add(C, complete_shape); + complete_shape = C; + Logger::Warning("Multiple components in IfcConnectedFaceSet"); + } + B.Add(complete_shape, result_shape); + } + } + + TopExp_Explorer loose_faces(shape, TopAbs_FACE, TopAbs_SHELL); + + for (; loose_faces.More(); loose_faces.Next()) { + BRep_Builder B; + if (complete_shape.ShapeType() != TopAbs_COMPOUND) { + TopoDS_Compound C; + B.MakeCompound(C); + B.Add(C, complete_shape); + complete_shape = C; + Logger::Warning("Loose faces in IfcConnectedFaceSet"); + } + B.Add(complete_shape, loose_faces.Current()); + } + + shape = complete_shape; + + } else { + Logger::Error("Failed to sew faceset"); + } + + return valid_shell; +} + +int OpenCascadeKernel::count(const TopoDS_Shape& s, TopAbs_ShapeEnum t, bool unique) { + if (unique) { + TopTools_IndexedMapOfShape map; + TopExp::MapShapes(s, t, map); + return map.Extent(); + } else { + int i = 0; + TopExp_Explorer exp(s, t); + for (; exp.More(); exp.Next()) { + ++i; + } + return i; + } +} + +OpenCascadeKernel::faceset_helper::~faceset_helper() { + kernel_->faceset_helper_ = nullptr; +} + +OpenCascadeKernel::faceset_helper::faceset_helper(OpenCascadeKernel* kernel, const taxonomy::shell* shell) + : kernel_(kernel) + , non_manifold_(false) { + kernel->faceset_helper_ = this; + + std::vector points; + for (auto& f : shell->children_as()) { + for (auto& l : f->children_as()) { + for (auto& e : l->children_as()) { + // @todo make sure only cartesian points are provided here + points.push_back(boost::get(e->start)); + } + } + } + + std::vector> pnts(points.size()); + std::vector vertices(pnts.size()); + + // @todo + /* + IfcGeom::impl::tree tree; + + BRep_Builder B; + + Bnd_Box box; + for (size_t i = 0; i < points->size(); ++i) { + gp_Pnt* p = new gp_Pnt(); + if (kernel->convert(*(points->begin() + i), *p)) { + pnts[i].reset(p); + B.MakeVertex(vertices[i], *p, Precision::Confusion()); + tree.add(i, vertices[i]); + box.Add(*p); + } else { + delete p; + } + } + + // Use the bbox diagonal to influence local epsilon + // double bdiff = std::sqrt(box.SquareExtent()); + + // @todo the bounding box diagonal is not used (see above) + // because we're explicitly interested in the miminal + // dimension of the element to limit the tolerance (for sheet- + // like elements for example). But the way below is very + // dependent on orientation due to the usage of the + // axis-aligned bounding box. Use PCA to find three non-aligned + // set of dimensions and use the one with the smallest eigenvalue. + + // Find the minimal bounding box edge + double bmin[3], bmax[3]; + box.Get(bmin[0], bmin[1], bmin[2], bmax[0], bmax[1], bmax[2]); + double bdiff = std::numeric_limits::infinity(); + for (size_t i = 0; i < 3; ++i) { + const double d = bmax[i] - bmin[i]; + if (d > kernel->getValue(GV_PRECISION) * 10. && d < bdiff) { + bdiff = d; + } + } + + eps_ = kernel->getValue(GV_PRECISION) * 10. * (std::min)(1.0, bdiff); + + // @todo, there a tiny possibility that the duplicate faces are triggered + // for an internal boundary, that is also present as an external boundary. + // This will result in non-manifold configuration then, but this is deemed + // such as corner-case that it is not considered. + IfcSchema::IfcPolyLoop::list::ptr loops = IfcParse::traverse((IfcUtil::IfcBaseClass*)l)->as(); + + size_t loops_removed, non_manifold, duplicate_faces; + + std::map, int> edge_use; + + for (int i = 0; i < 3; ++i) { + // Some times files, have large tolerance values specified collapsing too many vertices. + // This case we detect below and re-run the loop with smaller epsilon. Normally + // the body of this loop would only be executed once. + + loops_removed = 0; + non_manifold = 0; + duplicate_faces = 0; + + vertex_mapping_.clear(); + duplicates_.clear(); + + edge_use.clear(); + + if (eps_ < Precision::Confusion()) { + // occt uses some hard coded precision values, don't go smaller than that. + // @todo, can be reset though with BRepLib::Precision(double) + eps_ = Precision::Confusion(); + } + + for (int i = 0; i < (int)pnts.size(); ++i) { + if (pnts[i]) { + std::set vs; + find_neighbours(tree, pnts, vs, i, eps_); + + for (int v : vs) { + auto pt = *(points->begin() + v); + // NB: insert() ignores duplicate keys + vertex_mapping_.insert({ pt->data().id() , i }); + } + } + } + + typedef std::array edge_t; + typedef std::set edge_set_t; + std::set edge_sets; + + for (auto& loop : *loops) { + auto ps = loop->Polygon(); + + std::vector > segments; + edge_set_t segment_set; + + loop_(ps, [&segments, &segment_set](int C, int D, bool) { + segment_set.insert({ { C, D } }); + segments.push_back({ C, D }); + }); + + if (edge_sets.find(segment_set) != edge_sets.end()) { + duplicate_faces++; + duplicates_.insert(loop); + continue; + } + edge_sets.insert(segment_set); + + if (segments.size() >= 3) { + for (auto& p : segments) { + edge_use[p] ++; + } + } else { + loops_removed += 1; + } + } + + if (edge_use.size() != 0) { + break; + } else { + eps_ /= 10.; + } + } + + for (auto& p : edge_use) { + int a, b; + std::tie(a, b) = p.first; + edges_[p.first] = BRepBuilderAPI_MakeEdge(vertices[a], vertices[b]); + + if (p.second != 2) { + non_manifold += 1; + } + } + + if (loops_removed || (non_manifold && l->declaration().is(IfcSchema::IfcClosedShell::Class()))) { + Logger::Warning(boost::lexical_cast(duplicate_faces) + " duplicate faces removed, " + boost::lexical_cast(loops_removed) + " loops removed and " + boost::lexical_cast(non_manifold) + " non-manifold edges for:", l); + } + */ +} \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h index 101c6643c2..defcc52a0c 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h @@ -233,10 +233,18 @@ namespace kernels { *this = other; } + double shape_volume(const TopoDS_Shape&); + double face_area(const TopoDS_Face&); + int count(const TopoDS_Shape& s, TopAbs_ShapeEnum t, bool unique = false); + + bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& shape); + bool create_solid_from_faces(const TopTools_ListOfShape& face_list, TopoDS_Shape& shape); + bool convert(const taxonomy::extrusion*, TopoDS_Shape&); bool convert(const taxonomy::face*, TopoDS_Shape&); bool convert(const taxonomy::loop*, TopoDS_Wire&); bool convert(const taxonomy::matrix4*, gp_GTrsf&); + bool convert(const taxonomy::shell*, TopoDS_Shape&); bool approximate_plane_through_wire(const TopoDS_Wire& wire, gp_Pln& plane, double eps = -1.); bool triangulate_wire(const std::vector& wires, TopTools_ListOfShape& faces); From 3bfe3b9ab545aac9bcca557474be63038e46bcd0 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 28 Aug 2019 09:24:00 +0200 Subject: [PATCH 168/235] Seperate map() and map_impl() for automatic taxonomy item <> ifc instance mapping --- .../kernels/opencascade/IfcGeomShapes.cpp | 10 +++--- src/ifcgeom/schema/bind_convert_decl.i | 2 +- src/ifcgeom/schema/bind_convert_impl.i | 2 +- src/ifcgeom/schema/mapping.cpp | 32 +++++++++---------- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp index 08d1d6a09e..09c10dd964 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp @@ -824,16 +824,16 @@ bool OpenCascadeKernel::convert_impl(const taxonomy::extrusion* extrusion, ifcop return true; } -bool OpenCascadeKernel::convert_impl(const taxonomy::shell *extrusion, ifcopenshell::geometry::ConversionResults& results) { +bool OpenCascadeKernel::convert_impl(const taxonomy::shell *shell, ifcopenshell::geometry::ConversionResults& results) { TopoDS_Shape shape; - if (!convert(extrusion, shape)) { + if (!convert(shell, shape)) { return false; } results.emplace_back(ConversionResult( - extrusion->instance->data().id(), - extrusion->matrix, + shell->instance->data().id(), + shell->matrix, new OpenCascadeShape(shape), - extrusion->surface_style + shell->surface_style )); return true; } diff --git a/src/ifcgeom/schema/bind_convert_decl.i b/src/ifcgeom/schema/bind_convert_decl.i index b612616039..212c4e822d 100644 --- a/src/ifcgeom/schema/bind_convert_decl.i +++ b/src/ifcgeom/schema/bind_convert_decl.i @@ -2,6 +2,6 @@ #undef BIND #endif -#define BIND(T) ifcopenshell::geometry::taxonomy::item* map(const IfcSchema::T*); +#define BIND(T) ifcopenshell::geometry::taxonomy::item* map_impl(const IfcSchema::T*); #include "mapping.i" diff --git a/src/ifcgeom/schema/bind_convert_impl.i b/src/ifcgeom/schema/bind_convert_impl.i index 5914425f88..298c809e0e 100644 --- a/src/ifcgeom/schema/bind_convert_impl.i +++ b/src/ifcgeom/schema/bind_convert_impl.i @@ -5,7 +5,7 @@ #define BIND(T) \ if (l->declaration().is(IfcSchema::T::Class())) { \ try { \ - taxonomy::item* item = map((IfcSchema::T*)l); \ + taxonomy::item* item = map_impl((IfcSchema::T*)l); \ if (item != nullptr) { \ item->instance = l; \ try { \ diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index 3218e4355b..689a539f27 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -144,7 +144,7 @@ namespace { } }; -taxonomy::item* mapping::map(const IfcSchema::IfcExtrudedAreaSolid* inst) { +taxonomy::item* mapping::map_impl(const IfcSchema::IfcExtrudedAreaSolid* inst) { // @todo length unit return new taxonomy::extrusion( as(map(inst->Position())), @@ -154,19 +154,19 @@ taxonomy::item* mapping::map(const IfcSchema::IfcExtrudedAreaSolid* inst) { ); } -taxonomy::item* mapping::map(const IfcSchema::IfcRepresentation* inst) { +taxonomy::item* mapping::map_impl(const IfcSchema::IfcRepresentation* inst) { return map_to_collection(this, inst->Items()); } -taxonomy::item* mapping::map(const IfcSchema::IfcFaceBasedSurfaceModel* inst) { +taxonomy::item* mapping::map_impl(const IfcSchema::IfcFaceBasedSurfaceModel* inst) { return map_to_collection(this, inst->FbsmFaces()); } -taxonomy::item* mapping::map(const IfcSchema::IfcConnectedFaceSet* inst) { +taxonomy::item* mapping::map_impl(const IfcSchema::IfcConnectedFaceSet* inst) { return map_to_collection(this, inst->CfsFaces()); } -taxonomy::item* mapping::map(const IfcSchema::IfcFace* inst) { +taxonomy::item* mapping::map_impl(const IfcSchema::IfcFace* inst) { taxonomy::face* face = new taxonomy::face; auto bounds = inst->Bounds(); for (auto& bound : *bounds) { @@ -184,7 +184,7 @@ taxonomy::item* mapping::map(const IfcSchema::IfcFace* inst) { return face; } -taxonomy::item* mapping::map(const IfcSchema::IfcPolyLoop* inst) { +taxonomy::item* mapping::map_impl(const IfcSchema::IfcPolyLoop* inst) { taxonomy::loop* loop = new taxonomy::loop; taxonomy::point3 first, previous; @@ -218,7 +218,7 @@ taxonomy::item* mapping::map(const IfcSchema::IfcPolyLoop* inst) { return loop; } -taxonomy::item* mapping::map(const IfcSchema::IfcCartesianPoint* inst) { +taxonomy::item* mapping::map_impl(const IfcSchema::IfcCartesianPoint* inst) { auto coords = inst->Coordinates(); return new taxonomy::point3( coords.size() >= 1 ? coords[0] : 0., @@ -227,38 +227,38 @@ taxonomy::item* mapping::map(const IfcSchema::IfcCartesianPoint* inst) { ); } -taxonomy::item* mapping::map(const IfcSchema::IfcProduct* inst) { +taxonomy::item* mapping::map_impl(const IfcSchema::IfcProduct* inst) { auto n = new taxonomy::node; n->matrix = as(map(inst->ObjectPlacement())); return n; } -taxonomy::item* mapping::map(const IfcSchema::IfcAxis2Placement3D* inst) { +taxonomy::item* mapping::map_impl(const IfcSchema::IfcAxis2Placement3D* inst) { // @todo length unit return new taxonomy::matrix4(); } -taxonomy::item* mapping::map(const IfcSchema::IfcCartesianTransformationOperator2DnonUniform* inst) { +taxonomy::item* mapping::map_impl(const IfcSchema::IfcCartesianTransformationOperator2DnonUniform* inst) { // @todo length unit return new taxonomy::matrix4(); } -taxonomy::item* mapping::map(const IfcSchema::IfcCartesianTransformationOperator3DnonUniform* inst) { +taxonomy::item* mapping::map_impl(const IfcSchema::IfcCartesianTransformationOperator3DnonUniform* inst) { // @todo length unit return new taxonomy::matrix4(); } -taxonomy::item* mapping::map(const IfcSchema::IfcCartesianTransformationOperator2D* inst) { +taxonomy::item* mapping::map_impl(const IfcSchema::IfcCartesianTransformationOperator2D* inst) { // @todo length unit return new taxonomy::matrix4(); } -taxonomy::item* mapping::map(const IfcSchema::IfcCartesianTransformationOperator3D* inst) { +taxonomy::item* mapping::map_impl(const IfcSchema::IfcCartesianTransformationOperator3D* inst) { // @todo length unit return new taxonomy::matrix4(); } -taxonomy::item* mapping::map(const IfcSchema::IfcLocalPlacement* inst) { +taxonomy::item* mapping::map_impl(const IfcSchema::IfcLocalPlacement* inst) { // @todo length unit return new taxonomy::matrix4(); } @@ -672,7 +672,7 @@ namespace { } } -taxonomy::item* mapping::map(const IfcSchema::IfcMaterial* material) { +taxonomy::item* mapping::map_impl(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(); @@ -693,7 +693,7 @@ taxonomy::item* mapping::map(const IfcSchema::IfcMaterial* material) { // return &(style_cache[material->data().id()] = material_style); } -taxonomy::item* mapping::map(const IfcSchema::IfcStyledItem* inst) { +taxonomy::item* mapping::map_impl(const IfcSchema::IfcStyledItem* inst) { static taxonomy::colour white = taxonomy::colour(1., 1., 1.); taxonomy::style* surface_style = new taxonomy::style; From 64ee3e9af3c6eb9fd3826b5029e5e9a81da0ec3d Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 28 Aug 2019 09:54:20 +0200 Subject: [PATCH 169/235] closed shell; placements; faceset_helper --- .../kernels/opencascade/IfcGeomShapes.cpp | 73 ++++++++++++------- src/ifcgeom/kernels/opencascade/IfcGeomTree.h | 24 +++--- .../OpenCascadeConversionResult.cpp | 2 +- src/ifcgeom/schema/mapping.cpp | 4 +- .../schema_agnostic/IfcGeomRepresentation.cpp | 4 +- src/ifcgeom/taxonomy.h | 2 + 6 files changed, 66 insertions(+), 43 deletions(-) diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp index 09c10dd964..8db95bdd7a 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp @@ -841,7 +841,7 @@ bool OpenCascadeKernel::convert_impl(const taxonomy::shell *shell, ifcopenshell: bool OpenCascadeKernel::convert(const taxonomy::matrix4* matrix, gp_GTrsf& trsf) { // @todo check for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 4; ++i) { + for (int j = 0; j < 4; ++j) { trsf.SetValue(i + 1, j + 1, matrix->components(i, j)); } } @@ -1415,14 +1415,42 @@ OpenCascadeKernel::faceset_helper::~faceset_helper() { kernel_->faceset_helper_ = nullptr; } +#include "IfcGeomTree.h" + +namespace { + void find_neighbours(ifcopenshell::geometry::impl::tree& tree, std::vector>& pnts, std::set& visited, int p, double eps) { + visited.insert(p); + + Bnd_Box b; + b.Set(*pnts[p].get()); + b.Enlarge(eps); + + std::vector js = tree.select_box(b, false); + for (int j : js) { + visited.insert(j); +#ifdef FACESET_HELPER_RECURSIVE + if (visited.find(j) == visited.end()) { + // @todo, making this recursive removes the dependence on the initial ordering, but will + // likely result in empty results when all vertices are within 1 eps from another point. + find_neighbours(tree, pnts, visited, j, eps); + } +#endif + } + } +} + OpenCascadeKernel::faceset_helper::faceset_helper(OpenCascadeKernel* kernel, const taxonomy::shell* shell) : kernel_(kernel) , non_manifold_(false) { kernel->faceset_helper_ = this; + // @todo use pointers? std::vector points; + std::vector loops; + for (auto& f : shell->children_as()) { for (auto& l : f->children_as()) { + loops.push_back(l); for (auto& e : l->children_as()) { // @todo make sure only cartesian points are provided here points.push_back(boost::get(e->start)); @@ -1434,22 +1462,17 @@ OpenCascadeKernel::faceset_helper::faceset_helper(OpenCascadeKernel* kernel, con std::vector vertices(pnts.size()); // @todo - /* - IfcGeom::impl::tree tree; + impl::tree tree; BRep_Builder B; Bnd_Box box; - for (size_t i = 0; i < points->size(); ++i) { - gp_Pnt* p = new gp_Pnt(); - if (kernel->convert(*(points->begin() + i), *p)) { - pnts[i].reset(p); - B.MakeVertex(vertices[i], *p, Precision::Confusion()); - tree.add(i, vertices[i]); - box.Add(*p); - } else { - delete p; - } + for (size_t i = 0; i < points.size(); ++i) { + gp_Pnt* p = new gp_Pnt(convert_xyz(points[i])); + pnts[i].reset(p); + B.MakeVertex(vertices[i], *p, Precision::Confusion()); + tree.add(i, vertices[i]); + box.Add(*p); } // Use the bbox diagonal to influence local epsilon @@ -1469,19 +1492,18 @@ OpenCascadeKernel::faceset_helper::faceset_helper(OpenCascadeKernel* kernel, con double bdiff = std::numeric_limits::infinity(); for (size_t i = 0; i < 3; ++i) { const double d = bmax[i] - bmin[i]; - if (d > kernel->getValue(GV_PRECISION) * 10. && d < bdiff) { + if (d > kernel->precision_ * 10. && d < bdiff) { bdiff = d; } } - eps_ = kernel->getValue(GV_PRECISION) * 10. * (std::min)(1.0, bdiff); + eps_ = kernel->precision_ * 10. * (std::min)(1.0, bdiff); // @todo, there a tiny possibility that the duplicate faces are triggered // for an internal boundary, that is also present as an external boundary. // This will result in non-manifold configuration then, but this is deemed // such as corner-case that it is not considered. - IfcSchema::IfcPolyLoop::list::ptr loops = IfcParse::traverse((IfcUtil::IfcBaseClass*)l)->as(); - + size_t loops_removed, non_manifold, duplicate_faces; std::map, int> edge_use; @@ -1512,9 +1534,9 @@ OpenCascadeKernel::faceset_helper::faceset_helper(OpenCascadeKernel* kernel, con find_neighbours(tree, pnts, vs, i, eps_); for (int v : vs) { - auto pt = *(points->begin() + v); + auto& pt = points[v]; // NB: insert() ignores duplicate keys - vertex_mapping_.insert({ pt->data().id() , i }); + vertex_mapping_.insert({ pt.instance->data().id() , i }); } } } @@ -1523,20 +1545,18 @@ OpenCascadeKernel::faceset_helper::faceset_helper(OpenCascadeKernel* kernel, con typedef std::set edge_set_t; std::set edge_sets; - for (auto& loop : *loops) { - auto ps = loop->Polygon(); - + for (auto& loop : loops) { std::vector > segments; edge_set_t segment_set; - loop_(ps, [&segments, &segment_set](int C, int D, bool) { + loop_(loop, [&segments, &segment_set](int C, int D, bool) { segment_set.insert({ { C, D } }); segments.push_back({ C, D }); }); if (edge_sets.find(segment_set) != edge_sets.end()) { duplicate_faces++; - duplicates_.insert(loop); + duplicates_.insert(loop->instance->data().id()); continue; } edge_sets.insert(segment_set); @@ -1567,8 +1587,7 @@ OpenCascadeKernel::faceset_helper::faceset_helper(OpenCascadeKernel* kernel, con } } - if (loops_removed || (non_manifold && l->declaration().is(IfcSchema::IfcClosedShell::Class()))) { - Logger::Warning(boost::lexical_cast(duplicate_faces) + " duplicate faces removed, " + boost::lexical_cast(loops_removed) + " loops removed and " + boost::lexical_cast(non_manifold) + " non-manifold edges for:", l); + if (loops_removed || (non_manifold && shell->closed.get_value_or(false))) { + Logger::Warning(boost::lexical_cast(duplicate_faces) + " duplicate faces removed, " + boost::lexical_cast(loops_removed) + " loops removed and " + boost::lexical_cast(non_manifold) + " non-manifold edges for:", shell->instance); } - */ } \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomTree.h b/src/ifcgeom/kernels/opencascade/IfcGeomTree.h index 73869ae50c..060217a2c7 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomTree.h +++ b/src/ifcgeom/kernels/opencascade/IfcGeomTree.h @@ -23,7 +23,7 @@ #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/Converter.h" #include "../../../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h" #include @@ -33,7 +33,7 @@ #include #include -namespace IfcGeom { +namespace ifcopenshell { namespace geometry { namespace impl { template @@ -259,30 +259,30 @@ namespace IfcGeom { tree() {}; tree(IfcParse::IfcFile& f) { - add_file(f, IfcGeom::IteratorSettings()); + add_file(f, ifcopenshell::geometry::settings()); } - tree(IfcParse::IfcFile& f, const IfcGeom::IteratorSettings& settings) { + tree(IfcParse::IfcFile& f, const ifcopenshell::geometry::settings& settings) { add_file(f, settings); } - void add_file(IfcParse::IfcFile& f, const IfcGeom::IteratorSettings& settings) { - IfcGeom::IteratorSettings settings_ = settings; - settings_.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true); - settings_.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, true); - settings_.set(IfcGeom::IteratorSettings::SEW_SHELLS, true); + void add_file(IfcParse::IfcFile& f, const ifcopenshell::geometry::settings& settings) { + ifcopenshell::geometry::settings settings_ = settings; + settings_.set(ifcopenshell::geometry::settings::DISABLE_TRIANGULATION, true); + settings_.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, true); + settings_.set(ifcopenshell::geometry::settings::SEW_SHELLS, true); - IfcGeom::Iterator it(settings_, &f); + Iterator it(settings_, &f); if (it.initialize()) { do { - IfcGeom::NativeElement* elem = (IfcGeom::NativeElement*)it.get(); + NativeElement* elem = (NativeElement*)it.get(); add((IfcUtil::IfcBaseEntity*)f.instance_by_id(elem->id()), ((OpenCascadeShape*)elem->geometry().as_compound())->shape()); } while (it.next()); } } }; -} +}} #endif diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp index 6e45b00859..6d11395d79 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp @@ -12,7 +12,7 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(const settings& setti // @todo check gp_GTrsf trsf; for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 4; ++i) { + for (int j = 0; j < 4; ++j) { trsf.SetValue(i + 1, j + 1, place.components(i, j)); } } diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index 689a539f27..ecfef11143 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -163,7 +163,9 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcFaceBasedSurfaceModel* ins } taxonomy::item* mapping::map_impl(const IfcSchema::IfcConnectedFaceSet* inst) { - return map_to_collection(this, inst->CfsFaces()); + auto shell = map_to_collection(this, inst->CfsFaces()); + shell->closed = inst->declaration().is(IfcSchema::IfcClosedShell::Class()); + return shell; } taxonomy::item* mapping::map_impl(const IfcSchema::IfcFace* inst) { diff --git a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp index 28605992df..91465eabd4 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp +++ b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp @@ -96,7 +96,7 @@ ifcopenshell::geometry::ConversionResultShape* ifcopenshell::geometry::Represent // @todo, check gp_GTrsf trsf; for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 4; ++i) { + for (int j = 0; j < 4; ++j) { trsf.SetValue(i + 1, j + 1, it->Placement().components(i, j)); } } @@ -241,7 +241,7 @@ bool ifcopenshell::geometry::Representation::BRep::calculate_projected_surface_a // @todo check gp_GTrsf trsf; for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 4; ++i) { + for (int j = 0; j < 4; ++j) { trsf.SetValue(i + 1, j + 1, place.components(i, j)); } } diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index 3be8ec2f6d..b657d4ae32 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -193,6 +193,8 @@ struct collection : public geom_item { }; struct shell : public collection { + boost::optional closed; + virtual item* clone() const { return new shell(*this); } virtual kinds kind() const { return SHELL; } }; From ca2a4f243d5e330d57a4d9b3127f6e6af5510dc3 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 1 Sep 2019 09:18:29 +0200 Subject: [PATCH 170/235] initialize units in mapping --- src/ifcgeom/schema/mapping.cpp | 68 ++++++++++++++++++++++++++++++++++ src/ifcgeom/schema/mapping.h | 8 +++- 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index ecfef11143..d057166367 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -841,3 +841,71 @@ std::map mapping::get_layers(IfcUtil::IfcB } return layers; } + +#include "../../ifcparse/IfcSIPrefix.h" + +void mapping::initialize_units_() { + // Set default units, set length to meters, angles to undefined + length_unit_ = 1.; + angle_unit_ = -1.; + length_unit_name_ = "METER"; + + auto unit_assignments = file_->instances_by_type(); + if (unit_assignments->size() != 1) { + Logger::Warning("Not a single unit assignment in file"); + } + auto unit_assignment = *unit_assignments->begin(); + + bool length_unit_encountered = false, angle_unit_encountered = false; + + try { + IfcEntityList::ptr units = unit_assignment->Units(); + if (!units || !units->size()) { + Logger::Warning("No unit information found"); + } else { + for (IfcEntityList::it it = units->begin(); it != units->end(); ++it) { + IfcUtil::IfcBaseClass* base = *it; + if (base->declaration().is(IfcSchema::IfcNamedUnit::Class())) { + IfcSchema::IfcNamedUnit* named_unit = base->as(); + if (named_unit->UnitType() == IfcSchema::IfcUnitEnum::IfcUnit_LENGTHUNIT || + named_unit->UnitType() == IfcSchema::IfcUnitEnum::IfcUnit_PLANEANGLEUNIT) { + std::string current_unit_name; + const double current_unit_magnitude = IfcParse::get_SI_equivalent(named_unit); + if (current_unit_magnitude != 0.) { + if (named_unit->declaration().is(IfcSchema::IfcConversionBasedUnit::Class())) { + IfcSchema::IfcConversionBasedUnit* u = (IfcSchema::IfcConversionBasedUnit*)base; + current_unit_name = u->Name(); + } else if (named_unit->declaration().is(IfcSchema::IfcSIUnit::Class())) { + IfcSchema::IfcSIUnit* si_unit = named_unit->as(); + if (si_unit->hasPrefix()) { + current_unit_name = IfcSchema::IfcSIPrefix::ToString(si_unit->Prefix()); + } + current_unit_name += IfcSchema::IfcSIUnitName::ToString(si_unit->Name()); + } + if (named_unit->UnitType() == IfcSchema::IfcUnitEnum::IfcUnit_LENGTHUNIT) { + length_unit_name_ = current_unit_name; + length_unit_ = current_unit_magnitude; + length_unit_encountered = true; + } else { + angle_unit_ = current_unit_magnitude; + angle_unit_encountered = true; + } + } + } + } + } + } + } catch (const IfcParse::IfcException& ex) { + std::stringstream ss; + ss << "Failed to determine unit information '" << ex.what() << "'"; + Logger::Message(Logger::LOG_ERROR, ss.str()); + } + + if (!length_unit_encountered) { + Logger::Warning("No length unit encountered"); + } + + if (!angle_unit_encountered) { + Logger::Warning("No plane angle unit encountered"); + } +} diff --git a/src/ifcgeom/schema/mapping.h b/src/ifcgeom/schema/mapping.h index 4083966f0d..150196122c 100644 --- a/src/ifcgeom/schema/mapping.h +++ b/src/ifcgeom/schema/mapping.h @@ -16,8 +16,14 @@ namespace geometry { class POSTFIX_SCHEMA(mapping) : public abstract_mapping { private: IfcParse::IfcFile* file_; + double length_unit_, angle_unit_; + std::string length_unit_name_; + + void initialize_units_(); public: - POSTFIX_SCHEMA(mapping)(IfcParse::IfcFile* file) : file_(file) {} + POSTFIX_SCHEMA(mapping)(IfcParse::IfcFile* file) : file_(file) { + initialize_units_(); + } virtual ifcopenshell::geometry::taxonomy::item* map(const IfcUtil::IfcBaseClass*); virtual void get_representations(std::vector& tasks, std::vector& filters, settings& s); virtual std::map get_layers(IfcUtil::IfcBaseEntity*); From 2e7c43f59017273d43923000eda98838c8911e1f Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 1 Sep 2019 10:36:49 +0200 Subject: [PATCH 171/235] Work on placements --- src/ifcgeom/schema/mapping.cpp | 73 ++++++++++++++++++++++++++++++---- src/ifcgeom/schema/mapping.h | 3 +- src/ifcgeom/taxonomy.h | 12 +++++- 3 files changed, 78 insertions(+), 10 deletions(-) diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index d057166367..caedda2c6f 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -236,33 +236,90 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcProduct* inst) { } taxonomy::item* mapping::map_impl(const IfcSchema::IfcAxis2Placement3D* inst) { - // @todo length unit - return new taxonomy::matrix4(); + Eigen::Vector3d o, axis(0, 0, 1), refDirection, X(1, 0, 0); + { + taxonomy::point3 v = as(map(inst->Location())); + o = v.components; + } + const bool hasAxis = inst->hasAxis(); + const bool hasRef = inst->hasRefDirection(); + + if (hasAxis != hasRef) { + Logger::Warning("Axis and RefDirection should be specified together", inst); + } + + if (hasAxis) { + taxonomy::point3 v = as(map(inst->Axis())); + axis = v.components; + } + + if (hasRef) { + taxonomy::point3 v = as(map(inst->RefDirection())); + refDirection = v.components; + } else { + if (acos(axis.dot(X)) > 1.e-5) { + refDirection = { 1., 0., 0. }; + } else { + refDirection = { 0., 0., 1. }; + } + auto Xvec = axis.dot(refDirection) * axis; + auto Xaxis = refDirection - Xvec; + refDirection = Xaxis; + } + return new taxonomy::matrix4(o, axis, refDirection); } taxonomy::item* mapping::map_impl(const IfcSchema::IfcCartesianTransformationOperator2DnonUniform* inst) { - // @todo length unit + // @todo return new taxonomy::matrix4(); } taxonomy::item* mapping::map_impl(const IfcSchema::IfcCartesianTransformationOperator3DnonUniform* inst) { - // @todo length unit + // @todo return new taxonomy::matrix4(); } taxonomy::item* mapping::map_impl(const IfcSchema::IfcCartesianTransformationOperator2D* inst) { - // @todo length unit + // @todo return new taxonomy::matrix4(); } taxonomy::item* mapping::map_impl(const IfcSchema::IfcCartesianTransformationOperator3D* inst) { - // @todo length unit + // @todo return new taxonomy::matrix4(); } taxonomy::item* mapping::map_impl(const IfcSchema::IfcLocalPlacement* inst) { - // @todo length unit - return new taxonomy::matrix4(); + IfcSchema::IfcLocalPlacement* current = (IfcSchema::IfcLocalPlacement*)inst; + auto m4 = new taxonomy::matrix4; + for (;;) { + IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement(); + if (relplacement->declaration().is(IfcSchema::IfcAxis2Placement3D::Class())) { + taxonomy::matrix4 trsf2 = as(map(relplacement)); + // @todo check + m4->components = trsf2.components * m4->components; + } + if (current->hasPlacementRelTo()) { + IfcSchema::IfcObjectPlacement* parent = current->PlacementRelTo(); + IfcSchema::IfcProduct::list::ptr parentPlaces = parent->PlacesObject(); + bool parentPlacesType = false; + for (IfcSchema::IfcProduct::list::it iter = parentPlaces->begin(); + iter != parentPlaces->end(); ++iter) { + if ((*iter)->declaration().is(*placement_rel_to_)) { + parentPlacesType = true; + } + } + if (parentPlacesType) { + break; + } else if (parent->declaration().is(IfcSchema::IfcLocalPlacement::Class())) { + current = (IfcSchema::IfcLocalPlacement*)current->PlacementRelTo(); + } else { + break; + } + } else { + break; + } + } } IfcSchema::IfcProduct::list::ptr mapping::products_represented_by(const IfcSchema::IfcRepresentation* representation) { diff --git a/src/ifcgeom/schema/mapping.h b/src/ifcgeom/schema/mapping.h index 150196122c..c3334a4e61 100644 --- a/src/ifcgeom/schema/mapping.h +++ b/src/ifcgeom/schema/mapping.h @@ -18,10 +18,11 @@ namespace geometry { IfcParse::IfcFile* file_; double length_unit_, angle_unit_; std::string length_unit_name_; + const IfcParse::declaration* placement_rel_to_; void initialize_units_(); public: - POSTFIX_SCHEMA(mapping)(IfcParse::IfcFile* file) : file_(file) { + POSTFIX_SCHEMA(mapping)(IfcParse::IfcFile* file) : file_(file), placement_rel_to_(0) { initialize_units_(); } virtual ifcopenshell::geometry::taxonomy::item* map(const IfcUtil::IfcBaseClass*); diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index b657d4ae32..8ed21d8dd2 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -45,8 +45,18 @@ struct matrix4 : public item { Eigen::Matrix4d components; + matrix4() : components(Eigen::Matrix4d::Identity()), tag(IDENTITY) {} matrix4(const Eigen::Matrix4d& c) : components(c), tag(OTHER) {} - matrix4() : components(Eigen::Matrix4d::Identity()), tag(IDENTITY) {} + matrix4(const Eigen::Vector3d& o, const Eigen::Vector3d& z, const Eigen::Vector3d& x) : tag(AFFINE_WO_SCALE) { + auto X = x.normalized(); + auto Y = z.cross(x).normalized(); + auto Z = z.normalized(); + components << + X(0), Y(0), Z(0), o(0), + X(1), Y(1), Z(1), o(0), + X(2), Y(2), Z(2), o(0), + 0, 0, 0, 1.; + } virtual item* clone() const { return new matrix4(*this); } virtual kinds kind() const { return MATRIX4; } From 816c0d3618a8a2d5c94b471736ba539355979434 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 1 Sep 2019 13:36:46 +0200 Subject: [PATCH 172/235] Fix placements --- src/ifcgeom/schema/mapping.cpp | 10 ++++++++++ src/ifcgeom/schema/mapping.i | 2 +- src/ifcgeom/schema_agnostic/Converter.cpp | 3 +++ src/ifcgeom/taxonomy.h | 4 ++-- src/serializers/ColladaSerializer.cpp | 10 +++++----- 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index caedda2c6f..dd7a605dae 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -223,6 +223,15 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcPolyLoop* inst) { taxonomy::item* mapping::map_impl(const IfcSchema::IfcCartesianPoint* inst) { auto coords = inst->Coordinates(); return new taxonomy::point3( + coords.size() >= 1 ? coords[0] * length_unit_ : 0., + coords.size() >= 2 ? coords[1] * length_unit_ : 0., + coords.size() >= 3 ? coords[2] * length_unit_ : 0. + ); +} + +taxonomy::item* mapping::map_impl(const IfcSchema::IfcDirection* inst) { + auto coords = inst->DirectionRatios(); + return new taxonomy::direction3( coords.size() >= 1 ? coords[0] : 0., coords.size() >= 2 ? coords[1] : 0., coords.size() >= 3 ? coords[2] : 0. @@ -320,6 +329,7 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcLocalPlacement* inst) { break; } } + return m4; } IfcSchema::IfcProduct::list::ptr mapping::products_represented_by(const IfcSchema::IfcRepresentation* representation) { diff --git a/src/ifcgeom/schema/mapping.i b/src/ifcgeom/schema/mapping.i index c794c6f447..bc94010fd7 100644 --- a/src/ifcgeom/schema/mapping.i +++ b/src/ifcgeom/schema/mapping.i @@ -118,7 +118,7 @@ BIND(IfcPolyLoop); #endif BIND(IfcCartesianPoint); -// BIND(IfcDirection); +BIND(IfcDirection); // BIND(IfcAxis2Placement2D); BIND(IfcAxis2Placement3D); // BIND(IfcAxis1Placement); diff --git a/src/ifcgeom/schema_agnostic/Converter.cpp b/src/ifcgeom/schema_agnostic/Converter.cpp index 19843b11a8..97a6f41d78 100644 --- a/src/ifcgeom/schema_agnostic/Converter.cpp +++ b/src/ifcgeom/schema_agnostic/Converter.cpp @@ -42,6 +42,9 @@ ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create // @todo decide how to get placement from product auto placement = (taxonomy::geom_item*) mapping_->map(product); + if (placement == nullptr) { + return nullptr; + } kernel_->convert(rep_item, shapes); shape = new ifcopenshell::geometry::Representation::BRep(s, representation_id_builder.str(), shapes); diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index 8ed21d8dd2..35a79e176c 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -53,8 +53,8 @@ struct matrix4 : public item { auto Z = z.normalized(); components << X(0), Y(0), Z(0), o(0), - X(1), Y(1), Z(1), o(0), - X(2), Y(2), Z(2), o(0), + X(1), Y(1), Z(1), o(1), + X(2), Y(2), Z(2), o(2), 0, 0, 0, 1.; } diff --git a/src/serializers/ColladaSerializer.cpp b/src/serializers/ColladaSerializer.cpp index b9ca3a6786..4267ed7f3b 100644 --- a/src/serializers/ColladaSerializer.cpp +++ b/src/serializers/ColladaSerializer.cpp @@ -204,13 +204,13 @@ void ColladaSerializer::ColladaExporter::ColladaScene::add( // @todo verify - const double* posmatrix = transformation_towrite->data().components.data(); + const double* m = transformation_towrite->data().components.data(); double matrix_array[4][4] = { - { (double)posmatrix[0], (double)posmatrix[3], (double)posmatrix[6], (double)posmatrix[9] }, - { (double)posmatrix[1], (double)posmatrix[4], (double)posmatrix[7], (double)posmatrix[10] }, - { (double)posmatrix[2], (double)posmatrix[5], (double)posmatrix[8], (double)posmatrix[11] }, - { 0, 0, 0, 1 } + { m[0], m[4], m[8], m[12] }, + { m[1], m[5], m[9], m[13] }, + { m[2], m[6], m[10], m[14] }, + { m[3], m[7], m[11], m[15] } }; /// @todo: TFK: Rather than applying this offset to all leafs (which might be undesirable) should this offset be applied to a node higher up in the hierarchy? From 7f8bed9922f7feacd9667fe3341f4f55089f6622 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 1 Sep 2019 16:29:00 +0200 Subject: [PATCH 173/235] Begin reenable CGAL kernel --- .../kernel_agnostic/AbstractKernel.cpp | 3 + ...tions.cpp => CgalConversionFunctions.cpp_} | 0 .../cgal/CgalConversionResult.cpp | 35 +- .../cgal/CgalConversionResult.h | 59 +-- .../kernels/cgal/CgalEntityMapping.cpp | 96 ---- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 121 ----- .../cgal/CgalEntityMappingCreateCache.h | 6 - .../kernels/cgal/CgalEntityMappingCurve.h | 6 - .../cgal/CgalEntityMappingDeclaration.h | 10 - .../kernels/cgal/CgalEntityMappingDefine.h | 18 - .../kernels/cgal/CgalEntityMappingFace.h | 6 - .../cgal/CgalEntityMappingPurgeCache.h | 6 - .../kernels/cgal/CgalEntityMappingShape.h | 20 - .../kernels/cgal/CgalEntityMappingShapeType.h | 14 - .../kernels/cgal/CgalEntityMappingShapes.h | 13 - .../kernels/cgal/CgalEntityMappingUndefine.h | 18 - .../kernels/cgal/CgalEntityMappingWire.h | 6 - ...cGeomCurves.cpp => CgalIfcGeomCurves.cpp_} | 0 ...IfcGeomFaces.cpp => CgalIfcGeomFaces.cpp_} | 0 ...mitives.cpp => CgalIfcGeomPrimitives.cpp_} | 0 ...cGeomShapes.cpp => CgalIfcGeomShapes.cpp_} | 0 ...s.cpp => CgalIfcGeomShapesWithStyles.cpp_} | 0 ...IfcGeomWires.cpp => CgalIfcGeomWires.cpp_} | 0 src/ifcgeom/kernels/cgal/CgalKernel.cpp | 483 +++++++++--------- src/ifcgeom/kernels/cgal/CgalKernel.cpp_ | 267 ++++++++++ src/ifcgeom/kernels/cgal/CgalKernel.h | 77 +-- .../kernels/opencascade/IfcGeomShapes.cpp | 7 +- 27 files changed, 546 insertions(+), 725 deletions(-) rename src/ifcgeom/kernels/cgal/{CgalConversionFunctions.cpp => CgalConversionFunctions.cpp_} (100%) rename src/ifcgeom/{schema_agnostic => kernels}/cgal/CgalConversionResult.cpp (65%) rename src/ifcgeom/{schema_agnostic => kernels}/cgal/CgalConversionResult.h (65%) delete mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp delete mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMapping.h delete mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingCreateCache.h delete mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingCurve.h delete mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingDeclaration.h delete mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingDefine.h delete mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingFace.h delete mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingPurgeCache.h delete mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingShape.h delete mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingShapeType.h delete mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingShapes.h delete mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingUndefine.h delete mode 100644 src/ifcgeom/kernels/cgal/CgalEntityMappingWire.h rename src/ifcgeom/kernels/cgal/{CgalIfcGeomCurves.cpp => CgalIfcGeomCurves.cpp_} (100%) rename src/ifcgeom/kernels/cgal/{CgalIfcGeomFaces.cpp => CgalIfcGeomFaces.cpp_} (100%) rename src/ifcgeom/kernels/cgal/{CgalIfcGeomPrimitives.cpp => CgalIfcGeomPrimitives.cpp_} (100%) rename src/ifcgeom/kernels/cgal/{CgalIfcGeomShapes.cpp => CgalIfcGeomShapes.cpp_} (100%) rename src/ifcgeom/kernels/cgal/{CgalIfcGeomShapesWithStyles.cpp => CgalIfcGeomShapesWithStyles.cpp_} (100%) rename src/ifcgeom/kernels/cgal/{CgalIfcGeomWires.cpp => CgalIfcGeomWires.cpp_} (100%) create mode 100644 src/ifcgeom/kernels/cgal/CgalKernel.cpp_ diff --git a/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp index 10168dfaa8..65bfce6556 100644 --- a/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp +++ b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp @@ -2,6 +2,7 @@ #include "../../ifcgeom/schema_agnostic/IfcGeomElement.h" #include "../../ifcgeom/kernels/opencascade/OpenCascadeKernel.h" +#include "../../ifcgeom/kernels/cgal/CgalKernel.h" namespace { /* A compile-time for loop over the taxonomy kinds */ @@ -34,6 +35,8 @@ ifcopenshell::geometry::kernels::AbstractKernel* ifcopenshell::geometry::kernels const std::string geometry_library_lower = boost::to_lower_copy(geometry_library); if (geometry_library_lower == "opencascade") { return new OpenCascadeKernel; + } else if (geometry_library_lower == "cgal") { + return new CgalKernel; } else { throw IfcParse::IfcException("No geometry kernel registered for " + geometry_library); } diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp_ similarity index 100% rename from src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp rename to src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp_ diff --git a/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp similarity index 65% rename from src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.cpp rename to src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index cd59ecd70a..86f5f93cbb 100644 --- a/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -3,18 +3,23 @@ #include "../../../ifcparse/IfcLogger.h" #include "../../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h" -template -void triangulate_helper(const cgal_shape_t& shape_const, const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation* t, int surface_style_id) { - // Copy is made because triangulate_faces() does not accept a const argument - cgal_shape_t s = shape_const; +void ifcopenshell::geometry::CgalShape::Triangulate(const settings& settings, const ifcopenshell::geometry::taxonomy::matrix4& place, Representation::Triangulation* t, int surface_style_id) const { + // Copy is made because triangulate_faces() does not accept a const argument + cgal_shape_t s = shape_; - const cgal_placement_t& trsf = dynamic_cast(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 (!place.components.isIdentity()) { + const auto& m = place.components; + + // @todo check + const cgal_placement_t trsf( + m(0, 0), m(0, 1), m(0, 2), m(0, 3), + m(1, 0), m(1, 1), m(1, 2), m(1, 3), + m(2, 0), m(2, 1), m(2, 2), m(2, 3)); + + // Apply transformation + for (auto &vertex : vertices(s)) { + vertex->point() = vertex->point().transform(trsf); + } } if (!s.is_valid()) { @@ -78,11 +83,3 @@ void triangulate_helper(const cgal_shape_t& shape_const, const IfcGeom::Iterator } } - -void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation* 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* t, int surface_style_id) const { - triangulate_helper(shape_, settings, place, t, surface_style_id); -} diff --git a/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.h b/src/ifcgeom/kernels/cgal/CgalConversionResult.h similarity index 65% rename from src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.h rename to src/ifcgeom/kernels/cgal/CgalConversionResult.h index df085e0c8d..35aaa5d61d 100644 --- a/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.h +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.h @@ -20,12 +20,7 @@ #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 #include @@ -59,49 +54,9 @@ typedef boost::graph_traits>::face_descriptor cgal_f #include "../../../ifcgeom/schema_agnostic/ConversionResult.h" -namespace IfcGeom { +namespace ifcopenshell { namespace geometry { - 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 { + class CgalShape : public ConversionResultShape { public: CgalShape(const cgal_shape_t& shape) : shape_(shape) @@ -110,9 +65,7 @@ namespace IfcGeom { 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 * t, int surface_style_id) const; - - virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const; + virtual void Triangulate(const settings& settings, const ifcopenshell::geometry::taxonomy::matrix4& place, Representation::Triangulation* t, int surface_style_id) const; virtual void Serialize(std::string&) const { throw std::runtime_error("Not implemented"); @@ -122,6 +75,10 @@ namespace IfcGeom { return new CgalShape(shape_); } + virtual bool is_manifold() const { + throw std::runtime_error("Not implemented"); + } + virtual int surface_genus() const { throw std::runtime_error("Not implemented"); } @@ -129,6 +86,6 @@ namespace IfcGeom { cgal_shape_t shape_; }; -} +}} #endif diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp deleted file mode 100644 index a604069f8b..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp +++ /dev/null @@ -1,96 +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 . * -* * -********************************************************************************/ - -#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()))); - 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::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; -} diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h deleted file mode 100644 index 51874f1550..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ /dev/null @@ -1,121 +0,0 @@ -/******************************************************************************** -* * -* This file is part of IfcOpenShell. * -* * -* IfcOpenShell is free software: you can redistribute it and/or modify * -* it under the terms of the Lesser GNU General Public License as published by * -* the Free Software Foundation, either version 3.0 of the License, or * -* (at your option) any later version. * -* * -* IfcOpenShell is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -* Lesser GNU General Public License for more details. * -* * -* You should have received a copy of the Lesser GNU General Public License * -* along with this program. If not, see . * -* * -********************************************************************************/ - -/******************************************************************************** - * * - * This file 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); diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingCreateCache.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingCreateCache.h deleted file mode 100644 index ebfb8daca7..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingCreateCache.h +++ /dev/null @@ -1,6 +0,0 @@ -#include "CgalEntityMappingUndefine.h" -#define CLASS(T,V) \ - std::map T; -#include "CgalEntityMappingDefine.h" - -#include "CgalEntityMapping.h" diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingCurve.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingCurve.h deleted file mode 100644 index 5bebf39992..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingCurve.h +++ /dev/null @@ -1,6 +0,0 @@ -#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" \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingDeclaration.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingDeclaration.h deleted file mode 100644 index 7101613c26..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingDeclaration.h +++ /dev/null @@ -1,10 +0,0 @@ -#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" \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingDefine.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingDefine.h deleted file mode 100644 index 65f8704a81..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingDefine.h +++ /dev/null @@ -1,18 +0,0 @@ -#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 \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingFace.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingFace.h deleted file mode 100644 index 65087a1a5f..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingFace.h +++ /dev/null @@ -1,6 +0,0 @@ -#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" \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingPurgeCache.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingPurgeCache.h deleted file mode 100644 index ea8c2c2554..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingPurgeCache.h +++ /dev/null @@ -1,6 +0,0 @@ -#include "CgalEntityMappingUndefine.h" -#define CLASS(T,V) \ - T.clear(); -#include "CgalEntityMappingDefine.h" - -#include "CgalEntityMapping.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingShape.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingShape.h deleted file mode 100644 index 14dc9d51e1..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingShape.h +++ /dev/null @@ -1,20 +0,0 @@ -#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" \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingShapeType.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingShapeType.h deleted file mode 100644 index ec25d81d25..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingShapeType.h +++ /dev/null @@ -1,14 +0,0 @@ -#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" diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingShapes.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingShapes.h deleted file mode 100644 index 700b4a08a2..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingShapes.h +++ /dev/null @@ -1,13 +0,0 @@ -#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" diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingUndefine.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingUndefine.h deleted file mode 100644 index d2d537a073..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingUndefine.h +++ /dev/null @@ -1,18 +0,0 @@ -#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 \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingWire.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingWire.h deleted file mode 100644 index 459ad8267c..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingWire.h +++ /dev/null @@ -1,6 +0,0 @@ -#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" diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomCurves.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomCurves.cpp_ similarity index 100% rename from src/ifcgeom/kernels/cgal/CgalIfcGeomCurves.cpp rename to src/ifcgeom/kernels/cgal/CgalIfcGeomCurves.cpp_ diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp_ similarity index 100% rename from src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp rename to src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp_ diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp_ similarity index 100% rename from src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp rename to src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp_ diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp_ similarity index 100% rename from src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp rename to src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp_ diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp_ similarity index 100% rename from src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp rename to src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp_ diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp_ similarity index 100% rename from src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp rename to src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp_ diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index c885fa5974..f78f39a18c 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -1,267 +1,246 @@ -/******************************************************************************** -* * -* This file is part of IfcOpenShell. * -* * -* IfcOpenShell is free software: you can redistribute it and/or modify * -* it under the terms of the Lesser GNU General Public License as published by * -* the Free Software Foundation, either version 3.0 of the License, or * -* (at your option) any later version. * -* * -* IfcOpenShell is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -* Lesser GNU General Public License for more details. * -* * -* You should have received a copy of the Lesser GNU General Public License * -* along with this program. If not, see . * -* * -********************************************************************************/ +/******************************************************************************** + * * + * This file is part of IfcOpenShell. * + * * + * IfcOpenShell is free software: you can redistribute it and/or modify * + * it under the terms of the Lesser GNU General Public License as published by * + * the Free Software Foundation, either version 3.0 of the License, or * + * (at your option) any later version. * + * * + * IfcOpenShell is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * Lesser GNU General Public License for more details. * + * * + * You should have received a copy of the Lesser GNU General Public License * + * along with this program. If not, see . * + * * + ********************************************************************************/ #include "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; - } - }; -} +#include "../../../ifcparse/IfcLogger.h" +#include "../../../ifcgeom/kernels/cgal/CgalConversionResult.h" -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); -} +using namespace ifcopenshell::geometry; +using namespace ifcopenshell::geometry::kernels; -#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()) != 0) { - gp_GTrsf2d gtrsf2d; - convert(op2dnonu, gtrsf2d); - return gtrsf2d.Form() == gp_Identity; - } else if ((op2d = l->as()) != 0) { - gp_Trsf2d trsf2d; - convert(op2d, trsf2d); - return trsf2d.Form() == gp_Identity; - } else if ((op3dnonu = l->as()) != 0) { - gp_GTrsf gtrsf; - convert(op3dnonu, gtrsf); - return gtrsf.Form() == gp_Identity; - } else if ((op3d = l->as()) != 0) { - gp_Trsf trsf; - convert(op3d, trsf); - return trsf.Form() == gp_Identity; - } else if ((ax2d = l->as()) != 0) { - gp_Trsf2d trsf2d; - convert(ax2d, trsf2d); - return trsf2d.Form() == gp_Identity; - } else if ((ax3d = l->as()) != 0) { - gp_Trsf trsf; - convert(ax3d, trsf); - return trsf.Form() == gp_Identity; - } else { - throw IfcParse::IfcException("Invalid valuation for IfcAxis2Placement / IfcCartesianTransformationOperator"); +void CgalKernel::remove_duplicate_points_from_loop(cgal_wire_t& polygon) { + std::set 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]); } - */ } -bool IfcGeom::CgalKernel::apply_layerset(const IfcSchema::IfcProduct* product, IfcGeom::ConversionResults& shapes) { - throw std::runtime_error("not implemented"); +CGAL::Polyhedron_3 CgalKernel::create_polyhedron(std::list &face_list) { + + // Naive creation + CGAL::Polyhedron_3 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(); + } 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; } -bool IfcGeom::CgalKernel::validate_quantities(const IfcSchema::IfcProduct* product, const IfcGeom::Representation::BRep& brep) { - throw std::runtime_error("not implemented"); +CGAL::Polyhedron_3 CgalKernel::create_polyhedron(CGAL::Nef_polyhedron_3 &nef_polyhedron) { + if (nef_polyhedron.is_simple()) { + try { + CGAL::Polyhedron_3 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(); + } + } else { + Logger::Message(Logger::LOG_ERROR, "Nef polyhedron not simple: cannot create polyhedron!"); + return CGAL::Polyhedron_3(); + } } -bool IfcGeom::CgalKernel::convert_placement(IfcUtil::IfcBaseClass* item, ConversionResultPlacement*& trsf) { - if (item->as()) { - cgal_placement_t cgal_trsf; - if (convert(item->as(), cgal_trsf)) { - trsf = new CgalPlacement(cgal_trsf); - return true; - } - } - return false; +CGAL::Nef_polyhedron_3 CgalKernel::create_nef_polyhedron(std::list &face_list) { + CGAL::Polyhedron_3 polyhedron = create_polyhedron(face_list); + CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron); + CGAL::Nef_polyhedron_3 nef_polyhedron; + try { + nef_polyhedron = CGAL::Nef_polyhedron_3(polyhedron); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Conversion to Nef polyhedron failed!"); + return nef_polyhedron; + } return nef_polyhedron; } -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 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() ) { - 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 nef_brep_cut_result; - - try { - nef_brep_cut_result = CGAL::Nef_polyhedron_3(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 nef_opening; - - try { - nef_opening = CGAL::Nef_polyhedron_3(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; +CGAL::Nef_polyhedron_3 CgalKernel::create_nef_polyhedron(CGAL::Polyhedron_3 &polyhedron) { + if (polyhedron.is_valid()) { + CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron); + CGAL::Nef_polyhedron_3 nef_polyhedron; + try { + nef_polyhedron = CGAL::Nef_polyhedron_3(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(); + } +} + +bool CgalKernel::convert(const taxonomy::shell* l, cgal_shape_t& shape) { + auto faces = l->children_as(); + + std::list face_list; + for (auto& f : faces) { + bool success = false; + cgal_face_t face; + + try { + success = convert(f, face); + } catch (...) {} + + if (!success) { + Logger::Message(Logger::LOG_WARNING, "Failed to convert face:", f->instance); + 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 CgalKernel::convert(const taxonomy::face* face, cgal_face_t& result) { + auto bounds = face->children_as(); + + int num_outer_bounds = 0; + + for (auto& bound : bounds) { + if (bound->external.get_value_or(false)) num_outer_bounds++; + } + + if (num_outer_bounds != 1) { + Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", face->instance); + return false; + } + + cgal_face_t mf; + + for (auto& bound : bounds) { + + const bool is_interior = !bound->external.get_value_or(false); + + cgal_wire_t wire; + if (!convert(bound, wire)) { + Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", bound->instance); + return false; + } + + if (!is_interior) { + mf.outer = wire; + } else { + mf.inner.push_back(wire); + } + } + + result = mf; + + // std::cout << "Face: " << std::endl; + // for (auto &point: face.outer) { + // std::cout << "\tPoint(" << point << ")" << std::endl; + // } + + return true; +} + +bool CgalKernel::convert(const taxonomy::loop* loop, cgal_wire_t& result) { + // @todo only implement polygonal loops + + auto edges = loop->children_as(); + std::vector points; + + for (auto& e : edges) { + if (e->basis) { + return false; + } + points.push_back(boost::get(e->start)); + } + + // Parse and store the points in a sequence + cgal_wire_t polygon = std::vector(); + for (auto& p : points) { + cgal_point_t pnt(p.components(0), p.components(1), p.components(2)); + 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:", loop->instance); + 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(), loop->instance); + } + + if (count < 3) { + Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", loop->instance); + return false; + } + + result = polygon; + + // std::cout << "PolyLoop: " << std::endl; + // for (auto &point: polygon) { + // std::cout << "\tPoint(" << point << ")" << std::endl; + // } + + return true; +} + + +bool CgalKernel::convert_impl(const taxonomy::shell *shell, ifcopenshell::geometry::ConversionResults& results) { + cgal_shape_t shape; + if (!convert(shell, shape)) { + return false; + } + results.emplace_back(ConversionResult( + shell->instance->data().id(), + shell->matrix, + new CgalShape(shape), + shell->surface_style + )); + return true; } diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp_ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp_ new file mode 100644 index 0000000000..c885fa5974 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp_ @@ -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 . * +* * +********************************************************************************/ + +#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()) != 0) { + gp_GTrsf2d gtrsf2d; + convert(op2dnonu, gtrsf2d); + return gtrsf2d.Form() == gp_Identity; + } else if ((op2d = l->as()) != 0) { + gp_Trsf2d trsf2d; + convert(op2d, trsf2d); + return trsf2d.Form() == gp_Identity; + } else if ((op3dnonu = l->as()) != 0) { + gp_GTrsf gtrsf; + convert(op3dnonu, gtrsf); + return gtrsf.Form() == gp_Identity; + } else if ((op3d = l->as()) != 0) { + gp_Trsf trsf; + convert(op3d, trsf); + return trsf.Form() == gp_Identity; + } else if ((ax2d = l->as()) != 0) { + gp_Trsf2d trsf2d; + convert(ax2d, trsf2d); + return trsf2d.Form() == gp_Identity; + } else if ((ax3d = l->as()) != 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()) { + cgal_placement_t cgal_trsf; + if (convert(item->as(), 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 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() ) { + 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 nef_brep_cut_result; + + try { + nef_brep_cut_result = CGAL::Nef_polyhedron_3(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 nef_opening; + + try { + nef_opening = CGAL::Nef_polyhedron_3(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; +} diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 4f3186589d..0041c9c172 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -48,17 +48,12 @@ inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance=ALMO #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" +#include "../../../ifcgeom/kernels/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::HalfedgeDS> { private: std::list *face_list; @@ -102,66 +97,32 @@ public: } }; -namespace IfcGeom { +namespace ifcopenshell { +namespace geometry { +namespace kernels { - class IFC_GEOM_API CgalCache { - public: -#include "CgalEntityMappingCreateCache.h" - std::map Shape; - }; - - class IFC_GEOM_API MAKE_TYPE_NAME(CgalKernel) : public MAKE_TYPE_NAME(AbstractKernel) { + class IFC_GEOM_API CgalKernel : public AbstractKernel { public: - MAKE_TYPE_NAME(CgalKernel)() - : MAKE_TYPE_NAME(AbstractKernel)("cgal") {} + CgalKernel() + : AbstractKernel("cgal") {} -#ifndef NO_CACHE - CgalCache cache; -#endif + void remove_duplicate_points_from_loop(cgal_wire_t& polygon); - IfcGeom::ShapeType shape_type(const IfcUtil::IfcBaseClass* L); + CGAL::Polyhedron_3 create_polyhedron(std::list &face_list); + CGAL::Polyhedron_3 create_polyhedron(CGAL::Nef_polyhedron_3 &nef_polyhedron); + CGAL::Nef_polyhedron_3 create_nef_polyhedron(std::list &face_list); + CGAL::Nef_polyhedron_3 create_nef_polyhedron(CGAL::Polyhedron_3 &polyhedron); - 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(const taxonomy::face*, cgal_face_t&); + bool convert(const taxonomy::loop*, cgal_wire_t&); + bool convert(const taxonomy::shell* l, cgal_shape_t& shape); - 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 triangulate_faces(CGAL::Polyhedron_3 &polyhedron); - CGAL::Polyhedron_3 create_polyhedron(std::list &face_list); - CGAL::Polyhedron_3 create_polyhedron(CGAL::Nef_polyhedron_3 &nef_polyhedron); - CGAL::Nef_polyhedron_3 create_nef_polyhedron(std::list &face_list); - CGAL::Nef_polyhedron_3 create_nef_polyhedron(CGAL::Polyhedron_3 &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; + virtual bool convert_impl(const taxonomy::shell*, ifcopenshell::geometry::ConversionResults&); + virtual bool convert_impl(const taxonomy::extrusion*, ifcopenshell::geometry::ConversionResults&); }; } - +} +} #endif \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp index 8db95bdd7a..c59b3056d4 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp @@ -246,11 +246,8 @@ namespace { #include bool OpenCascadeKernel::convert(const taxonomy::face* face, TopoDS_Shape& result) { - std::vector bounds; - std::transform(face->children.begin(), face->children.end(), std::back_inserter(bounds), [](auto item){ - return static_cast(item); - }); - + auto bounds = face->children_as(); + face_definition fd; const bool is_face_surface = false; /* todo */ From 8efb86420e7aec09de224b726c53174e63de7f1a Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 1 Sep 2019 16:48:50 +0200 Subject: [PATCH 174/235] Compilation errors --- src/ifcgeom/kernel_agnostic/AbstractKernel.cpp | 3 +++ src/ifcgeom/kernel_agnostic/AbstractKernel.h | 7 +++++++ src/ifcgeom/kernels/cgal/CgalKernel.h | 7 ------- src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h | 7 ------- 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp index 65bfce6556..99d1ee1d17 100644 --- a/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp +++ b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp @@ -2,6 +2,9 @@ #include "../../ifcgeom/schema_agnostic/IfcGeomElement.h" #include "../../ifcgeom/kernels/opencascade/OpenCascadeKernel.h" + +#undef Handle + #include "../../ifcgeom/kernels/cgal/CgalKernel.h" namespace { diff --git a/src/ifcgeom/kernel_agnostic/AbstractKernel.h b/src/ifcgeom/kernel_agnostic/AbstractKernel.h index 45c3ed5bf5..27bacabe19 100644 --- a/src/ifcgeom/kernel_agnostic/AbstractKernel.h +++ b/src/ifcgeom/kernel_agnostic/AbstractKernel.h @@ -6,6 +6,13 @@ #include "../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h" #include "../../ifcgeom/taxonomy.h" +static const double ALMOST_ZERO = 1.e-9; + +template +inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance = ALMOST_ZERO) { + return fabs(a - b) < tolerance; +} + namespace ifcopenshell { namespace geometry { namespace kernels { class IFC_GEOM_API AbstractKernel { diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 0041c9c172..1ac193a673 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -37,13 +37,6 @@ if ( it != cache.T.end() ) { e = it->second; return true; } #include -#define ALMOST_ZERO 1.e-9 - -template -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" diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h index defcc52a0c..e4872fbfd0 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h @@ -22,13 +22,6 @@ #include -static const double ALMOST_ZERO = 1.e-9; - -template -inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance=ALMOST_ZERO) { - return fabs(a-b) < tolerance; -} - #include #include #include From bed9c448836770a5d3a5b72e7f9822c1fa431bd3 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 1 Sep 2019 18:46:11 +0200 Subject: [PATCH 175/235] mark bounds as external based on entity type --- src/ifcgeom/kernels/cgal/CgalKernel.h | 2 +- src/ifcgeom/schema/mapping.cpp | 7 +++++++ src/ifcgeom/schema_agnostic/IfcGeomIterator.h | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 1ac193a673..d3b2703606 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -112,7 +112,7 @@ namespace kernels { bool convert(const taxonomy::shell* l, cgal_shape_t& shape); virtual bool convert_impl(const taxonomy::shell*, ifcopenshell::geometry::ConversionResults&); - virtual bool convert_impl(const taxonomy::extrusion*, ifcopenshell::geometry::ConversionResults&); + // virtual bool convert_impl(const taxonomy::extrusion*, ifcopenshell::geometry::ConversionResults&); }; } diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index dd7a605dae..2ce140442f 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -176,6 +176,13 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcFace* inst) { if (!bound->Orientation()) { r->reverse(); } + if (bound->declaration().is(IfcSchema::IfcFaceOuterBound::Class())) { + // Make a copy in case we need immutability later for e.g. caching + auto s = r->clone(); + ((taxonomy::loop*)s)->external = true; + delete r; + r = s; + } face->children.push_back(r); } } diff --git a/src/ifcgeom/schema_agnostic/IfcGeomIterator.h b/src/ifcgeom/schema_agnostic/IfcGeomIterator.h index cc6bc32823..feb28af639 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomIterator.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomIterator.h @@ -219,6 +219,7 @@ namespace ifcopenshell { namespace geometry { task_iterator_ = tasks_.begin(); + task_result_index_ = 0; done = 0; total = tasks_.size(); From 0c54bdcd54f54a981e18112f38f34e6d300eee55 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 4 Sep 2019 09:10:57 +0200 Subject: [PATCH 176/235] Cleanup --- src/ifcgeom/kernels/cgal/CgalKernel.h | 3 - .../kernels/opencascade/IfcGeomShapeType.h | 38 ----- .../kernels/opencascade/IfcRegister.cpp_ | 123 --------------- src/ifcgeom/kernels/opencascade/IfcRegister.h | 148 ------------------ .../opencascade/IfcRegisterConvertCurve.h | 6 - .../opencascade/IfcRegisterConvertFace.h | 6 - .../opencascade/IfcRegisterConvertShape.h | 26 --- .../opencascade/IfcRegisterConvertShapes.h | 18 --- .../opencascade/IfcRegisterConvertWire.h | 6 - .../opencascade/IfcRegisterCreateCache.h | 6 - .../kernels/opencascade/IfcRegisterDef.h | 18 --- .../opencascade/IfcRegisterGeomHeader.h | 10 -- .../opencascade/IfcRegisterPurgeCache.h | 6 - .../opencascade/IfcRegisterShapeType.h | 14 -- .../kernels/opencascade/IfcRegisterUndef.h | 18 --- .../kernels/opencascade/OpenCascadeKernel.h | 1 - 16 files changed, 447 deletions(-) delete mode 100644 src/ifcgeom/kernels/opencascade/IfcGeomShapeType.h delete mode 100644 src/ifcgeom/kernels/opencascade/IfcRegister.cpp_ delete mode 100644 src/ifcgeom/kernels/opencascade/IfcRegister.h delete mode 100644 src/ifcgeom/kernels/opencascade/IfcRegisterConvertCurve.h delete mode 100644 src/ifcgeom/kernels/opencascade/IfcRegisterConvertFace.h delete mode 100644 src/ifcgeom/kernels/opencascade/IfcRegisterConvertShape.h delete mode 100644 src/ifcgeom/kernels/opencascade/IfcRegisterConvertShapes.h delete mode 100644 src/ifcgeom/kernels/opencascade/IfcRegisterConvertWire.h delete mode 100644 src/ifcgeom/kernels/opencascade/IfcRegisterCreateCache.h delete mode 100644 src/ifcgeom/kernels/opencascade/IfcRegisterDef.h delete mode 100644 src/ifcgeom/kernels/opencascade/IfcRegisterGeomHeader.h delete mode 100644 src/ifcgeom/kernels/opencascade/IfcRegisterPurgeCache.h delete mode 100644 src/ifcgeom/kernels/opencascade/IfcRegisterShapeType.h delete mode 100644 src/ifcgeom/kernels/opencascade/IfcRegisterUndef.h diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index d3b2703606..541c07e465 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -44,9 +44,6 @@ if ( it != cache.T.end() ) { e = it->second; return true; } #include "../../../ifcgeom/schema_agnostic/IfcGeomElement.h" #include "../../../ifcgeom/kernels/cgal/CgalConversionResult.h" -// @todo create separate shapetype enum? -#include "../../../ifcgeom/kernels/opencascade/IfcGeomShapeType.h" - struct PolyhedronBuilder : public CGAL::Modifier_base::HalfedgeDS> { private: std::list *face_list; diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomShapeType.h b/src/ifcgeom/kernels/opencascade/IfcGeomShapeType.h deleted file mode 100644 index 3d2c11233a..0000000000 --- a/src/ifcgeom/kernels/opencascade/IfcGeomShapeType.h +++ /dev/null @@ -1,38 +0,0 @@ -/******************************************************************************** -* * -* This file is part of IfcOpenShell. * -* * -* IfcOpenShell is free software: you can redistribute it and/or modify * -* it under the terms of the Lesser GNU General Public License as published by * -* the Free Software Foundation, either version 3.0 of the License, or * -* (at your option) any later version. * -* * -* IfcOpenShell is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -* Lesser GNU General Public License for more details. * -* * -* You should have received a copy of the Lesser GNU General Public License * -* along with this program. If not, see . * -* * -********************************************************************************/ - -#ifndef IFCGEOMSHAPETYPE_H -#define IFCGEOMSHAPETYPE_H - -namespace IfcGeom { - - enum ShapeType { - ST_SHAPELIST, - ST_SHAPE, - ST_FACE, - ST_WIRE, - ST_CURVE, - ST_EDGE, - ST_VERTEX, - ST_OTHER - }; - -} - -#endif \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/IfcRegister.cpp_ b/src/ifcgeom/kernels/opencascade/IfcRegister.cpp_ deleted file mode 100644 index 35b6baedcf..0000000000 --- a/src/ifcgeom/kernels/opencascade/IfcRegister.cpp_ +++ /dev/null @@ -1,123 +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 . * -* * -********************************************************************************/ - -#include "IfcGeom.h" -#include "IfcGeomShapeType.h" - -#define Kernel POSTFIX_SCHEMA(Kernel) - -using namespace IfcUtil; - -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::ConversionResult(l->data().id(), new OpenCascadeShape(shp), get_style(l->as()))); - return true; - } - return false; - } - -#include "IfcRegisterConvertShapes.h" - Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l); - return false; -} - -IfcGeom::ShapeType IfcGeom::Kernel::shape_type(const IfcBaseClass* l) { -#include "IfcRegisterShapeType.h" - return ST_OTHER; -} - -bool IfcGeom::Kernel::convert_shape(const IfcBaseClass* l, TopoDS_Shape& r) { - const unsigned int id = l->data().id(); - bool success = false; - bool processed = false; - bool ignored = false; - -#ifndef NO_CACHE - std::map::const_iterator it = cache.Shape.find(id); - if ( it != cache.Shape.end() ) { r = it->second; return true; } -#endif - const bool include_curves = getValue(GV_DIMENSIONALITY) != +1; - const bool include_solids_and_surfaces = getValue(GV_DIMENSIONALITY) != -1; - - IfcGeom::ShapeType st = shape_type(l); - ignored = (!include_solids_and_surfaces && (st == ST_SHAPE || st == ST_FACE)) || (!include_curves && (st == ST_WIRE || st == ST_CURVE)); - if (st == ST_SHAPELIST) { - processed = true; - 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" - } else if (st == ST_FACE && include_solids_and_surfaces) { - processed = true; - success = convert_face(l, r); - } else if (st == ST_WIRE && include_curves) { - processed = true; - TopoDS_Wire w; - success = convert_wire(l, w); - if (success) { - r = w; - } - } else if (st == ST_CURVE && include_curves) { - processed = true; - Handle(Geom_Curve) crv; - TopoDS_Wire w; - success = convert_curve(l, crv) && convert_curve_to_wire(crv, w); - if (success) { - r = w; - } - } - - if ( processed && success ) { - const double precision = getValue(GV_PRECISION); - apply_tolerance(r, precision); -#ifndef NO_CACHE - cache.Shape[id] = r; -#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::Kernel::convert_wire(const IfcBaseClass* l, TopoDS_Wire& r) { -#include "IfcRegisterConvertWire.h" - Handle(Geom_Curve) curve; - if (IfcGeom::Kernel::convert_curve(l, curve)) { - return IfcGeom::Kernel::convert_curve_to_wire(curve, r); - } - Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l); - return false; -} - -bool IfcGeom::Kernel::convert_face(const IfcBaseClass* l, TopoDS_Shape& r) { -#include "IfcRegisterConvertFace.h" - Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l); - return false; -} - -bool IfcGeom::Kernel::convert_curve(const IfcBaseClass* l, Handle(Geom_Curve)& r) { -#include "IfcRegisterConvertCurve.h" - Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l); - return false; -} \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/IfcRegister.h b/src/ifcgeom/kernels/opencascade/IfcRegister.h deleted file mode 100644 index 7993242f50..0000000000 --- a/src/ifcgeom/kernels/opencascade/IfcRegister.h +++ /dev/null @@ -1,148 +0,0 @@ -/******************************************************************************** -* * -* This file is part of IfcOpenShell. * -* * -* IfcOpenShell is free software: you can redistribute it and/or modify * -* it under the terms of the Lesser GNU General Public License as published by * -* the Free Software Foundation, either version 3.0 of the License, or * -* (at your option) any later version. * -* * -* IfcOpenShell is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -* Lesser GNU General Public License for more details. * -* * -* You should have received a copy of the Lesser GNU General Public License * -* along with this program. If not, see . * -* * -********************************************************************************/ - -/******************************************************************************** - * * - * This file 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../../../ifcparse/IfcBaseClass.h" -#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 SCHEMA_HAS_IfcCylindricalSurface -SHAPE(IfcCylindricalSurface); -#endif -#ifdef SCHEMA_HAS_IfcAdvancedBrep -SHAPE(IfcAdvancedBrep); -#endif -// FIXME: Surfaces should have a shape type of their own -#ifdef SCHEMA_HAS_IfcBSplineSurfaceWithKnots -SHAPE(IfcBSplineSurfaceWithKnots); -#endif -#ifdef SCHEMA_HAS_IfcTriangulatedFaceSet -SHAPE(IfcTriangulatedFaceSet); -#endif -#ifdef SCHEMA_HAS_IfcExtrudedAreaSolidTapered -SHAPE(IfcExtrudedAreaSolidTapered); -#endif -SHAPE(IfcPlane); -SHAPE(IfcExtrudedAreaSolid); -SHAPE(IfcRevolvedAreaSolid); -SHAPE(IfcConnectedFaceSet); -SHAPE(IfcBooleanResult); -SHAPE(IfcPolygonalBoundedHalfSpace); -SHAPE(IfcHalfSpaceSolid); -// FIXME: Surfaces should have a shape type of their own -SHAPE(IfcSurfaceOfLinearExtrusion); -SHAPE(IfcSurfaceOfRevolution); -SHAPE(IfcBlock); -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); -#ifdef SCHEMA_HAS_IfcIndexedPolyCurve -WIRE(IfcIndexedPolyCurve) -#endif - -CURVE(IfcCircle); -CURVE(IfcEllipse); -CURVE(IfcLine); -#ifdef SCHEMA_HAS_IfcBSplineCurveWithKnots -// IfcRationalBSplineCurveWithKnots included -CURVE(IfcBSplineCurveWithKnots); -#endif - -CLASS(IfcCartesianPoint,gp_Pnt); -CLASS(IfcDirection,gp_Dir); -CLASS(IfcAxis2Placement2D,gp_Trsf2d); -CLASS(IfcAxis2Placement3D,gp_Trsf); -CLASS(IfcAxis1Placement,gp_Ax1); -CLASS(IfcCartesianTransformationOperator2DnonUniform,gp_GTrsf2d); -CLASS(IfcCartesianTransformationOperator3DnonUniform,gp_GTrsf); -CLASS(IfcCartesianTransformationOperator2D,gp_Trsf2d); -CLASS(IfcCartesianTransformationOperator3D,gp_Trsf); -CLASS(IfcObjectPlacement,gp_Trsf); -CLASS(IfcVector,gp_Vec); -CLASS(IfcPlane,gp_Pln); \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/IfcRegisterConvertCurve.h b/src/ifcgeom/kernels/opencascade/IfcRegisterConvertCurve.h deleted file mode 100644 index 4b32b4dcbf..0000000000 --- a/src/ifcgeom/kernels/opencascade/IfcRegisterConvertCurve.h +++ /dev/null @@ -1,6 +0,0 @@ -#include "IfcRegisterUndef.h" -#define CURVE(T) \ - if ( l->declaration().is(IfcSchema::T::Class()) ) return convert((IfcSchema::T*)l,r); -#include "IfcRegisterDef.h" - -#include "IfcRegister.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/IfcRegisterConvertFace.h b/src/ifcgeom/kernels/opencascade/IfcRegisterConvertFace.h deleted file mode 100644 index 90b631667e..0000000000 --- a/src/ifcgeom/kernels/opencascade/IfcRegisterConvertFace.h +++ /dev/null @@ -1,6 +0,0 @@ -#include "IfcRegisterUndef.h" -#define FACE(T) \ - if ( l->declaration().is(IfcSchema::T::Class()) ) return convert((IfcSchema::T*)l,r); -#include "IfcRegisterDef.h" - -#include "IfcRegister.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/IfcRegisterConvertShape.h b/src/ifcgeom/kernels/opencascade/IfcRegisterConvertShape.h deleted file mode 100644 index 36e573eeb9..0000000000 --- a/src/ifcgeom/kernels/opencascade/IfcRegisterConvertShape.h +++ /dev/null @@ -1,26 +0,0 @@ -#include "IfcRegisterUndef.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; \ - } catch (const Standard_Failure& f) { \ - if (f.GetMessageString() && strlen(f.GetMessageString())) \ - Logger::Message(Logger::LOG_ERROR, std::string("Error in: ") + f.GetMessageString() + "\nFailed to convert:", l); \ - else \ - Logger::Message(Logger::LOG_ERROR, "Failed to convert:", l); \ - return false; \ - } \ - if (!success) { \ - Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l); \ - return false; \ - } \ - } -#include "IfcRegisterDef.h" - -#include "IfcRegister.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/IfcRegisterConvertShapes.h b/src/ifcgeom/kernels/opencascade/IfcRegisterConvertShapes.h deleted file mode 100644 index 1613b1f1fb..0000000000 --- a/src/ifcgeom/kernels/opencascade/IfcRegisterConvertShapes.h +++ /dev/null @@ -1,18 +0,0 @@ -#include "IfcRegisterUndef.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); \ - } catch (const Standard_Failure& f) { \ - if (f.GetMessageString()) \ - Logger::Message(Logger::LOG_ERROR, std::string("Error in: ") + f.GetMessageString() + "\nFailed to convert:", l); \ - else \ - Logger::Message(Logger::LOG_ERROR, "Failed to convert:", l); \ - } \ - return false; \ - } -#include "IfcRegisterDef.h" - -#include "IfcRegister.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/IfcRegisterConvertWire.h b/src/ifcgeom/kernels/opencascade/IfcRegisterConvertWire.h deleted file mode 100644 index fab25fac84..0000000000 --- a/src/ifcgeom/kernels/opencascade/IfcRegisterConvertWire.h +++ /dev/null @@ -1,6 +0,0 @@ -#include "IfcRegisterUndef.h" -#define WIRE(T) \ - if ( l->declaration().is(IfcSchema::T::Class()) ) return convert((IfcSchema::T*)l,r); -#include "IfcRegisterDef.h" - -#include "IfcRegister.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/IfcRegisterCreateCache.h b/src/ifcgeom/kernels/opencascade/IfcRegisterCreateCache.h deleted file mode 100644 index c1425d071f..0000000000 --- a/src/ifcgeom/kernels/opencascade/IfcRegisterCreateCache.h +++ /dev/null @@ -1,6 +0,0 @@ -#include "IfcRegisterUndef.h" -#define CLASS(T,V) \ - std::map T; -#include "IfcRegisterDef.h" - -#include "IfcRegister.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/IfcRegisterDef.h b/src/ifcgeom/kernels/opencascade/IfcRegisterDef.h deleted file mode 100644 index 65f8704a81..0000000000 --- a/src/ifcgeom/kernels/opencascade/IfcRegisterDef.h +++ /dev/null @@ -1,18 +0,0 @@ -#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 \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/IfcRegisterGeomHeader.h b/src/ifcgeom/kernels/opencascade/IfcRegisterGeomHeader.h deleted file mode 100644 index 51286f3693..0000000000 --- a/src/ifcgeom/kernels/opencascade/IfcRegisterGeomHeader.h +++ /dev/null @@ -1,10 +0,0 @@ -#include "IfcRegisterUndef.h" -#define CLASS(T,V) bool convert(const IfcSchema::T* L, V& r); -#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) -#define CURVE(T) CLASS(T,Handle(Geom_Curve)) -#include "IfcRegisterDef.h" - -#include "IfcRegister.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/IfcRegisterPurgeCache.h b/src/ifcgeom/kernels/opencascade/IfcRegisterPurgeCache.h deleted file mode 100644 index 1afa070943..0000000000 --- a/src/ifcgeom/kernels/opencascade/IfcRegisterPurgeCache.h +++ /dev/null @@ -1,6 +0,0 @@ -#include "IfcRegisterUndef.h" -#define CLASS(T,V) \ - T.clear(); -#include "IfcRegisterDef.h" - -#include "IfcRegister.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/IfcRegisterShapeType.h b/src/ifcgeom/kernels/opencascade/IfcRegisterShapeType.h deleted file mode 100644 index a0185a0279..0000000000 --- a/src/ifcgeom/kernels/opencascade/IfcRegisterShapeType.h +++ /dev/null @@ -1,14 +0,0 @@ -#include "IfcRegisterUndef.h" -#define SHAPES(T) \ - if ( l->declaration().is(IfcSchema::T::Class()) ) return ST_SHAPELIST; -#define SHAPE(T) \ - if ( l->declaration().is(IfcSchema::T::Class()) ) return ST_SHAPE; -#define WIRE(T) \ - if ( l->declaration().is(IfcSchema::T::Class()) ) return ST_WIRE; -#define FACE(T) \ - if ( l->declaration().is(IfcSchema::T::Class()) ) return ST_FACE; -#define CURVE(T) \ - if ( l->declaration().is(IfcSchema::T::Class()) ) return ST_CURVE; -#include "IfcRegisterDef.h" - -#include "IfcRegister.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/IfcRegisterUndef.h b/src/ifcgeom/kernels/opencascade/IfcRegisterUndef.h deleted file mode 100644 index d2d537a073..0000000000 --- a/src/ifcgeom/kernels/opencascade/IfcRegisterUndef.h +++ /dev/null @@ -1,18 +0,0 @@ -#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 \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h index e4872fbfd0..9120036799 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h @@ -46,7 +46,6 @@ #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 "../../../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h" From e3041219b5b6104b3d4950d9c23ac0d4288da382 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 15 Sep 2019 15:59:05 +0200 Subject: [PATCH 177/235] Further work on profiles --- .../kernels/opencascade/IfcGeomShapes.cpp | 45 ++++-- src/ifcgeom/schema/bind_convert_impl.i | 2 +- src/ifcgeom/schema/mapping.cpp | 147 +++++++++++++++++- src/ifcgeom/schema/mapping.i | 6 +- src/ifcgeom/taxonomy.h | 3 +- 5 files changed, 180 insertions(+), 23 deletions(-) diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp index c59b3056d4..6eaa97b427 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp @@ -505,7 +505,7 @@ namespace { /* A compile-time for loop over the curve kinds */ template struct dispatch_curve_creation { - static bool dispatch(const ifcopenshell::geometry::taxonomy::item* item, T visitor) { + static bool dispatch(const ifcopenshell::geometry::taxonomy::item* item, T& visitor) { // @todo it should be possible to eliminate this dynamic_cast when there is a static equivalent to kind() const ifcopenshell::geometry::taxonomy::curves::type* v = dynamic_cast*>(item); if (v) { @@ -519,7 +519,7 @@ namespace { template struct dispatch_curve_creation { - static bool dispatch(const ifcopenshell::geometry::taxonomy::item* item, T visitor) { + static bool dispatch(const ifcopenshell::geometry::taxonomy::item* item, T& visitor) { Logger::Error("No conversion for " + std::to_string(item->kind())); return false; } @@ -532,6 +532,7 @@ namespace { } struct curve_creation_visitor { + OpenCascadeKernel* kernel; typedef boost::variant result_type; result_type result; @@ -550,10 +551,32 @@ namespace { result_type operator()(const taxonomy::ellipse& e) { return result = Handle(Geom_Curve)(new Geom_Ellipse(gp_Ax2(convert_xyz(e.origin), convert_xyz(e.z), convert_xyz(e.x)), e.radius, e.radius2)); } + + result_type operator()(const taxonomy::loop& l) { + TopoDS_Wire wire; + kernel->convert(&l, wire); + return result = wire; + } + + result_type operator()(const taxonomy::edge& e) { + if (e.basis == nullptr) { + // @todo we should probably construct edges based on correct oriented TopoDS_Vertex instead. + auto p1 = convert_xyz(boost::get(e.start)); + auto p2 = convert_xyz(boost::get(e.end)); + TopoDS_Edge e = BRepBuilderAPI_MakeEdge(p1, p2).Edge(); + BRep_Builder B; + TopoDS_Wire W; + B.MakeWire(W); + B.Add(W, e); + return result = W; + } else { + throw std::runtime_error("not implemented"); + } + } }; - curve_creation_visitor::result_type convert_curve(const taxonomy::item* curve) { - curve_creation_visitor v; + curve_creation_visitor::result_type convert_curve(OpenCascadeKernel* kernel, const taxonomy::item* curve) { + curve_creation_visitor v{ kernel }; if (dispatch_curve_creation::dispatch(curve, v)) { return v.result; } else { @@ -771,7 +794,7 @@ bool OpenCascadeKernel::convert(const taxonomy::loop* loop, TopoDS_Wire& wire) { TopTools_ListOfShape converted_segments; for (auto& segment : segments) { - TopoDS_Wire segment_wire = boost::get(convert_curve(segment)); + auto segment_wire = boost::get(convert_curve(this, segment)); if (!segment->orientation) { segment_wire.Reverse(); @@ -837,11 +860,13 @@ bool OpenCascadeKernel::convert_impl(const taxonomy::shell *shell, ifcopenshell: bool OpenCascadeKernel::convert(const taxonomy::matrix4* matrix, gp_GTrsf& trsf) { // @todo check - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 4; ++j) { - trsf.SetValue(i + 1, j + 1, matrix->components(i, j)); - } - } + gp_Trsf t; + t.SetValues( + matrix->components(0, 0), matrix->components(1, 0), matrix->components(2, 0), matrix->components(3, 0), + matrix->components(0, 1), matrix->components(1, 1), matrix->components(2, 1), matrix->components(3, 1), + matrix->components(0, 2), matrix->components(1, 2), matrix->components(2, 2), matrix->components(3, 2) + ); + trsf = t; return true; } diff --git a/src/ifcgeom/schema/bind_convert_impl.i b/src/ifcgeom/schema/bind_convert_impl.i index 298c809e0e..32ebf485b6 100644 --- a/src/ifcgeom/schema/bind_convert_impl.i +++ b/src/ifcgeom/schema/bind_convert_impl.i @@ -9,7 +9,7 @@ if (item != nullptr) { \ item->instance = l; \ try { \ - if (l->as()) { \ + if (l->as() && !l->as()) { \ auto style = find_style(l->as()); \ if (style) { \ ((taxonomy::geom_item*)item)->surface_style = as(map(style)); \ diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index 2ce140442f..33919e8b90 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -106,7 +106,7 @@ namespace { as(taxonomy::item* item) : item_(item) {} operator T() const { if (!item_) { - throw taxonomy::topology_error(); + throw taxonomy::topology_error("item was nullptr"); } T* t = dynamic_cast(item_); if (t) { @@ -118,7 +118,7 @@ namespace { return upgrade; } } - throw taxonomy::topology_error(); + throw taxonomy::topology_error("item does not match type"); } } ~as() { @@ -145,12 +145,11 @@ namespace { }; taxonomy::item* mapping::map_impl(const IfcSchema::IfcExtrudedAreaSolid* inst) { - // @todo length unit return new taxonomy::extrusion( as(map(inst->Position())), as(map(inst->SweptArea())), as(map(inst->ExtrudedDirection())), - inst->Depth() + inst->Depth() * length_unit_ ); } @@ -265,12 +264,12 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcAxis2Placement3D* inst) { } if (hasAxis) { - taxonomy::point3 v = as(map(inst->Axis())); + taxonomy::direction3 v = as(map(inst->Axis())); axis = v.components; } if (hasRef) { - taxonomy::point3 v = as(map(inst->RefDirection())); + taxonomy::direction3 v = as(map(inst->RefDirection())); refDirection = v.components; } else { if (acos(axis.dot(X)) > 1.e-5) { @@ -285,6 +284,20 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcAxis2Placement3D* inst) { return new taxonomy::matrix4(o, axis, refDirection); } +taxonomy::item* mapping::map_impl(const IfcSchema::IfcAxis2Placement2D* inst) { + Eigen::Vector3d P, axis(0, 0, 1), V(1, 0, 0); + { + taxonomy::point3 v = as(map(inst->Location())); + P = v.components; + } + const bool hasRef = inst->hasRefDirection(); + if (hasRef) { + taxonomy::direction3 v = as(map(inst->RefDirection())); + V = v.components; + } + return new taxonomy::matrix4(P, axis, V); +} + taxonomy::item* mapping::map_impl(const IfcSchema::IfcCartesianTransformationOperator2DnonUniform* inst) { // @todo return new taxonomy::matrix4(); @@ -756,8 +769,8 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcMaterial* material) { for (IfcSchema::IfcRepresentation::list::it it = reps->begin(); it != reps->end(); ++it) { styles->push((**it).Items()->as()); } - for (IfcSchema::IfcStyledItem::list::it it = styles->begin(); it != styles->end(); ++it) { - return map(*it); + if (styles->size() == 1) { + return map(*styles->begin()); } } @@ -829,6 +842,7 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcStyledItem* inst) { taxonomy::item* mapping::map(const IfcBaseClass* l) { + // std::wcout << l->data().toString().c_str() << std::endl; #include "bind_convert_impl.i" Logger::Message(Logger::LOG_ERROR, "No operation defined for:", l); return nullptr; @@ -983,3 +997,120 @@ void mapping::initialize_units_() { Logger::Warning("No plane angle unit encountered"); } } + +namespace { + struct profile_point { + std::array xy; + boost::optional radius; + }; + + struct profile_point_with_neighbours { + std::array xy; + boost::optional radius; + profile_point* previous, *next; + }; + taxonomy::loop* profile_helper(mapping* self, const IfcSchema::IfcParameterizedProfileDef* inst, const std::vector& points) { + + /* TopoDS_Vertex* vertices = new TopoDS_Vertex[numVerts]; + + for (int i = 0; i < numVerts; i++) { + gp_XY xy(verts[2 * i], verts[2 * i + 1]); + trsf.Transforms(xy); + vertices[i] = BRepBuilderAPI_MakeVertex(gp_Pnt(xy.X(), xy.Y(), 0.0f)); + } + + BRepBuilderAPI_MakeWire w; + for (int i = 0; i < numVerts; i++) + w.Add(BRepBuilderAPI_MakeEdge(vertices[i], vertices[(i + 1) % numVerts])); + + TopoDS_Face face; + convert_wire_to_face(w.Wire(), face); + + if (numFillets && *std::max_element(filletRadii, filletRadii + numFillets) > ALMOST_ZERO) { + BRepFilletAPI_MakeFillet2d fillet(face); + for (int i = 0; i < numFillets; i++) { + const double radius = filletRadii[i]; + if (radius <= ALMOST_ZERO) continue; + fillet.AddFillet(vertices[filletIndices[i]], radius); + } + fillet.Build(); + if (fillet.IsDone()) { + face = TopoDS::Face(fillet.Shape()); + } else { + Logger::Error("Failed to process profile fillets"); + } + } + */ + + Eigen::Matrix4d m4; + + bool has_position = true; +#ifdef SCHEMA_IfcParameterizedProfileDef_Position_IS_OPTIONAL + has_position = inst->hasPosition(); +#endif + if (has_position) { + taxonomy::matrix4 m = as(self->map(inst->Position())); + m4 = m.components; + } + + // @todo precision + if (m4.isIdentity()) { + has_position = false; + } + + std::vector ps; + ps.reserve(points.size()); + std::transform(points.begin(), points.end(), std::back_inserter(ps), [&has_position, &m4](const profile_point& p) { + if (has_position) { + Eigen::Vector4d v(p.xy[0], p.xy[1], 0., 1.); + v = m4 * v; + return taxonomy::point3(v(0), v(1), 0.); + } else { + return taxonomy::point3(p.xy[0], p.xy[1], 0.); + } + }); + + auto loop = new taxonomy::loop(); + auto previous = ps.back(); + for (auto& p : ps) { + auto e = new taxonomy::edge; + e->start = previous; + e->end = p; + previous = p; + loop->children.push_back(e); + } + + return loop; + } +} + +taxonomy::item* mapping::map_impl(const IfcSchema::IfcRectangleProfileDef* inst) { + const double x = inst->XDim() / 2.0f * length_unit_; + const double y = inst->YDim() / 2.0f * length_unit_; + + // @todo + const double precision_ = 1.e-5; + + if (x < precision_ || y < precision_) { + Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", inst); + return nullptr; + } + + return profile_helper(this, inst, { + {{-x, -y}}, + {{+x, -y}}, + {{+x, +y}}, + {{-x, +y}}, + }); +} + +taxonomy::item* mapping::map_impl(const IfcSchema::IfcArbitraryClosedProfileDef* l) { + auto loop = map(l->OuterCurve()); + if (loop) { + auto face = new taxonomy::face; + face->children = { loop }; + return face; + } else { + return nullptr; + } +} \ No newline at end of file diff --git a/src/ifcgeom/schema/mapping.i b/src/ifcgeom/schema/mapping.i index bc94010fd7..d588e3360a 100644 --- a/src/ifcgeom/schema/mapping.i +++ b/src/ifcgeom/schema/mapping.i @@ -73,10 +73,10 @@ BIND(IfcConnectedFaceSet); // BIND(IfcSweptDiskSolid); // BIND(IfcArbitraryProfileDefWithVoids); -// BIND(IfcArbitraryClosedProfileDef); +BIND(IfcArbitraryClosedProfileDef); // BIND(IfcRoundedRectangleProfileDef); // BIND(IfcRectangleHollowProfileDef); -// BIND(IfcRectangleProfileDef); +BIND(IfcRectangleProfileDef); // BIND(IfcTrapeziumProfileDef) // BIND(IfcCShapeProfileDef); // IfcAsymmetricIShapeProfileDef included @@ -119,7 +119,7 @@ BIND(IfcPolyLoop); BIND(IfcCartesianPoint); BIND(IfcDirection); -// BIND(IfcAxis2Placement2D); +BIND(IfcAxis2Placement2D); BIND(IfcAxis2Placement3D); // BIND(IfcAxis1Placement); BIND(IfcCartesianTransformationOperator2DnonUniform); diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index 35a79e176c..d9f57828e4 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -22,6 +22,7 @@ namespace taxonomy { class topology_error : public std::runtime_error { public: topology_error() : std::runtime_error("Generic topology error") {} + topology_error(const char* const s) : std::runtime_error(s) {} }; enum kinds { MATRIX4, POINT3, DIRECTION3, LINE, CIRCLE, ELLIPSE, BSPLINE_CURVE, EDGE, LOOP, FACE, SHELL, EXTRUSION, NODE, COLLECTION, COLOUR, STYLE }; @@ -248,7 +249,7 @@ struct node : public geom_item { namespace impl { typedef std::tuple KindsTuple; - typedef std::tuple CurvesTuple; + typedef std::tuple CurvesTuple; } struct type_by_kind { From 04bce57e80e89084563b2ec2be7a7633403dd203 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Mon, 16 Sep 2019 10:25:39 +0200 Subject: [PATCH 178/235] Fix placements --- .../kernels/opencascade/IfcGeomShapes.cpp | 24 ++++++++++++----- .../OpenCascadeConversionResult.cpp | 13 ++++++---- .../schema_agnostic/IfcGeomRepresentation.cpp | 26 ++++++++++++------- 3 files changed, 41 insertions(+), 22 deletions(-) diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp index 6eaa97b427..93cc497246 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp @@ -124,12 +124,16 @@ bool OpenCascadeKernel::convert(const taxonomy::extrusion* extrusion, TopoDS_Sha return false; } + /* + // @todo we need to decide whether the matrix is kept on the taxonomy node or + // move the TopoDS_Shape, but obviously not both. gp_GTrsf gtrsf; if (!convert(&extrusion->matrix, gtrsf)) { Logger::Error("Unable to move extrusion"); } auto trsf = gtrsf.Trsf(); - + */ + auto fs = extrusion->direction.components.data(); gp_Dir dir(fs[0], fs[1], fs[2]); @@ -161,11 +165,13 @@ bool OpenCascadeKernel::convert(const taxonomy::extrusion* extrusion, TopoDS_Sha shape = BRepPrimAPI_MakePrism(face, height*dir); } + /* if (!shape.IsNull()) { // IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D // and therefore has a unit scale factor shape.Move(trsf); } + */ return !shape.IsNull(); } @@ -831,6 +837,9 @@ bool OpenCascadeKernel::convert(const taxonomy::loop* loop, TopoDS_Wire& wire) { } bool OpenCascadeKernel::convert_impl(const taxonomy::extrusion* extrusion, ifcopenshell::geometry::ConversionResults& results) { + if (((IfcUtil::IfcBaseEntity*)extrusion->instance)->data().id() == 5722) { + std::wcerr << 1; + } TopoDS_Shape shape; if (!convert(extrusion, shape)) { return false; @@ -860,13 +869,14 @@ bool OpenCascadeKernel::convert_impl(const taxonomy::shell *shell, ifcopenshell: bool OpenCascadeKernel::convert(const taxonomy::matrix4* matrix, gp_GTrsf& trsf) { // @todo check - gp_Trsf t; - t.SetValues( - matrix->components(0, 0), matrix->components(1, 0), matrix->components(2, 0), matrix->components(3, 0), - matrix->components(0, 1), matrix->components(1, 1), matrix->components(2, 1), matrix->components(3, 1), - matrix->components(0, 2), matrix->components(1, 2), matrix->components(2, 2), matrix->components(3, 2) + gp_Trsf tr; + const auto& m = matrix->components; + tr.SetValues( + m(0, 0), m(0, 1), m(0, 2), m(0, 3), + m(1, 0), m(1, 1), m(1, 2), m(1, 3), + m(2, 0), m(2, 1), m(2, 2), m(2, 3) ); - trsf = t; + trsf = tr; return true; } diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp index 6d11395d79..f96af5cdf7 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp @@ -11,11 +11,14 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(const settings& setti // @todo check gp_GTrsf trsf; - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 4; ++j) { - trsf.SetValue(i + 1, j + 1, place.components(i, j)); - } - } + gp_Trsf tr; + const auto& m = place.components; + tr.SetValues( + m(0, 0), m(0, 1), m(0, 2), m(0, 3), + m(1, 0), m(1, 1), m(1, 2), m(1, 3), + m(2, 0), m(2, 1), m(2, 2), m(2, 3) + ); + trsf = tr; // Triangulate the shape try { diff --git a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp index 91465eabd4..cffc251c29 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp +++ b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp @@ -95,11 +95,14 @@ ifcopenshell::geometry::ConversionResultShape* ifcopenshell::geometry::Represent // @todo, check gp_GTrsf trsf; - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 4; ++j) { - trsf.SetValue(i + 1, j + 1, it->Placement().components(i, j)); - } - } + gp_Trsf tr; + const auto& m = it->Placement().components; + tr.SetValues( + m(0, 0), m(0, 1), m(0, 2), m(0, 3), + m(1, 0), m(1, 1), m(1, 2), m(1, 3), + m(2, 0), m(2, 1), m(2, 2), m(2, 3) + ); + trsf = tr; if (!force_meters && settings().get(ifcopenshell::geometry::settings::CONVERT_BACK_UNITS)) { gp_Trsf scale; @@ -240,11 +243,14 @@ bool ifcopenshell::geometry::Representation::BRep::calculate_projected_surface_a try { // @todo check gp_GTrsf trsf; - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 4; ++j) { - trsf.SetValue(i + 1, j + 1, place.components(i, j)); - } - } + gp_Trsf tr; + const auto& m = place.components; + tr.SetValues( + m(0, 0), m(0, 1), m(0, 2), m(0, 3), + m(1, 0), m(1, 1), m(1, 2), m(1, 3), + m(2, 0), m(2, 1), m(2, 2), m(2, 3) + ); + trsf = tr; gp_Mat mat = trsf.Trsf().HVectorialPart(); gp_Ax3 ax(trsf.TranslationPart(), mat.Column(3), mat.Column(1)); From d59f3e9932680eaef7b7dbe6debe8178c73ab347 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Mon, 16 Sep 2019 15:40:13 +0200 Subject: [PATCH 179/235] Polyline --- .../kernel_agnostic/AbstractKernel.cpp | 7 +- src/ifcgeom/schema/mapping.cpp | 80 ++++++++++++++++--- src/ifcgeom/schema/mapping.i | 2 +- 3 files changed, 75 insertions(+), 14 deletions(-) diff --git a/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp index 99d1ee1d17..a73027edda 100644 --- a/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp +++ b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp @@ -31,7 +31,12 @@ namespace { } bool ifcopenshell::geometry::kernels::AbstractKernel::convert(const taxonomy::item* item, ifcopenshell::geometry::ConversionResults& results) { - return dispatch_conversion<0>::dispatch(this, item, results); + try { + return dispatch_conversion<0>::dispatch(this, item, results); + } catch (std::exception& e) { + Logger::Error(e, item->instance); + return false; + } } ifcopenshell::geometry::kernels::AbstractKernel* ifcopenshell::geometry::kernels::construct(const std::string& geometry_library, IfcParse::IfcFile* file) { diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index 33919e8b90..ae2645c4bc 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -1009,6 +1009,20 @@ namespace { boost::optional radius; profile_point* previous, *next; }; + + taxonomy::loop* polygon_from_points(const std::vector& ps) { + auto loop = new taxonomy::loop(); + auto previous = ps.back(); + for (auto& p : ps) { + auto e = new taxonomy::edge; + e->start = previous; + e->end = p; + previous = p; + loop->children.push_back(e); + } + return loop; + } + taxonomy::loop* profile_helper(mapping* self, const IfcSchema::IfcParameterizedProfileDef* inst, const std::vector& points) { /* TopoDS_Vertex* vertices = new TopoDS_Vertex[numVerts]; @@ -1070,17 +1084,7 @@ namespace { } }); - auto loop = new taxonomy::loop(); - auto previous = ps.back(); - for (auto& p : ps) { - auto e = new taxonomy::edge; - e->start = previous; - e->end = p; - previous = p; - loop->children.push_back(e); - } - - return loop; + return polygon_from_points(ps); } } @@ -1113,4 +1117,56 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcArbitraryClosedProfileDef* } else { return nullptr; } -} \ No newline at end of file +} + +namespace { + void remove_duplicate_points_from_loop(std::vector& polygon, bool closed, double tol) { + for (;;) { + bool removed = false; + int n = polygon.size() - (closed ? 0 : 1); + for (int i = 1; i <= n; ++i) { + // wrap around to the first point in case of a closed loop + int j = (i % polygon.size()) + 1; + double dist = (polygon.at(i - 1).components - polygon.at(j - 1).components).squaredNorm(); + if (dist < tol) { + // do not remove the first or last point to + // maintain connectivity with other wires + if ((closed && j == 1) || (!closed && j == n)) polygon.erase(polygon.begin() + i - 1); + else polygon.erase(polygon.begin() + j - 1); + removed = true; + break; + } + } + if (!removed) break; + } + } +} + +taxonomy::item* mapping::map_impl(const IfcSchema::IfcPolyline* inst) { + IfcSchema::IfcCartesianPoint::list::ptr points = inst->Points(); + + // @todo + const double precision_ = 1.e-5; + + // Parse and store the points in a sequence + std::vector polygon; + polygon.reserve(points->size()); + std::transform(points->begin(), points->end(), std::back_inserter(polygon), [this](const IfcSchema::IfcCartesianPoint* p) { + return as(map(p)); + }); + + const double eps = precision_ * 10; + const bool closed_by_proximity = polygon.size() >= 3 && (polygon.front().components - polygon.back().components).norm() < eps; + if (closed_by_proximity) { + polygon.resize(polygon.size() - 1); + } + + // Remove points that are too close to one another + remove_duplicate_points_from_loop(polygon, closed_by_proximity, eps); + + if (polygon.size() < 2) { + return false; + } + + return polygon_from_points(polygon); +} diff --git a/src/ifcgeom/schema/mapping.i b/src/ifcgeom/schema/mapping.i index d588e3360a..cada9d4ef1 100644 --- a/src/ifcgeom/schema/mapping.i +++ b/src/ifcgeom/schema/mapping.i @@ -100,7 +100,7 @@ BIND(IfcFace); // BIND(IfcOrientedEdge); // BIND(IfcEdge); // BIND(IfcEdgeLoop); -// BIND(IfcPolyline); +BIND(IfcPolyline); BIND(IfcPolyLoop); // BIND(IfcCompositeCurve); // BIND(IfcTrimmedCurve); From 3731c957284c2bac8face0be198c1365ea847917 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Mon, 16 Sep 2019 17:40:55 +0200 Subject: [PATCH 180/235] Mapped item --- src/ifcgeom/schema/mapping.cpp | 20 ++++++++++++++++++++ src/ifcgeom/schema/mapping.i | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index ae2645c4bc..9b4ce1ccef 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -1170,3 +1170,23 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcPolyline* inst) { return polygon_from_points(polygon); } + +taxonomy::item* mapping::map_impl(const IfcSchema::IfcMappedItem* inst) { + IfcSchema::IfcCartesianTransformationOperator* transform = inst->MappingTarget(); + taxonomy::matrix4 gtrsf = as(map(transform)); + IfcSchema::IfcRepresentationMap* rmap = inst->MappingSource(); + IfcSchema::IfcAxis2Placement* placement = rmap->MappingOrigin(); + taxonomy::matrix4 trsf2 = as(map(placement)); + gtrsf.components = gtrsf.components * trsf2.components; + + // @todo immutable for caching? + // @todo allow for multiple levels of matrix? + auto shapes = map(rmap->MappedRepresentation()); + for (auto& c : ((taxonomy::collection*)shapes)->children) { + auto item = ((taxonomy::geom_item*)c); + item->matrix.components = gtrsf.components * item->matrix.components; + // @todo previously style was also copied. + } + + return shapes; +} diff --git a/src/ifcgeom/schema/mapping.i b/src/ifcgeom/schema/mapping.i index cada9d4ef1..d023250b61 100644 --- a/src/ifcgeom/schema/mapping.i +++ b/src/ifcgeom/schema/mapping.i @@ -29,7 +29,7 @@ BIND(IfcProduct); // BIND(IfcShellBasedSurfaceModel); BIND(IfcFaceBasedSurfaceModel); BIND(IfcRepresentation); -// BIND(IfcMappedItem); +BIND(IfcMappedItem); // IfcFacetedBrep included // IfcAdvancedBrep included // IfcFacetedBrepWithVoids included From a447dc6208bde783b8bd6f148e37aae189dcf1e2 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Mon, 16 Sep 2019 19:30:11 +0200 Subject: [PATCH 181/235] Work towards trimmed curves --- .../kernels/opencascade/IfcGeomShapes.cpp | 19 ++- src/ifcgeom/schema/mapping.cpp | 125 ++++++++++++++++++ src/ifcgeom/schema/mapping.i | 6 +- src/ifcgeom/taxonomy.h | 11 +- 4 files changed, 145 insertions(+), 16 deletions(-) diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp index 93cc497246..fb7f92803a 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp @@ -533,8 +533,14 @@ namespace { template T convert_xyz(const U& u) { - const double* vs = u.components.data(); - return T(vs[0], vs[1], vs[2]); + const auto& vs = u.components; + return T(vs(0), vs(1), vs(2)); + } + + // @todo eliminate + template + T convert_xyz2(const U& vs) { + return T(vs(0), vs(1), vs(2)); } struct curve_creation_visitor { @@ -547,15 +553,18 @@ namespace { } result_type operator()(const taxonomy::line& l) { - return result = Handle(Geom_Curve)(new Geom_Line(convert_xyz(l.origin), convert_xyz(l.direction))); + const auto& m = l.matrix.components; + return result = Handle(Geom_Curve)(new Geom_Line(convert_xyz2(m.row(3)), convert_xyz2(m.row(0)))); } result_type operator()(const taxonomy::circle& c) { - return result = Handle(Geom_Curve)(new Geom_Circle(gp_Ax2(convert_xyz(c.origin), convert_xyz(c.z), convert_xyz(c.x)), c.radius)); + const auto& m = c.matrix.components; + return result = Handle(Geom_Curve)(new Geom_Circle(gp_Ax2(convert_xyz2(m.row(3)), convert_xyz2(m.row(2)), convert_xyz2(m.row(0))), c.radius)); } result_type operator()(const taxonomy::ellipse& e) { - return result = Handle(Geom_Curve)(new Geom_Ellipse(gp_Ax2(convert_xyz(e.origin), convert_xyz(e.z), convert_xyz(e.x)), e.radius, e.radius2)); + const auto& m = e.matrix.components; + return result = Handle(Geom_Curve)(new Geom_Ellipse(gp_Ax2(convert_xyz2(m.row(3)), convert_xyz2(m.row(2)), convert_xyz2(m.row(0))), e.radius, e.radius2)); } result_type operator()(const taxonomy::loop& l) { diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index 9b4ce1ccef..c87e29d015 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -1190,3 +1190,128 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcMappedItem* inst) { return shapes; } + +taxonomy::item* mapping::map_impl(const IfcSchema::IfcCompositeCurve* inst) { + auto loop = new taxonomy::loop; + auto segments = inst->Segments(); + for (auto& segment : *segments) { + auto crv = map(segment->ParentCurve()); + if (crv) { + ((taxonomy::geom_item*)crv)->orientation = segment->SameSense(); + loop->children.push_back(crv); + } + } + IfcEntityList::ptr profile = inst->data().getInverse(&IfcSchema::IfcProfileDef::Class(), -1); + const bool force_close = profile && profile->size() > 0; + loop->closed = force_close; + return loop; +} + +taxonomy::item* mapping::map_impl(const IfcSchema::IfcTrimmedCurve* inst) { + IfcSchema::IfcCurve* basis_curve = inst->BasisCurve(); + bool isConic = basis_curve->declaration().is(IfcSchema::IfcConic::Class()); + double parameterFactor = isConic ? angle_unit_ : length_unit_; + + auto tc = new taxonomy::edge; + tc->basis = map(inst->BasisCurve()); + + bool trim_cartesian = inst->MasterRepresentation() != IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER; + IfcEntityList::ptr trims1 = inst->Trim1(); + IfcEntityList::ptr trims2 = inst->Trim2(); + + unsigned sense_agreement = inst->SenseAgreement() ? 0 : 1; + double flts[2]; + taxonomy::point3 pnts[2]; + bool has_flts[2] = { false,false }; + bool has_pnts[2] = { false,false }; + + tc->orientation = sense_agreement != 0; + + for (IfcEntityList::it it = trims1->begin(); it != trims1->end(); it++) { + IfcUtil::IfcBaseClass* i = *it; + if (i->declaration().is(IfcSchema::IfcCartesianPoint::Class())) { + pnts[sense_agreement] = as(map(i)); + has_pnts[sense_agreement] = true; + } else if (i->declaration().is(IfcSchema::IfcParameterValue::Class())) { + const double value = *((IfcSchema::IfcParameterValue*)i); + flts[sense_agreement] = value * parameterFactor; + has_flts[sense_agreement] = true; + } + } + + for (IfcEntityList::it it = trims2->begin(); it != trims2->end(); it++) { + IfcUtil::IfcBaseClass* i = *it; + if (i->declaration().is(IfcSchema::IfcCartesianPoint::Class())) { + pnts[1 - sense_agreement] = as(map(i)); + has_pnts[1 - sense_agreement] = true; + } else if (i->declaration().is(IfcSchema::IfcParameterValue::Class())) { + const double value = *((IfcSchema::IfcParameterValue*)i); + flts[1 - sense_agreement] = value * parameterFactor; + has_flts[1 - sense_agreement] = true; + } + } + + // @todo + const double precision_ = 1.e-5; + const double M_PI = 3.141592653; + + trim_cartesian &= has_pnts[0] && has_pnts[1]; + if (trim_cartesian) { + if ((pnts[0].components - pnts[1].components).norm() < (2 * precision_)) { + Logger::Message(Logger::LOG_WARNING, "Skipping segment with length below tolerance level:", inst); + return false; + } + } else if (has_flts[0] && has_flts[1]) { + // The Geom_Line is constructed from a gp_Pnt and gp_Dir, whereas the IfcLine + // is defined by an IfcCartesianPoint and an IfcVector with Magnitude. Because + // the vector is normalised when passed to Geom_Line constructor the magnitude + // needs to be factored in with the IfcParameterValue here. + if (basis_curve->declaration().is(IfcSchema::IfcLine::Class())) { + IfcSchema::IfcLine* line = static_cast(basis_curve); + const double magnitude = line->Dir()->Magnitude(); + flts[0] *= magnitude; flts[1] *= magnitude; + } + if (basis_curve->declaration().is(IfcSchema::IfcEllipse::Class())) { + IfcSchema::IfcEllipse* ellipse = static_cast(basis_curve); + double x = ellipse->SemiAxis1() * length_unit_; + double y = ellipse->SemiAxis2() * length_unit_; + const bool rotated = y > x; + if (rotated) { + flts[0] -= M_PI / 2.; + flts[1] -= M_PI / 2.; + } + } + } + + /* + // @todo + if (isConic) { + // Tiny circle segnments can cause issues later on, for example + // when the comp curve is used as the sweeping directrix. + double a, b; + Handle(Geom_Curve) crv = BRep_Tool::Curve(e, a, b); + double radius = -1.; + if (crv->DynamicType() == STANDARD_TYPE(Geom_Circle)) { + radius = Handle(Geom_Circle)::DownCast(crv)->Radius(); + } else if (crv->DynamicType() == STANDARD_TYPE(Geom_Ellipse)) { + // The formula above is for circles, but probably good enough + radius = Handle(Geom_Ellipse)::DownCast(crv)->MajorRadius(); + } + if (radius > 0. && deflection_for_approximating_circle(radius, b - a) < getValue(GV_PRECISION)) { + TopoDS_Vertex v0, v1; + TopExp::Vertices(e, v0, v1); + e = TopoDS::Edge(BRepBuilderAPI_MakeEdge(v0, v1).Edge().Oriented(e.Orientation())); + Logger::Warning("Subsituted edge with linear approximation", l); + } + } + */ + + return tc; +} + +taxonomy::item* mapping::map_impl(const IfcSchema::IfcCircle* inst) { + auto c = new taxonomy::circle; + c->matrix = as(map(inst->Position())); + c->radius = inst->Radius(); + return c; +} diff --git a/src/ifcgeom/schema/mapping.i b/src/ifcgeom/schema/mapping.i index d023250b61..5cb68bd7fb 100644 --- a/src/ifcgeom/schema/mapping.i +++ b/src/ifcgeom/schema/mapping.i @@ -102,14 +102,14 @@ BIND(IfcFace); // BIND(IfcEdgeLoop); BIND(IfcPolyline); BIND(IfcPolyLoop); -// BIND(IfcCompositeCurve); -// BIND(IfcTrimmedCurve); +BIND(IfcCompositeCurve); +BIND(IfcTrimmedCurve); // BIND(IfcArbitraryOpenProfileDef); #ifdef SCHEMA_HAS_IfcIndexedPolyCurve // BIND(IfcIndexedPolyCurve) #endif -// BIND(IfcCircle); +BIND(IfcCircle); // BIND(IfcEllipse); // BIND(IfcLine); #ifdef SCHEMA_HAS_IfcBSplineCurveWithKnots diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index d9f57828e4..d7b9187c3e 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -97,6 +97,7 @@ struct style : public item { struct geom_item : public item { style surface_style; matrix4 matrix; + boost::optional orientation; geom_item(const IfcUtil::IfcBaseClass* instance = nullptr) : item(instance) {} geom_item(const IfcUtil::IfcBaseClass* instance, matrix4 m) : item(instance), matrix(m) {} @@ -128,17 +129,11 @@ struct direction3 : public cartesian_base<3> { struct curve : public geom_item {}; struct line : public curve { - point3 origin; - direction3 direction; - virtual item* clone() const { return new line(*this); } virtual kinds kind() const { return LINE; } }; struct circle : public curve { - point3 origin; - direction3 x; - direction3 z; double radius; virtual item* clone() const { return new circle(*this); } @@ -160,7 +155,7 @@ struct bspline_curve : public curve { struct trimmed_curve : public curve { boost::variant start, end; // @todo somehow account for the fact that curve in IFC can be trimmed curve, polyline and composite curve as well. - curve* basis; + item* basis; bool orientation; trimmed_curve() : basis(nullptr), orientation(true) {} @@ -216,7 +211,7 @@ struct face : public collection { }; struct loop : public collection { - boost::optional external; + boost::optional external, closed; virtual item* clone() const { return new loop(*this); } virtual kinds kind() const { return LOOP; } From 3cde411e1b558af6fb490c2c0d0163faa46fc8d9 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 18 Sep 2019 16:35:26 +0200 Subject: [PATCH 182/235] halfspaces and boolean ops --- src/ifcgeom/kernel_agnostic/AbstractKernel.h | 2 + .../kernels/opencascade/IfcGeomShapes.cpp | 682 +++++++++++++++++- .../kernels/opencascade/OpenCascadeKernel.h | 10 + src/ifcgeom/schema/mapping.cpp | 154 +++- src/ifcgeom/schema/mapping.h | 2 +- src/ifcgeom/schema/mapping.i | 8 +- src/ifcgeom/taxonomy.h | 26 +- 7 files changed, 843 insertions(+), 41 deletions(-) diff --git a/src/ifcgeom/kernel_agnostic/AbstractKernel.h b/src/ifcgeom/kernel_agnostic/AbstractKernel.h index 27bacabe19..735fbde202 100644 --- a/src/ifcgeom/kernel_agnostic/AbstractKernel.h +++ b/src/ifcgeom/kernel_agnostic/AbstractKernel.h @@ -60,6 +60,8 @@ namespace ifcopenshell { namespace geometry { namespace kernels { virtual bool convert_impl(const taxonomy::extrusion*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } virtual bool convert_impl(const taxonomy::node*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } virtual bool convert_impl(const taxonomy::colour*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } + virtual bool convert_impl(const taxonomy::boolean_result*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } + virtual bool convert_impl(const taxonomy::plane*, ifcopenshell::geometry::ConversionResults&) { throw std::runtime_error("Not implemented"); } virtual bool convert_impl(const taxonomy::collection*, ifcopenshell::geometry::ConversionResults&); }; diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp index fb7f92803a..15ea102524 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp @@ -506,6 +506,10 @@ bool OpenCascadeKernel::convert(const taxonomy::face* face, TopoDS_Shape& result #include #include +#include +#include +#include +#include namespace { /* A compile-time for loop over the curve kinds */ @@ -543,54 +547,98 @@ namespace { return T(vs(0), vs(1), vs(2)); } + typedef boost::variant curve_creation_visitor_result_type; + curve_creation_visitor_result_type convert_curve(OpenCascadeKernel* kernel, const taxonomy::item* curve); + struct curve_creation_visitor { OpenCascadeKernel* kernel; - typedef boost::variant result_type; - result_type result; + curve_creation_visitor_result_type result; - result_type operator()(const taxonomy::bspline_curve&) { + curve_creation_visitor_result_type operator()(const taxonomy::bspline_curve&) { throw std::runtime_error("Not implemented"); } - result_type operator()(const taxonomy::line& l) { + curve_creation_visitor_result_type operator()(const taxonomy::line& l) { const auto& m = l.matrix.components; - return result = Handle(Geom_Curve)(new Geom_Line(convert_xyz2(m.row(3)), convert_xyz2(m.row(0)))); + return result = Handle(Geom_Curve)(new Geom_Line(convert_xyz2(m.col(3)), convert_xyz2(m.col(0)))); } - result_type operator()(const taxonomy::circle& c) { + curve_creation_visitor_result_type operator()(const taxonomy::circle& c) { const auto& m = c.matrix.components; - return result = Handle(Geom_Curve)(new Geom_Circle(gp_Ax2(convert_xyz2(m.row(3)), convert_xyz2(m.row(2)), convert_xyz2(m.row(0))), c.radius)); + /*Eigen::IOFormat fmt; + std::stringstream ss; + ss << m.format(fmt) << std::endl; + ss << m.col(3).format(fmt); + auto s = ss.str(); + std::wcout << s.c_str() << std::endl;*/ + return result = Handle(Geom_Curve)(new Geom_Circle(gp_Ax2(convert_xyz2(m.col(3)), convert_xyz2(m.col(2)), convert_xyz2(m.col(0))), c.radius)); } - result_type operator()(const taxonomy::ellipse& e) { + curve_creation_visitor_result_type operator()(const taxonomy::ellipse& e) { const auto& m = e.matrix.components; - return result = Handle(Geom_Curve)(new Geom_Ellipse(gp_Ax2(convert_xyz2(m.row(3)), convert_xyz2(m.row(2)), convert_xyz2(m.row(0))), e.radius, e.radius2)); + return result = Handle(Geom_Curve)(new Geom_Ellipse(gp_Ax2(convert_xyz2(m.col(3)), convert_xyz2(m.col(2)), convert_xyz2(m.col(0))), e.radius, e.radius2)); } - result_type operator()(const taxonomy::loop& l) { + curve_creation_visitor_result_type operator()(const taxonomy::loop& l) { TopoDS_Wire wire; kernel->convert(&l, wire); return result = wire; } - result_type operator()(const taxonomy::edge& e) { - if (e.basis == nullptr) { - // @todo we should probably construct edges based on correct oriented TopoDS_Vertex instead. + curve_creation_visitor_result_type operator()(const taxonomy::edge& e) { + // @todo for polyloops/-lines we should probably construct edges based on correct oriented TopoDS_Vertex instead. + + if (e.start.which() != e.end.which()) { + throw std::runtime_error("Different trim types not supported"); + } + + TopoDS_Edge E; + if (e.basis) { + auto crv_or_wire = convert_curve(kernel, e.basis); + Handle(Geom_Curve) curve; + if (crv_or_wire.which() == 0) { + curve = boost::get(crv_or_wire); + } else { + // @todo + const double precision_ = 1.e-5; + Logger::Warning("Approximating BasisCurve due to possible discontinuities", e.instance); + BRepAdaptor_CompCurve cc(boost::get(crv_or_wire), true); + Handle(Adaptor3d_HCurve) hcc = Handle(Adaptor3d_HCurve)(new BRepAdaptor_HCompCurve(cc)); + // @todo, arbitrary numbers here, note they cannot be too high as contiguous memory is allocated based on them. + Approx_Curve3d approx(hcc, precision_, GeomAbs_C0, 10, 10); + curve = approx.Curve(); + } + + // @todo, copy over logic from previous IfcTrimmedCurve handling + if (e.start.which() == 0) { + auto p1 = convert_xyz(boost::get(e.start)); + auto p2 = convert_xyz(boost::get(e.end)); + + E = BRepBuilderAPI_MakeEdge(curve, p1, p2).Edge(); + } else { + auto v1 = boost::get(e.start); + auto v2 = boost::get(e.end); + + E = BRepBuilderAPI_MakeEdge(curve, v1, v2).Edge(); + } + } else { + if (e.start.which() != 0) { + throw std::runtime_error("Non-cartesian trim on edge without curve"); + } auto p1 = convert_xyz(boost::get(e.start)); auto p2 = convert_xyz(boost::get(e.end)); - TopoDS_Edge e = BRepBuilderAPI_MakeEdge(p1, p2).Edge(); - BRep_Builder B; - TopoDS_Wire W; - B.MakeWire(W); - B.Add(W, e); - return result = W; - } else { - throw std::runtime_error("not implemented"); + + E = BRepBuilderAPI_MakeEdge(p1, p2).Edge(); } + BRep_Builder B; + TopoDS_Wire W; + B.MakeWire(W); + B.Add(W, E); + return result = W; } }; - curve_creation_visitor::result_type convert_curve(OpenCascadeKernel* kernel, const taxonomy::item* curve) { + curve_creation_visitor_result_type convert_curve(OpenCascadeKernel* kernel, const taxonomy::item* curve) { curve_creation_visitor v{ kernel }; if (dispatch_curve_creation::dispatch(curve, v)) { return v.result; @@ -846,9 +894,6 @@ bool OpenCascadeKernel::convert(const taxonomy::loop* loop, TopoDS_Wire& wire) { } bool OpenCascadeKernel::convert_impl(const taxonomy::extrusion* extrusion, ifcopenshell::geometry::ConversionResults& results) { - if (((IfcUtil::IfcBaseEntity*)extrusion->instance)->data().id() == 5722) { - std::wcerr << 1; - } TopoDS_Shape shape; if (!convert(extrusion, shape)) { return false; @@ -1631,4 +1676,589 @@ OpenCascadeKernel::faceset_helper::faceset_helper(OpenCascadeKernel* kernel, con if (loops_removed || (non_manifold && shell->closed.get_value_or(false))) { Logger::Warning(boost::lexical_cast(duplicate_faces) + " duplicate faces removed, " + boost::lexical_cast(loops_removed) + " loops removed and " + boost::lexical_cast(non_manifold) + " non-manifold edges for:", shell->instance); } -} \ No newline at end of file +} + +#include +#include +#include + +namespace { + void copy_operand(const TopTools_ListOfShape& l, TopTools_ListOfShape& r) { +#if OCC_VERSION_HEX < 0x70000 + TopTools_ListIteratorOfListOfShape it(l); + for (; it.More(); it.Next()) { + r.Append(BRepBuilderAPI_Copy(it.Value())); + } +#else + // On OCCT 7.0 and higher BRepAlgoAPI_BuilderAlgo::SetNonDestructive(true) is + // called. Not entirely sure on the behaviour before 7.0, so overcautiously + // create copies. + r.Assign(l); +#endif + } + + TopoDS_Shape copy_operand(const TopoDS_Shape& s) { +#if OCC_VERSION_HEX < 0x70000 + return BRepBuilderAPI_Copy(s); +#else + return s; +#endif + } + + double min_edge_length(const TopoDS_Shape& a) { + double min_edge_len = std::numeric_limits::infinity(); + TopExp_Explorer exp(a, TopAbs_EDGE); + for (; exp.More(); exp.Next()) { + GProp_GProps prop; + BRepGProp::LinearProperties(exp.Current(), prop); + double l = prop.Mass(); + if (l < min_edge_len) { + min_edge_len = l; + } + } + return min_edge_len; + } + + double min_vertex_edge_distance(const TopoDS_Shape& a, double min_search, double max_search) { + double M = std::numeric_limits::infinity(); + + TopTools_IndexedMapOfShape vertices, edges; + + TopExp::MapShapes(a, TopAbs_VERTEX, vertices); + TopExp::MapShapes(a, TopAbs_EDGE, edges); + + impl::tree tree; + + // Add edges to tree + for (int i = 1; i <= edges.Extent(); ++i) { + tree.add(i, edges(i)); + } + + for (int j = 1; j <= vertices.Extent(); ++j) { + const TopoDS_Vertex& v = TopoDS::Vertex(vertices(j)); + gp_Pnt p = BRep_Tool::Pnt(v); + + Bnd_Box b; + b.Add(p); + b.Enlarge(max_search); + + std::vector edge_idxs = tree.select_box(b, false); + std::vector::const_iterator it = edge_idxs.begin(); + for (; it != edge_idxs.end(); ++it) { + const TopoDS_Edge& e = TopoDS::Edge(edges(*it)); + TopoDS_Vertex v1, v2; + TopExp::Vertices(e, v1, v2); + + if (v.IsSame(v1) || v.IsSame(v2)) { + continue; + } + + BRepAdaptor_Curve crv(e); + Extrema_ExtPC ext(p, crv); + if (!ext.IsDone()) { + continue; + } + + for (int i = 1; i <= ext.NbExt(); ++i) { + const double m = sqrt(ext.SquareDistance(i)); + if (m < M && m > min_search) { + M = m; + } + } + } + } + + return M; + } + + class points_on_planar_face_generator { + private: + const TopoDS_Face& f_; + Handle(Geom_Surface) plane_; + BRepTopAdaptor_FClass2d cls_; + double u0, u1, v0, v1; + int i, j; + static const int N = 10; + + public: + points_on_planar_face_generator(const TopoDS_Face& f) + : f_(f) + , plane_(BRep_Tool::Surface(f_)) + , cls_(f_, BRep_Tool::Tolerance(f_)) + , i(0), j(0) { + BRepTools::UVBounds(f_, u0, u1, v0, v1); + } + + void reset() { + i = j = 0; + } + + bool operator()(gp_Pnt& p) { + while (j < N) { + double u = u0 + (u1 - u0) * i / N; + double v = v0 + (v1 - v0) * j / N; + + i++; + if (i == N) { + i = 0; + j++; + } + + // Specifically does not consider ON + if (cls_.Perform(gp_Pnt2d(u, v)) == TopAbs_IN) { + plane_->D0(u, v, p); + return true; + } + } + + return false; + } + }; + + double min_face_face_distance(const TopoDS_Shape& a, double max_search) { + /* + NB: This is currently only implemented for planar surfaces. + */ + double M = std::numeric_limits::infinity(); + + TopTools_IndexedMapOfShape faces; + + TopExp::MapShapes(a, TopAbs_FACE, faces); + + ifcopenshell::geometry::impl::tree tree; + + // Add faces to tree + for (int i = 1; i <= faces.Extent(); ++i) { + if (BRep_Tool::Surface(TopoDS::Face(faces(i)))->DynamicType() == STANDARD_TYPE(Geom_Plane)) { + tree.add(i, faces(i)); + } + } + + for (int j = 1; j <= faces.Extent(); ++j) { + const TopoDS_Face& f = TopoDS::Face(faces(j)); + const Handle(Geom_Surface)& fs = BRep_Tool::Surface(f); + + if (fs->DynamicType() != STANDARD_TYPE(Geom_Plane)) { + continue; + } + + points_on_planar_face_generator pgen(f); + + Bnd_Box b; + BRepBndLib::AddClose(f, b); + b.Enlarge(max_search); + + std::vector face_idxs = tree.select_box(b, false); + std::vector::const_iterator it = face_idxs.begin(); + for (; it != face_idxs.end(); ++it) { + if (*it == j) { + continue; + } + + const TopoDS_Face& g = TopoDS::Face(faces(*it)); + const Handle(Geom_Surface)& gs = BRep_Tool::Surface(g); + + auto p0 = Handle(Geom_Plane)::DownCast(fs); + auto p1 = Handle(Geom_Plane)::DownCast(gs); + + if (p0->Position().IsCoplanar(p1->Position(), max_search, asin(max_search))) { + pgen.reset(); + + BRepTopAdaptor_FClass2d cls(g, BRep_Tool::Tolerance(g)); + + gp_Pnt test; + while (pgen(test)) { + gp_Vec d = test.XYZ() - p1->Position().Location().XYZ(); + double u = d.Dot(p1->Position().XDirection()); + double v = d.Dot(p1->Position().YDirection()); + + // nb: TopAbs_ON is explicitly not considered to prevent matching adjacent faces + // with similar orientations. + if (cls.Perform(gp_Pnt2d(u, v)) == TopAbs_IN) { + gp_Pnt test2; + p1->D0(u, v, test2); + double w = gp_Vec(p1->Position().Direction().XYZ()).Dot(test2.XYZ() - test.XYZ()); + if (w < M) { + M = w; + } + } + } + } + } + } + + return M; + } + + void bounding_box_overlap(double p, const TopoDS_Shape& a, const TopTools_ListOfShape& b, TopTools_ListOfShape& c) { + Bnd_Box A; + BRepBndLib::Add(a, A); + + if (A.IsVoid()) { + return; + } + + TopTools_ListIteratorOfListOfShape it(b); + for (; it.More(); it.Next()) { + Bnd_Box B; + BRepBndLib::Add(it.Value(), B); + + if (B.IsVoid()) { + continue; + } + + if (A.Distance(B) < p) { + c.Append(it.Value()); + } + } + } + + TopoDS_Shape unify(const TopoDS_Shape& s, double tolerance) { + tolerance = (std::min)(min_edge_length(s) / 2., tolerance); + ShapeUpgrade_UnifySameDomain usd(s); + usd.SetSafeInputMode(true); + usd.SetLinearTolerance(tolerance); + usd.SetAngularTolerance(1.e-3); + usd.Build(); + return usd.Shape(); + } + + bool is_manifold_occt(const TopoDS_Shape& a) { + if (a.ShapeType() == TopAbs_COMPOUND || a.ShapeType() == TopAbs_SOLID) { + TopoDS_Iterator it(a); + for (; it.More(); it.Next()) { + if (!is_manifold_occt(it.Value())) { + return false; + } + } + return true; + } else { + TopTools_IndexedDataMapOfShapeListOfShape map; + TopExp::MapShapesAndAncestors(a, TopAbs_EDGE, TopAbs_FACE, map); + + for (int i = 1; i <= map.Extent(); ++i) { + if (map.FindFromIndex(i).Extent() != 2) { + return false; + } + } + + return true; + } + } +} + +bool OpenCascadeKernel::boolean_operation(const TopoDS_Shape& a_, const TopTools_ListOfShape& b__, BOPAlgo_Operation op, TopoDS_Shape& result, double fuzziness) { + + if (fuzziness < 0.) { + fuzziness = precision_; + } + + // @todo, it does seem a bit odd, we first triangulate non-planar faces + // to later unify them again. Can we make this a bit more intelligent? + TopoDS_Shape a = unify(a_, fuzziness); + TopTools_ListOfShape b_; + { + TopTools_ListIteratorOfListOfShape it(b__); + for (; it.More(); it.Next()) { + b_.Append(unify(it.Value(), fuzziness)); + } + } + + bool success = false; + BRepAlgoAPI_BooleanOperation* builder; + TopTools_ListOfShape B, b; + if (op == BOPAlgo_CUT) { + builder = new BRepAlgoAPI_Cut(); + bounding_box_overlap(precision_, a, b_, b); + } else if (op == BOPAlgo_COMMON) { + builder = new BRepAlgoAPI_Common(); + b = b_; + } else if (op == BOPAlgo_FUSE) { + builder = new BRepAlgoAPI_Fuse(); + b = b_; + } else { + return false; + } + + if (b.Extent() == 0) { + result = a; + return true; + } + + // Find a sensible value for the fuzziness, based on precision + // and limited by edge lengths and vertex-edge distances. + const double len_a = min_edge_length(a_); + double min_length_orig = (std::min)(len_a, min_vertex_edge_distance(a_, precision_, len_a)); + TopTools_ListIteratorOfListOfShape it(b__); + for (; it.More(); it.Next()) { + double d = min_edge_length(it.Value()); + if (d < min_length_orig) { + min_length_orig = d; + } + d = min_vertex_edge_distance(it.Value(), precision_, d); + if (d < min_length_orig) { + min_length_orig = d; + } + } + + const double fuzz = (std::min)(min_length_orig / 3., fuzziness); + + TopTools_ListOfShape s1s; + s1s.Append(copy_operand(a)); +#if OCC_VERSION_HEX >= 0x70000 + builder->SetNonDestructive(true); +#endif + builder->SetFuzzyValue(fuzz); + builder->SetArguments(s1s); + copy_operand(b, B); + builder->SetTools(B); + builder->Build(); + if (builder->IsDone()) { + TopoDS_Shape r = *builder; + + ShapeFix_Shape fix(r); + try { + fix.SetMinTolerance(fuzz); + fix.SetMaxTolerance(fuzz); + fix.SetPrecision(fuzz); + fix.Perform(); + r = fix.Shape(); + } catch (...) { + Logger::Error("Shape healing failed on boolean result"); + } + + success = BRepCheck_Analyzer(r).IsValid() != 0; + + if (success) { + + success = !is_manifold_occt(a) || is_manifold_occt(r); + + if (success) { + + // when there are edges or vertex-edge distances close to the used fuzziness, the + // output is not trusted and the operation is attempted with a higher fuzziness. + int reason = 0; + double v; + if ((v = min_edge_length(r)) < fuzziness * 3.) { + reason = 0; + success = false; + } else if ((v = min_vertex_edge_distance(r, precision_, fuzziness * 3.)) < fuzziness * 3.) { + reason = 1; + success = false; + } else if ((v = min_face_face_distance(r, fuzziness * 3.)) < fuzziness * 3.) { + reason = 2; + success = false; + } + + if (success) { + result = r; + } else { + static const char* const reason_strings[] = { "edge length", "vertex-edge", "face-face" }; + std::stringstream str; + str << "Boolean operation result failing " << reason_strings[reason] << " interference check, with fuzziness " << fuzziness << " with length " << v; + Logger::Notice(str.str()); + } + } else { + Logger::Notice("Boolean operation yields non-manifold result"); + } + } else { + Logger::Notice("Boolean operation yields invalid result"); + } + } else { + std::stringstream str; +#if OCC_VERSION_HEX >= 0x70000 + builder->DumpErrors(str); +#else + str << "Error code: " << builder->ErrorStatus(); +#endif + std::string str_str = str.str(); + if (str_str.size()) { + Logger::Notice(str_str); + } + } + delete builder; + if (!success) { + const double new_fuzziness = fuzziness * 10.; + if (new_fuzziness - 1e-15 <= precision_ * 10000. && new_fuzziness < min_length_orig) { + return boolean_operation(a, b, op, result, new_fuzziness); + } else { + Logger::Notice("No longer attempting boolean operation with higher fuzziness"); + } + } + return success; +} + +namespace { + BOPAlgo_Operation op_to_occt(taxonomy::boolean_result::operation_t t) { + switch (t) { + case taxonomy::boolean_result::UNION: return BOPAlgo_FUSE; + case taxonomy::boolean_result::INTERSECTION: return BOPAlgo_COMMON; + case taxonomy::boolean_result::SUBTRACTION: return BOPAlgo_CUT; + } + } +} + +bool OpenCascadeKernel::convert_impl(const taxonomy::boolean_result* br, ifcopenshell::geometry::ConversionResults& results) { + bool first = true; + + TopoDS_Shape a; + TopTools_ListOfShape b; + + for (auto& c : br->children) { + ifcopenshell::geometry::ConversionResults cr; + // @todo half-space detection + AbstractKernel::convert(c, cr); + if (first && br->operation == taxonomy::boolean_result::SUBTRACTION) { + // @todo A will be null on union/intersection, intended? + flatten_shape_list(cr, a, false); + } else { + for (auto& r : cr) { + auto oshp = (OpenCascadeShape*)r.Shape(); + b.Append(oshp->shape()); + } + } + first = false; + } + + TopoDS_Shape r; + if (!boolean_operation(a, b, op_to_occt(br->operation), r)) { + return false; + } + + results.emplace_back(ConversionResult( + br->instance->data().id(), + br->matrix, + new OpenCascadeShape(r), + br->surface_style + )); + return true; +} + +bool OpenCascadeKernel::is_compound(const TopoDS_Shape& shape) { + bool has_solids = TopExp_Explorer(shape, TopAbs_SOLID).More() != 0; + bool has_shells = TopExp_Explorer(shape, TopAbs_SHELL).More() != 0; + bool has_compounds = TopExp_Explorer(shape, TopAbs_COMPOUND).More() != 0; + bool has_faces = TopExp_Explorer(shape, TopAbs_FACE).More() != 0; + return has_compounds && has_faces && !has_solids && !has_shells; +} + +const TopoDS_Shape& OpenCascadeKernel::ensure_fit_for_subtraction(const TopoDS_Shape& shape, TopoDS_Shape& solid) { + const bool is_comp = is_compound(shape); + if (!is_comp) { + return solid = shape; + } + + if (!create_solid_from_compound(shape, solid)) { + return solid = shape; + } + + return solid; +} + +bool OpenCascadeKernel::flatten_shape_list(const ifcopenshell::geometry::ConversionResults& shapes, TopoDS_Shape& result, bool fuse) { + TopoDS_Compound compound; + BRep_Builder builder; + builder.MakeCompound(compound); + + result = TopoDS_Shape(); + + for (ifcopenshell::geometry::ConversionResults::const_iterator it = shapes.begin(); it != shapes.end(); ++it) { + TopoDS_Shape merged; + const TopoDS_Shape& s = *(OpenCascadeShape*)it->Shape(); + if (fuse) { + ensure_fit_for_subtraction(s, merged); + } else { + merged = s; + } + const TopoDS_Shape moved_shape = apply_transformation(merged, it->Placement()); + + if (shapes.size() == 1) { + result = moved_shape; + return true; + } + + if (fuse) { + if (result.IsNull()) { + result = moved_shape; + } else { + BRepAlgoAPI_Fuse brep_fuse(result, moved_shape); + if (brep_fuse.IsDone()) { + TopoDS_Shape fused = brep_fuse; + + ShapeFix_Shape fix(result); + fix.Perform(); + result = fix.Shape(); + + bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0; + if (is_valid) { + result = fused; + } + } + } + } else { + builder.Add(compound, moved_shape); + } + } + + if (!fuse) { + result = compound; + } + + const bool success = !result.IsNull(); + return success; +} + +TopoDS_Shape OpenCascadeKernel::apply_transformation(const TopoDS_Shape& s, const taxonomy::matrix4& t) { + if (t.components.isIdentity()) { + return s; + } else { + gp_GTrsf trsf; + convert(&t, trsf); + return apply_transformation(s, trsf); + } +} + +#include + +TopoDS_Shape OpenCascadeKernel::apply_transformation(const TopoDS_Shape& s, const gp_GTrsf& t) { + if (t.Form() == gp_Other) { + Logger::Message(Logger::LOG_WARNING, "Applying non uniform transformation"); + return BRepBuilderAPI_GTransform(s, t, true); + } else { + return apply_transformation(s, t.Trsf()); + } +} + +TopoDS_Shape OpenCascadeKernel::apply_transformation(const TopoDS_Shape& s, const gp_Trsf& t) { + /// @todo set to 1. and exactly 1. or use epsilon? + if (t.ScaleFactor() != 1.) { + return BRepBuilderAPI_Transform(s, t, true); + } else { + return s.Moved(t); + } +} + +bool OpenCascadeKernel::convert_impl(const taxonomy::face* face, ifcopenshell::geometry::ConversionResults& results) { + // Root level faces are only encountered in case of half spaces + + if (face->basis == nullptr) { + Logger::Error("Half space without underlying surface:", face->instance); + return false; + } + + if (face->basis->kind() != taxonomy::PLANE) { + Logger::Message(Logger::LOG_ERROR, "Unsupported BaseSurface:", face->basis->instance); + return false; + } + + // @todo boundary + const auto& m = ((taxonomy::geom_item*)face->basis)->matrix.components; + gp_Pln pln(convert_xyz2(m.col(3)), convert_xyz2(m.col(2))); + const gp_Pnt pnt = pln.Location().Translated(face->orientation.get_value_or(false) ? -pln.Axis().Direction() : pln.Axis().Direction()); + TopoDS_Shape shape = BRepPrimAPI_MakeHalfSpace(BRepBuilderAPI_MakeFace(pln), pnt).Solid(); + results.emplace_back(ConversionResult( + face->instance->data().id(), + new OpenCascadeShape(shape), + face->surface_style + )); +} diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h index 9120036799..f2c564662f 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h @@ -240,9 +240,19 @@ namespace kernels { bool approximate_plane_through_wire(const TopoDS_Wire& wire, gp_Pln& plane, double eps = -1.); bool triangulate_wire(const std::vector& wires, TopTools_ListOfShape& faces); + bool boolean_operation(const TopoDS_Shape& a_, const TopTools_ListOfShape& b__, BOPAlgo_Operation op, TopoDS_Shape& result, double fuzziness = -1.); + const TopoDS_Shape& ensure_fit_for_subtraction(const TopoDS_Shape& shape, TopoDS_Shape& solid); + bool flatten_shape_list(const ifcopenshell::geometry::ConversionResults& shapes, TopoDS_Shape& result, bool fuse); + bool is_compound(const TopoDS_Shape& shape); + TopoDS_Shape apply_transformation(const TopoDS_Shape& s, const taxonomy::matrix4& t); + TopoDS_Shape apply_transformation(const TopoDS_Shape& s, const gp_GTrsf& t); + TopoDS_Shape apply_transformation(const TopoDS_Shape& s, const gp_Trsf& t); + + virtual bool convert_impl(const taxonomy::face*, ifcopenshell::geometry::ConversionResults&); virtual bool convert_impl(const taxonomy::shell*, ifcopenshell::geometry::ConversionResults&); virtual bool convert_impl(const taxonomy::extrusion*, ifcopenshell::geometry::ConversionResults&); + virtual bool convert_impl(const taxonomy::boolean_result*, ifcopenshell::geometry::ConversionResults&); }; /* diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index c87e29d015..d603a9b67d 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -74,6 +74,7 @@ namespace { face_->instance = loop->instance; face_->matrix = loop->matrix; // @todo make sure loop is not freed + // this is accounted for below with as::upgraded_ face_->children = { loop }; } } @@ -101,9 +102,10 @@ namespace { class as { private: taxonomy::item* item_; + mutable bool upgraded_; public: - as(taxonomy::item* item) : item_(item) {} + as(taxonomy::item* item) : item_(item), upgraded_(false) {} operator T() const { if (!item_) { throw taxonomy::topology_error("item was nullptr"); @@ -115,6 +117,7 @@ namespace { { loop_to_face_upgrade upgrade(item_); if (upgrade) { + upgraded_ = true; return upgrade; } } @@ -122,7 +125,10 @@ namespace { } } ~as() { - delete item_; + if (!upgraded_) { + // @todo revisit this + delete item_; + } } }; @@ -153,14 +159,68 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcExtrudedAreaSolid* inst) { ); } +namespace { + template + void visit(taxonomy::collection* deep, Fn fn) { + for (auto& c : deep->children) { + if (c->kind() == taxonomy::COLLECTION) { + visit((taxonomy::collection*)c, fn); + } else { + fn(c); + } + } + } + + taxonomy::collection* flatten(taxonomy::collection* deep) { + auto flat = new taxonomy::collection; + visit(deep, [&flat](taxonomy::item* i) { + flat->children.push_back(i); + }); + return flat; + } + + template + taxonomy::collection* filter(taxonomy::collection* collection, Fn fn) { + auto filtered = new taxonomy::collection; + for (auto& child : collection->children) { + if (fn(child)) { + filtered->children.push_back(child); + } + } + if (filtered->children.empty()) { + delete filtered; + return nullptr; + } + return filtered; + } +} + taxonomy::item* mapping::map_impl(const IfcSchema::IfcRepresentation* inst) { - return map_to_collection(this, inst->Items()); + auto items = map_to_collection(this, inst->Items()); + if (items == nullptr) { + return nullptr; + } + auto flat = flatten(items); + if (flat == nullptr) { + return nullptr; + } + auto filtered = filter(flat, [](taxonomy::item* i) { + // @todo just filter loops for now. + return i->kind() != taxonomy::LOOP; + }); + delete items; + delete flat; + return filtered; } taxonomy::item* mapping::map_impl(const IfcSchema::IfcFaceBasedSurfaceModel* inst) { return map_to_collection(this, inst->FbsmFaces()); } +taxonomy::item* mapping::map_impl(const IfcSchema::IfcGeometricSet* inst) { + return map_to_collection(this, inst->Elements()); +} + taxonomy::item* mapping::map_impl(const IfcSchema::IfcConnectedFaceSet* inst) { auto shell = map_to_collection(this, inst->CfsFaces()); shell->closed = inst->declaration().is(IfcSchema::IfcClosedShell::Class()); @@ -245,7 +305,8 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcDirection* inst) { } taxonomy::item* mapping::map_impl(const IfcSchema::IfcProduct* inst) { - auto n = new taxonomy::node; + auto openings = find_openings(inst); + auto n = map_to_collection(this, openings); n->matrix = as(map(inst->ObjectPlacement())); return n; } @@ -449,7 +510,7 @@ bool mapping::reuse_ok_(settings& s, const IfcSchema::IfcProduct::list::ptr& pro return associated_single_materials.size() == 1; } -IfcEntityList::ptr mapping::find_openings(IfcSchema::IfcProduct* product) { +IfcEntityList::ptr mapping::find_openings(const IfcSchema::IfcProduct* product) { IfcEntityList::ptr openings(new IfcEntityList); if (product->declaration().is(IfcSchema::IfcElement::Class()) && !product->declaration().is(IfcSchema::IfcOpeningElement::Class())) { @@ -458,7 +519,7 @@ IfcEntityList::ptr mapping::find_openings(IfcSchema::IfcProduct* product) { } // Is the IfcElement a decomposition of an IfcElement with any IfcOpeningElements? - IfcSchema::IfcObjectDefinition* obdef = product->as(); + const IfcSchema::IfcObjectDefinition* obdef = product->as(); for (;;) { auto decomposes = obdef->Decomposes()->generalize(); if (decomposes->size() != 1) break; @@ -1261,6 +1322,8 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcTrimmedCurve* inst) { Logger::Message(Logger::LOG_WARNING, "Skipping segment with length below tolerance level:", inst); return false; } + tc->start = pnts[0]; + tc->end = pnts[1]; } else if (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 @@ -1275,12 +1338,15 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcTrimmedCurve* inst) { IfcSchema::IfcEllipse* ellipse = static_cast(basis_curve); double x = ellipse->SemiAxis1() * length_unit_; double y = ellipse->SemiAxis2() * length_unit_; + // @todo the need for this rotation is OCCT-specific const bool rotated = y > x; if (rotated) { flts[0] -= M_PI / 2.; flts[1] -= M_PI / 2.; } } + tc->start = flts[0]; + tc->end = flts[1]; } /* @@ -1315,3 +1381,79 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcCircle* inst) { c->radius = inst->Radius(); return c; } + +namespace { + taxonomy::boolean_result::operation_t boolean_op_type(IfcSchema::IfcBooleanOperator::Value op) { + if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) { + return taxonomy::boolean_result::SUBTRACTION; + } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) { + return taxonomy::boolean_result::INTERSECTION; + } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) { + return taxonomy::boolean_result::UNION; + } else { + throw taxonomy::topology_error("Unknown boolean operation"); + } + } + +} + +taxonomy::item* mapping::map_impl(const IfcSchema::IfcBooleanResult* inst) { + IfcSchema::IfcBooleanOperand* operand1 = inst->FirstOperand(); + IfcSchema::IfcBooleanOperand* operand2 = inst->SecondOperand(); + + IfcEntityList::ptr operands(new IfcEntityList); + operands->push(operand1); + operands->push(operand2); + + auto op = boolean_op_type(inst->Operator()); + + bool process_as_list = true; + while (true) { + auto res1 = operand1->as(); + if (res1) { + if (boolean_op_type(res1->Operator()) == op) { + operand1 = res1->FirstOperand(); + operands->push(res1->SecondOperand()); + } else { + process_as_list = false; + break; + } + } else { + break; + } + } + + if (!process_as_list) { + operand1 = inst->FirstOperand(); + operands.reset(new IfcEntityList); + operands->push(operand1); + operands->push(operand2); + } + + auto br = map_to_collection(this, operands); + if (br) { + br->operation = op; + } + return br; +} + +taxonomy::item* mapping::map_impl(const IfcSchema::IfcPolygonalBoundedHalfSpace* inst) { + auto f = map_impl((IfcSchema::IfcHalfSpaceSolid*) inst); + ((taxonomy::face*)f)->children = ((taxonomy::loop)as(map(inst->PolygonalBoundary()))).children; + return f; +} + + +taxonomy::item* mapping::map_impl(const IfcSchema::IfcHalfSpaceSolid* inst) { + IfcSchema::IfcSurface* surface = inst->BaseSurface(); + if (!surface->declaration().is(IfcSchema::IfcPlane::Class())) { + Logger::Message(Logger::LOG_ERROR, "Unsupported BaseSurface:", surface); + return nullptr; + } + auto p = new taxonomy::plane; + p->matrix = as(map(((IfcSchema::IfcPlane*)surface)->Position())); + p->orientation = !inst->AgreementFlag(); + auto f = new taxonomy::face; + f->basis = p; + return f; +} diff --git a/src/ifcgeom/schema/mapping.h b/src/ifcgeom/schema/mapping.h index c3334a4e61..19b0a43e62 100644 --- a/src/ifcgeom/schema/mapping.h +++ b/src/ifcgeom/schema/mapping.h @@ -33,7 +33,7 @@ namespace geometry { IfcSchema::IfcRepresentation* representation_mapped_to(const IfcSchema::IfcRepresentation* representation); IfcSchema::IfcProduct::list::ptr products_represented_by(const IfcSchema::IfcRepresentation* representation); bool reuse_ok_(settings& s, const IfcSchema::IfcProduct::list::ptr& products); - IfcEntityList::ptr find_openings(IfcSchema::IfcProduct* product); + IfcEntityList::ptr find_openings(const IfcSchema::IfcProduct* product); IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity* product, bool include_openings); #include "bind_convert_decl.i" diff --git a/src/ifcgeom/schema/mapping.i b/src/ifcgeom/schema/mapping.i index 5cb68bd7fb..2ea4d901c5 100644 --- a/src/ifcgeom/schema/mapping.i +++ b/src/ifcgeom/schema/mapping.i @@ -35,7 +35,7 @@ BIND(IfcMappedItem); // IfcFacetedBrepWithVoids included // IfcAdvancedBrepWithVoids included // BIND(IfcManifoldSolidBrep); -// BIND(IfcGeometricSet); +BIND(IfcGeometricSet); #ifdef SCHEMA_HAS_IfcCylindricalSurface // BIND(IfcCylindricalSurface); @@ -56,9 +56,9 @@ BIND(IfcMappedItem); BIND(IfcExtrudedAreaSolid); // BIND(IfcRevolvedAreaSolid); BIND(IfcConnectedFaceSet); -// BIND(IfcBooleanResult); -// BIND(IfcPolygonalBoundedHalfSpace); -// BIND(IfcHalfSpaceSolid); +BIND(IfcBooleanResult); +BIND(IfcPolygonalBoundedHalfSpace); +BIND(IfcHalfSpaceSolid); // BIND(IfcSurfaceOfLinearExtrusion); // BIND(IfcSurfaceOfRevolution); // BIND(IfcBlock); diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index d7b9187c3e..696857b3db 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -25,7 +25,7 @@ public: topology_error(const char* const s) : std::runtime_error(s) {} }; -enum kinds { MATRIX4, POINT3, DIRECTION3, LINE, CIRCLE, ELLIPSE, BSPLINE_CURVE, EDGE, LOOP, FACE, SHELL, EXTRUSION, NODE, COLLECTION, COLOUR, STYLE }; +enum kinds { MATRIX4, POINT3, DIRECTION3, LINE, CIRCLE, ELLIPSE, BSPLINE_CURVE, PLANE, EDGE, LOOP, FACE, SHELL, EXTRUSION, NODE, COLLECTION, BOOLEAN_RESULT, COLOUR, STYLE }; struct item { const IfcUtil::IfcBaseClass* instance; @@ -205,7 +205,16 @@ struct shell : public collection { virtual kinds kind() const { return SHELL; } }; +struct surface : public geom_item {}; + +struct plane : public surface { + virtual item* clone() const { return new plane(*this); } + virtual kinds kind() const { return PLANE; } +}; + struct face : public collection { + item* basis; + virtual item* clone() const { return new face(*this); } virtual kinds kind() const { return FACE; } }; @@ -234,16 +243,25 @@ struct extrusion : public sweep { extrusion(matrix4 m, face basis, direction3 dir, double d) : sweep(m, basis), direction(dir), depth(d) {} }; -struct node : public geom_item { +struct node : public collection { std::map representations; - std::vector children; virtual item* clone() const { return new node(*this); } virtual kinds kind() const { return NODE; } }; +struct boolean_result : public collection { + enum operation_t { + UNION, SUBTRACTION, INTERSECTION + }; + + virtual item* clone() const { return new boolean_result(*this); } + virtual kinds kind() const { return BOOLEAN_RESULT; } + operation_t operation; +}; + namespace impl { - typedef std::tuple KindsTuple; + typedef std::tuple KindsTuple; typedef std::tuple CurvesTuple; } From 1f4bc28e2bf040ee7219477028ff4db54da14823 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 19 Sep 2019 10:11:01 +0200 Subject: [PATCH 183/235] Product placements and openings --- .../kernel_agnostic/AbstractKernel.cpp | 3 ++ .../kernels/opencascade/IfcGeomShapes.cpp | 39 ++++++++++++++-- .../kernels/opencascade/OpenCascadeKernel.h | 4 +- src/ifcgeom/schema/mapping.cpp | 46 +++++++++++++++++-- src/ifcgeom/schema_agnostic/Converter.cpp | 17 +++++-- 5 files changed, 94 insertions(+), 15 deletions(-) diff --git a/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp index a73027edda..62cebcabfb 100644 --- a/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp +++ b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp @@ -55,6 +55,9 @@ bool ifcopenshell::geometry::kernels::AbstractKernel::convert_impl(const taxonom for (auto& c : collection->children) { convert(c, r); } + for (auto i = s; i < r.size(); ++i) { + r[i].prepend(collection->matrix); + } return r.size() > s; } diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp index 15ea102524..f17955d9bf 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp @@ -2104,18 +2104,37 @@ bool OpenCascadeKernel::convert_impl(const taxonomy::boolean_result* br, ifcopen TopoDS_Shape a; TopTools_ListOfShape b; + taxonomy::style first_item_style; + for (auto& c : br->children) { + // AbstractKernel::convert(c, results); + // continue; + ifcopenshell::geometry::ConversionResults cr; // @todo half-space detection AbstractKernel::convert(c, cr); if (first && br->operation == taxonomy::boolean_result::SUBTRACTION) { // @todo A will be null on union/intersection, intended? flatten_shape_list(cr, a, false); + first_item_style = ((taxonomy::geom_item*)c)->surface_style; + if (!first_item_style.diffuse && c->kind() == taxonomy::COLLECTION) { + first_item_style = ((taxonomy::geom_item*) ((taxonomy::collection*)c)->children[0])->surface_style; + } } else { for (auto& r : cr) { - auto oshp = (OpenCascadeShape*)r.Shape(); - b.Append(oshp->shape()); - } + auto S = ((OpenCascadeShape*)r.Shape())->shape(); + gp_GTrsf trsf; + convert(&r.Placement(), trsf); + // @todo it really confuses me why I cannot use Moved() here instead + S.Location(S.Location() * trsf.Trsf()); + b.Append(S); + /*results.emplace_back(ConversionResult( + r.ItemId(), + ifcopenshell::geometry::taxonomy::matrix4(), + new OpenCascadeShape(S), + r.Style() + ));*/ + } } first = false; } @@ -2125,11 +2144,21 @@ bool OpenCascadeKernel::convert_impl(const taxonomy::boolean_result* br, ifcopen return false; } + /* + TopoDS_Compound r; + BRep_Builder B; + B.MakeCompound(r); + B.Add(r, a); + for (auto& bb : b) { + B.Add(r, bb); + } + */ + results.emplace_back(ConversionResult( br->instance->data().id(), br->matrix, new OpenCascadeShape(r), - br->surface_style + br->surface_style.diffuse ? br->surface_style : first_item_style )); return true; } @@ -2261,4 +2290,6 @@ bool OpenCascadeKernel::convert_impl(const taxonomy::face* face, ifcopenshell::g new OpenCascadeShape(shape), face->surface_style )); + + return true; } diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h index f2c564662f..9f49245e58 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h @@ -218,7 +218,9 @@ namespace kernels { public: OpenCascadeKernel() : AbstractKernel("opencascade") - , faceset_helper_(nullptr) {} + , faceset_helper_(nullptr) + // @todo + , precision_(1.e-5) {} OpenCascadeKernel(const OpenCascadeKernel& other) : AbstractKernel("opencascade") { diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index d603a9b67d..51a29a32a1 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -306,9 +306,39 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcDirection* inst) { taxonomy::item* mapping::map_impl(const IfcSchema::IfcProduct* inst) { auto openings = find_openings(inst); - auto n = map_to_collection(this, openings); - n->matrix = as(map(inst->ObjectPlacement())); - return n; + // @todo const cast + auto reps = inst->data().file->traverse((IfcSchema::IfcProduct*) inst, 2)->as(); + IfcSchema::IfcRepresentation* body = nullptr; + for (auto& rep : *reps) { + if (rep->RepresentationIdentifier() == "Body") { + body = rep; + } + } + if (!body) { + return nullptr; + } + + auto c = new taxonomy::collection; + c->matrix = as(map(inst->ObjectPlacement())); + + if (openings->size()) { + auto ci = c->matrix.components.inverse(); + + IfcEntityList::ptr operands(new IfcEntityList); + operands->push(body); + operands->push(openings); + auto n = map_to_collection(this, operands); + std::for_each(n->children.begin() + 1, n->children.end(), [&ci](taxonomy::item* i) { + ((taxonomy::geom_item*)i)->matrix.components = ci * ((taxonomy::geom_item*)i)->matrix.components; + }); + n->operation = taxonomy::boolean_result::SUBTRACTION; + // @todo one indirection too many + n->instance = inst; + c->children = { n }; + } else { + c->children = { map(body) }; + } + return c; } taxonomy::item* mapping::map_impl(const IfcSchema::IfcAxis2Placement3D* inst) { @@ -515,7 +545,10 @@ IfcEntityList::ptr mapping::find_openings(const IfcSchema::IfcProduct* product) IfcEntityList::ptr openings(new IfcEntityList); if (product->declaration().is(IfcSchema::IfcElement::Class()) && !product->declaration().is(IfcSchema::IfcOpeningElement::Class())) { IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)product; - openings = element->HasOpenings()->generalize(); + auto rels = element->HasOpenings(); + for (auto& rel : *rels) { + openings->push(rel->RelatedOpeningElement()); + } } // Is the IfcElement a decomposition of an IfcElement with any IfcOpeningElements? @@ -526,7 +559,10 @@ IfcEntityList::ptr mapping::find_openings(const IfcSchema::IfcProduct* product) IfcSchema::IfcObjectDefinition* rel_obdef = (*decomposes->begin())->as()->RelatingObject(); if (rel_obdef->declaration().is(IfcSchema::IfcElement::Class()) && !rel_obdef->declaration().is(IfcSchema::IfcOpeningElement::Class())) { IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)rel_obdef; - openings->push(element->HasOpenings()->generalize()); + auto rels = element->HasOpenings(); + for (auto& rel : *rels) { + openings->push(rel->RelatedOpeningElement()); + } } obdef = rel_obdef; diff --git a/src/ifcgeom/schema_agnostic/Converter.cpp b/src/ifcgeom/schema_agnostic/Converter.cpp index 97a6f41d78..0a72eb7efd 100644 --- a/src/ifcgeom/schema_agnostic/Converter.cpp +++ b/src/ifcgeom/schema_agnostic/Converter.cpp @@ -34,18 +34,24 @@ ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create ifcopenshell::geometry::Representation::BRep* shape; ifcopenshell::geometry::ConversionResults shapes; + /* auto rep_item = mapping_->map(representation); // @todo should map() throw an exception instead? if (rep_item == nullptr) { return nullptr; } + */ - // @todo decide how to get placement from product - auto placement = (taxonomy::geom_item*) mapping_->map(product); - if (placement == nullptr) { + // @todo how to combine product_node and rep_item? + auto product_node = (taxonomy::geom_item*) mapping_->map(product); + if (product_node == nullptr) { return nullptr; } - kernel_->convert(rep_item, shapes); + + auto place = taxonomy::matrix4(); + std::swap(place, product_node->matrix); + + kernel_->convert(product_node, shapes); shape = new ifcopenshell::geometry::Representation::BRep(s, representation_id_builder.str(), shapes); @@ -57,7 +63,8 @@ ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create guid, // @todo "", - placement->matrix, + place, + // product_node->matrix, boost::shared_ptr(shape), product ); From 474786c4c54645b1e355719cea9e1107778bb04d Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 22 Sep 2019 10:32:03 +0200 Subject: [PATCH 184/235] IfcArbitraryProfileDefWithVoids --- src/ifcgeom/schema/mapping.cpp | 16 ++++++++++++++-- src/ifcgeom/schema/mapping.i | 2 +- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index 51a29a32a1..7dfba8bb4a 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -1205,11 +1205,23 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcRectangleProfileDef* inst) }); } -taxonomy::item* mapping::map_impl(const IfcSchema::IfcArbitraryClosedProfileDef* l) { - auto loop = map(l->OuterCurve()); +taxonomy::item* mapping::map_impl(const IfcSchema::IfcArbitraryClosedProfileDef* inst) { + auto loop = map(inst->OuterCurve()); if (loop) { auto face = new taxonomy::face; + ((taxonomy::loop*)loop)->external = true; face->children = { loop }; + if (inst->as()) { + auto with_voids = inst->as(); + auto voids = with_voids->InnerCurves(); + for (auto& v : *voids) { + auto inner_loop = map(v); + if (inner_loop) { + ((taxonomy::loop*)inner_loop)->external = false; + face->children.push_back(inner_loop); + } + } + } return face; } else { return nullptr; diff --git a/src/ifcgeom/schema/mapping.i b/src/ifcgeom/schema/mapping.i index 2ea4d901c5..f743319b09 100644 --- a/src/ifcgeom/schema/mapping.i +++ b/src/ifcgeom/schema/mapping.i @@ -72,7 +72,7 @@ BIND(IfcHalfSpaceSolid); // BIND(IfcSurfaceCurveSweptAreaSolid); // BIND(IfcSweptDiskSolid); -// BIND(IfcArbitraryProfileDefWithVoids); +// IfcArbitraryProfileDefWithVoids included BIND(IfcArbitraryClosedProfileDef); // BIND(IfcRoundedRectangleProfileDef); // BIND(IfcRectangleHollowProfileDef); From a1671448db3fc60992ac6d177e4c53bf40fe9b36 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 22 Sep 2019 15:05:14 +0200 Subject: [PATCH 185/235] Default static runtime to off. --- cmake/CMakeLists.txt | 2 +- win/build-deps.cmd | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 88191a7f5b..e892f36eb5 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -44,7 +44,7 @@ OPTION(USE_VLD "Use Visual Leak Detector for debugging memory leaks, MSVC-only." 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(USE_STATIC_MSVC_RUNTIME "Link to the static runtime on MSVC." OFF) OPTION(BUILD_SHARED_LIBS "Build IfcParse and IfcGeom as shared libs (SO/DLL)." OFF) if (${HAS_MAX}) OPTION(BUILD_IFCMAX "Build IfcMax, a 3ds Max plug-in, Windows-only." ON) diff --git a/win/build-deps.cmd b/win/build-deps.cmd index 1805fb5180..d588c104a2 100644 --- a/win/build-deps.cmd +++ b/win/build-deps.cmd @@ -157,8 +157,6 @@ set OCE_VERSION=OCE-0.18 set PYTHON_VERSION=3.4.3 set SWIG_VERSION=3.0.12 -goto :Eigen - :: Note all of the dependencies have appropriate label so that user can easily skip something if wanted :: by modifying this file and using goto. :Boost From 61403e878ee40a57fda6ab2223fe6317157d988f Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 22 Sep 2019 16:02:05 +0200 Subject: [PATCH 186/235] Try catch face normal computation --- src/ifcgeom/kernels/cgal/CgalConversionResult.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index 86f5f93cbb..417dad4f22 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -53,7 +53,12 @@ void ifcopenshell::geometry::CgalShape::Triangulate(const settings& settings, co } // CGAL::Polygon_mesh_processing::compute_normals(s, vertex_normals_map, face_normals_map); - CGAL::Polygon_mesh_processing::compute_face_normals(s, face_normals_map); + try { + CGAL::Polygon_mesh_processing::compute_face_normals(s, face_normals_map); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Face normal calculation failed"); + return; + } int num_faces = 0, num_vertices = 0; for (auto &face: faces(s)) { From 008539388477af4b19a2ef75c14f0ffa255e795b Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 22 Sep 2019 16:02:22 +0200 Subject: [PATCH 187/235] Take into account vertex welding --- src/ifcgeom/kernels/cgal/CgalConversionResult.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index 417dad4f22..8df12efeee 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -67,8 +67,10 @@ void ifcopenshell::geometry::CgalShape::Triangulate(const settings& settings, co continue; } CGAL::Polyhedron_3::Halfedge_around_facet_const_circulator current_halfedge = face->facet_begin(); + int vertexidx[3]; + int i = 0; do { - t->addVertex(surface_style_id, + vertexidx[i++] = 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))); @@ -82,7 +84,7 @@ void ifcopenshell::geometry::CgalShape::Triangulate(const settings& settings, co ++current_halfedge; } while (current_halfedge != face->facet_begin()); - t->addFace(surface_style_id, num_vertices-3, num_vertices-2, num_vertices-1); + t->addFace(surface_style_id, vertexidx[0], vertexidx[1], vertexidx[2]); ++num_faces; } From d91ac7363f02c126b50f8de09ff414b882bea33d Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 22 Sep 2019 16:02:48 +0200 Subject: [PATCH 188/235] Mark loops from profile_helper as external --- src/ifcgeom/schema/mapping.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index 7dfba8bb4a..a671e34891 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -1107,8 +1107,9 @@ namespace { profile_point* previous, *next; }; - taxonomy::loop* polygon_from_points(const std::vector& ps) { + taxonomy::loop* polygon_from_points(const std::vector& ps, bool external = true) { auto loop = new taxonomy::loop(); + loop->external = external; auto previous = ps.back(); for (auto& p : ps) { auto e = new taxonomy::edge; From 11ad1b2cc56717a1a0c8ce677ffc65704546759e Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Tue, 24 Sep 2019 15:46:50 +0200 Subject: [PATCH 189/235] cgal extrusion --- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 154 ++++++++++++++++++++++++ src/ifcgeom/kernels/cgal/CgalKernel.h | 16 ++- 2 files changed, 166 insertions(+), 4 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index f78f39a18c..7ce5eeb9ed 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -179,6 +179,37 @@ bool CgalKernel::convert(const taxonomy::face* face, cgal_face_t& result) { return true; } +namespace { + bool convert_curve(CgalKernel* kernel, const taxonomy::item* curve, cgal_wire_t& builder) { + if (curve->kind() == taxonomy::EDGE) { + auto e = (taxonomy::edge*) curve; + if (true || e->basis == nullptr) { + if (builder.empty()) { + const auto& p = boost::get(e->start); + cgal_point_t pnt(p.components(0), p.components(1), p.components(2)); + builder.push_back(pnt); + } + const auto& p = boost::get(e->end); + cgal_point_t pnt(p.components(0), p.components(1), p.components(2)); + builder.push_back(pnt); + } else if (e->basis->kind() == taxonomy::CIRCLE) { + // @todo + } else if (e->basis->kind() == taxonomy::ELLIPSE) { + + } else { + throw std::runtime_error("Not implemented basis kind"); + } + } else if (curve->kind() == taxonomy::LOOP) { + const auto& edges = ((taxonomy::loop*) curve)->children; + for (auto& c : edges) { + convert_curve(kernel, c, builder); + } + } else { + throw std::runtime_error("Not implemented curve"); + } + } +} + bool CgalKernel::convert(const taxonomy::loop* loop, cgal_wire_t& result) { // @todo only implement polygonal loops @@ -187,6 +218,7 @@ bool CgalKernel::convert(const taxonomy::loop* loop, cgal_wire_t& result) { for (auto& e : edges) { if (e->basis) { + Logger::Error("Only polyhedra supported :("); return false; } points.push_back(boost::get(e->start)); @@ -244,3 +276,125 @@ bool CgalKernel::convert_impl(const taxonomy::shell *shell, ifcopenshell::geomet )); return true; } + +bool CgalKernel::convert_impl(const taxonomy::extrusion* extrusion, ifcopenshell::geometry::ConversionResults& results) { + cgal_shape_t shape; + if (!convert(extrusion, shape)) { + return false; + } + results.emplace_back(ConversionResult( + extrusion->instance->data().id(), + extrusion->matrix, + new CgalShape(shape), + extrusion->surface_style + )); + return true; +} + +bool CgalKernel::convert(const taxonomy::extrusion* extrusion, cgal_shape_t &shape) { + const double& height = extrusion->depth; + if (height < precision_) { + Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", extrusion->instance); + return false; + } + + // Outer + cgal_face_t bottom_face; + if (!convert(&extrusion->basis, bottom_face)) { + return false; + } + // std::cout << "Face vertices: " << face.outer.size() << std::endl; + + auto fs = extrusion->direction.components; + cgal_direction_t dir(fs(0), fs(1), fs(2)); + // std::cout << "Direction: " << dir << std::endl; + + std::list face_list; + face_list.push_back(bottom_face); + + for (std::vector::const_iterator current_vertex = bottom_face.outer.begin(); + current_vertex != bottom_face.outer.end(); + ++current_vertex) { + std::vector::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::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 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::const_iterator current_vertex = inner.begin(); + current_vertex != inner.end(); + ++current_vertex) { + std::vector::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::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:", extrusion->instance); + 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:", extrusion->instance); + return false; + } + +} \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 541c07e465..bb682a7e8f 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -92,10 +92,14 @@ namespace geometry { namespace kernels { class IFC_GEOM_API CgalKernel : public AbstractKernel { + private: + double precision_; public: CgalKernel() - : AbstractKernel("cgal") {} + : AbstractKernel("cgal") + // @todo + , precision_(1.e-5) {} void remove_duplicate_points_from_loop(cgal_wire_t& polygon); @@ -104,12 +108,16 @@ namespace kernels { CGAL::Nef_polyhedron_3 create_nef_polyhedron(std::list &face_list); CGAL::Nef_polyhedron_3 create_nef_polyhedron(CGAL::Polyhedron_3 &polyhedron); + bool convert(const taxonomy::extrusion*, cgal_shape_t&); bool convert(const taxonomy::face*, cgal_face_t&); bool convert(const taxonomy::loop*, cgal_wire_t&); - bool convert(const taxonomy::shell* l, cgal_shape_t& shape); - + // bool convert(const taxonomy::matrix4*, cgal_placement_t&); + bool convert(const taxonomy::shell*, cgal_shape_t&); + + // virtual bool convert_impl(const taxonomy::face*, ifcopenshell::geometry::ConversionResults&); virtual bool convert_impl(const taxonomy::shell*, ifcopenshell::geometry::ConversionResults&); - // virtual bool convert_impl(const taxonomy::extrusion*, ifcopenshell::geometry::ConversionResults&); + virtual bool convert_impl(const taxonomy::extrusion*, ifcopenshell::geometry::ConversionResults&); + // virtual bool convert_impl(const taxonomy::boolean_result*, ifcopenshell::geometry::ConversionResults&); }; } From 389964c9f4ca8f156bdde01ac92d8de8e37dacac Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 25 Sep 2019 15:30:11 +0200 Subject: [PATCH 190/235] cgal boolean result and minkowski sum for dilation --- .../kernels/cgal/CgalConversionResult.cpp | 16 +- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 208 ++++++++++++++++++ src/ifcgeom/kernels/cgal/CgalKernel.h | 14 +- 3 files changed, 233 insertions(+), 5 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index 8df12efeee..5bbfb2537c 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -75,9 +75,19 @@ void ifcopenshell::geometry::CgalShape::Triangulate(const settings& settings, co 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)); + double nx = 0.; + double ny = 0.; + double nz = 1.; + // @todo normal calculation throws divide by zero? + // try { + if (false) { + nx = CGAL::to_double(face_normals_map[face].cartesian(0)); + ny = CGAL::to_double(face_normals_map[face].cartesian(1)); + nz = CGAL::to_double(face_normals_map[face].cartesian(2)); + } + // catch (...) { + // Logger::Error("Error during normal calculation"); + // } t->addNormal(nx, ny, nz); ++num_vertices; diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index 7ce5eeb9ed..b14301762d 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -22,6 +22,8 @@ #include "../../../ifcparse/IfcLogger.h" #include "../../../ifcgeom/kernels/cgal/CgalConversionResult.h" +#include + using namespace ifcopenshell::geometry; using namespace ifcopenshell::geometry::kernels; @@ -397,4 +399,210 @@ bool CgalKernel::convert(const taxonomy::extrusion* extrusion, cgal_shape_t &sha return false; } +} + +CGAL::Polyhedron_3 CgalKernel::create_cube(double d) { + cgal_face_t bottom_face; + bottom_face.outer.push_back(Kernel_::Point_3(-d, -d, -d)); + bottom_face.outer.push_back(Kernel_::Point_3(+d, -d, -d)); + bottom_face.outer.push_back(Kernel_::Point_3(+d, +d, -d)); + bottom_face.outer.push_back(Kernel_::Point_3(-d, +d, -d)); + + cgal_direction_t dir(0, 0, 2 * d); + + std::list face_list = { bottom_face }; + + for (std::vector::const_iterator current_vertex = bottom_face.outer.begin(); + current_vertex != bottom_face.outer.end(); + ++current_vertex) + { + std::vector::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 + dir); + side_face.outer.push_back(*next_vertex + dir); + + face_list.push_back(side_face); + } + + cgal_face_t top_face; + + for (std::vector::const_reverse_iterator vertex = bottom_face.outer.rbegin(); + vertex != bottom_face.outer.rend(); + ++vertex) + { + top_face.outer.push_back(*vertex + dir); + } + + face_list.push_back(top_face); + + return create_polyhedron(face_list); +} + +bool CgalKernel::preprocess_boolean_operand(const IfcUtil::IfcBaseClass* log_reference, const cgal_shape_t& shape_const, CGAL::Nef_polyhedron_3& result, bool dilate) { + cgal_shape_t shape = shape_const; + + if (!shape.is_valid()) { + Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Invalid geometry:", log_reference); + return false; + } + + if (!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:", log_reference); + return false; + } + + bool success = false; + + try { + success = CGAL::Polygon_mesh_processing::triangulate_faces(shape); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Triangulation of geometry crashed:", log_reference); + return false; + } + + if (!success) { + Logger::Message(Logger::LOG_ERROR, "Triangulation of geometry failed:", log_reference); + return false; + } + + if (CGAL::Polygon_mesh_processing::does_self_intersect(shape)) { + Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Self-intersecting geometry:", log_reference); + return false; + } + + try { + result = CGAL::Nef_polyhedron_3(shape); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Could not convert geometry to Nef:", log_reference); + return false; + } + + if (false && dilate) { + try { + // @todo don't dilate in 3 dimensions but only in the XY plane, orthogonal to wall axis. + result = CGAL::minkowski_sum_3(result, precision_cube_); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Could not dilate boolean operand", log_reference); + return false; + } + } + + try { + cgal_shape_t convert_back; + result.convert_to_polyhedron(convert_back); + } catch (...) { + Logger::Message(Logger::LOG_WARNING, "Final conversion will likely fail. Could not convert geometry from Nef:", log_reference); + } + + return true; +} + +namespace { + bool convert_placement(const ifcopenshell::geometry::taxonomy::matrix4& place, cgal_placement_t& trsf) { + const auto& m = place.components; + + // @todo check + trsf = cgal_placement_t( + m(0, 0), m(0, 1), m(0, 2), m(0, 3), + m(1, 0), m(1, 1), m(1, 2), m(1, 3), + m(2, 0), m(2, 1), m(2, 2), m(2, 3)); + + return true; + } +} + + + +bool CgalKernel::convert_impl(const taxonomy::boolean_result* br, ifcopenshell::geometry::ConversionResults& results) { + bool first = true; + + CGAL::Nef_polyhedron_3 a; + + taxonomy::style first_item_style; + + for (auto& c : br->children) { + // AbstractKernel::convert(c, results); + // continue; + + ifcopenshell::geometry::ConversionResults cr; + // @todo half-space detection + AbstractKernel::convert(c, cr); + + if (first && br->operation == taxonomy::boolean_result::SUBTRACTION) { + first_item_style = ((taxonomy::geom_item*)c)->surface_style; + if (!first_item_style.diffuse && c->kind() == taxonomy::COLLECTION) { + first_item_style = ((taxonomy::geom_item*) ((taxonomy::collection*)c)->children[0])->surface_style; + } + } + + for (auto it = cr.begin(); it != cr.end(); ++it) { + const cgal_shape_t& entity_shape_unlocated(((CgalShape*)it->Shape())->shape()); + cgal_shape_t entity_shape(entity_shape_unlocated); + if (!it->Placement().components.isIdentity()) { + cgal_placement_t trsf; + convert_placement(it->Placement(), trsf); + for (auto &vertex : vertices(entity_shape)) { + if (false) { + auto x = CGAL::to_double(vertex->point().x()); + auto y = CGAL::to_double(vertex->point().y()); + auto z = CGAL::to_double(vertex->point().z()); + std::wcout << x << " " << y << " " << z << std::endl; + } + vertex->point() = vertex->point().transform(trsf); + if (false) { + auto x = CGAL::to_double(vertex->point().x()); + auto y = CGAL::to_double(vertex->point().y()); + auto z = CGAL::to_double(vertex->point().z()); + std::wcout << x << " " << y << " " << z << std::endl; + } + } + } + + CGAL::Nef_polyhedron_3 nef; + preprocess_boolean_operand(c->instance, entity_shape, nef, + // Dilate boolean subtraction operands + (!first && br->operation == taxonomy::boolean_result::SUBTRACTION) ? precision_ : 0.); + + if (first) { + a = nef; + } else { + if (br->operation == taxonomy::boolean_result::SUBTRACTION) { + a -= nef; + } else if (br->operation == taxonomy::boolean_result::INTERSECTION) { + a *= nef; + } else if (br->operation == taxonomy::boolean_result::UNION) { + a += nef; + } + } + } + + first = false; + } + + cgal_shape_t a_poly; + + try { + a.convert_to_polyhedron(a_poly); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Could not convert geometry with openings from Nef:", br->instance); + return false; + } + + results.emplace_back(ConversionResult( + br->instance->data().id(), + br->matrix, + new CgalShape(a_poly), + br->surface_style.diffuse ? br->surface_style : first_item_style + )); + return true; } \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index bb682a7e8f..8a4e7d9e74 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -94,12 +94,22 @@ namespace kernels { class IFC_GEOM_API CgalKernel : public AbstractKernel { private: double precision_; + size_t circle_segments_; + CGAL::Nef_polyhedron_3 precision_cube_; + + CGAL::Polyhedron_3 create_cube(double d); + bool preprocess_boolean_operand(const IfcUtil::IfcBaseClass* log_reference, const cgal_shape_t& shape_const, CGAL::Nef_polyhedron_3& result, bool dilate); public: CgalKernel() : AbstractKernel("cgal") // @todo - , precision_(1.e-5) {} + , precision_(1.e-5) + , circle_segments_(16) + { + auto cc = create_cube(precision_); + precision_cube_ = CGAL::Nef_polyhedron_3(cc); + } void remove_duplicate_points_from_loop(cgal_wire_t& polygon); @@ -117,7 +127,7 @@ namespace kernels { // virtual bool convert_impl(const taxonomy::face*, ifcopenshell::geometry::ConversionResults&); virtual bool convert_impl(const taxonomy::shell*, ifcopenshell::geometry::ConversionResults&); virtual bool convert_impl(const taxonomy::extrusion*, ifcopenshell::geometry::ConversionResults&); - // virtual bool convert_impl(const taxonomy::boolean_result*, ifcopenshell::geometry::ConversionResults&); + virtual bool convert_impl(const taxonomy::boolean_result*, ifcopenshell::geometry::ConversionResults&); }; } From f391b425baa5197e954799bcddab8bff42cf0906 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 6 Oct 2019 09:11:44 +0200 Subject: [PATCH 191/235] dilate as boolean --- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index b14301762d..695333ef15 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -487,7 +487,7 @@ bool CgalKernel::preprocess_boolean_operand(const IfcUtil::IfcBaseClass* log_ref return false; } - if (false && dilate) { + if (dilate) { try { // @todo don't dilate in 3 dimensions but only in the XY plane, orthogonal to wall axis. result = CGAL::minkowski_sum_3(result, precision_cube_); @@ -571,7 +571,7 @@ bool CgalKernel::convert_impl(const taxonomy::boolean_result* br, ifcopenshell:: CGAL::Nef_polyhedron_3 nef; preprocess_boolean_operand(c->instance, entity_shape, nef, // Dilate boolean subtraction operands - (!first && br->operation == taxonomy::boolean_result::SUBTRACTION) ? precision_ : 0.); + (!first && br->operation == taxonomy::boolean_result::SUBTRACTION)); if (first) { a = nef; From a5de17228ab660d03351e0ccc8750e92caa29e01 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 6 Oct 2019 19:03:31 +0200 Subject: [PATCH 192/235] Work towards space boundaries fix --- src/ifcconvert/IfcConvert.cpp | 224 +++++++++++++++++- src/ifcgeom/abstract_mapping.cpp | 4 +- src/ifcgeom/abstract_mapping.h | 8 +- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 23 +- src/ifcgeom/kernels/cgal/CgalKernel.h | 3 + src/ifcgeom/schema/mapping.cpp | 6 +- src/ifcgeom/schema/mapping.h | 4 +- src/ifcgeom/schema_agnostic/Converter.cpp | 12 +- src/ifcgeom/schema_agnostic/Converter.h | 10 +- src/ifcgeom/schema_agnostic/IfcGeomFilter.h | 8 +- src/ifcgeom/schema_agnostic/IfcGeomIterator.h | 10 +- src/serializers/SvgSerializer.cpp | 4 +- .../schema_dependent/XmlSerializer.h | 4 +- 13 files changed, 292 insertions(+), 28 deletions(-) diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 271f5c0794..845ad5d2c1 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -143,6 +143,7 @@ bool file_exists(const std::string& filename) { static std::basic_stringstream log_stream; void write_log(bool); void fix_quantities(IfcParse::IfcFile&, bool, bool, bool); +void fix_spaceboundaries(IfcParse::IfcFile&, bool, bool, bool); std::string format_duration(time_t start, time_t end); /// @todo make the filters non-global @@ -219,7 +220,9 @@ int main(int argc, char** argv) { po::options_description ifc_options("IFC options"); ifc_options.add_options() ("calculate-quantities", "Calculate or fix the physical quantity definitions " - "based on an interpretation of the geometry when exporting IFC"); + "based on an interpretation of the geometry when exporting IFC") + ("fix-space-boundaries", "Calculate or fix space boundary geometries " + "when exporting IFC"); int num_threads; @@ -577,6 +580,9 @@ int main(int argc, char** argv) { if (vmap.count("calculate-quantities")) { fix_quantities(*ifc_file, no_progress, quiet, stderr_progress); } + if (vmap.count("fix-space-boundaries")) { + fix_spaceboundaries(*ifc_file, no_progress, quiet, stderr_progress); + } fs << *ifc_file; exit_code = EXIT_SUCCESS; } else { @@ -1171,6 +1177,222 @@ namespace latebound_access { } } +#undef Handle +#include "../ifcgeom/kernels/cgal/CgalKernel.h" +#include +#include + +template +T enlarge(const T& t, double d = 1.e-5) { + T::NT min[3]; + T::NT max[3]; + for (int i = 0; i < t.dimension(); ++i) { + min[i] = t.min_coord(i) - d; + max[i] = t.max_coord(i) + d; + } + return T(min, max, t.handle()); +} + +int convert_to_nef(cgal_shape_t& shape, CGAL::Nef_polyhedron_3& result) { + if (!shape.is_valid()) { + return 1; + } + + if (!shape.is_closed()) { + return 2; + } + + bool success = false; + + try { + success = CGAL::Polygon_mesh_processing::triangulate_faces(shape); + } catch (...) { + return 3; + } + + if (!success) { + return 4; + } + + if (CGAL::Polygon_mesh_processing::does_self_intersect(shape)) { + return 5; + } + + try { + result = CGAL::Nef_polyhedron_3(shape); + } catch (...) { + return 6; + } + + return 0; +} + +void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) { + typedef std::vector> > nefs_t; + typedef CGAL::Box_intersection_d::Box_with_handle_d Box; + + ifcopenshell::geometry::settings settings; + settings.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, false); + settings.set(ifcopenshell::geometry::settings::WELD_VERTICES, false); + settings.set(ifcopenshell::geometry::settings::SEW_SHELLS, true); + settings.set(ifcopenshell::geometry::settings::CONVERT_BACK_UNITS, true); + settings.set(ifcopenshell::geometry::settings::DISABLE_TRIANGULATION, true); + settings.set(ifcopenshell::geometry::settings::DISABLE_OPENING_SUBTRACTIONS, true); + + std::vector spaces_and_walls = { + IfcGeom::entity_filter(true, false, {"IfcWall", "IfcSpace"}) + }; + + ifcopenshell::geometry::Iterator context_iterator("cgal", settings, &f, spaces_and_walls); + + if (!context_iterator.initialize()) { + return; + } + + auto kernel = (ifcopenshell::geometry::kernels::CgalKernel*) context_iterator.converter().kernel(); + auto cube = kernel->precision_cube(); + + size_t num_created = 0; + int old_progress = quiet ? 0 : -1; + + std::vector boxes; + nefs_t nefs; + + for (;; ++num_created) { + bool has_more = true; + if (num_created) { + has_more = context_iterator.next(); + } + ifcopenshell::geometry::NativeElement* geom_object = nullptr; + if (has_more) { + geom_object = context_iterator.get_native(); + } + if (!geom_object) { + break; + } + + std::stringstream ss; + ss << geom_object->product()->data().toString(); + auto sss = ss.str(); + std::wcout << sss.c_str() << std::endl; + + for (auto& g : geom_object->geometry()) { + auto s = ((ifcopenshell::geometry::CgalShape*) g.Shape())->shape(); + const auto& m = g.Placement().components; + const auto& n = geom_object->transformation().data().components; + + if (true || !m.isIdentity()) { + const cgal_placement_t trsf( + m(0, 0), m(0, 1), m(0, 2), m(0, 3), + m(1, 0), m(1, 1), m(1, 2), m(1, 3), + m(2, 0), m(2, 1), m(2, 2), m(2, 3)); + + const cgal_placement_t trsf2( + n(0, 0), n(0, 1), n(0, 2), n(0, 3), + n(1, 0), n(1, 1), n(1, 2), n(1, 3), + n(2, 0), n(2, 1), n(2, 2), n(2, 3)); + + // Apply transformation + for (auto &vertex : vertices(s)) { + vertex->point() = vertex->point().transform(trsf).transform(trsf2); + /* + std::ostringstream ss; + ss << vertex->point().cartesian(0); + auto sss = ss.str(); + std::wcout << sss.c_str() << std::endl; + */ + } + } + + std::wcout << 1 << std::endl; + CGAL::Nef_polyhedron_3 nef; + auto c = convert_to_nef(s, nef); + if (c != 0) { + std::wcout << "Error " << c << std::endl; + continue; + } + std::wcout << 2 << std::endl; + nef = CGAL::minkowski_sum_3(nef, cube); + std::wcout << 3 << std::endl; + nefs.push_back({ geom_object->product(), nef }); + std::wcout << 4 << std::endl; + + Kernel_::RT inf(std::numeric_limits::infinity()); + Kernel_::RT min[3] = { +inf, +inf, +inf }; + Kernel_::RT max[3] = { -inf, -inf, -inf }; + Box b(min, max, nefs.end() - 1); + + for (auto &vertex : vertices(s)) { + Kernel_::RT p[3] = { + vertex->point().cartesian(0), + vertex->point().cartesian(1), + vertex->point().cartesian(2) + }; + b.extend(p); + } + + boxes.push_back(enlarge(b)); + + /* + std::ostringstream ss; + ss << geom_object->product()->data().toString() << std::endl << b.min_coord(0) << " - " << b.max_coord(0) << std::endl; + auto sss = ss.str(); + std::wcout << sss.c_str(); + */ + } + + if (!no_progress) { + if (quiet) { + const int progress = context_iterator.progress(); + for (; old_progress < progress; ++old_progress) { + std::cout << "."; + if (stderr_progress) + std::cerr << "."; + } + std::cout << std::flush; + if (stderr_progress) + std::cerr << std::flush; + } else { + const int progress = context_iterator.progress() / 2; + if (old_progress != progress) Logger::ProgressBar(progress); + old_progress = progress; + } + } + } + + CGAL::box_self_intersection_d(boxes.begin(), boxes.end(), [](const Box& a, const Box& b) { + std::ostringstream ss; + ss << a.handle()->first->data().toString() << "x" << b.handle()->first->data().toString() << std::endl; + auto x = a.handle()->second * b.handle()->second; + cgal_shape_t x_poly; + x.convert_to_polyhedron(x_poly); + for (auto& v : vertices(x_poly)) { + auto p = v->point(); + for (int i = 0; i < 3; ++i) { + ss << p.cartesian(i) << " "; + } + ss << std::endl; + } + ss << "---" << std::endl; + auto sss = ss.str(); + std::wcout << sss.c_str(); + }); + + if (!no_progress && quiet) { + for (; old_progress < 100; ++old_progress) { + std::cout << "."; + if (stderr_progress) + std::cerr << "."; + } + std::cout << std::flush; + if (stderr_progress) + std::cerr << std::flush; + } else { + Logger::Status("\rDone fixing space boundaries for " + boost::lexical_cast(num_created) + + " objects "); + } +} + void fix_quantities(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) { { auto delete_reversed = [&f](const IfcEntityList::ptr& insts) { diff --git a/src/ifcgeom/abstract_mapping.cpp b/src/ifcgeom/abstract_mapping.cpp index 387e2c53a3..215b9d5caf 100644 --- a/src/ifcgeom/abstract_mapping.cpp +++ b/src/ifcgeom/abstract_mapping.cpp @@ -24,12 +24,12 @@ void ifcopenshell::geometry::impl::MappingFactoryImplementation::bind(const std: this->insert(std::make_pair(schema_name_lower, fn)); } -ifcopenshell::geometry::abstract_mapping* ifcopenshell::geometry::impl::MappingFactoryImplementation::construct(IfcParse::IfcFile* file) { +ifcopenshell::geometry::abstract_mapping* ifcopenshell::geometry::impl::MappingFactoryImplementation::construct(IfcParse::IfcFile* file, settings& s) { const std::string schema_name_lower = boost::to_lower_copy(file->schema()->name()); std::map::const_iterator it; it = this->find(schema_name_lower); if (it == end()) { throw IfcParse::IfcException("No geometry mapping registered for " + schema_name_lower); } - return it->second(file); + return it->second(file, s); } diff --git a/src/ifcgeom/abstract_mapping.h b/src/ifcgeom/abstract_mapping.h index 5ff2e575bc..97f6254f6c 100644 --- a/src/ifcgeom/abstract_mapping.h +++ b/src/ifcgeom/abstract_mapping.h @@ -29,7 +29,11 @@ namespace geometry { typedef boost::function filter_t; class abstract_mapping { + protected: + settings settings_; public: + abstract_mapping(settings& s) : settings_(s) {} + virtual ifcopenshell::geometry::taxonomy::item* map(const IfcUtil::IfcBaseClass*) = 0; virtual void get_representations(std::vector& tasks, std::vector& filters, settings& s) = 0; virtual IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity* product, bool include_openings = true) = 0; @@ -37,13 +41,13 @@ namespace geometry { }; namespace impl { - typedef boost::function1 mapping_fn; + typedef boost::function2 mapping_fn; class MappingFactoryImplementation : public std::map { public: MappingFactoryImplementation(); void bind(const std::string& schema_name, mapping_fn); - abstract_mapping* construct(IfcParse::IfcFile*); + abstract_mapping* construct(IfcParse::IfcFile*, settings&); }; MappingFactoryImplementation& mapping_implementations(); diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index 695333ef15..d5b1561072 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -447,6 +447,24 @@ CGAL::Polyhedron_3 CgalKernel::create_cube(double d) { return create_polyhedron(face_list); } +bool CgalKernel::thin_solid(const CGAL::Nef_polyhedron_3& a, CGAL::Nef_polyhedron_3& result) { + // @todo this should be possible as a minkowski sum of facet & cube. rather than a set of boolean ops. + + auto a_nonconst = a; + auto ax = CGAL::minkowski_sum_3(a_nonconst, precision_cube_); + auto x = ax - a; + + result = x; + return true; + + auto yxy = CGAL::minkowski_sum_3(x, precision_cube_); + auto y = yxy * a; + auto zyz = CGAL::minkowski_sum_3(y, precision_cube_); + result = yxy * zyz; + + return true; +} + bool CgalKernel::preprocess_boolean_operand(const IfcUtil::IfcBaseClass* log_reference, const cgal_shape_t& shape_const, CGAL::Nef_polyhedron_3& result, bool dilate) { cgal_shape_t shape = shape_const; @@ -589,7 +607,10 @@ bool CgalKernel::convert_impl(const taxonomy::boolean_result* br, ifcopenshell:: first = false; } - cgal_shape_t a_poly; + cgal_shape_t a_poly, b_poly; + + // CGAL::Nef_polyhedron_3 b; + // thin_solid(a, b); try { a.convert_to_polyhedron(a_poly); diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 8a4e7d9e74..e5755a4772 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -99,6 +99,7 @@ namespace kernels { CGAL::Polyhedron_3 create_cube(double d); bool preprocess_boolean_operand(const IfcUtil::IfcBaseClass* log_reference, const cgal_shape_t& shape_const, CGAL::Nef_polyhedron_3& result, bool dilate); + bool thin_solid(const CGAL::Nef_polyhedron_3& a, CGAL::Nef_polyhedron_3& result); public: CgalKernel() @@ -128,6 +129,8 @@ namespace kernels { virtual bool convert_impl(const taxonomy::shell*, ifcopenshell::geometry::ConversionResults&); virtual bool convert_impl(const taxonomy::extrusion*, ifcopenshell::geometry::ConversionResults&); virtual bool convert_impl(const taxonomy::boolean_result*, ifcopenshell::geometry::ConversionResults&); + + const CGAL::Nef_polyhedron_3& precision_cube() const { return precision_cube_; } }; } diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index a671e34891..cbc395c51d 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -27,8 +27,8 @@ using namespace ifcopenshell::geometry; namespace { struct POSTFIX_SCHEMA(factory_t) { - abstract_mapping* operator()(IfcParse::IfcFile* file) const { - ifcopenshell::geometry::POSTFIX_SCHEMA(mapping)* m = new ifcopenshell::geometry::POSTFIX_SCHEMA(mapping)(file); + abstract_mapping* operator()(IfcParse::IfcFile* file, settings& settings) const { + ifcopenshell::geometry::POSTFIX_SCHEMA(mapping)* m = new ifcopenshell::geometry::POSTFIX_SCHEMA(mapping)(file, settings); return m; } }; @@ -321,7 +321,7 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcProduct* inst) { auto c = new taxonomy::collection; c->matrix = as(map(inst->ObjectPlacement())); - if (openings->size()) { + if (openings->size() && !settings_.get(settings::DISABLE_OPENING_SUBTRACTIONS)) { auto ci = c->matrix.components.inverse(); IfcEntityList::ptr operands(new IfcEntityList); diff --git a/src/ifcgeom/schema/mapping.h b/src/ifcgeom/schema/mapping.h index 19b0a43e62..597826cf33 100644 --- a/src/ifcgeom/schema/mapping.h +++ b/src/ifcgeom/schema/mapping.h @@ -19,10 +19,10 @@ namespace geometry { double length_unit_, angle_unit_; std::string length_unit_name_; const IfcParse::declaration* placement_rel_to_; - + void initialize_units_(); public: - POSTFIX_SCHEMA(mapping)(IfcParse::IfcFile* file) : file_(file), placement_rel_to_(0) { + POSTFIX_SCHEMA(mapping)(IfcParse::IfcFile* file, settings& settings) : abstract_mapping(settings), file_(file), placement_rel_to_(0) { initialize_units_(); } virtual ifcopenshell::geometry::taxonomy::item* map(const IfcUtil::IfcBaseClass*); diff --git a/src/ifcgeom/schema_agnostic/Converter.cpp b/src/ifcgeom/schema_agnostic/Converter.cpp index 0a72eb7efd..0a866e35a2 100644 --- a/src/ifcgeom/schema_agnostic/Converter.cpp +++ b/src/ifcgeom/schema_agnostic/Converter.cpp @@ -2,19 +2,21 @@ #include "../../ifcgeom/schema_agnostic/IfcGeomElement.h" -ifcopenshell::geometry::Converter::Converter(const std::string& geometry_library, IfcParse::IfcFile* file) { +ifcopenshell::geometry::Converter::Converter(const std::string& geometry_library, IfcParse::IfcFile* file, settings& s) + : settings_(s) +{ kernel_ = kernels::construct(geometry_library, file); - mapping_ = impl::mapping_implementations().construct(file); + mapping_ = impl::mapping_implementations().construct(file, settings_); } ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create_brep_for_representation_and_product( - const ifcopenshell::geometry::settings& settings, IfcUtil::IfcBaseEntity* representation, IfcUtil::IfcBaseEntity* product) { + IfcUtil::IfcBaseEntity* representation, IfcUtil::IfcBaseEntity* product) { std::stringstream representation_id_builder; const std::string product_type = product->declaration().name(); // @todo - element_settings s(settings, 1.0 /*getValue(GV_LENGTH_UNIT) */, product_type); + element_settings s(settings_, 1.0 /*getValue(GV_LENGTH_UNIT) */, product_type); int parent_id = -1; try { @@ -210,7 +212,7 @@ ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create } ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create_brep_for_processed_representation( - const ifcopenshell::geometry::settings& /* settings */, IfcUtil::IfcBaseEntity* /* representation */, IfcUtil::IfcBaseEntity* product, + IfcUtil::IfcBaseEntity* /* representation */, IfcUtil::IfcBaseEntity* product, ifcopenshell::geometry::NativeElement* brep) { int parent_id = -1; diff --git a/src/ifcgeom/schema_agnostic/Converter.h b/src/ifcgeom/schema_agnostic/Converter.h index 598123f360..1f28e284fe 100644 --- a/src/ifcgeom/schema_agnostic/Converter.h +++ b/src/ifcgeom/schema_agnostic/Converter.h @@ -17,8 +17,10 @@ namespace ifcopenshell { namespace geometry { private: abstract_mapping* mapping_; kernels::AbstractKernel* kernel_; - + ifcopenshell::geometry::settings settings_; public: + kernels::AbstractKernel* kernel() { return kernel_; } + // Tolerances and settings for various geometrical operations: enum GeomValue { // Specifies the deflection of the mesher @@ -49,7 +51,7 @@ namespace ifcopenshell { namespace geometry { GV_DIMENSIONALITY }; - Converter(const std::string& geometry_library, IfcParse::IfcFile* file); + Converter(const std::string& geometry_library, IfcParse::IfcFile* file, ifcopenshell::geometry::settings& settings); ~Converter() {} @@ -81,8 +83,8 @@ namespace ifcopenshell { namespace geometry { return results; } - ifcopenshell::geometry::NativeElement* create_brep_for_representation_and_product(const ifcopenshell::geometry::settings& settings, IfcUtil::IfcBaseEntity* representation, IfcUtil::IfcBaseEntity* product); - ifcopenshell::geometry::NativeElement* create_brep_for_processed_representation(const ifcopenshell::geometry::settings& settings, IfcUtil::IfcBaseEntity* representation, IfcUtil::IfcBaseEntity* product, ifcopenshell::geometry::NativeElement* brep); + ifcopenshell::geometry::NativeElement* create_brep_for_representation_and_product(IfcUtil::IfcBaseEntity* representation, IfcUtil::IfcBaseEntity* product); + ifcopenshell::geometry::NativeElement* create_brep_for_processed_representation(IfcUtil::IfcBaseEntity* representation, IfcUtil::IfcBaseEntity* product, ifcopenshell::geometry::NativeElement* brep); /* static int count(const ifcopenshell::geometry::ConversionResultShape*, int, bool unique=false); diff --git a/src/ifcgeom/schema_agnostic/IfcGeomFilter.h b/src/ifcgeom/schema_agnostic/IfcGeomFilter.h index 523cc0b8f0..e699be8bbd 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomFilter.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomFilter.h @@ -69,7 +69,9 @@ namespace IfcGeom { // @todo examine if this can indeed be static. For now usage is only // in IfcConvert so invocation is bound to a single file with a single // schema. - static auto mapping = ifcopenshell::geometry::impl::mapping_implementations().construct(prod->data().file); + // @todo pass settings + ifcopenshell::geometry::settings s; + static auto mapping = ifcopenshell::geometry::impl::mapping_implementations().construct(prod->data().file, s); while ((parent = mapping->get_decomposing_entity(current, traverse_openings)) != nullptr) { if (pred(parent)) { return true; @@ -175,7 +177,9 @@ namespace IfcGeom { : wildcard_filter(include, traverse, patterns) {} bool match(IfcUtil::IfcBaseEntity* prod) const { - static auto mapping = ifcopenshell::geometry::impl::mapping_implementations().construct(prod->data().file); + // @todo + ifcopenshell::geometry::settings s; + static auto mapping = ifcopenshell::geometry::impl::mapping_implementations().construct(prod->data().file, s); layer_map_t layers = mapping->get_layers(prod); return std::find_if(layers.begin(), layers.end(), wildcards_match(values)) != layers.end(); } diff --git a/src/ifcgeom/schema_agnostic/IfcGeomIterator.h b/src/ifcgeom/schema_agnostic/IfcGeomIterator.h index feb28af639..dc9014023c 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomIterator.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomIterator.h @@ -141,7 +141,7 @@ namespace { { IfcUtil::IfcBaseEntity* representation = rep->representation; IfcUtil::IfcBaseEntity* product = (IfcUtil::IfcBaseEntity*) *rep->products->begin(); - auto brep = converter->create_brep_for_representation_and_product(settings, representation, product); + auto brep = converter->create_brep_for_representation_and_product(representation, product); if (!brep) { return; } @@ -155,7 +155,7 @@ namespace { rep->elements = { elem }; for (auto it = rep->products->begin() + 1; it != rep->products->end(); ++it) { - auto brep2 = converter->create_brep_for_processed_representation(settings, representation, (IfcUtil::IfcBaseEntity*) *it, brep); + auto brep2 = converter->create_brep_for_processed_representation(representation, (IfcUtil::IfcBaseEntity*) *it, brep); if (brep2) { auto elem2 = process_based_on_settings(settings, brep, dynamic_cast(elem)); if (elem2) { @@ -209,7 +209,7 @@ namespace ifcopenshell { namespace geometry { const double unit_magnitude() const { return unit_magnitude_; } bool initialize() { - converter_ = new Converter(geometry_library_, ifc_file); + converter_ = new Converter(geometry_library_, ifc_file, settings_); converter_->mapping()->get_representations(tasks_, filters_, settings_); if (tasks_.size() == 0) { @@ -243,7 +243,7 @@ namespace ifcopenshell { namespace geometry { std::vector kernel_pool; kernel_pool.reserve(conc_threads); for (unsigned i = 0; i < conc_threads; ++i) { - kernel_pool.push_back(new Converter(geometry_library_, ifc_file)); + kernel_pool.push_back(new Converter(geometry_library_, ifc_file, settings_)); } std::vector> threadpool; @@ -377,6 +377,8 @@ namespace ifcopenshell { namespace geometry { const gp_XYZ& bounds_min() const { return bounds_min_; } const gp_XYZ& bounds_max() const { return bounds_max_; } + Converter& converter() { return *converter_; } + private: // Move to the next IfcRepresentation void _nextShape() { diff --git a/src/serializers/SvgSerializer.cpp b/src/serializers/SvgSerializer.cpp index 323351010b..85cda03eda 100644 --- a/src/serializers/SvgSerializer.cpp +++ b/src/serializers/SvgSerializer.cpp @@ -472,7 +472,9 @@ std::string SvgSerializer::nameElement(const IfcUtil::IfcBaseEntity* elem) { void SvgSerializer::setFile(IfcParse::IfcFile* f) { file = f; - mapping_ = ifcopenshell::geometry::impl::mapping_implementations().construct(f); + // @todo + ifcopenshell::geometry::settings s; + mapping_ = ifcopenshell::geometry::impl::mapping_implementations().construct(f, s); auto storeys = f->instances_by_type("IfcBuildingStorey"); if (!storeys || storeys->size() == 0) { diff --git a/src/serializers/schema_dependent/XmlSerializer.h b/src/serializers/schema_dependent/XmlSerializer.h index 2141576e41..2ee22f2e83 100644 --- a/src/serializers/schema_dependent/XmlSerializer.h +++ b/src/serializers/schema_dependent/XmlSerializer.h @@ -30,12 +30,14 @@ class POSTFIX_SCHEMA(XmlSerializer) : public XmlSerializer { private: IfcParse::IfcFile* file; + // @todo + ifcopenshell::geometry::settings settings_; ifcopenshell::geometry::abstract_mapping* mapping_; public: POSTFIX_SCHEMA(XmlSerializer)(IfcParse::IfcFile* file, const std::string& xml_filename) : XmlSerializer(0, "") - , mapping_(ifcopenshell::geometry::impl::mapping_implementations().construct(file)) + , mapping_(ifcopenshell::geometry::impl::mapping_implementations().construct(file, settings_)) { this->file = file; this->xml_filename = xml_filename; From 59b04c785708c0651a4288c2635a3590f1c07f75 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sat, 14 Dec 2019 13:25:30 +0100 Subject: [PATCH 193/235] Validation work using Nef --- src/ifcconvert/IfcConvert.cpp | 824 ++++++++++++++++++++++++++- src/ifcgeom/kernel_agnostic/blog.txt | 71 --- src/ifcgeom/schema/mapping.cpp | 13 +- 3 files changed, 814 insertions(+), 94 deletions(-) delete mode 100644 src/ifcgeom/kernel_agnostic/blog.txt diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 845ad5d2c1..060b75e4c8 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -1182,6 +1182,13 @@ namespace latebound_access { #include #include +#include +#include +#include +#include +#include +namespace SMS = CGAL::Surface_mesh_simplification; + template T enlarge(const T& t, double d = 1.e-5) { T::NT min[3]; @@ -1191,6 +1198,7 @@ T enlarge(const T& t, double d = 1.e-5) { max[i] = t.max_coord(i) + d; } return T(min, max, t.handle()); + // return T(min, max); } int convert_to_nef(cgal_shape_t& shape, CGAL::Nef_polyhedron_3& result) { @@ -1227,9 +1235,576 @@ int convert_to_nef(cgal_shape_t& shape, CGAL::Nef_polyhedron_3& result) return 0; } +namespace { + // Can be used to convert polyhedron from exact to inexact and vice-versa + template + struct Copy_polyhedron_to + : public CGAL::Modifier_base { + Copy_polyhedron_to(const Polyhedron_input& in_poly) + : in_poly(in_poly) {} + + void operator()(typename Polyhedron_output::HalfedgeDS& out_hds) { + typedef typename Polyhedron_output::HalfedgeDS Output_HDS; + typedef typename Polyhedron_input::HalfedgeDS Input_HDS; + + CGAL::Polyhedron_incremental_builder_3 builder(out_hds); + + typedef typename Polyhedron_input::Vertex_const_iterator Vertex_const_iterator; + typedef typename Polyhedron_input::Facet_const_iterator Facet_const_iterator; + typedef typename Polyhedron_input::Halfedge_around_facet_const_circulator HFCC; + + builder.begin_surface(in_poly.size_of_vertices(), + in_poly.size_of_facets(), + in_poly.size_of_halfedges()); + + for (Vertex_const_iterator + vi = in_poly.vertices_begin(), end = in_poly.vertices_end(); + vi != end; ++vi) { + typename Polyhedron_output::Point_3 p(::CGAL::to_double(vi->point().x()), + ::CGAL::to_double(vi->point().y()), + ::CGAL::to_double(vi->point().z())); + builder.add_vertex(p); + } + + typedef CGAL::Inverse_index Index; + Index index(in_poly.vertices_begin(), in_poly.vertices_end()); + + for (Facet_const_iterator + fi = in_poly.facets_begin(), end = in_poly.facets_end(); + fi != end; ++fi) { + HFCC hc = fi->facet_begin(); + HFCC hc_end = hc; + builder.begin_facet(); + do { + builder.add_vertex_to_facet(index[hc->vertex()]); + ++hc; + } while (hc != hc_end); + builder.end_facet(); + } + builder.end_surface(); + } // end operator()(..) + private: + const Polyhedron_input& in_poly; + }; // end Copy_polyhedron_to<> + + template + void poly_copy(Poly_B& poly_b, const Poly_A& poly_a) { + poly_b.clear(); + Copy_polyhedron_to modifier(poly_a); + poly_b.delegate(modifier); + } + +} + +namespace { + // The following is a Visitor that keeps track of the simplification process. +// In this example the progress is printed real-time and a few statistics are +// recorded (and printed in the end). +// + struct Stats { + Stats() + : collected(0) + , processed(0) + , collapsed(0) + , non_collapsable(0) + , cost_uncomputable(0) + , placement_uncomputable(0) {} + + std::size_t collected; + std::size_t processed; + std::size_t collapsed; + std::size_t non_collapsable; + std::size_t cost_uncomputable; + std::size_t placement_uncomputable; + }; + struct My_visitor : SMS::Edge_collapse_visitor_base>> { + My_visitor(Stats* s) : stats(s) {} + // Called during the collecting phase for each edge collected. + void OnCollected(Profile const&, boost::optional const&) { + ++stats->collected; + std::wcerr << "\rEdges collected: " << stats->collected << std::flush; + } + + // Called during the processing phase for each edge selected. + // If cost is absent the edge won't be collapsed. + void OnSelected(Profile const& + , boost::optional cost + , std::size_t initial + , std::size_t current + ) { + ++stats->processed; + if (!cost) + ++stats->cost_uncomputable; + + if (current == initial) + std::wcerr << "\n" << std::flush; + std::wcerr << "\r" << current << std::flush; + } + + // Called during the processing phase for each edge being collapsed. + // If placement is absent the edge is left uncollapsed. + void OnCollapsing(Profile const& + , boost::optional placement + ) { + if (!placement) + ++stats->placement_uncomputable; + } + + // Called for each edge which failed the so called link-condition, + // that is, which cannot be collapsed because doing so would + // turn the surface mesh into a non-manifold. + void OnNonCollapsable(Profile const&) { + ++stats->non_collapsable; + } + + // Called after each edge has been collapsed + void OnCollapsed(Profile const&, vertex_descriptor) { + ++stats->collapsed; + } + + Stats* stats; + }; + +} + +namespace { + template + T approx_normalized(const T& t) { + return t * (1. / Kernel_::FT(CGAL::sqrt(CGAL::to_double(t.squared_length())))); + } +} + +#include +#include +#include +#include + +namespace { + template + struct Build_Offset : public CGAL::Modifier_base { + std::list input; + + void operator()(HDS& hds) { + // Postcondition: hds is a valid polyhedral surface. + CGAL::Polyhedron_incremental_builder_3 B(hds); + + int Nv = 0, Nf = 0; + for (auto& f : input) { + Nv += 3; + Nf += 1; + } + + B.begin_surface(Nv, Nf); + + for (auto& f : input) { + auto p0 = f->facet_begin()->vertex()->point(); + auto p1 = f->facet_begin()->next()->vertex()->point(); + auto p2 = f->facet_begin()->next()->next()->vertex()->point(); + + auto O = CGAL::centroid(p0, p1, p2); + + Kernel_::Point_3* p012[3] = { &p0, &p1, &p2 }; + for (int i = 0; i < 3; ++i) { + *p012[i] = CGAL::ORIGIN + (((*(p012[i])) - CGAL::ORIGIN) + ((*(p012[i])) - O)); + B.add_vertex(*p012[i]); + } + } + + Nv = 0; + for (int i = 0; i < Nf; ++i) { + B.begin_facet(); + B.add_vertex_to_facet(Nv++); + B.add_vertex_to_facet(Nv++); + B.add_vertex_to_facet(Nv++); + B.end_facet(); + } + + B.end_surface(); + } + }; + + template + std::list connected_faces(cgal_shape_t::Facet_handle& f, const Ts& excluded) { + std::set fs = { f }; + + std::function process; + process = [&fs, &process, &excluded](cgal_shape_t::Facet_handle& f) { + cgal_shape_t::Halfedge_around_facet_circulator circ = f->facet_begin(), end(circ); + do { + auto ff = circ->opposite()->facet(); + if (excluded.find(ff) == excluded.end()) { + auto p = fs.insert(ff); + if (p.second) { + process(ff); + } + } + } while (++circ != end); + }; + + process(f); + return std::list(fs.begin(), fs.end()); + } + + template + struct Builder_With_Map : public CGAL::Modifier_base { + std::list input; + std::map mapping; + + void operator()(HDS& hds) { + // Postcondition: hds is a valid polyhedral surface. + CGAL::Polyhedron_incremental_builder_3 B(hds); + + std::set used_points; + + for (auto& f : input) { + cgal_shape_t::Halfedge_around_facet_circulator circ = f->facet_begin(), end(circ); + do { + auto P = circ->vertex()->point(); + auto it = mapping.find(P); + if (it == mapping.end()) { + std::wcout << "WARNING unprojected point :(" << std::endl; + } else { + P = it->second; + } + used_points.insert(P); + } while (++circ != end); + } + + B.begin_surface(used_points.size(), input.size()); + + for (auto& p : used_points) { + B.add_vertex(p); + } + + for (auto& f : input) { + B.begin_facet(); + cgal_shape_t::Halfedge_around_facet_circulator circ = f->facet_begin(), end(circ); + do { + auto it = used_points.find(circ->vertex()->point()); + B.add_vertex_to_facet(std::distance(used_points.begin(), it)); + } while (++circ != end); + + B.end_facet(); + } + + B.end_surface(); + } + }; +} + +namespace { + template + T edge_collapse(T polyhedron) { + typedef CGAL::Simple_cartesian simple; + CGAL::Polyhedron_3 simple_poly; + poly_copy(simple_poly, polyhedron); + + // flattening from a thin box to a plane is not valid in edge_collapse() + Stats stats; + My_visitor vis(&stats); + SMS::Edge_length_cost elc; + SMS::Edge_length_stop_predicate stop(1.e-3); + + int r = SMS::edge_collapse(simple_poly, stop, + CGAL::parameters::vertex_index_map(get(CGAL::vertex_external_index, simple_poly)) + .halfedge_index_map(get(CGAL::halfedge_external_index, simple_poly)) + .visitor(vis) + .get_cost(elc) + ); + + std::wcout << "Removed: " << r << std::endl; + + T result; + poly_copy(result, simple_poly); + return result; + } + + + double facet_area(const cgal_shape_t::Facet_handle& f) { + auto p0 = f->facet_begin()->vertex()->point(); + auto p1 = f->facet_begin()->next()->vertex()->point(); + auto p2 = f->facet_begin()->next()->next()->vertex()->point(); + return std::sqrt(CGAL::to_double(CGAL::cross_product(p0 - p1, p2 - p1).squared_length())); + } + + void dump_facet(const cgal_shape_t::Facet_handle& f) { + auto p0 = f->facet_begin()->vertex()->point(); + auto p1 = f->facet_begin()->next()->vertex()->point(); + auto p2 = f->facet_begin()->next()->next()->vertex()->point(); + auto V = CGAL::cross_product(p0 - p1, p2 - p1); + auto d = std::sqrt(CGAL::to_double(V.squared_length())); + if (d > 1.e-20) { + V /= d; + } + + std::ostringstream oss; + oss.precision(8); + oss << "Facet with area " << facet_area(f) << " and normal (" + << CGAL::to_double(V.cartesian(0)) << " " << CGAL::to_double(V.cartesian(1)) << " " + << CGAL::to_double(V.cartesian(2)) << ")"; + + auto osss = oss.str(); + std::wcout << osss.c_str() << std::endl; + } + + struct remove_thickness { + typedef Kernel_::Point_3 Point; + typedef Kernel_::Plane_3 Plane; + typedef Kernel_::Vector_3 Vector; + typedef Kernel_::Segment_3 Segment; + typedef Kernel_::Ray_3 Ray; + + typedef CGAL::Polyhedron_3 Polyhedron; + typedef CGAL::AABB_face_graph_triangle_primitive Primitive; + typedef CGAL::AABB_traits Traits; + typedef CGAL::AABB_tree Tree; + typedef boost::optional::Type> Ray_intersection; + + cgal_shape_t polyhedron, polyhedron2, flattened; + + remove_thickness(const cgal_shape_t& p) + // edge_collapse(p) still does not work :( + : polyhedron(p) + , polyhedron2(p) + { + CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron); + CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron2); + + std::list non_degenerate, longitudonal; + std::set thin_sides; + + std::wcout << "ALL FACES:" << std::endl; + + for (auto& f : faces(polyhedron)) { + dump_facet(f); + if (facet_area(f) > 1.e-20) { + non_degenerate.push_back(f); + } + } + + std::wcout << "NON DEGENERATE:" << std::endl; + for (auto& f : non_degenerate) { + dump_facet(f); + } + + cgal_shape_t enlarged_non_degenerate_triangles; + Build_Offset bo; + bo.input = non_degenerate; + enlarged_non_degenerate_triangles.delegate(bo); + + Tree tree(non_degenerate.begin(), non_degenerate.end(), polyhedron); + + std::map face_normals; + boost::associative_property_map> face_normals_map(face_normals); + CGAL::Polygon_mesh_processing::compute_face_normals(polyhedron, face_normals_map); + + for (auto& f : non_degenerate) { + auto O = CGAL::centroid( + f->facet_begin()->vertex()->point(), + f->facet_begin()->next()->vertex()->point(), + f->facet_begin()->next()->next()->vertex()->point() + ); + + Ray ray(O, -face_normals_map[f]); + Ray_intersection intersection = tree.first_intersection(ray, [f](const cgal_shape_t::Facet_handle& p) { + return p == f; + }); + if (intersection) { + if (boost::get(&(intersection->first))) { + const Point* p = boost::get(&(intersection->first)); + const double d = std::sqrt(CGAL::to_double((*p - O).squared_length())); + if (d > 1.e-4) { + thin_sides.insert(f); + } + } + } else { + std::wcout << "No intersection :((!!!" << std::endl; + } + } + + std::wcout << "THIN SIDES:" << std::endl; + for (auto& f : thin_sides) { + dump_facet(f); + } + + for (auto& f : non_degenerate) { + if (thin_sides.find(f) == thin_sides.end()) { + longitudonal.push_back(f); + } + } + + std::wcout << "LONGITUDONAL:" << std::endl; + for (auto& f : longitudonal) { + dump_facet(f); + } + + cgal_shape_t enlarged_indiv_triangles; + Build_Offset bo; + bo.input = longitudonal; + enlarged_indiv_triangles.delegate(bo); + + { + std::ofstream ofs("enlarged.off"); + ofs.precision(17); + ofs << enlarged_indiv_triangles; + } + + Tree tree2(faces(enlarged_indiv_triangles).begin(), faces(enlarged_indiv_triangles).end(), enlarged_indiv_triangles); + + // std::map face_normals_2; + // boost::associative_property_map> face_normals_map_2(face_normals_2); + // CGAL::Polygon_mesh_processing::compute_face_normals(polyhedron, face_normals_map_2); + + // below does not seem to work? Do manually? + // std::map vertex_normals; + // boost::associative_property_map> vertex_normals_map(vertex_normals); + // CGAL::Polygon_mesh_processing::compute_normals(polyhedron, vertex_normals_map, face_normals_map_2); + + std::map new_points; + + for (Polyhedron::Facet_iterator fit = polyhedron.facets_begin(); + fit != polyhedron.facets_end(); + ++fit) { + if (CGAL::collinear( + fit->halfedge()->vertex()->point(), + fit->halfedge()->next()->vertex()->point(), + fit->halfedge()->opposite()->vertex()->point())) { + std::wcout << "degenerate triangle" << std::endl; + } + } + + /* + std::list vertices; + for (auto& f : non_degenerate) { + CGAL::Face_around_target_circulator it(f->halfedge(), polyhedron), end(it); + do { + vertices.push_back((*it)->halfedge()->vertex()); + ++it; + } while (it != end); + }*/ + + + for (auto& v : vertices(polyhedron)) { + auto O = v->point(); + + Kernel_::Vector_3 norm; + Kernel_::Vector_3 accum; + int count = 0; + CGAL::Face_around_target_circulator it(v->halfedge(), polyhedron), end(it); + do { + cgal_shape_t::Facet_handle fh = (*it)->halfedge()->facet(); + + auto jt = std::find(non_degenerate.begin(), non_degenerate.end(), fh); + std::wcout << "non degen: " << (jt != non_degenerate.end()) << std::endl; + auto kt = std::find(thin_sides.begin(), thin_sides.end(), fh); + std::wcout << "thin side: " << (kt != thin_sides.end()) << std::endl; + if (jt != non_degenerate.end() && kt == thin_sides.end()) { + // else degenerate, prevent div by zero, do not incorporate in vnorm. + // or else part of thin side + + auto p0 = (*it)->facet_begin()->vertex()->point(); + auto p1 = (*it)->facet_begin()->next()->vertex()->point(); + auto p2 = (*it)->facet_begin()->next()->next()->vertex()->point(); + + { + std::ostringstream oss; + oss.precision(8); + oss << "p0 " << p0.cartesian(0) << " " << p0.cartesian(1) << " " << p0.cartesian(2) << "\n"; + oss << "p1 " << p1.cartesian(0) << " " << p1.cartesian(1) << " " << p1.cartesian(2) << "\n"; + oss << "p2 " << p2.cartesian(0) << " " << p2.cartesian(1) << " " << p2.cartesian(2) << "\n"; + auto osss = oss.str(); + std::wcout << osss.c_str() << std::endl; + } + + auto fnorm = CGAL::cross_product(p0 - p1, p2 - p1); + fnorm /= std::sqrt(CGAL::to_double(fnorm.squared_length())); + + // const auto& fnorm = face_normals_map_2[*it]; + std::ostringstream oss; + oss.precision(8); + oss << fnorm.cartesian(0) << " " << fnorm.cartesian(1) << " " << fnorm.cartesian(2); + auto osss = oss.str(); + std::wcout << osss.c_str() << std::endl; + accum += fnorm; + + ++count; + } + + ++it; + } while (it != end); + + norm = accum / count; + std::wcout << "count " << count << std::endl; + + if (count == 0) { + continue; + } + + // v->vertex_begin(); + Ray ray(O, norm); + std::ostringstream oss; + oss.precision(8); + oss << O << " -> " << norm; + auto osss = oss.str(); + std::wcout << osss.c_str() << std::endl; + //// skip does not work anymore because we have offset the facets + // auto skip = [this, &v](const cgal_shape_t::Facet_handle& p) { + // CGAL::Face_around_target_circulator it(v->halfedge(), polyhedron), end(it); + // do { + // if ((*it)->facet_begin()->facet() == p) { + // return true; + // } + // } while (++it != end); + // return false; + // }; + std::list intersections; + tree2.all_intersections(ray, std::back_inserter(intersections)); + double N = std::numeric_limits::infinity(); + Point P; + if (intersections.size()) { + for (auto& intersection : intersections) { + if (boost::get(&(intersection->first))) { + const Point* p = boost::get(&(intersection->first)); + const double d = std::sqrt(CGAL::to_double((*p - O).squared_length())); + if (d < N) { + N = d; + P = *p; + } + std::wcout << "intersection @ " << d << std::endl; + } + } + std::wcout << "-----------" << std::endl; + + new_points[O] = P; + } else { + std::wcout << "no intersection :(" << std::endl; + } + } + + /* + for (auto& fi : thin_sides) { + auto f_circ = fi->facet_begin(); + polyhedron2.erase_facet(f_circ); + } + */ + + auto connected = connected_faces(*longitudonal.begin(), thin_sides); + + Builder_With_Map b2; + b2.input = connected; + b2.mapping = new_points; + + flattened.delegate(b2); + } + }; +} + void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) { - typedef std::vector> > nefs_t; - typedef CGAL::Box_intersection_d::Box_with_handle_d Box; + typedef std::list> > nefs_t; + typedef CGAL::Box_intersection_d::Box_with_handle_d Box; + // typedef CGAL::Box_intersection_d::Box_d Box; + // std::map id_map; ifcopenshell::geometry::settings settings; settings.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, false); @@ -1295,38 +1870,31 @@ void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, boo // Apply transformation for (auto &vertex : vertices(s)) { vertex->point() = vertex->point().transform(trsf).transform(trsf2); - /* std::ostringstream ss; ss << vertex->point().cartesian(0); auto sss = ss.str(); std::wcout << sss.c_str() << std::endl; - */ } } - std::wcout << 1 << std::endl; CGAL::Nef_polyhedron_3 nef; auto c = convert_to_nef(s, nef); if (c != 0) { std::wcout << "Error " << c << std::endl; continue; } - std::wcout << 2 << std::endl; nef = CGAL::minkowski_sum_3(nef, cube); - std::wcout << 3 << std::endl; + std::wcout << "product: " << geom_object->product() << std::endl; nefs.push_back({ geom_object->product(), nef }); - std::wcout << 4 << std::endl; - - Kernel_::RT inf(std::numeric_limits::infinity()); - Kernel_::RT min[3] = { +inf, +inf, +inf }; - Kernel_::RT max[3] = { -inf, -inf, -inf }; - Box b(min, max, nefs.end() - 1); + Box b(&*(nefs.rbegin())); + // id_map[b.id()] = ; + for (auto &vertex : vertices(s)) { - Kernel_::RT p[3] = { - vertex->point().cartesian(0), - vertex->point().cartesian(1), - vertex->point().cartesian(2) + double p[3] = { + CGAL::to_double(vertex->point().cartesian(0)), + CGAL::to_double(vertex->point().cartesian(1)), + CGAL::to_double(vertex->point().cartesian(2)) }; b.extend(p); } @@ -1362,10 +1930,229 @@ void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, boo CGAL::box_self_intersection_d(boxes.begin(), boxes.end(), [](const Box& a, const Box& b) { std::ostringstream ss; - ss << a.handle()->first->data().toString() << "x" << b.handle()->first->data().toString() << std::endl; + // ss << id_map[a.id()]->first->data().toString() << "x" << id_map[b.id()]->first->data().toString() << std::endl; + // auto x = id_map[a.id()]->second * id_map[b.id()]->second; + + ss << a.handle()->first->data().toString() << "x" << a.handle()->first->data().toString() << std::endl; auto x = a.handle()->second * b.handle()->second; cgal_shape_t x_poly; x.convert_to_polyhedron(x_poly); + + CGAL::Polygon_mesh_processing::triangulate_faces(x_poly); + + auto vs = vertices(x_poly); + if (std::distance(vs.begin(), vs.end()) == 0) { + return; + } + + auto s0 = a.handle()->first->declaration().name(); + auto s1 = b.handle()->first->declaration().name(); + auto i0 = a.handle()->first->data().id(); + auto i1 = b.handle()->first->data().id(); + + if (s0 < s1) { + std::swap(s1, s0); + std::swap(i0, i1); + } + + { + auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "sb.off"; + + std::ofstream os(FN.c_str()); + os.precision(17); + os << x_poly; + } + + remove_thickness r(x_poly); + + { + auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "-sides-sb.off"; + + std::ofstream os(FN.c_str()); + os.precision(17); + os << r.polyhedron2; + } + + { + auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "-flat-sb.off"; + + std::ofstream os(FN.c_str()); + os.precision(17); + os << r.flattened; + } + // r(); + + /* + std::map collapsed; + std::map collapsed_v; + + for (auto it = x_poly.edges_begin(); it != x_poly.edges_end(); ++it) { + auto& e = *it; + cgal_shape_t::Vertex_iterator v0 = e.vertex(); + cgal_shape_t::Vertex_iterator v1 = e.prev()->vertex(); + auto p0 = v0->point(); + auto p1 = v1->point(); + auto l = std::sqrt(CGAL::to_double((p1 - p0).squared_length())); + std::wcout << "edge w/ length " << l << std::endl; + + cgal_shape_t::Plane_3 plane(it->vertex()->point(), + it->next()->vertex()->point(), + it->next()->next()->vertex()->point()); + + auto d0 = plane.to_2d(e.prev()->vertex()->point()) - plane.to_2d(e.prev()->prev()->vertex()->point()); + auto d1 = plane.to_2d(e.vertex()->point()) - plane.to_2d(e.prev()->vertex()->point()); + auto d2 = plane.to_2d(e.next()->vertex()->point()) - plane.to_2d(e.vertex()->point()); + auto a0 = std::atan2(CGAL::to_double(d0.cartesian(1)), CGAL::to_double(d0.cartesian(0))); + auto a1 = std::atan2(CGAL::to_double(d1.cartesian(1)), CGAL::to_double(d1.cartesian(0))); + auto a2 = std::atan2(CGAL::to_double(d2.cartesian(1)), CGAL::to_double(d2.cartesian(0))); + auto a10 = a1 - a0; + auto a21 = a2 - a1; + if (a10 < 0.) { + a10 += 2 * M_PI; + } + if (a21 < 0.) { + a21 += 2 * M_PI; + } + + const bool is_convex = a10 < M_PI && a21 < M_PI; + + cgal_shape_t::Plane_3 opposite_plane(it->opposite()->vertex()->point(), + it->opposite()->next()->vertex()->point(), + it->opposite()->next()->next()->vertex()->point() + ); + + { + std::ostringstream oss; + oss << plane << " vs " << opposite_plane << "\n"; + oss << plane.orthogonal_vector() << " vs " << opposite_plane.orthogonal_vector(); + auto osss = oss.str(); + std::wcout << osss.c_str() << std::endl; + } + + bool is_internal = false; + if (std::sqrt(CGAL::to_double(plane.orthogonal_vector().squared_length())) < 1.e-15 || + std::sqrt(CGAL::to_double(opposite_plane.orthogonal_vector().squared_length())) < 1.e-15 + ) { + is_internal = true; + std::wcout << "Degenerate" << std::endl; + } else { + const double face_normal_dot = CGAL::to_double(approx_normalized(plane.orthogonal_vector()) * approx_normalized(opposite_plane.orthogonal_vector())); + std::wcout << "Face normal dot " << face_normal_dot << std::endl; + is_internal = face_normal_dot > 0.9; + } + + std::wcout << "Angles " << a0 << " " << a1 << " " << a2 << std::endl; + + if (l < 4.e-5 && (is_convex || is_internal)) { + auto p2 = CGAL::ORIGIN + ((p0 - CGAL::ORIGIN) + (p1 - CGAL::ORIGIN)) / 2; + + std::wcout << "(a) " << CGAL::to_double(p0.cartesian(0)) << " " << CGAL::to_double(p0.cartesian(1)) << " " << CGAL::to_double(p0.cartesian(2)) << "\n"; + std::wcout << "(b) " << CGAL::to_double(p1.cartesian(0)) << " " << CGAL::to_double(p1.cartesian(1)) << " " << CGAL::to_double(p1.cartesian(2)) << "\n"; + std::wcout << "(c) " << CGAL::to_double(p2.cartesian(0)) << " " << CGAL::to_double(p2.cartesian(1)) << " " << CGAL::to_double(p2.cartesian(2)) << "\n"; + // collapsed.insert({ v0, p2 }); + // collapsed.insert({ v1, p2 }); + collapsed.insert({ it, p2 }); + // Edges includes only half of the halfedges + collapsed.insert({ it->opposite(), p2 }); + + collapsed_v.insert({ v0, p2 }); + collapsed_v.insert({ v1, p2 }); + } + } + + { + auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "sb.obj"; + std::ofstream ofs(FN.c_str()); + ofs.precision(17); + + int N = 1; + + std::set > faces_emitted; + for (auto& f : faces(x_poly)) { + std::ostringstream oss; + auto start = f->facet_begin(); + + bool part_collapsed = false; + + CGAL::Polyhedron_3::Halfedge_around_facet_const_circulator e = f->facet_begin(); + do { + auto it = collapsed.find(e); + if (it != collapsed.end()) { + part_collapsed = true; + break; + } + ++e; + } while (e != f->facet_begin()); + + decltype(faces_emitted)::key_type vss; + std::list points; + + if (!part_collapsed) { + e = f->facet_begin(); + do { + cgal_shape_t::Vertex_const_handle v = e->vertex(); + auto it = collapsed_v.find(v); + if (it == collapsed_v.end()) { + std::wcout << "Unexpected " + << CGAL::to_double(v->point().cartesian(0)) << " " + << CGAL::to_double(v->point().cartesian(1)) << " " + << CGAL::to_double(v->point().cartesian(2)) << std::endl; + } else { + points.push_back(it->second); + vss.insert(it->second); + } + ++e; + } while (e != f->facet_begin()); + + if (faces_emitted.find(vss) != faces_emitted.end()) { + std::wcout << "Emitted" << std::endl; + } else { + faces_emitted.insert(vss); + + for (auto& p : points) { + ofs << "v " << CGAL::to_double(p.cartesian(0)) << " " << CGAL::to_double(p.cartesian(1)) << " " << CGAL::to_double(p.cartesian(2)) << "\n"; + } + + ofs << "f "; + for (auto i = 0; i < points.size(); ++i) { + if (i) { + ofs << " "; + } + ofs << i + N; + } + ofs << "\n"; + + N += points.size(); + } + } + } + } + + */ + + /* + // edge collapse does not work on the rational number types + typedef CGAL::Simple_cartesian simple; + CGAL::Polyhedron_3 x_simple; + poly_copy(x_simple, x_poly); + + // flattening from a thin box to a plane is not valid in edge_collapse() + Stats stats; + My_visitor vis(&stats); + SMS::Edge_length_cost elc; + SMS::Edge_length_stop_predicate stop(1.e-3); + + int r = SMS::edge_collapse(x_simple, stop, + CGAL::parameters::vertex_index_map(get(CGAL::vertex_external_index, x_simple)) + .halfedge_index_map(get(CGAL::halfedge_external_index, x_simple)) + .visitor(vis) + .get_cost(elc) + ); + + std::wcout << "Removed: " << r << std::endl; + */ + + /* for (auto& v : vertices(x_poly)) { auto p = v->point(); for (int i = 0; i < 3; ++i) { @@ -1376,6 +2163,7 @@ void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, boo ss << "---" << std::endl; auto sss = ss.str(); std::wcout << sss.c_str(); + */ }); if (!no_progress && quiet) { diff --git a/src/ifcgeom/kernel_agnostic/blog.txt b/src/ifcgeom/kernel_agnostic/blog.txt deleted file mode 100644 index e188c8d407..0000000000 --- a/src/ifcgeom/kernel_agnostic/blog.txt +++ /dev/null @@ -1,71 +0,0 @@ -v0.6.0 - -People not following the development of IfcOpenShell actively and happily using the master branch of the github repository might be surprised to know there is a lot of activity happening in the v0.6.0 and v0.7.0 branches. This post discusses the changes in the v0.6.0 branch. The following post will elaborate on some of the design decisions we are making in the v0.7.0 branch. - -Schemas - -The most significant improvement in the v0.6.0 branch is that multiple schemas (IFC2X3, IFC4, IFC4X1 and IFC4X2) are supported from within the same executable, module or plug-in. Previously, selecting the schema had been a compile-time option. - -In IfcOpenShell and most other EXPRESS-based toolkits, the IFC schema is compiled into (a) the early-bound definitions: a class hierarchy with member functions and (b) a set of methods to operate on the schema definitions at runtime (late-bound access). C++ only allows very limited introspection (but the development of C++ is very active, see for example P1240 https://github.com/cplusplus/papers/issues/545) so to complement the lack of introspection a set of methods exists to query for example all attribute names or the sub- and supertypes of an entity. In the master branch these methods are static, in the v0.6.0 branch these are the member functions of a schema class, that is a more complete reference mirrorring the EXPRESS schema definition at runtime. See IfcBaseEntity::declararation() or IfcParse::schema::declaration_by_name("IfcWall")->as_entity()->all_attribute_names(). - -Writing schema agnostic code - -The code generated from the four schemas are completely orthogonal class hiercharies. For the C++ compiler there is no relationship between a Ifc2x3::IfcWall and a Ifc4::IfcWall. But IfcOpenShell offers three ways to write code that adapts to the schema of the file known at runtime. - -(a) preprocessor - -This is the approach taken in the IfcGeom modules in v0.6.0. Essentially the same code base is compiled multiple times where the schema is available as a preprocessor constant. This means you can enable specific code paths with for example #ifdef directives. In this way the added entities in Ifc4 (IfcBSplineSurface, yay!) can be selectively compiled for example. - -https://github.com/IfcOpenShell/IfcOpenShell/blob/v0.6.0/src/ifcgeom/IfcGeomFaces.cpp#L1127 - -Smaller code blocks can be written as macros as well. - -https://github.com/IfcOpenShell/IfcOpenShell/blob/v0.6.0/src/ifcgeom_schema_agnostic/Kernel.cpp#L74 - -Benefits: fairly readible code, full autocompletion typically in an IDE when using the static library approach -Downsides: Some infrastructure required to compile the different libraries and select the correct implementation at runtime - -(b) late-bound access - -There are two modes of accessing schemas. In the early-bound approach function signatures and return types are known at compilation time. In the late-bound approach attribute names are referenced by strings and types are - -Ifc2x3::IfcWall* wall; -// Early-bound access; -std::string global_id = wall->GlobalId(); -// Late-bound access. -std::string global_id = *wall->get("GlobalId"); -// ERROR: By dereferencing the return type, it is casted into a string, which will cause an exception *at runtime* when the types do not match. -int global_id = *wall->get("GlobalId"); - -Benefits: -fairly readible code -no complicated setup of different libraries -Downsides: -no code completion -errors are only spotted at runtime, not compile-time -late-bound manipulation of inverse attributes is not well supported currently in IfcOpenShell -less means for the compiler to create highly optimized code - -(c) templates - -C++ has very extensive support for compile time generic arguments: templates. - -template -void print_globalid(Schema::IfcWall* wall) { - std::cout << wall->GlobalId(); -} - -Benefits: -no complicated setup of different libraries -no autocompletion typically, but errors caught at compile-time -Downsides: -fairly unreadible code due to additional template and typename keywords. -error messages are harder to make sense up (due to two phase lookup rules for example) - -All three approaches are used in the IfcOpenShell code-base. - -Other improvements: - -Multi-threading in collaboration with TNO, MAUC and Airsquire - -Direct binary glTF output (previously supported through Collada and Collada2Gltf) in collaboration with Schuco US. diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index cbc395c51d..1e063ec52d 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -700,12 +700,15 @@ void mapping::get_representations(std::vector& tasks, continue; } - geometry_conversion_task task; - task.index = task_index++; - task.representation = representation; - task.products = ifcproducts->generalize(); + // @todo, fix this properly by considering the mapped geometry types in the representation. + if (representation->hasRepresentationIdentifier() && representation->RepresentationIdentifier() == "Body") { + geometry_conversion_task task; + task.index = task_index++; + task.representation = representation; + task.products = ifcproducts->generalize(); - tasks.emplace_back(task); + tasks.emplace_back(task); + } } } From a729f489ee93daa205c04a6018b10ea21cafb257 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sat, 14 Dec 2019 14:41:41 +0100 Subject: [PATCH 194/235] Fix double free --- src/ifcgeom/schema_agnostic/IfcGeomIterator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ifcgeom/schema_agnostic/IfcGeomIterator.h b/src/ifcgeom/schema_agnostic/IfcGeomIterator.h index dc9014023c..2a9420c426 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomIterator.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomIterator.h @@ -622,7 +622,7 @@ namespace ifcopenshell { namespace geometry { delete ifc_file; } - if (settings_.get(settings::DISABLE_TRIANGULATION)) { + if (!settings_.get(settings::DISABLE_TRIANGULATION)) { for (auto& p : all_processed_native_elements_) { delete p; } From 612fb8d8d5dc62f4ec3e8d9845415e714fa59998 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sat, 14 Dec 2019 14:50:20 +0100 Subject: [PATCH 195/235] Average space boundary construction in Nef polyhedra --- src/ifcconvert/IfcConvert.cpp | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 060b75e4c8..e6da2884e6 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -1481,8 +1481,21 @@ namespace { B.begin_facet(); cgal_shape_t::Halfedge_around_facet_circulator circ = f->facet_begin(), end(circ); do { - auto it = used_points.find(circ->vertex()->point()); - B.add_vertex_to_facet(std::distance(used_points.begin(), it)); + auto P = circ->vertex()->point(); + auto it = mapping.find(P); + if (it == mapping.end()) { + std::wcout << "WARNING unprojected point :(" << std::endl; + } else { + P = it->second; + } + + auto jt = used_points.find(P); + if (jt == used_points.end()) { + throw std::runtime_error("Unable to map point"); + } + size_t idx = std::distance(used_points.begin(), jt); + std::wcout << "idx " << idx << std::endl; + B.add_vertex_to_facet(idx); } while (++circ != end); B.end_facet(); @@ -1640,9 +1653,9 @@ namespace { } cgal_shape_t enlarged_indiv_triangles; - Build_Offset bo; - bo.input = longitudonal; - enlarged_indiv_triangles.delegate(bo); + Build_Offset bo2; + bo2.input = longitudonal; + enlarged_indiv_triangles.delegate(bo2); { std::ofstream ofs("enlarged.off"); @@ -1767,7 +1780,7 @@ namespace { if (boost::get(&(intersection->first))) { const Point* p = boost::get(&(intersection->first)); const double d = std::sqrt(CGAL::to_double((*p - O).squared_length())); - if (d < N) { + if (d < N && d > 1.e-20) { N = d; P = *p; } @@ -1776,7 +1789,8 @@ namespace { } std::wcout << "-----------" << std::endl; - new_points[O] = P; + // average the new point + new_points[O] = CGAL::ORIGIN + (((O - CGAL::ORIGIN) + (P - CGAL::ORIGIN))) / 2; } else { std::wcout << "no intersection :(" << std::endl; } From 487be4b65ebf8e74ee079bca16c8e16b8b28c869 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sat, 14 Dec 2019 16:17:36 +0100 Subject: [PATCH 196/235] Correct projection to middle surface --- src/ifcconvert/IfcConvert.cpp | 81 ++++++++++++++++++++++++++++++----- 1 file changed, 70 insertions(+), 11 deletions(-) diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index e6da2884e6..2d6d178a79 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -1576,15 +1576,14 @@ namespace { cgal_shape_t polyhedron, polyhedron2, flattened; - remove_thickness(const cgal_shape_t& p) + remove_thickness(const cgal_shape_t& p) // edge_collapse(p) still does not work :( : polyhedron(p) - , polyhedron2(p) - { + , polyhedron2(p) { CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron); CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron2); - std::list non_degenerate, longitudonal; + std::list non_degenerate, degenerate, longitudonal; std::set thin_sides; std::wcout << "ALL FACES:" << std::endl; @@ -1593,6 +1592,9 @@ namespace { dump_facet(f); if (facet_area(f) > 1.e-20) { non_degenerate.push_back(f); + } else { + degenerate.push_front(f); + std::wcout << "Degenerate, area: " << facet_area(f) << std::endl; } } @@ -1606,20 +1608,41 @@ namespace { bo.input = non_degenerate; enlarged_non_degenerate_triangles.delegate(bo); - Tree tree(non_degenerate.begin(), non_degenerate.end(), polyhedron); + // @todo, first on non-enlarged faces, then on enlarged; to fix projection on concave surfaces where the enlarging operation shortens projection distances. + + Tree tree(faces(enlarged_non_degenerate_triangles).first, faces(enlarged_non_degenerate_triangles).second, enlarged_non_degenerate_triangles); std::map face_normals; boost::associative_property_map> face_normals_map(face_normals); CGAL::Polygon_mesh_processing::compute_face_normals(polyhedron, face_normals_map); - + for (auto& f : non_degenerate) { auto O = CGAL::centroid( f->facet_begin()->vertex()->point(), f->facet_begin()->next()->vertex()->point(), f->facet_begin()->next()->next()->vertex()->point() - ); + ); Ray ray(O, -face_normals_map[f]); + + std::list intersections; + tree.all_intersections(ray, std::back_inserter(intersections)); + double N = std::numeric_limits::infinity(); + Point P; + for (auto& intersection : intersections) { + if (boost::get(&(intersection->first))) { + const Point* p = boost::get(&(intersection->first)); + const double d = std::sqrt(CGAL::to_double((*p - O).squared_length())); + if (d > 1.e-20 && d < N) { + N = d; + } + } + } + if (N != std::numeric_limits::infinity() && N > 1.e-4) { + thin_sides.insert(f); + } + + /* Ray_intersection intersection = tree.first_intersection(ray, [f](const cgal_shape_t::Facet_handle& p) { return p == f; }); @@ -1634,6 +1657,7 @@ namespace { } else { std::wcout << "No intersection :((!!!" << std::endl; } + */ } std::wcout << "THIN SIDES:" << std::endl; @@ -1652,6 +1676,8 @@ namespace { dump_facet(f); } + std::wcout << "faces " << faces(polyhedron).size() << "long " << longitudonal.size() << "thin " << thin_sides.size() << "non-degen " << non_degenerate.size() << std::endl; + cgal_shape_t enlarged_indiv_triangles; Build_Offset bo2; bo2.input = longitudonal; @@ -1700,7 +1726,7 @@ namespace { for (auto& v : vertices(polyhedron)) { auto O = v->point(); - + Kernel_::Vector_3 norm; Kernel_::Vector_3 accum; int count = 0; @@ -1751,6 +1777,7 @@ namespace { std::wcout << "count " << count << std::endl; if (count == 0) { + // part of only degenerate or only thin sides continue; } @@ -1761,6 +1788,7 @@ namespace { oss << O << " -> " << norm; auto osss = oss.str(); std::wcout << osss.c_str() << std::endl; + //// skip does not work anymore because we have offset the facets // auto skip = [this, &v](const cgal_shape_t::Facet_handle& p) { // CGAL::Face_around_target_circulator it(v->halfedge(), polyhedron), end(it); @@ -1771,10 +1799,14 @@ namespace { // } while (++it != end); // return false; // }; + std::list intersections; tree2.all_intersections(ray, std::back_inserter(intersections)); double N = std::numeric_limits::infinity(); Point P; + + bool used_intersection = false; + if (intersections.size()) { for (auto& intersection : intersections) { if (boost::get(&(intersection->first))) { @@ -1783,15 +1815,18 @@ namespace { if (d < N && d > 1.e-20) { N = d; P = *p; + std::wcout << "intersection @ " << d << std::endl; } - std::wcout << "intersection @ " << d << std::endl; } } std::wcout << "-----------" << std::endl; // average the new point new_points[O] = CGAL::ORIGIN + (((O - CGAL::ORIGIN) + (P - CGAL::ORIGIN))) / 2; - } else { + used_intersection = true; + } + + if (!used_intersection) { std::wcout << "no intersection :(" << std::endl; } } @@ -1803,7 +1838,31 @@ namespace { } */ - auto connected = connected_faces(*longitudonal.begin(), thin_sides); + auto thin_sides_degenerate = thin_sides; + thin_sides_degenerate.insert(degenerate.begin(), degenerate.end()); + + // @todo choose connected / connected_opposing based on largest combined area of facets? + + auto connected = connected_faces(*longitudonal.begin(), thin_sides_degenerate); + decltype(connected) connected_opposing; + + for (auto& f : longitudonal) { + if (std::find(connected.begin(), connected.end(), f) == connected.end()) { + connected_opposing = connected_faces(f, thin_sides_degenerate); + + std::set longi(longitudonal.begin(), longitudonal.end()); + std::set both_sides(connected.begin(), connected.end()); + both_sides.insert(connected_opposing.begin(), connected_opposing.end()); + + if (longi == both_sides) { + std::wcout << "Facet connection functioning properly" << std::endl; + } else { + std::wcout << "Facet connection functioning incorrectly" << std::endl; + } + + break; + } + } Builder_With_Map b2; b2.input = connected; From 3575aded905d6e95297b264c39bd2cced0fbe567 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Tue, 21 Jan 2020 16:26:00 +0100 Subject: [PATCH 197/235] containment check --- src/ifcconvert/IfcConvert.cpp | 1086 +---------------- src/ifcconvert/validate_space_boundaries.cpp | 1081 ++++++++++++++++ .../validate_storey_containment.cpp | 242 ++++ src/ifcconvert/validate_wall_connectivity.cpp | 0 src/ifcgeom/kernels/cgal/CgalKernel.cpp | 82 +- src/ifcgeom/kernels/cgal/CgalKernel.h | 17 +- 6 files changed, 1410 insertions(+), 1098 deletions(-) create mode 100644 src/ifcconvert/validate_space_boundaries.cpp create mode 100644 src/ifcconvert/validate_storey_containment.cpp create mode 100644 src/ifcconvert/validate_wall_connectivity.cpp diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 2d6d178a79..fb48bd2874 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -144,8 +144,11 @@ static std::basic_stringstream log_stream; void write_log(bool); void fix_quantities(IfcParse::IfcFile&, bool, bool, bool); void fix_spaceboundaries(IfcParse::IfcFile&, bool, bool, bool); +void fix_storeycontainment(IfcParse::IfcFile&, bool, bool, bool); + std::string format_duration(time_t start, time_t end); + /// @todo make the filters non-global IfcGeom::entity_filter entity_filter; // Entity filter is used always by default. IfcGeom::layer_filter layer_filter; @@ -222,7 +225,8 @@ int main(int argc, char** argv) { ("calculate-quantities", "Calculate or fix the physical quantity definitions " "based on an interpretation of the geometry when exporting IFC") ("fix-space-boundaries", "Calculate or fix space boundary geometries " - "when exporting IFC"); + "when exporting IFC") + ("fix-storey-containment", "Calculate or containment in building storeys"); int num_threads; @@ -583,6 +587,9 @@ int main(int argc, char** argv) { if (vmap.count("fix-space-boundaries")) { fix_spaceboundaries(*ifc_file, no_progress, quiet, stderr_progress); } + if (vmap.count("fix-storey-containment")) { + fix_storeycontainment(*ifc_file, no_progress, quiet, stderr_progress); + } fs << *ifc_file; exit_code = EXIT_SUCCESS; } else { @@ -1177,1083 +1184,6 @@ namespace latebound_access { } } -#undef Handle -#include "../ifcgeom/kernels/cgal/CgalKernel.h" -#include -#include - -#include -#include -#include -#include -#include -namespace SMS = CGAL::Surface_mesh_simplification; - -template -T enlarge(const T& t, double d = 1.e-5) { - T::NT min[3]; - T::NT max[3]; - for (int i = 0; i < t.dimension(); ++i) { - min[i] = t.min_coord(i) - d; - max[i] = t.max_coord(i) + d; - } - return T(min, max, t.handle()); - // return T(min, max); -} - -int convert_to_nef(cgal_shape_t& shape, CGAL::Nef_polyhedron_3& result) { - if (!shape.is_valid()) { - return 1; - } - - if (!shape.is_closed()) { - return 2; - } - - bool success = false; - - try { - success = CGAL::Polygon_mesh_processing::triangulate_faces(shape); - } catch (...) { - return 3; - } - - if (!success) { - return 4; - } - - if (CGAL::Polygon_mesh_processing::does_self_intersect(shape)) { - return 5; - } - - try { - result = CGAL::Nef_polyhedron_3(shape); - } catch (...) { - return 6; - } - - return 0; -} - -namespace { - // Can be used to convert polyhedron from exact to inexact and vice-versa - template - struct Copy_polyhedron_to - : public CGAL::Modifier_base { - Copy_polyhedron_to(const Polyhedron_input& in_poly) - : in_poly(in_poly) {} - - void operator()(typename Polyhedron_output::HalfedgeDS& out_hds) { - typedef typename Polyhedron_output::HalfedgeDS Output_HDS; - typedef typename Polyhedron_input::HalfedgeDS Input_HDS; - - CGAL::Polyhedron_incremental_builder_3 builder(out_hds); - - typedef typename Polyhedron_input::Vertex_const_iterator Vertex_const_iterator; - typedef typename Polyhedron_input::Facet_const_iterator Facet_const_iterator; - typedef typename Polyhedron_input::Halfedge_around_facet_const_circulator HFCC; - - builder.begin_surface(in_poly.size_of_vertices(), - in_poly.size_of_facets(), - in_poly.size_of_halfedges()); - - for (Vertex_const_iterator - vi = in_poly.vertices_begin(), end = in_poly.vertices_end(); - vi != end; ++vi) { - typename Polyhedron_output::Point_3 p(::CGAL::to_double(vi->point().x()), - ::CGAL::to_double(vi->point().y()), - ::CGAL::to_double(vi->point().z())); - builder.add_vertex(p); - } - - typedef CGAL::Inverse_index Index; - Index index(in_poly.vertices_begin(), in_poly.vertices_end()); - - for (Facet_const_iterator - fi = in_poly.facets_begin(), end = in_poly.facets_end(); - fi != end; ++fi) { - HFCC hc = fi->facet_begin(); - HFCC hc_end = hc; - builder.begin_facet(); - do { - builder.add_vertex_to_facet(index[hc->vertex()]); - ++hc; - } while (hc != hc_end); - builder.end_facet(); - } - builder.end_surface(); - } // end operator()(..) - private: - const Polyhedron_input& in_poly; - }; // end Copy_polyhedron_to<> - - template - void poly_copy(Poly_B& poly_b, const Poly_A& poly_a) { - poly_b.clear(); - Copy_polyhedron_to modifier(poly_a); - poly_b.delegate(modifier); - } - -} - -namespace { - // The following is a Visitor that keeps track of the simplification process. -// In this example the progress is printed real-time and a few statistics are -// recorded (and printed in the end). -// - struct Stats { - Stats() - : collected(0) - , processed(0) - , collapsed(0) - , non_collapsable(0) - , cost_uncomputable(0) - , placement_uncomputable(0) {} - - std::size_t collected; - std::size_t processed; - std::size_t collapsed; - std::size_t non_collapsable; - std::size_t cost_uncomputable; - std::size_t placement_uncomputable; - }; - struct My_visitor : SMS::Edge_collapse_visitor_base>> { - My_visitor(Stats* s) : stats(s) {} - // Called during the collecting phase for each edge collected. - void OnCollected(Profile const&, boost::optional const&) { - ++stats->collected; - std::wcerr << "\rEdges collected: " << stats->collected << std::flush; - } - - // Called during the processing phase for each edge selected. - // If cost is absent the edge won't be collapsed. - void OnSelected(Profile const& - , boost::optional cost - , std::size_t initial - , std::size_t current - ) { - ++stats->processed; - if (!cost) - ++stats->cost_uncomputable; - - if (current == initial) - std::wcerr << "\n" << std::flush; - std::wcerr << "\r" << current << std::flush; - } - - // Called during the processing phase for each edge being collapsed. - // If placement is absent the edge is left uncollapsed. - void OnCollapsing(Profile const& - , boost::optional placement - ) { - if (!placement) - ++stats->placement_uncomputable; - } - - // Called for each edge which failed the so called link-condition, - // that is, which cannot be collapsed because doing so would - // turn the surface mesh into a non-manifold. - void OnNonCollapsable(Profile const&) { - ++stats->non_collapsable; - } - - // Called after each edge has been collapsed - void OnCollapsed(Profile const&, vertex_descriptor) { - ++stats->collapsed; - } - - Stats* stats; - }; - -} - -namespace { - template - T approx_normalized(const T& t) { - return t * (1. / Kernel_::FT(CGAL::sqrt(CGAL::to_double(t.squared_length())))); - } -} - -#include -#include -#include -#include - -namespace { - template - struct Build_Offset : public CGAL::Modifier_base { - std::list input; - - void operator()(HDS& hds) { - // Postcondition: hds is a valid polyhedral surface. - CGAL::Polyhedron_incremental_builder_3 B(hds); - - int Nv = 0, Nf = 0; - for (auto& f : input) { - Nv += 3; - Nf += 1; - } - - B.begin_surface(Nv, Nf); - - for (auto& f : input) { - auto p0 = f->facet_begin()->vertex()->point(); - auto p1 = f->facet_begin()->next()->vertex()->point(); - auto p2 = f->facet_begin()->next()->next()->vertex()->point(); - - auto O = CGAL::centroid(p0, p1, p2); - - Kernel_::Point_3* p012[3] = { &p0, &p1, &p2 }; - for (int i = 0; i < 3; ++i) { - *p012[i] = CGAL::ORIGIN + (((*(p012[i])) - CGAL::ORIGIN) + ((*(p012[i])) - O)); - B.add_vertex(*p012[i]); - } - } - - Nv = 0; - for (int i = 0; i < Nf; ++i) { - B.begin_facet(); - B.add_vertex_to_facet(Nv++); - B.add_vertex_to_facet(Nv++); - B.add_vertex_to_facet(Nv++); - B.end_facet(); - } - - B.end_surface(); - } - }; - - template - std::list connected_faces(cgal_shape_t::Facet_handle& f, const Ts& excluded) { - std::set fs = { f }; - - std::function process; - process = [&fs, &process, &excluded](cgal_shape_t::Facet_handle& f) { - cgal_shape_t::Halfedge_around_facet_circulator circ = f->facet_begin(), end(circ); - do { - auto ff = circ->opposite()->facet(); - if (excluded.find(ff) == excluded.end()) { - auto p = fs.insert(ff); - if (p.second) { - process(ff); - } - } - } while (++circ != end); - }; - - process(f); - return std::list(fs.begin(), fs.end()); - } - - template - struct Builder_With_Map : public CGAL::Modifier_base { - std::list input; - std::map mapping; - - void operator()(HDS& hds) { - // Postcondition: hds is a valid polyhedral surface. - CGAL::Polyhedron_incremental_builder_3 B(hds); - - std::set used_points; - - for (auto& f : input) { - cgal_shape_t::Halfedge_around_facet_circulator circ = f->facet_begin(), end(circ); - do { - auto P = circ->vertex()->point(); - auto it = mapping.find(P); - if (it == mapping.end()) { - std::wcout << "WARNING unprojected point :(" << std::endl; - } else { - P = it->second; - } - used_points.insert(P); - } while (++circ != end); - } - - B.begin_surface(used_points.size(), input.size()); - - for (auto& p : used_points) { - B.add_vertex(p); - } - - for (auto& f : input) { - B.begin_facet(); - cgal_shape_t::Halfedge_around_facet_circulator circ = f->facet_begin(), end(circ); - do { - auto P = circ->vertex()->point(); - auto it = mapping.find(P); - if (it == mapping.end()) { - std::wcout << "WARNING unprojected point :(" << std::endl; - } else { - P = it->second; - } - - auto jt = used_points.find(P); - if (jt == used_points.end()) { - throw std::runtime_error("Unable to map point"); - } - size_t idx = std::distance(used_points.begin(), jt); - std::wcout << "idx " << idx << std::endl; - B.add_vertex_to_facet(idx); - } while (++circ != end); - - B.end_facet(); - } - - B.end_surface(); - } - }; -} - -namespace { - template - T edge_collapse(T polyhedron) { - typedef CGAL::Simple_cartesian simple; - CGAL::Polyhedron_3 simple_poly; - poly_copy(simple_poly, polyhedron); - - // flattening from a thin box to a plane is not valid in edge_collapse() - Stats stats; - My_visitor vis(&stats); - SMS::Edge_length_cost elc; - SMS::Edge_length_stop_predicate stop(1.e-3); - - int r = SMS::edge_collapse(simple_poly, stop, - CGAL::parameters::vertex_index_map(get(CGAL::vertex_external_index, simple_poly)) - .halfedge_index_map(get(CGAL::halfedge_external_index, simple_poly)) - .visitor(vis) - .get_cost(elc) - ); - - std::wcout << "Removed: " << r << std::endl; - - T result; - poly_copy(result, simple_poly); - return result; - } - - - double facet_area(const cgal_shape_t::Facet_handle& f) { - auto p0 = f->facet_begin()->vertex()->point(); - auto p1 = f->facet_begin()->next()->vertex()->point(); - auto p2 = f->facet_begin()->next()->next()->vertex()->point(); - return std::sqrt(CGAL::to_double(CGAL::cross_product(p0 - p1, p2 - p1).squared_length())); - } - - void dump_facet(const cgal_shape_t::Facet_handle& f) { - auto p0 = f->facet_begin()->vertex()->point(); - auto p1 = f->facet_begin()->next()->vertex()->point(); - auto p2 = f->facet_begin()->next()->next()->vertex()->point(); - auto V = CGAL::cross_product(p0 - p1, p2 - p1); - auto d = std::sqrt(CGAL::to_double(V.squared_length())); - if (d > 1.e-20) { - V /= d; - } - - std::ostringstream oss; - oss.precision(8); - oss << "Facet with area " << facet_area(f) << " and normal (" - << CGAL::to_double(V.cartesian(0)) << " " << CGAL::to_double(V.cartesian(1)) << " " - << CGAL::to_double(V.cartesian(2)) << ")"; - - auto osss = oss.str(); - std::wcout << osss.c_str() << std::endl; - } - - struct remove_thickness { - typedef Kernel_::Point_3 Point; - typedef Kernel_::Plane_3 Plane; - typedef Kernel_::Vector_3 Vector; - typedef Kernel_::Segment_3 Segment; - typedef Kernel_::Ray_3 Ray; - - typedef CGAL::Polyhedron_3 Polyhedron; - typedef CGAL::AABB_face_graph_triangle_primitive Primitive; - typedef CGAL::AABB_traits Traits; - typedef CGAL::AABB_tree Tree; - typedef boost::optional::Type> Ray_intersection; - - cgal_shape_t polyhedron, polyhedron2, flattened; - - remove_thickness(const cgal_shape_t& p) - // edge_collapse(p) still does not work :( - : polyhedron(p) - , polyhedron2(p) { - CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron); - CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron2); - - std::list non_degenerate, degenerate, longitudonal; - std::set thin_sides; - - std::wcout << "ALL FACES:" << std::endl; - - for (auto& f : faces(polyhedron)) { - dump_facet(f); - if (facet_area(f) > 1.e-20) { - non_degenerate.push_back(f); - } else { - degenerate.push_front(f); - std::wcout << "Degenerate, area: " << facet_area(f) << std::endl; - } - } - - std::wcout << "NON DEGENERATE:" << std::endl; - for (auto& f : non_degenerate) { - dump_facet(f); - } - - cgal_shape_t enlarged_non_degenerate_triangles; - Build_Offset bo; - bo.input = non_degenerate; - enlarged_non_degenerate_triangles.delegate(bo); - - // @todo, first on non-enlarged faces, then on enlarged; to fix projection on concave surfaces where the enlarging operation shortens projection distances. - - Tree tree(faces(enlarged_non_degenerate_triangles).first, faces(enlarged_non_degenerate_triangles).second, enlarged_non_degenerate_triangles); - - std::map face_normals; - boost::associative_property_map> face_normals_map(face_normals); - CGAL::Polygon_mesh_processing::compute_face_normals(polyhedron, face_normals_map); - - for (auto& f : non_degenerate) { - auto O = CGAL::centroid( - f->facet_begin()->vertex()->point(), - f->facet_begin()->next()->vertex()->point(), - f->facet_begin()->next()->next()->vertex()->point() - ); - - Ray ray(O, -face_normals_map[f]); - - std::list intersections; - tree.all_intersections(ray, std::back_inserter(intersections)); - double N = std::numeric_limits::infinity(); - Point P; - for (auto& intersection : intersections) { - if (boost::get(&(intersection->first))) { - const Point* p = boost::get(&(intersection->first)); - const double d = std::sqrt(CGAL::to_double((*p - O).squared_length())); - if (d > 1.e-20 && d < N) { - N = d; - } - } - } - if (N != std::numeric_limits::infinity() && N > 1.e-4) { - thin_sides.insert(f); - } - - /* - Ray_intersection intersection = tree.first_intersection(ray, [f](const cgal_shape_t::Facet_handle& p) { - return p == f; - }); - if (intersection) { - if (boost::get(&(intersection->first))) { - const Point* p = boost::get(&(intersection->first)); - const double d = std::sqrt(CGAL::to_double((*p - O).squared_length())); - if (d > 1.e-4) { - thin_sides.insert(f); - } - } - } else { - std::wcout << "No intersection :((!!!" << std::endl; - } - */ - } - - std::wcout << "THIN SIDES:" << std::endl; - for (auto& f : thin_sides) { - dump_facet(f); - } - - for (auto& f : non_degenerate) { - if (thin_sides.find(f) == thin_sides.end()) { - longitudonal.push_back(f); - } - } - - std::wcout << "LONGITUDONAL:" << std::endl; - for (auto& f : longitudonal) { - dump_facet(f); - } - - std::wcout << "faces " << faces(polyhedron).size() << "long " << longitudonal.size() << "thin " << thin_sides.size() << "non-degen " << non_degenerate.size() << std::endl; - - cgal_shape_t enlarged_indiv_triangles; - Build_Offset bo2; - bo2.input = longitudonal; - enlarged_indiv_triangles.delegate(bo2); - - { - std::ofstream ofs("enlarged.off"); - ofs.precision(17); - ofs << enlarged_indiv_triangles; - } - - Tree tree2(faces(enlarged_indiv_triangles).begin(), faces(enlarged_indiv_triangles).end(), enlarged_indiv_triangles); - - // std::map face_normals_2; - // boost::associative_property_map> face_normals_map_2(face_normals_2); - // CGAL::Polygon_mesh_processing::compute_face_normals(polyhedron, face_normals_map_2); - - // below does not seem to work? Do manually? - // std::map vertex_normals; - // boost::associative_property_map> vertex_normals_map(vertex_normals); - // CGAL::Polygon_mesh_processing::compute_normals(polyhedron, vertex_normals_map, face_normals_map_2); - - std::map new_points; - - for (Polyhedron::Facet_iterator fit = polyhedron.facets_begin(); - fit != polyhedron.facets_end(); - ++fit) { - if (CGAL::collinear( - fit->halfedge()->vertex()->point(), - fit->halfedge()->next()->vertex()->point(), - fit->halfedge()->opposite()->vertex()->point())) { - std::wcout << "degenerate triangle" << std::endl; - } - } - - /* - std::list vertices; - for (auto& f : non_degenerate) { - CGAL::Face_around_target_circulator it(f->halfedge(), polyhedron), end(it); - do { - vertices.push_back((*it)->halfedge()->vertex()); - ++it; - } while (it != end); - }*/ - - - for (auto& v : vertices(polyhedron)) { - auto O = v->point(); - - Kernel_::Vector_3 norm; - Kernel_::Vector_3 accum; - int count = 0; - CGAL::Face_around_target_circulator it(v->halfedge(), polyhedron), end(it); - do { - cgal_shape_t::Facet_handle fh = (*it)->halfedge()->facet(); - - auto jt = std::find(non_degenerate.begin(), non_degenerate.end(), fh); - std::wcout << "non degen: " << (jt != non_degenerate.end()) << std::endl; - auto kt = std::find(thin_sides.begin(), thin_sides.end(), fh); - std::wcout << "thin side: " << (kt != thin_sides.end()) << std::endl; - if (jt != non_degenerate.end() && kt == thin_sides.end()) { - // else degenerate, prevent div by zero, do not incorporate in vnorm. - // or else part of thin side - - auto p0 = (*it)->facet_begin()->vertex()->point(); - auto p1 = (*it)->facet_begin()->next()->vertex()->point(); - auto p2 = (*it)->facet_begin()->next()->next()->vertex()->point(); - - { - std::ostringstream oss; - oss.precision(8); - oss << "p0 " << p0.cartesian(0) << " " << p0.cartesian(1) << " " << p0.cartesian(2) << "\n"; - oss << "p1 " << p1.cartesian(0) << " " << p1.cartesian(1) << " " << p1.cartesian(2) << "\n"; - oss << "p2 " << p2.cartesian(0) << " " << p2.cartesian(1) << " " << p2.cartesian(2) << "\n"; - auto osss = oss.str(); - std::wcout << osss.c_str() << std::endl; - } - - auto fnorm = CGAL::cross_product(p0 - p1, p2 - p1); - fnorm /= std::sqrt(CGAL::to_double(fnorm.squared_length())); - - // const auto& fnorm = face_normals_map_2[*it]; - std::ostringstream oss; - oss.precision(8); - oss << fnorm.cartesian(0) << " " << fnorm.cartesian(1) << " " << fnorm.cartesian(2); - auto osss = oss.str(); - std::wcout << osss.c_str() << std::endl; - accum += fnorm; - - ++count; - } - - ++it; - } while (it != end); - - norm = accum / count; - std::wcout << "count " << count << std::endl; - - if (count == 0) { - // part of only degenerate or only thin sides - continue; - } - - // v->vertex_begin(); - Ray ray(O, norm); - std::ostringstream oss; - oss.precision(8); - oss << O << " -> " << norm; - auto osss = oss.str(); - std::wcout << osss.c_str() << std::endl; - - //// skip does not work anymore because we have offset the facets - // auto skip = [this, &v](const cgal_shape_t::Facet_handle& p) { - // CGAL::Face_around_target_circulator it(v->halfedge(), polyhedron), end(it); - // do { - // if ((*it)->facet_begin()->facet() == p) { - // return true; - // } - // } while (++it != end); - // return false; - // }; - - std::list intersections; - tree2.all_intersections(ray, std::back_inserter(intersections)); - double N = std::numeric_limits::infinity(); - Point P; - - bool used_intersection = false; - - if (intersections.size()) { - for (auto& intersection : intersections) { - if (boost::get(&(intersection->first))) { - const Point* p = boost::get(&(intersection->first)); - const double d = std::sqrt(CGAL::to_double((*p - O).squared_length())); - if (d < N && d > 1.e-20) { - N = d; - P = *p; - std::wcout << "intersection @ " << d << std::endl; - } - } - } - std::wcout << "-----------" << std::endl; - - // average the new point - new_points[O] = CGAL::ORIGIN + (((O - CGAL::ORIGIN) + (P - CGAL::ORIGIN))) / 2; - used_intersection = true; - } - - if (!used_intersection) { - std::wcout << "no intersection :(" << std::endl; - } - } - - /* - for (auto& fi : thin_sides) { - auto f_circ = fi->facet_begin(); - polyhedron2.erase_facet(f_circ); - } - */ - - auto thin_sides_degenerate = thin_sides; - thin_sides_degenerate.insert(degenerate.begin(), degenerate.end()); - - // @todo choose connected / connected_opposing based on largest combined area of facets? - - auto connected = connected_faces(*longitudonal.begin(), thin_sides_degenerate); - decltype(connected) connected_opposing; - - for (auto& f : longitudonal) { - if (std::find(connected.begin(), connected.end(), f) == connected.end()) { - connected_opposing = connected_faces(f, thin_sides_degenerate); - - std::set longi(longitudonal.begin(), longitudonal.end()); - std::set both_sides(connected.begin(), connected.end()); - both_sides.insert(connected_opposing.begin(), connected_opposing.end()); - - if (longi == both_sides) { - std::wcout << "Facet connection functioning properly" << std::endl; - } else { - std::wcout << "Facet connection functioning incorrectly" << std::endl; - } - - break; - } - } - - Builder_With_Map b2; - b2.input = connected; - b2.mapping = new_points; - - flattened.delegate(b2); - } - }; -} - -void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) { - typedef std::list> > nefs_t; - typedef CGAL::Box_intersection_d::Box_with_handle_d Box; - // typedef CGAL::Box_intersection_d::Box_d Box; - // std::map id_map; - - ifcopenshell::geometry::settings settings; - settings.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, false); - settings.set(ifcopenshell::geometry::settings::WELD_VERTICES, false); - settings.set(ifcopenshell::geometry::settings::SEW_SHELLS, true); - settings.set(ifcopenshell::geometry::settings::CONVERT_BACK_UNITS, true); - settings.set(ifcopenshell::geometry::settings::DISABLE_TRIANGULATION, true); - settings.set(ifcopenshell::geometry::settings::DISABLE_OPENING_SUBTRACTIONS, true); - - std::vector spaces_and_walls = { - IfcGeom::entity_filter(true, false, {"IfcWall", "IfcSpace"}) - }; - - ifcopenshell::geometry::Iterator context_iterator("cgal", settings, &f, spaces_and_walls); - - if (!context_iterator.initialize()) { - return; - } - - auto kernel = (ifcopenshell::geometry::kernels::CgalKernel*) context_iterator.converter().kernel(); - auto cube = kernel->precision_cube(); - - size_t num_created = 0; - int old_progress = quiet ? 0 : -1; - - std::vector boxes; - nefs_t nefs; - - for (;; ++num_created) { - bool has_more = true; - if (num_created) { - has_more = context_iterator.next(); - } - ifcopenshell::geometry::NativeElement* geom_object = nullptr; - if (has_more) { - geom_object = context_iterator.get_native(); - } - if (!geom_object) { - break; - } - - std::stringstream ss; - ss << geom_object->product()->data().toString(); - auto sss = ss.str(); - std::wcout << sss.c_str() << std::endl; - - for (auto& g : geom_object->geometry()) { - auto s = ((ifcopenshell::geometry::CgalShape*) g.Shape())->shape(); - const auto& m = g.Placement().components; - const auto& n = geom_object->transformation().data().components; - - if (true || !m.isIdentity()) { - const cgal_placement_t trsf( - m(0, 0), m(0, 1), m(0, 2), m(0, 3), - m(1, 0), m(1, 1), m(1, 2), m(1, 3), - m(2, 0), m(2, 1), m(2, 2), m(2, 3)); - - const cgal_placement_t trsf2( - n(0, 0), n(0, 1), n(0, 2), n(0, 3), - n(1, 0), n(1, 1), n(1, 2), n(1, 3), - n(2, 0), n(2, 1), n(2, 2), n(2, 3)); - - // Apply transformation - for (auto &vertex : vertices(s)) { - vertex->point() = vertex->point().transform(trsf).transform(trsf2); - std::ostringstream ss; - ss << vertex->point().cartesian(0); - auto sss = ss.str(); - std::wcout << sss.c_str() << std::endl; - } - } - - CGAL::Nef_polyhedron_3 nef; - auto c = convert_to_nef(s, nef); - if (c != 0) { - std::wcout << "Error " << c << std::endl; - continue; - } - nef = CGAL::minkowski_sum_3(nef, cube); - std::wcout << "product: " << geom_object->product() << std::endl; - nefs.push_back({ geom_object->product(), nef }); - - Box b(&*(nefs.rbegin())); - // id_map[b.id()] = ; - - for (auto &vertex : vertices(s)) { - double p[3] = { - CGAL::to_double(vertex->point().cartesian(0)), - CGAL::to_double(vertex->point().cartesian(1)), - CGAL::to_double(vertex->point().cartesian(2)) - }; - b.extend(p); - } - - boxes.push_back(enlarge(b)); - - /* - std::ostringstream ss; - ss << geom_object->product()->data().toString() << std::endl << b.min_coord(0) << " - " << b.max_coord(0) << std::endl; - auto sss = ss.str(); - std::wcout << sss.c_str(); - */ - } - - if (!no_progress) { - if (quiet) { - const int progress = context_iterator.progress(); - for (; old_progress < progress; ++old_progress) { - std::cout << "."; - if (stderr_progress) - std::cerr << "."; - } - std::cout << std::flush; - if (stderr_progress) - std::cerr << std::flush; - } else { - const int progress = context_iterator.progress() / 2; - if (old_progress != progress) Logger::ProgressBar(progress); - old_progress = progress; - } - } - } - - CGAL::box_self_intersection_d(boxes.begin(), boxes.end(), [](const Box& a, const Box& b) { - std::ostringstream ss; - // ss << id_map[a.id()]->first->data().toString() << "x" << id_map[b.id()]->first->data().toString() << std::endl; - // auto x = id_map[a.id()]->second * id_map[b.id()]->second; - - ss << a.handle()->first->data().toString() << "x" << a.handle()->first->data().toString() << std::endl; - auto x = a.handle()->second * b.handle()->second; - cgal_shape_t x_poly; - x.convert_to_polyhedron(x_poly); - - CGAL::Polygon_mesh_processing::triangulate_faces(x_poly); - - auto vs = vertices(x_poly); - if (std::distance(vs.begin(), vs.end()) == 0) { - return; - } - - auto s0 = a.handle()->first->declaration().name(); - auto s1 = b.handle()->first->declaration().name(); - auto i0 = a.handle()->first->data().id(); - auto i1 = b.handle()->first->data().id(); - - if (s0 < s1) { - std::swap(s1, s0); - std::swap(i0, i1); - } - - { - auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "sb.off"; - - std::ofstream os(FN.c_str()); - os.precision(17); - os << x_poly; - } - - remove_thickness r(x_poly); - - { - auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "-sides-sb.off"; - - std::ofstream os(FN.c_str()); - os.precision(17); - os << r.polyhedron2; - } - - { - auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "-flat-sb.off"; - - std::ofstream os(FN.c_str()); - os.precision(17); - os << r.flattened; - } - // r(); - - /* - std::map collapsed; - std::map collapsed_v; - - for (auto it = x_poly.edges_begin(); it != x_poly.edges_end(); ++it) { - auto& e = *it; - cgal_shape_t::Vertex_iterator v0 = e.vertex(); - cgal_shape_t::Vertex_iterator v1 = e.prev()->vertex(); - auto p0 = v0->point(); - auto p1 = v1->point(); - auto l = std::sqrt(CGAL::to_double((p1 - p0).squared_length())); - std::wcout << "edge w/ length " << l << std::endl; - - cgal_shape_t::Plane_3 plane(it->vertex()->point(), - it->next()->vertex()->point(), - it->next()->next()->vertex()->point()); - - auto d0 = plane.to_2d(e.prev()->vertex()->point()) - plane.to_2d(e.prev()->prev()->vertex()->point()); - auto d1 = plane.to_2d(e.vertex()->point()) - plane.to_2d(e.prev()->vertex()->point()); - auto d2 = plane.to_2d(e.next()->vertex()->point()) - plane.to_2d(e.vertex()->point()); - auto a0 = std::atan2(CGAL::to_double(d0.cartesian(1)), CGAL::to_double(d0.cartesian(0))); - auto a1 = std::atan2(CGAL::to_double(d1.cartesian(1)), CGAL::to_double(d1.cartesian(0))); - auto a2 = std::atan2(CGAL::to_double(d2.cartesian(1)), CGAL::to_double(d2.cartesian(0))); - auto a10 = a1 - a0; - auto a21 = a2 - a1; - if (a10 < 0.) { - a10 += 2 * M_PI; - } - if (a21 < 0.) { - a21 += 2 * M_PI; - } - - const bool is_convex = a10 < M_PI && a21 < M_PI; - - cgal_shape_t::Plane_3 opposite_plane(it->opposite()->vertex()->point(), - it->opposite()->next()->vertex()->point(), - it->opposite()->next()->next()->vertex()->point() - ); - - { - std::ostringstream oss; - oss << plane << " vs " << opposite_plane << "\n"; - oss << plane.orthogonal_vector() << " vs " << opposite_plane.orthogonal_vector(); - auto osss = oss.str(); - std::wcout << osss.c_str() << std::endl; - } - - bool is_internal = false; - if (std::sqrt(CGAL::to_double(plane.orthogonal_vector().squared_length())) < 1.e-15 || - std::sqrt(CGAL::to_double(opposite_plane.orthogonal_vector().squared_length())) < 1.e-15 - ) { - is_internal = true; - std::wcout << "Degenerate" << std::endl; - } else { - const double face_normal_dot = CGAL::to_double(approx_normalized(plane.orthogonal_vector()) * approx_normalized(opposite_plane.orthogonal_vector())); - std::wcout << "Face normal dot " << face_normal_dot << std::endl; - is_internal = face_normal_dot > 0.9; - } - - std::wcout << "Angles " << a0 << " " << a1 << " " << a2 << std::endl; - - if (l < 4.e-5 && (is_convex || is_internal)) { - auto p2 = CGAL::ORIGIN + ((p0 - CGAL::ORIGIN) + (p1 - CGAL::ORIGIN)) / 2; - - std::wcout << "(a) " << CGAL::to_double(p0.cartesian(0)) << " " << CGAL::to_double(p0.cartesian(1)) << " " << CGAL::to_double(p0.cartesian(2)) << "\n"; - std::wcout << "(b) " << CGAL::to_double(p1.cartesian(0)) << " " << CGAL::to_double(p1.cartesian(1)) << " " << CGAL::to_double(p1.cartesian(2)) << "\n"; - std::wcout << "(c) " << CGAL::to_double(p2.cartesian(0)) << " " << CGAL::to_double(p2.cartesian(1)) << " " << CGAL::to_double(p2.cartesian(2)) << "\n"; - // collapsed.insert({ v0, p2 }); - // collapsed.insert({ v1, p2 }); - collapsed.insert({ it, p2 }); - // Edges includes only half of the halfedges - collapsed.insert({ it->opposite(), p2 }); - - collapsed_v.insert({ v0, p2 }); - collapsed_v.insert({ v1, p2 }); - } - } - - { - auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "sb.obj"; - std::ofstream ofs(FN.c_str()); - ofs.precision(17); - - int N = 1; - - std::set > faces_emitted; - for (auto& f : faces(x_poly)) { - std::ostringstream oss; - auto start = f->facet_begin(); - - bool part_collapsed = false; - - CGAL::Polyhedron_3::Halfedge_around_facet_const_circulator e = f->facet_begin(); - do { - auto it = collapsed.find(e); - if (it != collapsed.end()) { - part_collapsed = true; - break; - } - ++e; - } while (e != f->facet_begin()); - - decltype(faces_emitted)::key_type vss; - std::list points; - - if (!part_collapsed) { - e = f->facet_begin(); - do { - cgal_shape_t::Vertex_const_handle v = e->vertex(); - auto it = collapsed_v.find(v); - if (it == collapsed_v.end()) { - std::wcout << "Unexpected " - << CGAL::to_double(v->point().cartesian(0)) << " " - << CGAL::to_double(v->point().cartesian(1)) << " " - << CGAL::to_double(v->point().cartesian(2)) << std::endl; - } else { - points.push_back(it->second); - vss.insert(it->second); - } - ++e; - } while (e != f->facet_begin()); - - if (faces_emitted.find(vss) != faces_emitted.end()) { - std::wcout << "Emitted" << std::endl; - } else { - faces_emitted.insert(vss); - - for (auto& p : points) { - ofs << "v " << CGAL::to_double(p.cartesian(0)) << " " << CGAL::to_double(p.cartesian(1)) << " " << CGAL::to_double(p.cartesian(2)) << "\n"; - } - - ofs << "f "; - for (auto i = 0; i < points.size(); ++i) { - if (i) { - ofs << " "; - } - ofs << i + N; - } - ofs << "\n"; - - N += points.size(); - } - } - } - } - - */ - - /* - // edge collapse does not work on the rational number types - typedef CGAL::Simple_cartesian simple; - CGAL::Polyhedron_3 x_simple; - poly_copy(x_simple, x_poly); - - // flattening from a thin box to a plane is not valid in edge_collapse() - Stats stats; - My_visitor vis(&stats); - SMS::Edge_length_cost elc; - SMS::Edge_length_stop_predicate stop(1.e-3); - - int r = SMS::edge_collapse(x_simple, stop, - CGAL::parameters::vertex_index_map(get(CGAL::vertex_external_index, x_simple)) - .halfedge_index_map(get(CGAL::halfedge_external_index, x_simple)) - .visitor(vis) - .get_cost(elc) - ); - - std::wcout << "Removed: " << r << std::endl; - */ - - /* - for (auto& v : vertices(x_poly)) { - auto p = v->point(); - for (int i = 0; i < 3; ++i) { - ss << p.cartesian(i) << " "; - } - ss << std::endl; - } - ss << "---" << std::endl; - auto sss = ss.str(); - std::wcout << sss.c_str(); - */ - }); - - if (!no_progress && quiet) { - for (; old_progress < 100; ++old_progress) { - std::cout << "."; - if (stderr_progress) - std::cerr << "."; - } - std::cout << std::flush; - if (stderr_progress) - std::cerr << std::flush; - } else { - Logger::Status("\rDone fixing space boundaries for " + boost::lexical_cast(num_created) + - " objects "); - } -} - void fix_quantities(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) { { auto delete_reversed = [&f](const IfcEntityList::ptr& insts) { diff --git a/src/ifcconvert/validate_space_boundaries.cpp b/src/ifcconvert/validate_space_boundaries.cpp new file mode 100644 index 0000000000..f4086579f7 --- /dev/null +++ b/src/ifcconvert/validate_space_boundaries.cpp @@ -0,0 +1,1081 @@ +#include "../ifcgeom/kernels/cgal/CgalKernel.h" +#include "../ifcgeom/schema_agnostic/IfcGeomFilter.h" +#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h" + +#include +#include + +#include +#include +#include +#include +#include +namespace SMS = CGAL::Surface_mesh_simplification; + +#include +#include + +template +T enlarge(const T& t, double d = 1.e-5) { + T::NT min[3]; + T::NT max[3]; + for (int i = 0; i < t.dimension(); ++i) { + min[i] = t.min_coord(i) - d; + max[i] = t.max_coord(i) + d; + } + return T(min, max, t.handle()); + // return T(min, max); +} + +int convert_to_nef(cgal_shape_t& shape, CGAL::Nef_polyhedron_3& result) { + if (!shape.is_valid()) { + return 1; + } + + if (!shape.is_closed()) { + return 2; + } + + bool success = false; + + try { + success = CGAL::Polygon_mesh_processing::triangulate_faces(shape); + } catch (...) { + return 3; + } + + if (!success) { + return 4; + } + + if (CGAL::Polygon_mesh_processing::does_self_intersect(shape)) { + return 5; + } + + try { + result = CGAL::Nef_polyhedron_3(shape); + } catch (...) { + return 6; + } + + return 0; +} + +namespace { + // Can be used to convert polyhedron from exact to inexact and vice-versa + template + struct Copy_polyhedron_to + : public CGAL::Modifier_base { + Copy_polyhedron_to(const Polyhedron_input& in_poly) + : in_poly(in_poly) {} + + void operator()(typename Polyhedron_output::HalfedgeDS& out_hds) { + typedef typename Polyhedron_output::HalfedgeDS Output_HDS; + typedef typename Polyhedron_input::HalfedgeDS Input_HDS; + + CGAL::Polyhedron_incremental_builder_3 builder(out_hds); + + typedef typename Polyhedron_input::Vertex_const_iterator Vertex_const_iterator; + typedef typename Polyhedron_input::Facet_const_iterator Facet_const_iterator; + typedef typename Polyhedron_input::Halfedge_around_facet_const_circulator HFCC; + + builder.begin_surface(in_poly.size_of_vertices(), + in_poly.size_of_facets(), + in_poly.size_of_halfedges()); + + for (Vertex_const_iterator + vi = in_poly.vertices_begin(), end = in_poly.vertices_end(); + vi != end; ++vi) { + typename Polyhedron_output::Point_3 p(::CGAL::to_double(vi->point().x()), + ::CGAL::to_double(vi->point().y()), + ::CGAL::to_double(vi->point().z())); + builder.add_vertex(p); + } + + typedef CGAL::Inverse_index Index; + Index index(in_poly.vertices_begin(), in_poly.vertices_end()); + + for (Facet_const_iterator + fi = in_poly.facets_begin(), end = in_poly.facets_end(); + fi != end; ++fi) { + HFCC hc = fi->facet_begin(); + HFCC hc_end = hc; + builder.begin_facet(); + do { + builder.add_vertex_to_facet(index[hc->vertex()]); + ++hc; + } while (hc != hc_end); + builder.end_facet(); + } + builder.end_surface(); + } // end operator()(..) + private: + const Polyhedron_input& in_poly; + }; // end Copy_polyhedron_to<> + + template + void poly_copy(Poly_B& poly_b, const Poly_A& poly_a) { + poly_b.clear(); + Copy_polyhedron_to modifier(poly_a); + poly_b.delegate(modifier); + } + +} + +namespace { + // The following is a Visitor that keeps track of the simplification process. +// In this example the progress is printed real-time and a few statistics are +// recorded (and printed in the end). +// + struct Stats { + Stats() + : collected(0) + , processed(0) + , collapsed(0) + , non_collapsable(0) + , cost_uncomputable(0) + , placement_uncomputable(0) {} + + std::size_t collected; + std::size_t processed; + std::size_t collapsed; + std::size_t non_collapsable; + std::size_t cost_uncomputable; + std::size_t placement_uncomputable; + }; + struct My_visitor : SMS::Edge_collapse_visitor_base>> { + My_visitor(Stats* s) : stats(s) {} + // Called during the collecting phase for each edge collected. + void OnCollected(Profile const&, boost::optional const&) { + ++stats->collected; + std::wcerr << "\rEdges collected: " << stats->collected << std::flush; + } + + // Called during the processing phase for each edge selected. + // If cost is absent the edge won't be collapsed. + void OnSelected(Profile const& + , boost::optional cost + , std::size_t initial + , std::size_t current + ) { + ++stats->processed; + if (!cost) + ++stats->cost_uncomputable; + + if (current == initial) + std::wcerr << "\n" << std::flush; + std::wcerr << "\r" << current << std::flush; + } + + // Called during the processing phase for each edge being collapsed. + // If placement is absent the edge is left uncollapsed. + void OnCollapsing(Profile const& + , boost::optional placement + ) { + if (!placement) + ++stats->placement_uncomputable; + } + + // Called for each edge which failed the so called link-condition, + // that is, which cannot be collapsed because doing so would + // turn the surface mesh into a non-manifold. + void OnNonCollapsable(Profile const&) { + ++stats->non_collapsable; + } + + // Called after each edge has been collapsed + void OnCollapsed(Profile const&, vertex_descriptor) { + ++stats->collapsed; + } + + Stats* stats; + }; + +} + +namespace { + template + T approx_normalized(const T& t) { + return t * (1. / Kernel_::FT(CGAL::sqrt(CGAL::to_double(t.squared_length())))); + } +} + +#include +#include +#include +#include + +namespace { + template + struct Build_Offset : public CGAL::Modifier_base { + std::list input; + + void operator()(HDS& hds) { + // Postcondition: hds is a valid polyhedral surface. + CGAL::Polyhedron_incremental_builder_3 B(hds); + + int Nv = 0, Nf = 0; + for (auto& f : input) { + Nv += 3; + Nf += 1; + } + + B.begin_surface(Nv, Nf); + + for (auto& f : input) { + auto p0 = f->facet_begin()->vertex()->point(); + auto p1 = f->facet_begin()->next()->vertex()->point(); + auto p2 = f->facet_begin()->next()->next()->vertex()->point(); + + auto O = CGAL::centroid(p0, p1, p2); + + Kernel_::Point_3* p012[3] = { &p0, &p1, &p2 }; + for (int i = 0; i < 3; ++i) { + *p012[i] = CGAL::ORIGIN + (((*(p012[i])) - CGAL::ORIGIN) + ((*(p012[i])) - O)); + B.add_vertex(*p012[i]); + } + } + + Nv = 0; + for (int i = 0; i < Nf; ++i) { + B.begin_facet(); + B.add_vertex_to_facet(Nv++); + B.add_vertex_to_facet(Nv++); + B.add_vertex_to_facet(Nv++); + B.end_facet(); + } + + B.end_surface(); + } + }; + + template + std::list connected_faces(cgal_shape_t::Facet_handle& f, const Ts& excluded) { + std::set fs = { f }; + + std::function process; + process = [&fs, &process, &excluded](cgal_shape_t::Facet_handle& f) { + cgal_shape_t::Halfedge_around_facet_circulator circ = f->facet_begin(), end(circ); + do { + auto ff = circ->opposite()->facet(); + if (excluded.find(ff) == excluded.end()) { + auto p = fs.insert(ff); + if (p.second) { + process(ff); + } + } + } while (++circ != end); + }; + + process(f); + return std::list(fs.begin(), fs.end()); + } + + template + struct Builder_With_Map : public CGAL::Modifier_base { + std::list input; + std::map mapping; + + void operator()(HDS& hds) { + // Postcondition: hds is a valid polyhedral surface. + CGAL::Polyhedron_incremental_builder_3 B(hds); + + std::set used_points; + + for (auto& f : input) { + cgal_shape_t::Halfedge_around_facet_circulator circ = f->facet_begin(), end(circ); + do { + auto P = circ->vertex()->point(); + auto it = mapping.find(P); + if (it == mapping.end()) { + std::wcout << "WARNING unprojected point :(" << std::endl; + } else { + P = it->second; + } + used_points.insert(P); + } while (++circ != end); + } + + B.begin_surface(used_points.size(), input.size()); + + for (auto& p : used_points) { + B.add_vertex(p); + } + + for (auto& f : input) { + B.begin_facet(); + cgal_shape_t::Halfedge_around_facet_circulator circ = f->facet_begin(), end(circ); + do { + auto P = circ->vertex()->point(); + auto it = mapping.find(P); + if (it == mapping.end()) { + std::wcout << "WARNING unprojected point :(" << std::endl; + } else { + P = it->second; + } + + auto jt = used_points.find(P); + if (jt == used_points.end()) { + throw std::runtime_error("Unable to map point"); + } + size_t idx = std::distance(used_points.begin(), jt); + std::wcout << "idx " << idx << std::endl; + B.add_vertex_to_facet(idx); + } while (++circ != end); + + B.end_facet(); + } + + B.end_surface(); + } + }; +} + +namespace { + template + T edge_collapse(T polyhedron) { + typedef CGAL::Simple_cartesian simple; + CGAL::Polyhedron_3 simple_poly; + poly_copy(simple_poly, polyhedron); + + // flattening from a thin box to a plane is not valid in edge_collapse() + Stats stats; + My_visitor vis(&stats); + SMS::Edge_length_cost elc; + SMS::Edge_length_stop_predicate stop(1.e-3); + + int r = SMS::edge_collapse(simple_poly, stop, + CGAL::parameters::vertex_index_map(get(CGAL::vertex_external_index, simple_poly)) + .halfedge_index_map(get(CGAL::halfedge_external_index, simple_poly)) + .visitor(vis) + .get_cost(elc) + ); + + std::wcout << "Removed: " << r << std::endl; + + T result; + poly_copy(result, simple_poly); + return result; + } + + + double facet_area(const cgal_shape_t::Facet_handle& f) { + auto p0 = f->facet_begin()->vertex()->point(); + auto p1 = f->facet_begin()->next()->vertex()->point(); + auto p2 = f->facet_begin()->next()->next()->vertex()->point(); + return std::sqrt(CGAL::to_double(CGAL::cross_product(p0 - p1, p2 - p1).squared_length())); + } + + void dump_facet(const cgal_shape_t::Facet_handle& f) { + auto p0 = f->facet_begin()->vertex()->point(); + auto p1 = f->facet_begin()->next()->vertex()->point(); + auto p2 = f->facet_begin()->next()->next()->vertex()->point(); + auto V = CGAL::cross_product(p0 - p1, p2 - p1); + auto d = std::sqrt(CGAL::to_double(V.squared_length())); + if (d > 1.e-20) { + V /= d; + } + + std::ostringstream oss; + oss.precision(8); + oss << "Facet with area " << facet_area(f) << " and normal (" + << CGAL::to_double(V.cartesian(0)) << " " << CGAL::to_double(V.cartesian(1)) << " " + << CGAL::to_double(V.cartesian(2)) << ")"; + + auto osss = oss.str(); + std::wcout << osss.c_str() << std::endl; + } + + struct remove_thickness { + typedef Kernel_::Point_3 Point; + typedef Kernel_::Plane_3 Plane; + typedef Kernel_::Vector_3 Vector; + typedef Kernel_::Segment_3 Segment; + typedef Kernel_::Ray_3 Ray; + + typedef CGAL::Polyhedron_3 Polyhedron; + typedef CGAL::AABB_face_graph_triangle_primitive Primitive; + typedef CGAL::AABB_traits Traits; + typedef CGAL::AABB_tree Tree; + typedef boost::optional::Type> Ray_intersection; + + cgal_shape_t polyhedron, polyhedron2, flattened; + + remove_thickness(const cgal_shape_t& p) + // edge_collapse(p) still does not work :( + : polyhedron(p) + , polyhedron2(p) { + CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron); + CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron2); + + std::list non_degenerate, degenerate, longitudonal; + std::set thin_sides; + + std::wcout << "ALL FACES:" << std::endl; + + for (auto& f : faces(polyhedron)) { + dump_facet(f); + if (facet_area(f) > 1.e-20) { + non_degenerate.push_back(f); + } else { + degenerate.push_front(f); + std::wcout << "Degenerate, area: " << facet_area(f) << std::endl; + } + } + + std::wcout << "NON DEGENERATE:" << std::endl; + for (auto& f : non_degenerate) { + dump_facet(f); + } + + cgal_shape_t enlarged_non_degenerate_triangles; + Build_Offset bo; + bo.input = non_degenerate; + enlarged_non_degenerate_triangles.delegate(bo); + + // @todo, first on non-enlarged faces, then on enlarged; to fix projection on concave surfaces where the enlarging operation shortens projection distances. + + Tree tree(faces(enlarged_non_degenerate_triangles).first, faces(enlarged_non_degenerate_triangles).second, enlarged_non_degenerate_triangles); + + std::map face_normals; + boost::associative_property_map> face_normals_map(face_normals); + CGAL::Polygon_mesh_processing::compute_face_normals(polyhedron, face_normals_map); + + for (auto& f : non_degenerate) { + auto O = CGAL::centroid( + f->facet_begin()->vertex()->point(), + f->facet_begin()->next()->vertex()->point(), + f->facet_begin()->next()->next()->vertex()->point() + ); + + Ray ray(O, -face_normals_map[f]); + + std::list intersections; + tree.all_intersections(ray, std::back_inserter(intersections)); + double N = std::numeric_limits::infinity(); + Point P; + for (auto& intersection : intersections) { + if (boost::get(&(intersection->first))) { + const Point* p = boost::get(&(intersection->first)); + const double d = std::sqrt(CGAL::to_double((*p - O).squared_length())); + if (d > 1.e-20 && d < N) { + N = d; + } + } + } + if (N != std::numeric_limits::infinity() && N > 1.e-4) { + thin_sides.insert(f); + } + + /* + Ray_intersection intersection = tree.first_intersection(ray, [f](const cgal_shape_t::Facet_handle& p) { + return p == f; + }); + if (intersection) { + if (boost::get(&(intersection->first))) { + const Point* p = boost::get(&(intersection->first)); + const double d = std::sqrt(CGAL::to_double((*p - O).squared_length())); + if (d > 1.e-4) { + thin_sides.insert(f); + } + } + } else { + std::wcout << "No intersection :((!!!" << std::endl; + } + */ + } + + std::wcout << "THIN SIDES:" << std::endl; + for (auto& f : thin_sides) { + dump_facet(f); + } + + for (auto& f : non_degenerate) { + if (thin_sides.find(f) == thin_sides.end()) { + longitudonal.push_back(f); + } + } + + std::wcout << "LONGITUDONAL:" << std::endl; + for (auto& f : longitudonal) { + dump_facet(f); + } + + std::wcout << "faces " << faces(polyhedron).size() << "long " << longitudonal.size() << "thin " << thin_sides.size() << "non-degen " << non_degenerate.size() << std::endl; + + cgal_shape_t enlarged_indiv_triangles; + Build_Offset bo2; + bo2.input = longitudonal; + enlarged_indiv_triangles.delegate(bo2); + + { + std::ofstream ofs("enlarged.off"); + ofs.precision(17); + ofs << enlarged_indiv_triangles; + } + + Tree tree2(faces(enlarged_indiv_triangles).begin(), faces(enlarged_indiv_triangles).end(), enlarged_indiv_triangles); + + // std::map face_normals_2; + // boost::associative_property_map> face_normals_map_2(face_normals_2); + // CGAL::Polygon_mesh_processing::compute_face_normals(polyhedron, face_normals_map_2); + + // below does not seem to work? Do manually? + // std::map vertex_normals; + // boost::associative_property_map> vertex_normals_map(vertex_normals); + // CGAL::Polygon_mesh_processing::compute_normals(polyhedron, vertex_normals_map, face_normals_map_2); + + std::map new_points; + + for (Polyhedron::Facet_iterator fit = polyhedron.facets_begin(); + fit != polyhedron.facets_end(); + ++fit) { + if (CGAL::collinear( + fit->halfedge()->vertex()->point(), + fit->halfedge()->next()->vertex()->point(), + fit->halfedge()->opposite()->vertex()->point())) { + std::wcout << "degenerate triangle" << std::endl; + } + } + + /* + std::list vertices; + for (auto& f : non_degenerate) { + CGAL::Face_around_target_circulator it(f->halfedge(), polyhedron), end(it); + do { + vertices.push_back((*it)->halfedge()->vertex()); + ++it; + } while (it != end); + }*/ + + + for (auto& v : vertices(polyhedron)) { + auto O = v->point(); + + Kernel_::Vector_3 norm; + Kernel_::Vector_3 accum; + int count = 0; + CGAL::Face_around_target_circulator it(v->halfedge(), polyhedron), end(it); + do { + cgal_shape_t::Facet_handle fh = (*it)->halfedge()->facet(); + + auto jt = std::find(non_degenerate.begin(), non_degenerate.end(), fh); + std::wcout << "non degen: " << (jt != non_degenerate.end()) << std::endl; + auto kt = std::find(thin_sides.begin(), thin_sides.end(), fh); + std::wcout << "thin side: " << (kt != thin_sides.end()) << std::endl; + if (jt != non_degenerate.end() && kt == thin_sides.end()) { + // else degenerate, prevent div by zero, do not incorporate in vnorm. + // or else part of thin side + + auto p0 = (*it)->facet_begin()->vertex()->point(); + auto p1 = (*it)->facet_begin()->next()->vertex()->point(); + auto p2 = (*it)->facet_begin()->next()->next()->vertex()->point(); + + { + std::ostringstream oss; + oss.precision(8); + oss << "p0 " << p0.cartesian(0) << " " << p0.cartesian(1) << " " << p0.cartesian(2) << "\n"; + oss << "p1 " << p1.cartesian(0) << " " << p1.cartesian(1) << " " << p1.cartesian(2) << "\n"; + oss << "p2 " << p2.cartesian(0) << " " << p2.cartesian(1) << " " << p2.cartesian(2) << "\n"; + auto osss = oss.str(); + std::wcout << osss.c_str() << std::endl; + } + + auto fnorm = CGAL::cross_product(p0 - p1, p2 - p1); + fnorm /= std::sqrt(CGAL::to_double(fnorm.squared_length())); + + // const auto& fnorm = face_normals_map_2[*it]; + std::ostringstream oss; + oss.precision(8); + oss << fnorm.cartesian(0) << " " << fnorm.cartesian(1) << " " << fnorm.cartesian(2); + auto osss = oss.str(); + std::wcout << osss.c_str() << std::endl; + accum += fnorm; + + ++count; + } + + ++it; + } while (it != end); + + norm = accum / count; + std::wcout << "count " << count << std::endl; + + if (count == 0) { + // part of only degenerate or only thin sides + continue; + } + + // v->vertex_begin(); + Ray ray(O, norm); + std::ostringstream oss; + oss.precision(8); + oss << O << " -> " << norm; + auto osss = oss.str(); + std::wcout << osss.c_str() << std::endl; + + //// skip does not work anymore because we have offset the facets + // auto skip = [this, &v](const cgal_shape_t::Facet_handle& p) { + // CGAL::Face_around_target_circulator it(v->halfedge(), polyhedron), end(it); + // do { + // if ((*it)->facet_begin()->facet() == p) { + // return true; + // } + // } while (++it != end); + // return false; + // }; + + std::list intersections; + tree2.all_intersections(ray, std::back_inserter(intersections)); + double N = std::numeric_limits::infinity(); + Point P; + + bool used_intersection = false; + + if (intersections.size()) { + for (auto& intersection : intersections) { + if (boost::get(&(intersection->first))) { + const Point* p = boost::get(&(intersection->first)); + const double d = std::sqrt(CGAL::to_double((*p - O).squared_length())); + if (d < N && d > 1.e-20) { + N = d; + P = *p; + std::wcout << "intersection @ " << d << std::endl; + } + } + } + std::wcout << "-----------" << std::endl; + + // average the new point + new_points[O] = CGAL::ORIGIN + (((O - CGAL::ORIGIN) + (P - CGAL::ORIGIN))) / 2; + used_intersection = true; + } + + if (!used_intersection) { + std::wcout << "no intersection :(" << std::endl; + } + } + + /* + for (auto& fi : thin_sides) { + auto f_circ = fi->facet_begin(); + polyhedron2.erase_facet(f_circ); + } + */ + + auto thin_sides_degenerate = thin_sides; + thin_sides_degenerate.insert(degenerate.begin(), degenerate.end()); + + // @todo choose connected / connected_opposing based on largest combined area of facets? + + auto connected = connected_faces(*longitudonal.begin(), thin_sides_degenerate); + decltype(connected) connected_opposing; + + for (auto& f : longitudonal) { + if (std::find(connected.begin(), connected.end(), f) == connected.end()) { + connected_opposing = connected_faces(f, thin_sides_degenerate); + + std::set longi(longitudonal.begin(), longitudonal.end()); + std::set both_sides(connected.begin(), connected.end()); + both_sides.insert(connected_opposing.begin(), connected_opposing.end()); + + if (longi == both_sides) { + std::wcout << "Facet connection functioning properly" << std::endl; + } else { + std::wcout << "Facet connection functioning incorrectly" << std::endl; + } + + break; + } + } + + Builder_With_Map b2; + b2.input = connected; + b2.mapping = new_points; + + flattened.delegate(b2); + } + }; +} + +void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) { + typedef std::list> > nefs_t; + typedef CGAL::Box_intersection_d::Box_with_handle_d Box; + // typedef CGAL::Box_intersection_d::Box_d Box; + // std::map id_map; + + ifcopenshell::geometry::settings settings; + settings.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, false); + settings.set(ifcopenshell::geometry::settings::WELD_VERTICES, false); + settings.set(ifcopenshell::geometry::settings::SEW_SHELLS, true); + settings.set(ifcopenshell::geometry::settings::CONVERT_BACK_UNITS, true); + settings.set(ifcopenshell::geometry::settings::DISABLE_TRIANGULATION, true); + settings.set(ifcopenshell::geometry::settings::DISABLE_OPENING_SUBTRACTIONS, true); + + std::vector spaces_and_walls = { + IfcGeom::entity_filter(true, false, {"IfcWall", "IfcSpace"}) + }; + + ifcopenshell::geometry::Iterator context_iterator("cgal", settings, &f, spaces_and_walls); + + if (!context_iterator.initialize()) { + return; + } + + auto kernel = (ifcopenshell::geometry::kernels::CgalKernel*) context_iterator.converter().kernel(); + auto cube = kernel->precision_cube(); + + size_t num_created = 0; + int old_progress = quiet ? 0 : -1; + + std::vector boxes; + nefs_t nefs; + + for (;; ++num_created) { + bool has_more = true; + if (num_created) { + has_more = context_iterator.next(); + } + ifcopenshell::geometry::NativeElement* geom_object = nullptr; + if (has_more) { + geom_object = context_iterator.get_native(); + } + if (!geom_object) { + break; + } + + std::stringstream ss; + ss << geom_object->product()->data().toString(); + auto sss = ss.str(); + std::wcout << sss.c_str() << std::endl; + + for (auto& g : geom_object->geometry()) { + auto s = ((ifcopenshell::geometry::CgalShape*) g.Shape())->shape(); + const auto& m = g.Placement().components; + const auto& n = geom_object->transformation().data().components; + + if (true || !m.isIdentity()) { + const cgal_placement_t trsf( + m(0, 0), m(0, 1), m(0, 2), m(0, 3), + m(1, 0), m(1, 1), m(1, 2), m(1, 3), + m(2, 0), m(2, 1), m(2, 2), m(2, 3)); + + const cgal_placement_t trsf2( + n(0, 0), n(0, 1), n(0, 2), n(0, 3), + n(1, 0), n(1, 1), n(1, 2), n(1, 3), + n(2, 0), n(2, 1), n(2, 2), n(2, 3)); + + // Apply transformation + for (auto &vertex : vertices(s)) { + vertex->point() = vertex->point().transform(trsf).transform(trsf2); + std::ostringstream ss; + ss << vertex->point().cartesian(0); + auto sss = ss.str(); + std::wcout << sss.c_str() << std::endl; + } + } + + CGAL::Nef_polyhedron_3 nef; + auto c = convert_to_nef(s, nef); + if (c != 0) { + std::wcout << "Error " << c << std::endl; + continue; + } + nef = CGAL::minkowski_sum_3(nef, cube); + std::wcout << "product: " << geom_object->product() << std::endl; + nefs.push_back({ geom_object->product(), nef }); + + Box b(&*(nefs.rbegin())); + // id_map[b.id()] = ; + + for (auto &vertex : vertices(s)) { + double p[3] = { + CGAL::to_double(vertex->point().cartesian(0)), + CGAL::to_double(vertex->point().cartesian(1)), + CGAL::to_double(vertex->point().cartesian(2)) + }; + b.extend(p); + } + + boxes.push_back(enlarge(b)); + + /* + std::ostringstream ss; + ss << geom_object->product()->data().toString() << std::endl << b.min_coord(0) << " - " << b.max_coord(0) << std::endl; + auto sss = ss.str(); + std::wcout << sss.c_str(); + */ + } + + if (!no_progress) { + if (quiet) { + const int progress = context_iterator.progress(); + for (; old_progress < progress; ++old_progress) { + std::cout << "."; + if (stderr_progress) + std::cerr << "."; + } + std::cout << std::flush; + if (stderr_progress) + std::cerr << std::flush; + } else { + const int progress = context_iterator.progress() / 2; + if (old_progress != progress) Logger::ProgressBar(progress); + old_progress = progress; + } + } + } + + CGAL::box_self_intersection_d(boxes.begin(), boxes.end(), [](const Box& a, const Box& b) { + std::ostringstream ss; + // ss << id_map[a.id()]->first->data().toString() << "x" << id_map[b.id()]->first->data().toString() << std::endl; + // auto x = id_map[a.id()]->second * id_map[b.id()]->second; + + ss << a.handle()->first->data().toString() << "x" << a.handle()->first->data().toString() << std::endl; + auto x = a.handle()->second * b.handle()->second; + cgal_shape_t x_poly; + x.convert_to_polyhedron(x_poly); + + CGAL::Polygon_mesh_processing::triangulate_faces(x_poly); + + auto vs = vertices(x_poly); + if (std::distance(vs.begin(), vs.end()) == 0) { + return; + } + + auto s0 = a.handle()->first->declaration().name(); + auto s1 = b.handle()->first->declaration().name(); + auto i0 = a.handle()->first->data().id(); + auto i1 = b.handle()->first->data().id(); + + if (s0 < s1) { + std::swap(s1, s0); + std::swap(i0, i1); + } + + { + auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "sb.off"; + + std::ofstream os(FN.c_str()); + os.precision(17); + os << x_poly; + } + + remove_thickness r(x_poly); + + { + auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "-sides-sb.off"; + + std::ofstream os(FN.c_str()); + os.precision(17); + os << r.polyhedron2; + } + + { + auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "-flat-sb.off"; + + std::ofstream os(FN.c_str()); + os.precision(17); + os << r.flattened; + } + // r(); + + /* + std::map collapsed; + std::map collapsed_v; + + for (auto it = x_poly.edges_begin(); it != x_poly.edges_end(); ++it) { + auto& e = *it; + cgal_shape_t::Vertex_iterator v0 = e.vertex(); + cgal_shape_t::Vertex_iterator v1 = e.prev()->vertex(); + auto p0 = v0->point(); + auto p1 = v1->point(); + auto l = std::sqrt(CGAL::to_double((p1 - p0).squared_length())); + std::wcout << "edge w/ length " << l << std::endl; + + cgal_shape_t::Plane_3 plane(it->vertex()->point(), + it->next()->vertex()->point(), + it->next()->next()->vertex()->point()); + + auto d0 = plane.to_2d(e.prev()->vertex()->point()) - plane.to_2d(e.prev()->prev()->vertex()->point()); + auto d1 = plane.to_2d(e.vertex()->point()) - plane.to_2d(e.prev()->vertex()->point()); + auto d2 = plane.to_2d(e.next()->vertex()->point()) - plane.to_2d(e.vertex()->point()); + auto a0 = std::atan2(CGAL::to_double(d0.cartesian(1)), CGAL::to_double(d0.cartesian(0))); + auto a1 = std::atan2(CGAL::to_double(d1.cartesian(1)), CGAL::to_double(d1.cartesian(0))); + auto a2 = std::atan2(CGAL::to_double(d2.cartesian(1)), CGAL::to_double(d2.cartesian(0))); + auto a10 = a1 - a0; + auto a21 = a2 - a1; + if (a10 < 0.) { + a10 += 2 * M_PI; + } + if (a21 < 0.) { + a21 += 2 * M_PI; + } + + const bool is_convex = a10 < M_PI && a21 < M_PI; + + cgal_shape_t::Plane_3 opposite_plane(it->opposite()->vertex()->point(), + it->opposite()->next()->vertex()->point(), + it->opposite()->next()->next()->vertex()->point() + ); + + { + std::ostringstream oss; + oss << plane << " vs " << opposite_plane << "\n"; + oss << plane.orthogonal_vector() << " vs " << opposite_plane.orthogonal_vector(); + auto osss = oss.str(); + std::wcout << osss.c_str() << std::endl; + } + + bool is_internal = false; + if (std::sqrt(CGAL::to_double(plane.orthogonal_vector().squared_length())) < 1.e-15 || + std::sqrt(CGAL::to_double(opposite_plane.orthogonal_vector().squared_length())) < 1.e-15 + ) { + is_internal = true; + std::wcout << "Degenerate" << std::endl; + } else { + const double face_normal_dot = CGAL::to_double(approx_normalized(plane.orthogonal_vector()) * approx_normalized(opposite_plane.orthogonal_vector())); + std::wcout << "Face normal dot " << face_normal_dot << std::endl; + is_internal = face_normal_dot > 0.9; + } + + std::wcout << "Angles " << a0 << " " << a1 << " " << a2 << std::endl; + + if (l < 4.e-5 && (is_convex || is_internal)) { + auto p2 = CGAL::ORIGIN + ((p0 - CGAL::ORIGIN) + (p1 - CGAL::ORIGIN)) / 2; + + std::wcout << "(a) " << CGAL::to_double(p0.cartesian(0)) << " " << CGAL::to_double(p0.cartesian(1)) << " " << CGAL::to_double(p0.cartesian(2)) << "\n"; + std::wcout << "(b) " << CGAL::to_double(p1.cartesian(0)) << " " << CGAL::to_double(p1.cartesian(1)) << " " << CGAL::to_double(p1.cartesian(2)) << "\n"; + std::wcout << "(c) " << CGAL::to_double(p2.cartesian(0)) << " " << CGAL::to_double(p2.cartesian(1)) << " " << CGAL::to_double(p2.cartesian(2)) << "\n"; + // collapsed.insert({ v0, p2 }); + // collapsed.insert({ v1, p2 }); + collapsed.insert({ it, p2 }); + // Edges includes only half of the halfedges + collapsed.insert({ it->opposite(), p2 }); + + collapsed_v.insert({ v0, p2 }); + collapsed_v.insert({ v1, p2 }); + } + } + + { + auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "sb.obj"; + std::ofstream ofs(FN.c_str()); + ofs.precision(17); + + int N = 1; + + std::set > faces_emitted; + for (auto& f : faces(x_poly)) { + std::ostringstream oss; + auto start = f->facet_begin(); + + bool part_collapsed = false; + + CGAL::Polyhedron_3::Halfedge_around_facet_const_circulator e = f->facet_begin(); + do { + auto it = collapsed.find(e); + if (it != collapsed.end()) { + part_collapsed = true; + break; + } + ++e; + } while (e != f->facet_begin()); + + decltype(faces_emitted)::key_type vss; + std::list points; + + if (!part_collapsed) { + e = f->facet_begin(); + do { + cgal_shape_t::Vertex_const_handle v = e->vertex(); + auto it = collapsed_v.find(v); + if (it == collapsed_v.end()) { + std::wcout << "Unexpected " + << CGAL::to_double(v->point().cartesian(0)) << " " + << CGAL::to_double(v->point().cartesian(1)) << " " + << CGAL::to_double(v->point().cartesian(2)) << std::endl; + } else { + points.push_back(it->second); + vss.insert(it->second); + } + ++e; + } while (e != f->facet_begin()); + + if (faces_emitted.find(vss) != faces_emitted.end()) { + std::wcout << "Emitted" << std::endl; + } else { + faces_emitted.insert(vss); + + for (auto& p : points) { + ofs << "v " << CGAL::to_double(p.cartesian(0)) << " " << CGAL::to_double(p.cartesian(1)) << " " << CGAL::to_double(p.cartesian(2)) << "\n"; + } + + ofs << "f "; + for (auto i = 0; i < points.size(); ++i) { + if (i) { + ofs << " "; + } + ofs << i + N; + } + ofs << "\n"; + + N += points.size(); + } + } + } + } + + */ + + /* + // edge collapse does not work on the rational number types + typedef CGAL::Simple_cartesian simple; + CGAL::Polyhedron_3 x_simple; + poly_copy(x_simple, x_poly); + + // flattening from a thin box to a plane is not valid in edge_collapse() + Stats stats; + My_visitor vis(&stats); + SMS::Edge_length_cost elc; + SMS::Edge_length_stop_predicate stop(1.e-3); + + int r = SMS::edge_collapse(x_simple, stop, + CGAL::parameters::vertex_index_map(get(CGAL::vertex_external_index, x_simple)) + .halfedge_index_map(get(CGAL::halfedge_external_index, x_simple)) + .visitor(vis) + .get_cost(elc) + ); + + std::wcout << "Removed: " << r << std::endl; + */ + + /* + for (auto& v : vertices(x_poly)) { + auto p = v->point(); + for (int i = 0; i < 3; ++i) { + ss << p.cartesian(i) << " "; + } + ss << std::endl; + } + ss << "---" << std::endl; + auto sss = ss.str(); + std::wcout << sss.c_str(); + */ + }); + + if (!no_progress && quiet) { + for (; old_progress < 100; ++old_progress) { + std::cout << "."; + if (stderr_progress) + std::cerr << "."; + } + std::cout << std::flush; + if (stderr_progress) + std::cerr << std::flush; + } else { + Logger::Status("\rDone fixing space boundaries for " + boost::lexical_cast(num_created) + + " objects "); + } +} diff --git a/src/ifcconvert/validate_storey_containment.cpp b/src/ifcconvert/validate_storey_containment.cpp new file mode 100644 index 0000000000..8e824f6275 --- /dev/null +++ b/src/ifcconvert/validate_storey_containment.cpp @@ -0,0 +1,242 @@ +#include "../ifcgeom/kernels/cgal/CgalKernel.h" +#include "../ifcgeom/schema_agnostic/IfcGeomFilter.h" +#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h" + +#include +#include + +#include + +void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) { + ifcopenshell::geometry::settings settings; + settings.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, false); + settings.set(ifcopenshell::geometry::settings::WELD_VERTICES, false); + settings.set(ifcopenshell::geometry::settings::SEW_SHELLS, true); + settings.set(ifcopenshell::geometry::settings::CONVERT_BACK_UNITS, true); + settings.set(ifcopenshell::geometry::settings::DISABLE_TRIANGULATION, true); + settings.set(ifcopenshell::geometry::settings::DISABLE_OPENING_SUBTRACTIONS, true); + + std::vector no_openings_and_spaces = { + IfcGeom::entity_filter(false, false, {"IfcOpeningElement", "IfcSpace"}) + }; + + ifcopenshell::geometry::Iterator context_iterator("cgal", settings, &f, no_openings_and_spaces); + + auto get_elevation = [](IfcUtil::IfcBaseClass* a) { + return ((IfcUtil::IfcBaseEntity*)a)->get_value_or("Elevation", 0.); + }; + + // latebound inverse attribute lookup not working + auto rels = f.instances_by_type("IfcRelContainedInSpatialStructure"); + std::map elem_to_storey; + std::for_each(rels->begin(), rels->end(), [&elem_to_storey](IfcUtil::IfcBaseClass* r) { + auto elems = ((IfcUtil::IfcBaseEntity*)r)->get_value("RelatedElements"); + auto storey = ((IfcUtil::IfcBaseEntity*)r)->get_value("RelatingStructure"); + + if (storey->declaration().name() == "IfcBuildingStorey") { + for (auto it = elems->begin(); it != elems->end(); ++it) { + elem_to_storey[*it] = storey; + } + } + }); + + auto storeys = f.instances_by_type("IfcBuildingStorey"); + std::vector storeys_sorted(storeys->begin(), storeys->end()); + std::sort(storeys_sorted.begin(), storeys_sorted.end(), [&get_elevation](IfcUtil::IfcBaseClass* a, IfcUtil::IfcBaseClass* b) { + return get_elevation(a) < get_elevation(b); + }); + + std::vector elevations; + std::transform(storeys_sorted.begin(), storeys_sorted.end(), std::back_inserter(elevations), get_elevation); + + double LARGE = 100; + + std::vector> elevation_slices; + for (size_t i = 0; i < elevations.size(); ++i) { + elevation_slices.push_back({ + i == 0 ? -LARGE : elevations[i], + i + 1 == elevations.size() ? LARGE : elevations[i + 1] + }); + } + + std::vector> nefs; + std::transform(elevation_slices.begin(), elevation_slices.end(), std::back_inserter(nefs), [&LARGE](const std::pair& p) { + Kernel_::Point_3 p1(-LARGE, -LARGE, p.first); + Kernel_::Point_3 p2(+LARGE, +LARGE, p.second); + auto poly = ifcopenshell::geometry::utils::create_cube(p1, p2); + + auto bb = CGAL::Polygon_mesh_processing::bbox(poly); + std::wcout << "storey "; + for (int i = 0; i < 3; ++i) { + std::wcout << bb.min(i) << " "; + } + std::wcout << "- "; + for (int i = 0; i < 3; ++i) { + std::wcout << bb.max(i) << " "; + } + std::wcout << std::endl; + + std::wcout << "volume " << CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)) << std::endl; + + auto nef = ifcopenshell::geometry::utils::create_nef_polyhedron(poly); + + { + auto poly = ifcopenshell::geometry::utils::create_polyhedron(nef); + std::wcout << "volume " << CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)) << std::endl; + } + + return nef; + }); + + if (!context_iterator.initialize()) { + return; + } + + size_t num_created = 0; + int old_progress = quiet ? 0 : -1; + + for (;; ++num_created) { + bool has_more = true; + if (num_created) { + has_more = context_iterator.next(); + } + ifcopenshell::geometry::NativeElement* geom_object = nullptr; + if (has_more) { + geom_object = context_iterator.get_native(); + } + if (!geom_object) { + break; + } + + std::stringstream ss; + ss << geom_object->product()->data().toString(); + auto sss = ss.str(); + std::wcout << sss.c_str() << std::endl; + + if (elem_to_storey.find(geom_object->product()) == elem_to_storey.end()) { + std::wcout << "not associated to storey" << std::endl; + continue; + } + + for (auto& g : geom_object->geometry()) { + auto s = ((ifcopenshell::geometry::CgalShape*) g.Shape())->shape(); + const auto& m = g.Placement().components; + const auto& n = geom_object->transformation().data().components; + + if (!m.isIdentity()) { + const cgal_placement_t trsf( + m(0, 0), m(0, 1), m(0, 2), m(0, 3), + m(1, 0), m(1, 1), m(1, 2), m(1, 3), + m(2, 0), m(2, 1), m(2, 2), m(2, 3)); + + const cgal_placement_t trsf2( + n(0, 0), n(0, 1), n(0, 2), n(0, 3), + n(1, 0), n(1, 1), n(1, 2), n(1, 3), + n(2, 0), n(2, 1), n(2, 2), n(2, 3)); + + // Apply transformation + for (auto &vertex : vertices(s)) { + vertex->point() = vertex->point().transform(trsf).transform(trsf2); + } + } + + auto bb = CGAL::Polygon_mesh_processing::bbox(s); + std::wcout << "elem "; + for (int i = 0; i < 3; ++i) { + std::wcout << bb.min(i) << " "; + } + std::wcout << "- "; + for (int i = 0; i < 3; ++i) { + std::wcout << bb.max(i) << " "; + } + std::wcout << std::endl; + + CGAL::Nef_polyhedron_3 part_nef = ifcopenshell::geometry::utils::create_nef_polyhedron(s); + + if (!part_nef.is_simple()) { + std::wcout << "not simple" << std::endl; + continue; + } + + std::wcout << "volume " << CGAL::to_double(CGAL::Polygon_mesh_processing::volume(s)) << std::endl; + + + { + auto poly = ifcopenshell::geometry::utils::create_polyhedron(part_nef); + std::wcout << " part faces " << faces(poly).size() << " volume " << CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)) << std::endl; + } + + std::vector intersection_volumes; + + std::transform(nefs.begin(), nefs.end(), std::back_inserter(intersection_volumes), [&part_nef](const CGAL::Nef_polyhedron_3& storey_nef) { + { + auto poly = ifcopenshell::geometry::utils::create_polyhedron(storey_nef); + std::wcout << " storey faces " << faces(poly).size() << " volume " << CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)) << std::endl; + } + { + auto poly = ifcopenshell::geometry::utils::create_polyhedron(part_nef); + std::wcout << " part faces " << faces(poly).size() << " volume " << CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)) << std::endl; + } + { + auto poly = ifcopenshell::geometry::utils::create_polyhedron(part_nef + storey_nef); + std::wcout << " faces " << faces(poly).size() << " volume " << CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)) << std::endl; + } + { + auto poly = ifcopenshell::geometry::utils::create_polyhedron(part_nef - storey_nef); + std::wcout << " faces " << faces(poly).size() << " volume " << CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)) << std::endl; + } + { + auto poly = ifcopenshell::geometry::utils::create_polyhedron(part_nef * storey_nef); + std::wcout << " faces " << faces(poly).size(); + return CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)); + } + }); + + std::wcout << "volumes: "; + for (auto& v : intersection_volumes) { + std::wcout << v << " "; + } + std::wcout << std::endl; + + auto idx = std::max_element(intersection_volumes.begin(), intersection_volumes.end()) - intersection_volumes.begin(); + if (storeys_sorted[idx] != elem_to_storey[geom_object->product()]) { + auto s = geom_object->product()->data().toString(); + auto s1 = storeys_sorted[idx]->data().toString(); + auto s2 = elem_to_storey[geom_object->product()]->data().toString(); + std::wcout << "Mismatch on " << s.c_str() << ": " << s1.c_str() << " vs " << s2.c_str() << std::endl; + } + } + + if (!no_progress) { + if (quiet) { + const int progress = context_iterator.progress(); + for (; old_progress < progress; ++old_progress) { + std::cout << "."; + if (stderr_progress) + std::cerr << "."; + } + std::cout << std::flush; + if (stderr_progress) + std::cerr << std::flush; + } else { + const int progress = context_iterator.progress() / 2; + if (old_progress != progress) Logger::ProgressBar(progress); + old_progress = progress; + } + } + } + + if (!no_progress && quiet) { + for (; old_progress < 100; ++old_progress) { + std::cout << "."; + if (stderr_progress) + std::cerr << "."; + } + std::cout << std::flush; + if (stderr_progress) + std::cerr << std::flush; + } else { + Logger::Status("\rDone fixing space boundaries for " + boost::lexical_cast(num_created) + + " objects "); + } +} diff --git a/src/ifcconvert/validate_wall_connectivity.cpp b/src/ifcconvert/validate_wall_connectivity.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index d5b1561072..190a851470 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -37,7 +37,7 @@ void CgalKernel::remove_duplicate_points_from_loop(cgal_wire_t& polygon) { } } -CGAL::Polyhedron_3 CgalKernel::create_polyhedron(std::list &face_list) { +CGAL::Polyhedron_3 ifcopenshell::geometry::utils::create_polyhedron(std::list &face_list) { // Naive creation CGAL::Polyhedron_3 polyhedron; @@ -65,7 +65,7 @@ CGAL::Polyhedron_3 CgalKernel::create_polyhedron(std::list return polyhedron; } -CGAL::Polyhedron_3 CgalKernel::create_polyhedron(CGAL::Nef_polyhedron_3 &nef_polyhedron) { +CGAL::Polyhedron_3 ifcopenshell::geometry::utils::create_polyhedron(const CGAL::Nef_polyhedron_3& nef_polyhedron) { if (nef_polyhedron.is_simple()) { try { CGAL::Polyhedron_3 polyhedron; @@ -81,7 +81,7 @@ CGAL::Polyhedron_3 CgalKernel::create_polyhedron(CGAL::Nef_polyhedron_3 } } -CGAL::Nef_polyhedron_3 CgalKernel::create_nef_polyhedron(std::list &face_list) { +CGAL::Nef_polyhedron_3 ifcopenshell::geometry::utils::create_nef_polyhedron(std::list &face_list) { CGAL::Polyhedron_3 polyhedron = create_polyhedron(face_list); CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron); CGAL::Nef_polyhedron_3 nef_polyhedron; @@ -89,11 +89,11 @@ CGAL::Nef_polyhedron_3 CgalKernel::create_nef_polyhedron(std::list(polyhedron); } catch (...) { Logger::Message(Logger::LOG_ERROR, "Conversion to Nef polyhedron failed!"); - return nef_polyhedron; - } return nef_polyhedron; + } + return nef_polyhedron; } -CGAL::Nef_polyhedron_3 CgalKernel::create_nef_polyhedron(CGAL::Polyhedron_3 &polyhedron) { +CGAL::Nef_polyhedron_3 ifcopenshell::geometry::utils::create_nef_polyhedron(CGAL::Polyhedron_3 &polyhedron) { if (polyhedron.is_valid()) { CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron); CGAL::Nef_polyhedron_3 nef_polyhedron; @@ -101,8 +101,8 @@ CGAL::Nef_polyhedron_3 CgalKernel::create_nef_polyhedron(CGAL::Polyhedr nef_polyhedron = CGAL::Nef_polyhedron_3(polyhedron); } catch (...) { Logger::Message(Logger::LOG_ERROR, "Conversion to Nef polyhedron failed!"); - return nef_polyhedron; - } return nef_polyhedron; + } + return nef_polyhedron; } else { Logger::Message(Logger::LOG_ERROR, "Polyhedron not valid: cannot create Nef polyhedron!"); return CGAL::Nef_polyhedron_3(); @@ -134,7 +134,7 @@ bool CgalKernel::convert(const taxonomy::shell* l, cgal_shape_t& shape) { face_list.push_back(face); } - shape = create_polyhedron(face_list); + shape = utils::create_polyhedron(face_list); return true; } @@ -337,12 +337,12 @@ bool CgalKernel::convert(const taxonomy::extrusion* extrusion, cgal_shape_t &sha } face_list.push_back(top_face); if (bottom_face.inner.empty()) { - shape = create_polyhedron(face_list); + shape = utils::create_polyhedron(face_list); // if (has_position) for (auto &vertex : vertices(shape)) vertex->point() = vertex->point().transform(trsf); return true; } - CGAL::Nef_polyhedron_3 nef_shape = create_nef_polyhedron(face_list); + CGAL::Nef_polyhedron_3 nef_shape = utils::create_nef_polyhedron(face_list); // Inner // TODO: Would be faster to triangulate top/bottom face template rather than use Nef polyhedra for subtraction @@ -378,7 +378,7 @@ bool CgalKernel::convert(const taxonomy::extrusion* extrusion, cgal_shape_t &sha } face_list.push_back(hole_top_face); try { - nef_shape -= create_nef_polyhedron(face_list); + nef_shape -= utils::create_nef_polyhedron(face_list); } catch (...) { Logger::Message(Logger::LOG_ERROR, "IfcExtrudedAreaSolid: cannot subtract opening for:", extrusion->instance); return false; @@ -401,7 +401,7 @@ bool CgalKernel::convert(const taxonomy::extrusion* extrusion, cgal_shape_t &sha } -CGAL::Polyhedron_3 CgalKernel::create_cube(double d) { +CGAL::Polyhedron_3 ifcopenshell::geometry::utils::create_cube(double d) { cgal_face_t bottom_face; bottom_face.outer.push_back(Kernel_::Point_3(-d, -d, -d)); bottom_face.outer.push_back(Kernel_::Point_3(+d, -d, -d)); @@ -447,6 +447,62 @@ CGAL::Polyhedron_3 CgalKernel::create_cube(double d) { return create_polyhedron(face_list); } + +CGAL::Polyhedron_3 ifcopenshell::geometry::utils::create_cube(const Kernel_::Point_3& lower, const Kernel_::Point_3& upper) { + cgal_face_t bottom_face; + + auto& a0 = lower.cartesian(0); + auto& a1 = lower.cartesian(1); + auto& a2 = lower.cartesian(2); + + auto& b0 = upper.cartesian(0); + auto& b1 = upper.cartesian(1); + auto& b2 = upper.cartesian(2); + + bottom_face.outer.push_back(Kernel_::Point_3(a0, a1, a2)); + bottom_face.outer.push_back(Kernel_::Point_3(b0, a1, a2)); + bottom_face.outer.push_back(Kernel_::Point_3(b0, b1, a2)); + bottom_face.outer.push_back(Kernel_::Point_3(a0, b1, a2)); + + cgal_direction_t dir(0, 0, b2 - a2); + + std::list face_list = { bottom_face }; + + for (std::vector::const_iterator current_vertex = bottom_face.outer.begin(); + current_vertex != bottom_face.outer.end(); + ++current_vertex) + { + std::vector::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 + dir); + side_face.outer.push_back(*next_vertex + dir); + + face_list.push_back(side_face); + } + + cgal_face_t top_face; + + for (std::vector::const_reverse_iterator vertex = bottom_face.outer.rbegin(); + vertex != bottom_face.outer.rend(); + ++vertex) + { + top_face.outer.push_back(*vertex + dir); + } + + face_list.push_back(top_face); + + return create_polyhedron(face_list); +} + bool CgalKernel::thin_solid(const CGAL::Nef_polyhedron_3& a, CGAL::Nef_polyhedron_3& result) { // @todo this should be possible as a minkowski sum of facet & cube. rather than a set of boolean ops. diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index e5755a4772..588fd5b3a8 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -89,6 +89,15 @@ public: namespace ifcopenshell { namespace geometry { +namespace utils { + IFC_GEOM_API CGAL::Polyhedron_3 create_cube(double d); + IFC_GEOM_API CGAL::Polyhedron_3 create_cube(const Kernel_::Point_3& lower, const Kernel_::Point_3& upper); + IFC_GEOM_API CGAL::Polyhedron_3 create_polyhedron(std::list &face_list); + IFC_GEOM_API CGAL::Polyhedron_3 create_polyhedron(const CGAL::Nef_polyhedron_3 &nef_polyhedron); + IFC_GEOM_API CGAL::Nef_polyhedron_3 create_nef_polyhedron(std::list &face_list); + IFC_GEOM_API CGAL::Nef_polyhedron_3 create_nef_polyhedron(CGAL::Polyhedron_3 &polyhedron); +} + namespace kernels { class IFC_GEOM_API CgalKernel : public AbstractKernel { @@ -97,7 +106,6 @@ namespace kernels { size_t circle_segments_; CGAL::Nef_polyhedron_3 precision_cube_; - CGAL::Polyhedron_3 create_cube(double d); bool preprocess_boolean_operand(const IfcUtil::IfcBaseClass* log_reference, const cgal_shape_t& shape_const, CGAL::Nef_polyhedron_3& result, bool dilate); bool thin_solid(const CGAL::Nef_polyhedron_3& a, CGAL::Nef_polyhedron_3& result); public: @@ -108,17 +116,12 @@ namespace kernels { , precision_(1.e-5) , circle_segments_(16) { - auto cc = create_cube(precision_); + auto cc = utils::create_cube(precision_); precision_cube_ = CGAL::Nef_polyhedron_3(cc); } void remove_duplicate_points_from_loop(cgal_wire_t& polygon); - CGAL::Polyhedron_3 create_polyhedron(std::list &face_list); - CGAL::Polyhedron_3 create_polyhedron(CGAL::Nef_polyhedron_3 &nef_polyhedron); - CGAL::Nef_polyhedron_3 create_nef_polyhedron(std::list &face_list); - CGAL::Nef_polyhedron_3 create_nef_polyhedron(CGAL::Polyhedron_3 &polyhedron); - bool convert(const taxonomy::extrusion*, cgal_shape_t&); bool convert(const taxonomy::face*, cgal_face_t&); bool convert(const taxonomy::loop*, cgal_wire_t&); From 030ea06aac4d9b92401d74cc4cd4ff22a3efbbf1 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sat, 25 Jan 2020 14:24:18 +0100 Subject: [PATCH 198/235] Fix placement on containment case --- src/ifcconvert/validate_space_boundaries.cpp | 32 ++-- .../validate_storey_containment.cpp | 157 ++++++++---------- 2 files changed, 82 insertions(+), 107 deletions(-) diff --git a/src/ifcconvert/validate_space_boundaries.cpp b/src/ifcconvert/validate_space_boundaries.cpp index f4086579f7..f7fecb461d 100644 --- a/src/ifcconvert/validate_space_boundaries.cpp +++ b/src/ifcconvert/validate_space_boundaries.cpp @@ -755,25 +755,23 @@ void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, boo const auto& m = g.Placement().components; const auto& n = geom_object->transformation().data().components; - if (true || !m.isIdentity()) { - const cgal_placement_t trsf( - m(0, 0), m(0, 1), m(0, 2), m(0, 3), - m(1, 0), m(1, 1), m(1, 2), m(1, 3), - m(2, 0), m(2, 1), m(2, 2), m(2, 3)); + const cgal_placement_t trsf( + m(0, 0), m(0, 1), m(0, 2), m(0, 3), + m(1, 0), m(1, 1), m(1, 2), m(1, 3), + m(2, 0), m(2, 1), m(2, 2), m(2, 3)); - const cgal_placement_t trsf2( - n(0, 0), n(0, 1), n(0, 2), n(0, 3), - n(1, 0), n(1, 1), n(1, 2), n(1, 3), - n(2, 0), n(2, 1), n(2, 2), n(2, 3)); + const cgal_placement_t trsf2( + n(0, 0), n(0, 1), n(0, 2), n(0, 3), + n(1, 0), n(1, 1), n(1, 2), n(1, 3), + n(2, 0), n(2, 1), n(2, 2), n(2, 3)); - // Apply transformation - for (auto &vertex : vertices(s)) { - vertex->point() = vertex->point().transform(trsf).transform(trsf2); - std::ostringstream ss; - ss << vertex->point().cartesian(0); - auto sss = ss.str(); - std::wcout << sss.c_str() << std::endl; - } + // Apply transformation + for (auto &vertex : vertices(s)) { + vertex->point() = vertex->point().transform(trsf).transform(trsf2); + std::ostringstream ss; + ss << vertex->point().cartesian(0); + auto sss = ss.str(); + std::wcout << sss.c_str() << std::endl; } CGAL::Nef_polyhedron_3 nef; diff --git a/src/ifcconvert/validate_storey_containment.cpp b/src/ifcconvert/validate_storey_containment.cpp index 8e824f6275..1fdb6d906f 100644 --- a/src/ifcconvert/validate_storey_containment.cpp +++ b/src/ifcconvert/validate_storey_containment.cpp @@ -7,6 +7,10 @@ #include +class containment_validator { + +}; + void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) { ifcopenshell::geometry::settings settings; settings.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, false); @@ -46,10 +50,17 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b return get_elevation(a) < get_elevation(b); }); + std::wcout << "Storeys "; + for (auto& s : storeys_sorted) { + auto n = ((IfcUtil::IfcBaseEntity*)s)->get_value("Name"); + std::wcout << n.c_str() << " "; + } + std::wcout << std::endl; + std::vector elevations; std::transform(storeys_sorted.begin(), storeys_sorted.end(), std::back_inserter(elevations), get_elevation); - double LARGE = 100; + double LARGE = 1e4; std::vector> elevation_slices; for (size_t i = 0; i < elevations.size(); ++i) { @@ -59,34 +70,27 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b }); } + std::vector> nefs; std::transform(elevation_slices.begin(), elevation_slices.end(), std::back_inserter(nefs), [&LARGE](const std::pair& p) { + std::wcout << p.first << " - " << p.second << std::endl; Kernel_::Point_3 p1(-LARGE, -LARGE, p.first); Kernel_::Point_3 p2(+LARGE, +LARGE, p.second); auto poly = ifcopenshell::geometry::utils::create_cube(p1, p2); - - auto bb = CGAL::Polygon_mesh_processing::bbox(poly); - std::wcout << "storey "; - for (int i = 0; i < 3; ++i) { - std::wcout << bb.min(i) << " "; - } - std::wcout << "- "; - for (int i = 0; i < 3; ++i) { - std::wcout << bb.max(i) << " "; - } - std::wcout << std::endl; - - std::wcout << "volume " << CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)) << std::endl; - - auto nef = ifcopenshell::geometry::utils::create_nef_polyhedron(poly); - - { - auto poly = ifcopenshell::geometry::utils::create_polyhedron(nef); - std::wcout << "volume " << CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)) << std::endl; - } - - return nef; + return ifcopenshell::geometry::utils::create_nef_polyhedron(poly); }); + + for (auto& n : nefs) { + auto poly = ifcopenshell::geometry::utils::create_polyhedron(n); + auto bounds = CGAL::Polygon_mesh_processing::bbox_3(poly); + for (int i = 0; i < 3; ++i) { + std::wcout << bounds.min(i) << std::endl; + } + for (int i = 0; i < 3; ++i) { + std::wcout << bounds.max(i) << std::endl; + } + std::wcout << "---" << std::endl; + } if (!context_iterator.initialize()) { return; @@ -118,39 +122,39 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b continue; } + std::vector intersection_volumes(nefs.size()); + for (auto& g : geom_object->geometry()) { auto s = ((ifcopenshell::geometry::CgalShape*) g.Shape())->shape(); const auto& m = g.Placement().components; const auto& n = geom_object->transformation().data().components; - if (!m.isIdentity()) { - const cgal_placement_t trsf( - m(0, 0), m(0, 1), m(0, 2), m(0, 3), - m(1, 0), m(1, 1), m(1, 2), m(1, 3), - m(2, 0), m(2, 1), m(2, 2), m(2, 3)); + const cgal_placement_t trsf( + m(0, 0), m(0, 1), m(0, 2), m(0, 3), + m(1, 0), m(1, 1), m(1, 2), m(1, 3), + m(2, 0), m(2, 1), m(2, 2), m(2, 3)); - const cgal_placement_t trsf2( - n(0, 0), n(0, 1), n(0, 2), n(0, 3), - n(1, 0), n(1, 1), n(1, 2), n(1, 3), - n(2, 0), n(2, 1), n(2, 2), n(2, 3)); + const cgal_placement_t trsf2( + n(0, 0), n(0, 1), n(0, 2), n(0, 3), + n(1, 0), n(1, 1), n(1, 2), n(1, 3), + n(2, 0), n(2, 1), n(2, 2), n(2, 3)); - // Apply transformation - for (auto &vertex : vertices(s)) { - vertex->point() = vertex->point().transform(trsf).transform(trsf2); + // Apply transformation + for (auto &vertex : vertices(s)) { + vertex->point() = vertex->point().transform(trsf).transform(trsf2); + } + + { + auto bounds = CGAL::Polygon_mesh_processing::bbox_3(s); + for (int i = 0; i < 3; ++i) { + std::wcout << bounds.min(i) << std::endl; } + for (int i = 0; i < 3; ++i) { + std::wcout << bounds.max(i) << std::endl; + } + std::wcout << "---" << std::endl; } - auto bb = CGAL::Polygon_mesh_processing::bbox(s); - std::wcout << "elem "; - for (int i = 0; i < 3; ++i) { - std::wcout << bb.min(i) << " "; - } - std::wcout << "- "; - for (int i = 0; i < 3; ++i) { - std::wcout << bb.max(i) << " "; - } - std::wcout << std::endl; - CGAL::Nef_polyhedron_3 part_nef = ifcopenshell::geometry::utils::create_nef_polyhedron(s); if (!part_nef.is_simple()) { @@ -158,53 +162,26 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b continue; } - std::wcout << "volume " << CGAL::to_double(CGAL::Polygon_mesh_processing::volume(s)) << std::endl; - - - { - auto poly = ifcopenshell::geometry::utils::create_polyhedron(part_nef); - std::wcout << " part faces " << faces(poly).size() << " volume " << CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)) << std::endl; - } - - std::vector intersection_volumes; - - std::transform(nefs.begin(), nefs.end(), std::back_inserter(intersection_volumes), [&part_nef](const CGAL::Nef_polyhedron_3& storey_nef) { - { - auto poly = ifcopenshell::geometry::utils::create_polyhedron(storey_nef); - std::wcout << " storey faces " << faces(poly).size() << " volume " << CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)) << std::endl; - } - { - auto poly = ifcopenshell::geometry::utils::create_polyhedron(part_nef); - std::wcout << " part faces " << faces(poly).size() << " volume " << CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)) << std::endl; - } - { - auto poly = ifcopenshell::geometry::utils::create_polyhedron(part_nef + storey_nef); - std::wcout << " faces " << faces(poly).size() << " volume " << CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)) << std::endl; - } - { - auto poly = ifcopenshell::geometry::utils::create_polyhedron(part_nef - storey_nef); - std::wcout << " faces " << faces(poly).size() << " volume " << CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)) << std::endl; - } - { - auto poly = ifcopenshell::geometry::utils::create_polyhedron(part_nef * storey_nef); - std::wcout << " faces " << faces(poly).size(); - return CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)); - } + std::vector::iterator accumulator; + std::for_each(nefs.begin(), nefs.end(), [&accumulator, &part_nef](const CGAL::Nef_polyhedron_3& storey_nef) { + auto poly = ifcopenshell::geometry::utils::create_polyhedron(part_nef * storey_nef); + CGAL::Polygon_mesh_processing::triangulate_faces(poly); + accumulator++ += CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)); }); + } - std::wcout << "volumes: "; - for (auto& v : intersection_volumes) { - std::wcout << v << " "; - } - std::wcout << std::endl; + std::wcout << "volumes: "; + for (auto& v : intersection_volumes) { + std::wcout << v << " "; + } + std::wcout << std::endl; - auto idx = std::max_element(intersection_volumes.begin(), intersection_volumes.end()) - intersection_volumes.begin(); - if (storeys_sorted[idx] != elem_to_storey[geom_object->product()]) { - auto s = geom_object->product()->data().toString(); - auto s1 = storeys_sorted[idx]->data().toString(); - auto s2 = elem_to_storey[geom_object->product()]->data().toString(); - std::wcout << "Mismatch on " << s.c_str() << ": " << s1.c_str() << " vs " << s2.c_str() << std::endl; - } + auto idx = std::max_element(intersection_volumes.begin(), intersection_volumes.end()) - intersection_volumes.begin(); + if (storeys_sorted[idx] != elem_to_storey[geom_object->product()]) { + auto s = geom_object->product()->data().toString(); + auto s1 = storeys_sorted[idx]->data().toString(); + auto s2 = elem_to_storey[geom_object->product()]->data().toString(); + std::wcout << "Mismatch on " << s.c_str() << ": " << s1.c_str() << " vs " << s2.c_str() << std::endl; } if (!no_progress) { From 060c35939a96b063918dcad4cdc0c9159373826e Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 26 Jan 2020 13:12:19 +0100 Subject: [PATCH 199/235] Wall connectivity --- src/ifcconvert/IfcConvert.cpp | 7 +- src/ifcconvert/validate_space_boundaries.cpp | 1028 +---------------- .../validate_storey_containment.cpp | 4 - src/ifcconvert/validate_wall_connectivity.cpp | 77 ++ src/ifcconvert/validation_utils.cpp | 28 + src/ifcconvert/validation_utils.h | 549 +++++++++ 6 files changed, 664 insertions(+), 1029 deletions(-) create mode 100644 src/ifcconvert/validation_utils.cpp create mode 100644 src/ifcconvert/validation_utils.h diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index fb48bd2874..f320165e5a 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -145,6 +145,7 @@ void write_log(bool); void fix_quantities(IfcParse::IfcFile&, bool, bool, bool); void fix_spaceboundaries(IfcParse::IfcFile&, bool, bool, bool); void fix_storeycontainment(IfcParse::IfcFile&, bool, bool, bool); +void fix_wallconnectivity(IfcParse::IfcFile&, bool, bool, bool); std::string format_duration(time_t start, time_t end); @@ -226,7 +227,8 @@ int main(int argc, char** argv) { "based on an interpretation of the geometry when exporting IFC") ("fix-space-boundaries", "Calculate or fix space boundary geometries " "when exporting IFC") - ("fix-storey-containment", "Calculate or containment in building storeys"); + ("fix-storey-containment", "Calculate or fix containment in building storeys") + ("fix-wall-connectivity", "Calculate or fix wall connectivity relationships"); int num_threads; @@ -590,6 +592,9 @@ int main(int argc, char** argv) { if (vmap.count("fix-storey-containment")) { fix_storeycontainment(*ifc_file, no_progress, quiet, stderr_progress); } + if (vmap.count("fix-wall-connectivity")) { + fix_wallconnectivity(*ifc_file, no_progress, quiet, stderr_progress); + } fs << *ifc_file; exit_code = EXIT_SUCCESS; } else { diff --git a/src/ifcconvert/validate_space_boundaries.cpp b/src/ifcconvert/validate_space_boundaries.cpp index f7fecb461d..e0322badfd 100644 --- a/src/ifcconvert/validate_space_boundaries.cpp +++ b/src/ifcconvert/validate_space_boundaries.cpp @@ -1,831 +1,9 @@ -#include "../ifcgeom/kernels/cgal/CgalKernel.h" -#include "../ifcgeom/schema_agnostic/IfcGeomFilter.h" -#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h" - -#include -#include - -#include -#include -#include -#include -#include -namespace SMS = CGAL::Surface_mesh_simplification; - -#include -#include - -template -T enlarge(const T& t, double d = 1.e-5) { - T::NT min[3]; - T::NT max[3]; - for (int i = 0; i < t.dimension(); ++i) { - min[i] = t.min_coord(i) - d; - max[i] = t.max_coord(i) + d; - } - return T(min, max, t.handle()); - // return T(min, max); -} - -int convert_to_nef(cgal_shape_t& shape, CGAL::Nef_polyhedron_3& result) { - if (!shape.is_valid()) { - return 1; - } - - if (!shape.is_closed()) { - return 2; - } - - bool success = false; - - try { - success = CGAL::Polygon_mesh_processing::triangulate_faces(shape); - } catch (...) { - return 3; - } - - if (!success) { - return 4; - } - - if (CGAL::Polygon_mesh_processing::does_self_intersect(shape)) { - return 5; - } - - try { - result = CGAL::Nef_polyhedron_3(shape); - } catch (...) { - return 6; - } - - return 0; -} - -namespace { - // Can be used to convert polyhedron from exact to inexact and vice-versa - template - struct Copy_polyhedron_to - : public CGAL::Modifier_base { - Copy_polyhedron_to(const Polyhedron_input& in_poly) - : in_poly(in_poly) {} - - void operator()(typename Polyhedron_output::HalfedgeDS& out_hds) { - typedef typename Polyhedron_output::HalfedgeDS Output_HDS; - typedef typename Polyhedron_input::HalfedgeDS Input_HDS; - - CGAL::Polyhedron_incremental_builder_3 builder(out_hds); - - typedef typename Polyhedron_input::Vertex_const_iterator Vertex_const_iterator; - typedef typename Polyhedron_input::Facet_const_iterator Facet_const_iterator; - typedef typename Polyhedron_input::Halfedge_around_facet_const_circulator HFCC; - - builder.begin_surface(in_poly.size_of_vertices(), - in_poly.size_of_facets(), - in_poly.size_of_halfedges()); - - for (Vertex_const_iterator - vi = in_poly.vertices_begin(), end = in_poly.vertices_end(); - vi != end; ++vi) { - typename Polyhedron_output::Point_3 p(::CGAL::to_double(vi->point().x()), - ::CGAL::to_double(vi->point().y()), - ::CGAL::to_double(vi->point().z())); - builder.add_vertex(p); - } - - typedef CGAL::Inverse_index Index; - Index index(in_poly.vertices_begin(), in_poly.vertices_end()); - - for (Facet_const_iterator - fi = in_poly.facets_begin(), end = in_poly.facets_end(); - fi != end; ++fi) { - HFCC hc = fi->facet_begin(); - HFCC hc_end = hc; - builder.begin_facet(); - do { - builder.add_vertex_to_facet(index[hc->vertex()]); - ++hc; - } while (hc != hc_end); - builder.end_facet(); - } - builder.end_surface(); - } // end operator()(..) - private: - const Polyhedron_input& in_poly; - }; // end Copy_polyhedron_to<> - - template - void poly_copy(Poly_B& poly_b, const Poly_A& poly_a) { - poly_b.clear(); - Copy_polyhedron_to modifier(poly_a); - poly_b.delegate(modifier); - } - -} - -namespace { - // The following is a Visitor that keeps track of the simplification process. -// In this example the progress is printed real-time and a few statistics are -// recorded (and printed in the end). -// - struct Stats { - Stats() - : collected(0) - , processed(0) - , collapsed(0) - , non_collapsable(0) - , cost_uncomputable(0) - , placement_uncomputable(0) {} - - std::size_t collected; - std::size_t processed; - std::size_t collapsed; - std::size_t non_collapsable; - std::size_t cost_uncomputable; - std::size_t placement_uncomputable; - }; - struct My_visitor : SMS::Edge_collapse_visitor_base>> { - My_visitor(Stats* s) : stats(s) {} - // Called during the collecting phase for each edge collected. - void OnCollected(Profile const&, boost::optional const&) { - ++stats->collected; - std::wcerr << "\rEdges collected: " << stats->collected << std::flush; - } - - // Called during the processing phase for each edge selected. - // If cost is absent the edge won't be collapsed. - void OnSelected(Profile const& - , boost::optional cost - , std::size_t initial - , std::size_t current - ) { - ++stats->processed; - if (!cost) - ++stats->cost_uncomputable; - - if (current == initial) - std::wcerr << "\n" << std::flush; - std::wcerr << "\r" << current << std::flush; - } - - // Called during the processing phase for each edge being collapsed. - // If placement is absent the edge is left uncollapsed. - void OnCollapsing(Profile const& - , boost::optional placement - ) { - if (!placement) - ++stats->placement_uncomputable; - } - - // Called for each edge which failed the so called link-condition, - // that is, which cannot be collapsed because doing so would - // turn the surface mesh into a non-manifold. - void OnNonCollapsable(Profile const&) { - ++stats->non_collapsable; - } - - // Called after each edge has been collapsed - void OnCollapsed(Profile const&, vertex_descriptor) { - ++stats->collapsed; - } - - Stats* stats; - }; - -} - -namespace { - template - T approx_normalized(const T& t) { - return t * (1. / Kernel_::FT(CGAL::sqrt(CGAL::to_double(t.squared_length())))); - } -} - -#include -#include -#include -#include - -namespace { - template - struct Build_Offset : public CGAL::Modifier_base { - std::list input; - - void operator()(HDS& hds) { - // Postcondition: hds is a valid polyhedral surface. - CGAL::Polyhedron_incremental_builder_3 B(hds); - - int Nv = 0, Nf = 0; - for (auto& f : input) { - Nv += 3; - Nf += 1; - } - - B.begin_surface(Nv, Nf); - - for (auto& f : input) { - auto p0 = f->facet_begin()->vertex()->point(); - auto p1 = f->facet_begin()->next()->vertex()->point(); - auto p2 = f->facet_begin()->next()->next()->vertex()->point(); - - auto O = CGAL::centroid(p0, p1, p2); - - Kernel_::Point_3* p012[3] = { &p0, &p1, &p2 }; - for (int i = 0; i < 3; ++i) { - *p012[i] = CGAL::ORIGIN + (((*(p012[i])) - CGAL::ORIGIN) + ((*(p012[i])) - O)); - B.add_vertex(*p012[i]); - } - } - - Nv = 0; - for (int i = 0; i < Nf; ++i) { - B.begin_facet(); - B.add_vertex_to_facet(Nv++); - B.add_vertex_to_facet(Nv++); - B.add_vertex_to_facet(Nv++); - B.end_facet(); - } - - B.end_surface(); - } - }; - - template - std::list connected_faces(cgal_shape_t::Facet_handle& f, const Ts& excluded) { - std::set fs = { f }; - - std::function process; - process = [&fs, &process, &excluded](cgal_shape_t::Facet_handle& f) { - cgal_shape_t::Halfedge_around_facet_circulator circ = f->facet_begin(), end(circ); - do { - auto ff = circ->opposite()->facet(); - if (excluded.find(ff) == excluded.end()) { - auto p = fs.insert(ff); - if (p.second) { - process(ff); - } - } - } while (++circ != end); - }; - - process(f); - return std::list(fs.begin(), fs.end()); - } - - template - struct Builder_With_Map : public CGAL::Modifier_base { - std::list input; - std::map mapping; - - void operator()(HDS& hds) { - // Postcondition: hds is a valid polyhedral surface. - CGAL::Polyhedron_incremental_builder_3 B(hds); - - std::set used_points; - - for (auto& f : input) { - cgal_shape_t::Halfedge_around_facet_circulator circ = f->facet_begin(), end(circ); - do { - auto P = circ->vertex()->point(); - auto it = mapping.find(P); - if (it == mapping.end()) { - std::wcout << "WARNING unprojected point :(" << std::endl; - } else { - P = it->second; - } - used_points.insert(P); - } while (++circ != end); - } - - B.begin_surface(used_points.size(), input.size()); - - for (auto& p : used_points) { - B.add_vertex(p); - } - - for (auto& f : input) { - B.begin_facet(); - cgal_shape_t::Halfedge_around_facet_circulator circ = f->facet_begin(), end(circ); - do { - auto P = circ->vertex()->point(); - auto it = mapping.find(P); - if (it == mapping.end()) { - std::wcout << "WARNING unprojected point :(" << std::endl; - } else { - P = it->second; - } - - auto jt = used_points.find(P); - if (jt == used_points.end()) { - throw std::runtime_error("Unable to map point"); - } - size_t idx = std::distance(used_points.begin(), jt); - std::wcout << "idx " << idx << std::endl; - B.add_vertex_to_facet(idx); - } while (++circ != end); - - B.end_facet(); - } - - B.end_surface(); - } - }; -} - -namespace { - template - T edge_collapse(T polyhedron) { - typedef CGAL::Simple_cartesian simple; - CGAL::Polyhedron_3 simple_poly; - poly_copy(simple_poly, polyhedron); - - // flattening from a thin box to a plane is not valid in edge_collapse() - Stats stats; - My_visitor vis(&stats); - SMS::Edge_length_cost elc; - SMS::Edge_length_stop_predicate stop(1.e-3); - - int r = SMS::edge_collapse(simple_poly, stop, - CGAL::parameters::vertex_index_map(get(CGAL::vertex_external_index, simple_poly)) - .halfedge_index_map(get(CGAL::halfedge_external_index, simple_poly)) - .visitor(vis) - .get_cost(elc) - ); - - std::wcout << "Removed: " << r << std::endl; - - T result; - poly_copy(result, simple_poly); - return result; - } - - - double facet_area(const cgal_shape_t::Facet_handle& f) { - auto p0 = f->facet_begin()->vertex()->point(); - auto p1 = f->facet_begin()->next()->vertex()->point(); - auto p2 = f->facet_begin()->next()->next()->vertex()->point(); - return std::sqrt(CGAL::to_double(CGAL::cross_product(p0 - p1, p2 - p1).squared_length())); - } - - void dump_facet(const cgal_shape_t::Facet_handle& f) { - auto p0 = f->facet_begin()->vertex()->point(); - auto p1 = f->facet_begin()->next()->vertex()->point(); - auto p2 = f->facet_begin()->next()->next()->vertex()->point(); - auto V = CGAL::cross_product(p0 - p1, p2 - p1); - auto d = std::sqrt(CGAL::to_double(V.squared_length())); - if (d > 1.e-20) { - V /= d; - } - - std::ostringstream oss; - oss.precision(8); - oss << "Facet with area " << facet_area(f) << " and normal (" - << CGAL::to_double(V.cartesian(0)) << " " << CGAL::to_double(V.cartesian(1)) << " " - << CGAL::to_double(V.cartesian(2)) << ")"; - - auto osss = oss.str(); - std::wcout << osss.c_str() << std::endl; - } - - struct remove_thickness { - typedef Kernel_::Point_3 Point; - typedef Kernel_::Plane_3 Plane; - typedef Kernel_::Vector_3 Vector; - typedef Kernel_::Segment_3 Segment; - typedef Kernel_::Ray_3 Ray; - - typedef CGAL::Polyhedron_3 Polyhedron; - typedef CGAL::AABB_face_graph_triangle_primitive Primitive; - typedef CGAL::AABB_traits Traits; - typedef CGAL::AABB_tree Tree; - typedef boost::optional::Type> Ray_intersection; - - cgal_shape_t polyhedron, polyhedron2, flattened; - - remove_thickness(const cgal_shape_t& p) - // edge_collapse(p) still does not work :( - : polyhedron(p) - , polyhedron2(p) { - CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron); - CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron2); - - std::list non_degenerate, degenerate, longitudonal; - std::set thin_sides; - - std::wcout << "ALL FACES:" << std::endl; - - for (auto& f : faces(polyhedron)) { - dump_facet(f); - if (facet_area(f) > 1.e-20) { - non_degenerate.push_back(f); - } else { - degenerate.push_front(f); - std::wcout << "Degenerate, area: " << facet_area(f) << std::endl; - } - } - - std::wcout << "NON DEGENERATE:" << std::endl; - for (auto& f : non_degenerate) { - dump_facet(f); - } - - cgal_shape_t enlarged_non_degenerate_triangles; - Build_Offset bo; - bo.input = non_degenerate; - enlarged_non_degenerate_triangles.delegate(bo); - - // @todo, first on non-enlarged faces, then on enlarged; to fix projection on concave surfaces where the enlarging operation shortens projection distances. - - Tree tree(faces(enlarged_non_degenerate_triangles).first, faces(enlarged_non_degenerate_triangles).second, enlarged_non_degenerate_triangles); - - std::map face_normals; - boost::associative_property_map> face_normals_map(face_normals); - CGAL::Polygon_mesh_processing::compute_face_normals(polyhedron, face_normals_map); - - for (auto& f : non_degenerate) { - auto O = CGAL::centroid( - f->facet_begin()->vertex()->point(), - f->facet_begin()->next()->vertex()->point(), - f->facet_begin()->next()->next()->vertex()->point() - ); - - Ray ray(O, -face_normals_map[f]); - - std::list intersections; - tree.all_intersections(ray, std::back_inserter(intersections)); - double N = std::numeric_limits::infinity(); - Point P; - for (auto& intersection : intersections) { - if (boost::get(&(intersection->first))) { - const Point* p = boost::get(&(intersection->first)); - const double d = std::sqrt(CGAL::to_double((*p - O).squared_length())); - if (d > 1.e-20 && d < N) { - N = d; - } - } - } - if (N != std::numeric_limits::infinity() && N > 1.e-4) { - thin_sides.insert(f); - } - - /* - Ray_intersection intersection = tree.first_intersection(ray, [f](const cgal_shape_t::Facet_handle& p) { - return p == f; - }); - if (intersection) { - if (boost::get(&(intersection->first))) { - const Point* p = boost::get(&(intersection->first)); - const double d = std::sqrt(CGAL::to_double((*p - O).squared_length())); - if (d > 1.e-4) { - thin_sides.insert(f); - } - } - } else { - std::wcout << "No intersection :((!!!" << std::endl; - } - */ - } - - std::wcout << "THIN SIDES:" << std::endl; - for (auto& f : thin_sides) { - dump_facet(f); - } - - for (auto& f : non_degenerate) { - if (thin_sides.find(f) == thin_sides.end()) { - longitudonal.push_back(f); - } - } - - std::wcout << "LONGITUDONAL:" << std::endl; - for (auto& f : longitudonal) { - dump_facet(f); - } - - std::wcout << "faces " << faces(polyhedron).size() << "long " << longitudonal.size() << "thin " << thin_sides.size() << "non-degen " << non_degenerate.size() << std::endl; - - cgal_shape_t enlarged_indiv_triangles; - Build_Offset bo2; - bo2.input = longitudonal; - enlarged_indiv_triangles.delegate(bo2); - - { - std::ofstream ofs("enlarged.off"); - ofs.precision(17); - ofs << enlarged_indiv_triangles; - } - - Tree tree2(faces(enlarged_indiv_triangles).begin(), faces(enlarged_indiv_triangles).end(), enlarged_indiv_triangles); - - // std::map face_normals_2; - // boost::associative_property_map> face_normals_map_2(face_normals_2); - // CGAL::Polygon_mesh_processing::compute_face_normals(polyhedron, face_normals_map_2); - - // below does not seem to work? Do manually? - // std::map vertex_normals; - // boost::associative_property_map> vertex_normals_map(vertex_normals); - // CGAL::Polygon_mesh_processing::compute_normals(polyhedron, vertex_normals_map, face_normals_map_2); - - std::map new_points; - - for (Polyhedron::Facet_iterator fit = polyhedron.facets_begin(); - fit != polyhedron.facets_end(); - ++fit) { - if (CGAL::collinear( - fit->halfedge()->vertex()->point(), - fit->halfedge()->next()->vertex()->point(), - fit->halfedge()->opposite()->vertex()->point())) { - std::wcout << "degenerate triangle" << std::endl; - } - } - - /* - std::list vertices; - for (auto& f : non_degenerate) { - CGAL::Face_around_target_circulator it(f->halfedge(), polyhedron), end(it); - do { - vertices.push_back((*it)->halfedge()->vertex()); - ++it; - } while (it != end); - }*/ - - - for (auto& v : vertices(polyhedron)) { - auto O = v->point(); - - Kernel_::Vector_3 norm; - Kernel_::Vector_3 accum; - int count = 0; - CGAL::Face_around_target_circulator it(v->halfedge(), polyhedron), end(it); - do { - cgal_shape_t::Facet_handle fh = (*it)->halfedge()->facet(); - - auto jt = std::find(non_degenerate.begin(), non_degenerate.end(), fh); - std::wcout << "non degen: " << (jt != non_degenerate.end()) << std::endl; - auto kt = std::find(thin_sides.begin(), thin_sides.end(), fh); - std::wcout << "thin side: " << (kt != thin_sides.end()) << std::endl; - if (jt != non_degenerate.end() && kt == thin_sides.end()) { - // else degenerate, prevent div by zero, do not incorporate in vnorm. - // or else part of thin side - - auto p0 = (*it)->facet_begin()->vertex()->point(); - auto p1 = (*it)->facet_begin()->next()->vertex()->point(); - auto p2 = (*it)->facet_begin()->next()->next()->vertex()->point(); - - { - std::ostringstream oss; - oss.precision(8); - oss << "p0 " << p0.cartesian(0) << " " << p0.cartesian(1) << " " << p0.cartesian(2) << "\n"; - oss << "p1 " << p1.cartesian(0) << " " << p1.cartesian(1) << " " << p1.cartesian(2) << "\n"; - oss << "p2 " << p2.cartesian(0) << " " << p2.cartesian(1) << " " << p2.cartesian(2) << "\n"; - auto osss = oss.str(); - std::wcout << osss.c_str() << std::endl; - } - - auto fnorm = CGAL::cross_product(p0 - p1, p2 - p1); - fnorm /= std::sqrt(CGAL::to_double(fnorm.squared_length())); - - // const auto& fnorm = face_normals_map_2[*it]; - std::ostringstream oss; - oss.precision(8); - oss << fnorm.cartesian(0) << " " << fnorm.cartesian(1) << " " << fnorm.cartesian(2); - auto osss = oss.str(); - std::wcout << osss.c_str() << std::endl; - accum += fnorm; - - ++count; - } - - ++it; - } while (it != end); - - norm = accum / count; - std::wcout << "count " << count << std::endl; - - if (count == 0) { - // part of only degenerate or only thin sides - continue; - } - - // v->vertex_begin(); - Ray ray(O, norm); - std::ostringstream oss; - oss.precision(8); - oss << O << " -> " << norm; - auto osss = oss.str(); - std::wcout << osss.c_str() << std::endl; - - //// skip does not work anymore because we have offset the facets - // auto skip = [this, &v](const cgal_shape_t::Facet_handle& p) { - // CGAL::Face_around_target_circulator it(v->halfedge(), polyhedron), end(it); - // do { - // if ((*it)->facet_begin()->facet() == p) { - // return true; - // } - // } while (++it != end); - // return false; - // }; - - std::list intersections; - tree2.all_intersections(ray, std::back_inserter(intersections)); - double N = std::numeric_limits::infinity(); - Point P; - - bool used_intersection = false; - - if (intersections.size()) { - for (auto& intersection : intersections) { - if (boost::get(&(intersection->first))) { - const Point* p = boost::get(&(intersection->first)); - const double d = std::sqrt(CGAL::to_double((*p - O).squared_length())); - if (d < N && d > 1.e-20) { - N = d; - P = *p; - std::wcout << "intersection @ " << d << std::endl; - } - } - } - std::wcout << "-----------" << std::endl; - - // average the new point - new_points[O] = CGAL::ORIGIN + (((O - CGAL::ORIGIN) + (P - CGAL::ORIGIN))) / 2; - used_intersection = true; - } - - if (!used_intersection) { - std::wcout << "no intersection :(" << std::endl; - } - } - - /* - for (auto& fi : thin_sides) { - auto f_circ = fi->facet_begin(); - polyhedron2.erase_facet(f_circ); - } - */ - - auto thin_sides_degenerate = thin_sides; - thin_sides_degenerate.insert(degenerate.begin(), degenerate.end()); - - // @todo choose connected / connected_opposing based on largest combined area of facets? - - auto connected = connected_faces(*longitudonal.begin(), thin_sides_degenerate); - decltype(connected) connected_opposing; - - for (auto& f : longitudonal) { - if (std::find(connected.begin(), connected.end(), f) == connected.end()) { - connected_opposing = connected_faces(f, thin_sides_degenerate); - - std::set longi(longitudonal.begin(), longitudonal.end()); - std::set both_sides(connected.begin(), connected.end()); - both_sides.insert(connected_opposing.begin(), connected_opposing.end()); - - if (longi == both_sides) { - std::wcout << "Facet connection functioning properly" << std::endl; - } else { - std::wcout << "Facet connection functioning incorrectly" << std::endl; - } - - break; - } - } - - Builder_With_Map b2; - b2.input = connected; - b2.mapping = new_points; - - flattened.delegate(b2); - } - }; -} +#include "validation_utils.h" void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) { - typedef std::list> > nefs_t; - typedef CGAL::Box_intersection_d::Box_with_handle_d Box; - // typedef CGAL::Box_intersection_d::Box_d Box; - // std::map id_map; - - ifcopenshell::geometry::settings settings; - settings.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, false); - settings.set(ifcopenshell::geometry::settings::WELD_VERTICES, false); - settings.set(ifcopenshell::geometry::settings::SEW_SHELLS, true); - settings.set(ifcopenshell::geometry::settings::CONVERT_BACK_UNITS, true); - settings.set(ifcopenshell::geometry::settings::DISABLE_TRIANGULATION, true); - settings.set(ifcopenshell::geometry::settings::DISABLE_OPENING_SUBTRACTIONS, true); - - std::vector spaces_and_walls = { - IfcGeom::entity_filter(true, false, {"IfcWall", "IfcSpace"}) - }; - - ifcopenshell::geometry::Iterator context_iterator("cgal", settings, &f, spaces_and_walls); - - if (!context_iterator.initialize()) { - return; - } - - auto kernel = (ifcopenshell::geometry::kernels::CgalKernel*) context_iterator.converter().kernel(); - auto cube = kernel->precision_cube(); - - size_t num_created = 0; - int old_progress = quiet ? 0 : -1; - - std::vector boxes; - nefs_t nefs; - - for (;; ++num_created) { - bool has_more = true; - if (num_created) { - has_more = context_iterator.next(); - } - ifcopenshell::geometry::NativeElement* geom_object = nullptr; - if (has_more) { - geom_object = context_iterator.get_native(); - } - if (!geom_object) { - break; - } - - std::stringstream ss; - ss << geom_object->product()->data().toString(); - auto sss = ss.str(); - std::wcout << sss.c_str() << std::endl; - - for (auto& g : geom_object->geometry()) { - auto s = ((ifcopenshell::geometry::CgalShape*) g.Shape())->shape(); - const auto& m = g.Placement().components; - const auto& n = geom_object->transformation().data().components; - - const cgal_placement_t trsf( - m(0, 0), m(0, 1), m(0, 2), m(0, 3), - m(1, 0), m(1, 1), m(1, 2), m(1, 3), - m(2, 0), m(2, 1), m(2, 2), m(2, 3)); - - const cgal_placement_t trsf2( - n(0, 0), n(0, 1), n(0, 2), n(0, 3), - n(1, 0), n(1, 1), n(1, 2), n(1, 3), - n(2, 0), n(2, 1), n(2, 2), n(2, 3)); - - // Apply transformation - for (auto &vertex : vertices(s)) { - vertex->point() = vertex->point().transform(trsf).transform(trsf2); - std::ostringstream ss; - ss << vertex->point().cartesian(0); - auto sss = ss.str(); - std::wcout << sss.c_str() << std::endl; - } - - CGAL::Nef_polyhedron_3 nef; - auto c = convert_to_nef(s, nef); - if (c != 0) { - std::wcout << "Error " << c << std::endl; - continue; - } - nef = CGAL::minkowski_sum_3(nef, cube); - std::wcout << "product: " << geom_object->product() << std::endl; - nefs.push_back({ geom_object->product(), nef }); - - Box b(&*(nefs.rbegin())); - // id_map[b.id()] = ; - - for (auto &vertex : vertices(s)) { - double p[3] = { - CGAL::to_double(vertex->point().cartesian(0)), - CGAL::to_double(vertex->point().cartesian(1)), - CGAL::to_double(vertex->point().cartesian(2)) - }; - b.extend(p); - } - - boxes.push_back(enlarge(b)); - - /* - std::ostringstream ss; - ss << geom_object->product()->data().toString() << std::endl << b.min_coord(0) << " - " << b.max_coord(0) << std::endl; - auto sss = ss.str(); - std::wcout << sss.c_str(); - */ - } - - if (!no_progress) { - if (quiet) { - const int progress = context_iterator.progress(); - for (; old_progress < progress; ++old_progress) { - std::cout << "."; - if (stderr_progress) - std::cerr << "."; - } - std::cout << std::flush; - if (stderr_progress) - std::cerr << std::flush; - } else { - const int progress = context_iterator.progress() / 2; - if (old_progress != progress) Logger::ProgressBar(progress); - old_progress = progress; - } - } - } - - CGAL::box_self_intersection_d(boxes.begin(), boxes.end(), [](const Box& a, const Box& b) { + intersection_validator v(f, { "IfcWall", "IfcSpace" }, no_progress, quiet, stderr_progress); + + v([](const intersection_validator::Box& a, const intersection_validator::Box& b) { std::ostringstream ss; // ss << id_map[a.id()]->first->data().toString() << "x" << id_map[b.id()]->first->data().toString() << std::endl; // auto x = id_map[a.id()]->second * id_map[b.id()]->second; @@ -877,203 +55,5 @@ void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, boo os.precision(17); os << r.flattened; } - // r(); - - /* - std::map collapsed; - std::map collapsed_v; - - for (auto it = x_poly.edges_begin(); it != x_poly.edges_end(); ++it) { - auto& e = *it; - cgal_shape_t::Vertex_iterator v0 = e.vertex(); - cgal_shape_t::Vertex_iterator v1 = e.prev()->vertex(); - auto p0 = v0->point(); - auto p1 = v1->point(); - auto l = std::sqrt(CGAL::to_double((p1 - p0).squared_length())); - std::wcout << "edge w/ length " << l << std::endl; - - cgal_shape_t::Plane_3 plane(it->vertex()->point(), - it->next()->vertex()->point(), - it->next()->next()->vertex()->point()); - - auto d0 = plane.to_2d(e.prev()->vertex()->point()) - plane.to_2d(e.prev()->prev()->vertex()->point()); - auto d1 = plane.to_2d(e.vertex()->point()) - plane.to_2d(e.prev()->vertex()->point()); - auto d2 = plane.to_2d(e.next()->vertex()->point()) - plane.to_2d(e.vertex()->point()); - auto a0 = std::atan2(CGAL::to_double(d0.cartesian(1)), CGAL::to_double(d0.cartesian(0))); - auto a1 = std::atan2(CGAL::to_double(d1.cartesian(1)), CGAL::to_double(d1.cartesian(0))); - auto a2 = std::atan2(CGAL::to_double(d2.cartesian(1)), CGAL::to_double(d2.cartesian(0))); - auto a10 = a1 - a0; - auto a21 = a2 - a1; - if (a10 < 0.) { - a10 += 2 * M_PI; - } - if (a21 < 0.) { - a21 += 2 * M_PI; - } - - const bool is_convex = a10 < M_PI && a21 < M_PI; - - cgal_shape_t::Plane_3 opposite_plane(it->opposite()->vertex()->point(), - it->opposite()->next()->vertex()->point(), - it->opposite()->next()->next()->vertex()->point() - ); - - { - std::ostringstream oss; - oss << plane << " vs " << opposite_plane << "\n"; - oss << plane.orthogonal_vector() << " vs " << opposite_plane.orthogonal_vector(); - auto osss = oss.str(); - std::wcout << osss.c_str() << std::endl; - } - - bool is_internal = false; - if (std::sqrt(CGAL::to_double(plane.orthogonal_vector().squared_length())) < 1.e-15 || - std::sqrt(CGAL::to_double(opposite_plane.orthogonal_vector().squared_length())) < 1.e-15 - ) { - is_internal = true; - std::wcout << "Degenerate" << std::endl; - } else { - const double face_normal_dot = CGAL::to_double(approx_normalized(plane.orthogonal_vector()) * approx_normalized(opposite_plane.orthogonal_vector())); - std::wcout << "Face normal dot " << face_normal_dot << std::endl; - is_internal = face_normal_dot > 0.9; - } - - std::wcout << "Angles " << a0 << " " << a1 << " " << a2 << std::endl; - - if (l < 4.e-5 && (is_convex || is_internal)) { - auto p2 = CGAL::ORIGIN + ((p0 - CGAL::ORIGIN) + (p1 - CGAL::ORIGIN)) / 2; - - std::wcout << "(a) " << CGAL::to_double(p0.cartesian(0)) << " " << CGAL::to_double(p0.cartesian(1)) << " " << CGAL::to_double(p0.cartesian(2)) << "\n"; - std::wcout << "(b) " << CGAL::to_double(p1.cartesian(0)) << " " << CGAL::to_double(p1.cartesian(1)) << " " << CGAL::to_double(p1.cartesian(2)) << "\n"; - std::wcout << "(c) " << CGAL::to_double(p2.cartesian(0)) << " " << CGAL::to_double(p2.cartesian(1)) << " " << CGAL::to_double(p2.cartesian(2)) << "\n"; - // collapsed.insert({ v0, p2 }); - // collapsed.insert({ v1, p2 }); - collapsed.insert({ it, p2 }); - // Edges includes only half of the halfedges - collapsed.insert({ it->opposite(), p2 }); - - collapsed_v.insert({ v0, p2 }); - collapsed_v.insert({ v1, p2 }); - } - } - - { - auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "sb.obj"; - std::ofstream ofs(FN.c_str()); - ofs.precision(17); - - int N = 1; - - std::set > faces_emitted; - for (auto& f : faces(x_poly)) { - std::ostringstream oss; - auto start = f->facet_begin(); - - bool part_collapsed = false; - - CGAL::Polyhedron_3::Halfedge_around_facet_const_circulator e = f->facet_begin(); - do { - auto it = collapsed.find(e); - if (it != collapsed.end()) { - part_collapsed = true; - break; - } - ++e; - } while (e != f->facet_begin()); - - decltype(faces_emitted)::key_type vss; - std::list points; - - if (!part_collapsed) { - e = f->facet_begin(); - do { - cgal_shape_t::Vertex_const_handle v = e->vertex(); - auto it = collapsed_v.find(v); - if (it == collapsed_v.end()) { - std::wcout << "Unexpected " - << CGAL::to_double(v->point().cartesian(0)) << " " - << CGAL::to_double(v->point().cartesian(1)) << " " - << CGAL::to_double(v->point().cartesian(2)) << std::endl; - } else { - points.push_back(it->second); - vss.insert(it->second); - } - ++e; - } while (e != f->facet_begin()); - - if (faces_emitted.find(vss) != faces_emitted.end()) { - std::wcout << "Emitted" << std::endl; - } else { - faces_emitted.insert(vss); - - for (auto& p : points) { - ofs << "v " << CGAL::to_double(p.cartesian(0)) << " " << CGAL::to_double(p.cartesian(1)) << " " << CGAL::to_double(p.cartesian(2)) << "\n"; - } - - ofs << "f "; - for (auto i = 0; i < points.size(); ++i) { - if (i) { - ofs << " "; - } - ofs << i + N; - } - ofs << "\n"; - - N += points.size(); - } - } - } - } - - */ - - /* - // edge collapse does not work on the rational number types - typedef CGAL::Simple_cartesian simple; - CGAL::Polyhedron_3 x_simple; - poly_copy(x_simple, x_poly); - - // flattening from a thin box to a plane is not valid in edge_collapse() - Stats stats; - My_visitor vis(&stats); - SMS::Edge_length_cost elc; - SMS::Edge_length_stop_predicate stop(1.e-3); - - int r = SMS::edge_collapse(x_simple, stop, - CGAL::parameters::vertex_index_map(get(CGAL::vertex_external_index, x_simple)) - .halfedge_index_map(get(CGAL::halfedge_external_index, x_simple)) - .visitor(vis) - .get_cost(elc) - ); - - std::wcout << "Removed: " << r << std::endl; - */ - - /* - for (auto& v : vertices(x_poly)) { - auto p = v->point(); - for (int i = 0; i < 3; ++i) { - ss << p.cartesian(i) << " "; - } - ss << std::endl; - } - ss << "---" << std::endl; - auto sss = ss.str(); - std::wcout << sss.c_str(); - */ }); - - if (!no_progress && quiet) { - for (; old_progress < 100; ++old_progress) { - std::cout << "."; - if (stderr_progress) - std::cerr << "."; - } - std::cout << std::flush; - if (stderr_progress) - std::cerr << std::flush; - } else { - Logger::Status("\rDone fixing space boundaries for " + boost::lexical_cast(num_created) + - " objects "); - } } diff --git a/src/ifcconvert/validate_storey_containment.cpp b/src/ifcconvert/validate_storey_containment.cpp index 1fdb6d906f..53bbe95914 100644 --- a/src/ifcconvert/validate_storey_containment.cpp +++ b/src/ifcconvert/validate_storey_containment.cpp @@ -7,10 +7,6 @@ #include -class containment_validator { - -}; - void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) { ifcopenshell::geometry::settings settings; settings.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, false); diff --git a/src/ifcconvert/validate_wall_connectivity.cpp b/src/ifcconvert/validate_wall_connectivity.cpp index e69de29bb2..fbfb9aca66 100644 --- a/src/ifcconvert/validate_wall_connectivity.cpp +++ b/src/ifcconvert/validate_wall_connectivity.cpp @@ -0,0 +1,77 @@ +#include "validation_utils.h" + +void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) { + intersection_validator v(f, { "IfcWall" }, no_progress, quiet, stderr_progress); + + + ifcopenshell::geometry::settings settings; + settings.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, false); + settings.set(ifcopenshell::geometry::settings::WELD_VERTICES, false); + settings.set(ifcopenshell::geometry::settings::SEW_SHELLS, true); + settings.set(ifcopenshell::geometry::settings::CONVERT_BACK_UNITS, true); + settings.set(ifcopenshell::geometry::settings::DISABLE_TRIANGULATION, true); + settings.set(ifcopenshell::geometry::settings::DISABLE_OPENING_SUBTRACTIONS, true); + + settings.set(ifcopenshell::geometry::settings::INCLUDE_CURVES, true); + settings.set(ifcopenshell::geometry::settings::EXCLUDE_SOLIDS_AND_SURFACES, true); + + ifcopenshell::geometry::Converter c("cgal", &f, settings); + + v([&c](const intersection_validator::Box& a, const intersection_validator::Box& b) { + std::ostringstream ss; + + ss << a.handle()->first->data().toString() << "x" << a.handle()->first->data().toString() << std::endl; + auto x = a.handle()->second * b.handle()->second; + if (x.is_empty()) { + return; + } + + c.convert(a.handle()->first); + + cgal_shape_t x_poly; + x.convert_to_polyhedron(x_poly); + + for (auto& v : vertices(x_poly)) { + // project onto axes + } + + CGAL::Polygon_mesh_processing::triangulate_faces(x_poly); + + auto s0 = a.handle()->first->declaration().name(); + auto s1 = b.handle()->first->declaration().name(); + auto i0 = a.handle()->first->data().id(); + auto i1 = b.handle()->first->data().id(); + + if (s0 < s1) { + std::swap(s1, s0); + std::swap(i0, i1); + } + + { + auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "sb.off"; + + std::ofstream os(FN.c_str()); + os.precision(17); + os << x_poly; + } + + remove_thickness r(x_poly); + + { + auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "-sides-sb.off"; + + std::ofstream os(FN.c_str()); + os.precision(17); + os << r.polyhedron2; + } + + { + auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "-flat-sb.off"; + + std::ofstream os(FN.c_str()); + os.precision(17); + os << r.flattened; + } + }); +} + diff --git a/src/ifcconvert/validation_utils.cpp b/src/ifcconvert/validation_utils.cpp new file mode 100644 index 0000000000..512f6163d6 --- /dev/null +++ b/src/ifcconvert/validation_utils.cpp @@ -0,0 +1,28 @@ +#include "validation_utils.h" + +double facet_area(const cgal_shape_t::Facet_handle& f) { + auto p0 = f->facet_begin()->vertex()->point(); + auto p1 = f->facet_begin()->next()->vertex()->point(); + auto p2 = f->facet_begin()->next()->next()->vertex()->point(); + return std::sqrt(CGAL::to_double(CGAL::cross_product(p0 - p1, p2 - p1).squared_length())); +} + +void dump_facet(const cgal_shape_t::Facet_handle& f) { + auto p0 = f->facet_begin()->vertex()->point(); + auto p1 = f->facet_begin()->next()->vertex()->point(); + auto p2 = f->facet_begin()->next()->next()->vertex()->point(); + auto V = CGAL::cross_product(p0 - p1, p2 - p1); + auto d = std::sqrt(CGAL::to_double(V.squared_length())); + if (d > 1.e-20) { + V /= d; + } + + std::ostringstream oss; + oss.precision(8); + oss << "Facet with area " << facet_area(f) << " and normal (" + << CGAL::to_double(V.cartesian(0)) << " " << CGAL::to_double(V.cartesian(1)) << " " + << CGAL::to_double(V.cartesian(2)) << ")"; + + auto osss = oss.str(); + std::wcout << osss.c_str() << std::endl; +} \ No newline at end of file diff --git a/src/ifcconvert/validation_utils.h b/src/ifcconvert/validation_utils.h new file mode 100644 index 0000000000..eca3406563 --- /dev/null +++ b/src/ifcconvert/validation_utils.h @@ -0,0 +1,549 @@ +#include "../ifcgeom/kernels/cgal/CgalKernel.h" +#include "../ifcgeom/schema_agnostic/IfcGeomFilter.h" +#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h" + +#include +#include + +#include +#include +#include +#include + +#include +#include + +template +T enlarge(const T& t, double d = 1.e-5) { + T::NT min[3]; + T::NT max[3]; + for (int i = 0; i < t.dimension(); ++i) { + min[i] = t.min_coord(i) - d; + max[i] = t.max_coord(i) + d; + } + return T(min, max, t.handle()); +} + +template +struct Build_Offset : public CGAL::Modifier_base { + std::list input; + + void operator()(HDS& hds) { + // Postcondition: hds is a valid polyhedral surface. + CGAL::Polyhedron_incremental_builder_3 B(hds); + + int Nv = 0, Nf = 0; + for (auto& f : input) { + Nv += 3; + Nf += 1; + } + + B.begin_surface(Nv, Nf); + + for (auto& f : input) { + auto p0 = f->facet_begin()->vertex()->point(); + auto p1 = f->facet_begin()->next()->vertex()->point(); + auto p2 = f->facet_begin()->next()->next()->vertex()->point(); + + auto O = CGAL::centroid(p0, p1, p2); + + Kernel_::Point_3* p012[3] = { &p0, &p1, &p2 }; + for (int i = 0; i < 3; ++i) { + *p012[i] = CGAL::ORIGIN + (((*(p012[i])) - CGAL::ORIGIN) + ((*(p012[i])) - O)); + B.add_vertex(*p012[i]); + } + } + + Nv = 0; + for (int i = 0; i < Nf; ++i) { + B.begin_facet(); + B.add_vertex_to_facet(Nv++); + B.add_vertex_to_facet(Nv++); + B.add_vertex_to_facet(Nv++); + B.end_facet(); + } + + B.end_surface(); + } +}; + +template +std::list connected_faces(cgal_shape_t::Facet_handle& f, const Ts& excluded) { + std::set fs = { f }; + + std::function process; + process = [&fs, &process, &excluded](cgal_shape_t::Facet_handle& f) { + cgal_shape_t::Halfedge_around_facet_circulator circ = f->facet_begin(), end(circ); + do { + auto ff = circ->opposite()->facet(); + if (excluded.find(ff) == excluded.end()) { + auto p = fs.insert(ff); + if (p.second) { + process(ff); + } + } + } while (++circ != end); + }; + + process(f); + return std::list(fs.begin(), fs.end()); +} + +template +struct Builder_With_Map : public CGAL::Modifier_base { + std::list input; + std::map mapping; + + void operator()(HDS& hds) { + // Postcondition: hds is a valid polyhedral surface. + CGAL::Polyhedron_incremental_builder_3 B(hds); + + std::set used_points; + + for (auto& f : input) { + cgal_shape_t::Halfedge_around_facet_circulator circ = f->facet_begin(), end(circ); + do { + auto P = circ->vertex()->point(); + auto it = mapping.find(P); + if (it == mapping.end()) { + std::wcout << "WARNING unprojected point :(" << std::endl; + } else { + P = it->second; + } + used_points.insert(P); + } while (++circ != end); + } + + B.begin_surface(used_points.size(), input.size()); + + for (auto& p : used_points) { + B.add_vertex(p); + } + + for (auto& f : input) { + B.begin_facet(); + cgal_shape_t::Halfedge_around_facet_circulator circ = f->facet_begin(), end(circ); + do { + auto P = circ->vertex()->point(); + auto it = mapping.find(P); + if (it == mapping.end()) { + std::wcout << "WARNING unprojected point :(" << std::endl; + } else { + P = it->second; + } + + auto jt = used_points.find(P); + if (jt == used_points.end()) { + throw std::runtime_error("Unable to map point"); + } + size_t idx = std::distance(used_points.begin(), jt); + std::wcout << "idx " << idx << std::endl; + B.add_vertex_to_facet(idx); + } while (++circ != end); + + B.end_facet(); + } + + B.end_surface(); + } +}; + +double facet_area(const cgal_shape_t::Facet_handle& f); + +void dump_facet(const cgal_shape_t::Facet_handle& f); + +struct remove_thickness { + typedef Kernel_::Point_3 Point; + typedef Kernel_::Plane_3 Plane; + typedef Kernel_::Vector_3 Vector; + typedef Kernel_::Segment_3 Segment; + typedef Kernel_::Ray_3 Ray; + + typedef CGAL::Polyhedron_3 Polyhedron; + typedef CGAL::AABB_face_graph_triangle_primitive Primitive; + typedef CGAL::AABB_traits Traits; + typedef CGAL::AABB_tree Tree; + typedef boost::optional::Type> Ray_intersection; + + cgal_shape_t polyhedron, polyhedron2, flattened; + + remove_thickness(const cgal_shape_t& p) + // edge_collapse(p) still does not work :( + : polyhedron(p) + , polyhedron2(p) { + CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron); + CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron2); + + std::list non_degenerate, degenerate, longitudonal; + std::set thin_sides; + + std::wcout << "ALL FACES:" << std::endl; + + for (auto& f : faces(polyhedron)) { + dump_facet(f); + if (facet_area(f) > 1.e-20) { + non_degenerate.push_back(f); + } else { + degenerate.push_front(f); + std::wcout << "Degenerate, area: " << facet_area(f) << std::endl; + } + } + + std::wcout << "NON DEGENERATE:" << std::endl; + for (auto& f : non_degenerate) { + dump_facet(f); + } + + cgal_shape_t enlarged_non_degenerate_triangles; + Build_Offset bo; + bo.input = non_degenerate; + enlarged_non_degenerate_triangles.delegate(bo); + + // @todo, first on non-enlarged faces, then on enlarged; to fix projection on concave surfaces where the enlarging operation shortens projection distances. + + Tree tree(faces(enlarged_non_degenerate_triangles).first, faces(enlarged_non_degenerate_triangles).second, enlarged_non_degenerate_triangles); + + std::map face_normals; + boost::associative_property_map> face_normals_map(face_normals); + CGAL::Polygon_mesh_processing::compute_face_normals(polyhedron, face_normals_map); + + for (auto& f : non_degenerate) { + auto O = CGAL::centroid( + f->facet_begin()->vertex()->point(), + f->facet_begin()->next()->vertex()->point(), + f->facet_begin()->next()->next()->vertex()->point() + ); + + Ray ray(O, -face_normals_map[f]); + + std::list intersections; + tree.all_intersections(ray, std::back_inserter(intersections)); + double N = std::numeric_limits::infinity(); + Point P; + for (auto& intersection : intersections) { + if (boost::get(&(intersection->first))) { + const Point* p = boost::get(&(intersection->first)); + const double d = std::sqrt(CGAL::to_double((*p - O).squared_length())); + if (d > 1.e-20 && d < N) { + N = d; + } + } + } + if (N != std::numeric_limits::infinity() && N > 1.e-4) { + thin_sides.insert(f); + } + } + + std::wcout << "THIN SIDES:" << std::endl; + for (auto& f : thin_sides) { + dump_facet(f); + } + + for (auto& f : non_degenerate) { + if (thin_sides.find(f) == thin_sides.end()) { + longitudonal.push_back(f); + } + } + + std::wcout << "LONGITUDONAL:" << std::endl; + for (auto& f : longitudonal) { + dump_facet(f); + } + + std::wcout << "faces " << faces(polyhedron).size() << "long " << longitudonal.size() << "thin " << thin_sides.size() << "non-degen " << non_degenerate.size() << std::endl; + + cgal_shape_t enlarged_indiv_triangles; + Build_Offset bo2; + bo2.input = longitudonal; + enlarged_indiv_triangles.delegate(bo2); + + { + std::ofstream ofs("enlarged.off"); + ofs.precision(17); + ofs << enlarged_indiv_triangles; + } + + Tree tree2(faces(enlarged_indiv_triangles).begin(), faces(enlarged_indiv_triangles).end(), enlarged_indiv_triangles); + + std::map new_points; + + for (Polyhedron::Facet_iterator fit = polyhedron.facets_begin(); + fit != polyhedron.facets_end(); + ++fit) { + if (CGAL::collinear( + fit->halfedge()->vertex()->point(), + fit->halfedge()->next()->vertex()->point(), + fit->halfedge()->opposite()->vertex()->point())) { + std::wcout << "degenerate triangle" << std::endl; + } + } + + for (auto& v : vertices(polyhedron)) { + auto O = v->point(); + + Kernel_::Vector_3 norm; + Kernel_::Vector_3 accum; + int count = 0; + CGAL::Face_around_target_circulator it(v->halfedge(), polyhedron), end(it); + do { + cgal_shape_t::Facet_handle fh = (*it)->halfedge()->facet(); + + auto jt = std::find(non_degenerate.begin(), non_degenerate.end(), fh); + std::wcout << "non degen: " << (jt != non_degenerate.end()) << std::endl; + auto kt = std::find(thin_sides.begin(), thin_sides.end(), fh); + std::wcout << "thin side: " << (kt != thin_sides.end()) << std::endl; + if (jt != non_degenerate.end() && kt == thin_sides.end()) { + // else degenerate, prevent div by zero, do not incorporate in vnorm. + // or else part of thin side + + auto p0 = (*it)->facet_begin()->vertex()->point(); + auto p1 = (*it)->facet_begin()->next()->vertex()->point(); + auto p2 = (*it)->facet_begin()->next()->next()->vertex()->point(); + + { + std::ostringstream oss; + oss.precision(8); + oss << "p0 " << p0.cartesian(0) << " " << p0.cartesian(1) << " " << p0.cartesian(2) << "\n"; + oss << "p1 " << p1.cartesian(0) << " " << p1.cartesian(1) << " " << p1.cartesian(2) << "\n"; + oss << "p2 " << p2.cartesian(0) << " " << p2.cartesian(1) << " " << p2.cartesian(2) << "\n"; + auto osss = oss.str(); + std::wcout << osss.c_str() << std::endl; + } + + auto fnorm = CGAL::cross_product(p0 - p1, p2 - p1); + fnorm /= std::sqrt(CGAL::to_double(fnorm.squared_length())); + + // const auto& fnorm = face_normals_map_2[*it]; + std::ostringstream oss; + oss.precision(8); + oss << fnorm.cartesian(0) << " " << fnorm.cartesian(1) << " " << fnorm.cartesian(2); + auto osss = oss.str(); + std::wcout << osss.c_str() << std::endl; + accum += fnorm; + + ++count; + } + + ++it; + } while (it != end); + + norm = accum / count; + std::wcout << "count " << count << std::endl; + + if (count == 0) { + // part of only degenerate or only thin sides + continue; + } + + // v->vertex_begin(); + Ray ray(O, norm); + std::ostringstream oss; + oss.precision(8); + oss << O << " -> " << norm; + auto osss = oss.str(); + std::wcout << osss.c_str() << std::endl; + + std::list intersections; + tree2.all_intersections(ray, std::back_inserter(intersections)); + double N = std::numeric_limits::infinity(); + Point P; + + bool used_intersection = false; + + if (intersections.size()) { + for (auto& intersection : intersections) { + if (boost::get(&(intersection->first))) { + const Point* p = boost::get(&(intersection->first)); + const double d = std::sqrt(CGAL::to_double((*p - O).squared_length())); + if (d < N && d > 1.e-20) { + N = d; + P = *p; + std::wcout << "intersection @ " << d << std::endl; + } + } + } + std::wcout << "-----------" << std::endl; + + // average the new point + new_points[O] = CGAL::ORIGIN + (((O - CGAL::ORIGIN) + (P - CGAL::ORIGIN))) / 2; + used_intersection = true; + } + + if (!used_intersection) { + std::wcout << "no intersection :(" << std::endl; + } + } + + auto thin_sides_degenerate = thin_sides; + thin_sides_degenerate.insert(degenerate.begin(), degenerate.end()); + + // @todo choose connected / connected_opposing based on largest combined area of facets? + + auto connected = connected_faces(*longitudonal.begin(), thin_sides_degenerate); + decltype(connected) connected_opposing; + + for (auto& f : longitudonal) { + if (std::find(connected.begin(), connected.end(), f) == connected.end()) { + connected_opposing = connected_faces(f, thin_sides_degenerate); + + std::set longi(longitudonal.begin(), longitudonal.end()); + std::set both_sides(connected.begin(), connected.end()); + both_sides.insert(connected_opposing.begin(), connected_opposing.end()); + + if (longi == both_sides) { + std::wcout << "Facet connection functioning properly" << std::endl; + } else { + std::wcout << "Facet connection functioning incorrectly" << std::endl; + } + + break; + } + } + + Builder_With_Map b2; + b2.input = connected; + b2.mapping = new_points; + + flattened.delegate(b2); + } +}; + + +struct intersection_validator { + typedef std::list> > nefs_t; + typedef CGAL::Box_intersection_d::Box_with_handle_d Box; + + std::vector boxes; + nefs_t nefs; + + intersection_validator(IfcParse::IfcFile& f, std::initializer_list entities, bool no_progress, bool quiet, bool stderr_progress) { + + ifcopenshell::geometry::settings settings; + settings.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, false); + settings.set(ifcopenshell::geometry::settings::WELD_VERTICES, false); + settings.set(ifcopenshell::geometry::settings::SEW_SHELLS, true); + settings.set(ifcopenshell::geometry::settings::CONVERT_BACK_UNITS, true); + settings.set(ifcopenshell::geometry::settings::DISABLE_TRIANGULATION, true); + settings.set(ifcopenshell::geometry::settings::DISABLE_OPENING_SUBTRACTIONS, true); + + std::vector spaces_and_walls = { + IfcGeom::entity_filter(true, false, entities) + }; + + ifcopenshell::geometry::Iterator context_iterator("cgal", settings, &f, spaces_and_walls); + + if (!context_iterator.initialize()) { + return; + } + + auto kernel = (ifcopenshell::geometry::kernels::CgalKernel*) context_iterator.converter().kernel(); + auto cube = kernel->precision_cube(); + + size_t num_created = 0; + int old_progress = quiet ? 0 : -1; + + for (;; ++num_created) { + bool has_more = true; + if (num_created) { + has_more = context_iterator.next(); + } + ifcopenshell::geometry::NativeElement* geom_object = nullptr; + if (has_more) { + geom_object = context_iterator.get_native(); + } + if (!geom_object) { + break; + } + + std::stringstream ss; + ss << geom_object->product()->data().toString(); + auto sss = ss.str(); + std::wcout << sss.c_str() << std::endl; + + for (auto& g : geom_object->geometry()) { + auto s = ((ifcopenshell::geometry::CgalShape*) g.Shape())->shape(); + const auto& m = g.Placement().components; + const auto& n = geom_object->transformation().data().components; + + const cgal_placement_t trsf( + m(0, 0), m(0, 1), m(0, 2), m(0, 3), + m(1, 0), m(1, 1), m(1, 2), m(1, 3), + m(2, 0), m(2, 1), m(2, 2), m(2, 3)); + + const cgal_placement_t trsf2( + n(0, 0), n(0, 1), n(0, 2), n(0, 3), + n(1, 0), n(1, 1), n(1, 2), n(1, 3), + n(2, 0), n(2, 1), n(2, 2), n(2, 3)); + + // Apply transformation + for (auto &vertex : vertices(s)) { + vertex->point() = vertex->point().transform(trsf).transform(trsf2); + } + + CGAL::Nef_polyhedron_3 nef = ifcopenshell::geometry::utils::create_nef_polyhedron(s); + nef = CGAL::minkowski_sum_3(nef, cube); + std::wcout << "product: " << geom_object->product() << std::endl; + nefs.push_back({ geom_object->product(), nef }); + + Box b(&*(nefs.rbegin())); + // id_map[b.id()] = ; + + for (auto &vertex : vertices(s)) { + double p[3] = { + CGAL::to_double(vertex->point().cartesian(0)), + CGAL::to_double(vertex->point().cartesian(1)), + CGAL::to_double(vertex->point().cartesian(2)) + }; + b.extend(p); + } + + boxes.push_back(enlarge(b)); + + /* + std::ostringstream ss; + ss << geom_object->product()->data().toString() << std::endl << b.min_coord(0) << " - " << b.max_coord(0) << std::endl; + auto sss = ss.str(); + std::wcout << sss.c_str(); + */ + } + + if (!no_progress) { + if (quiet) { + const int progress = context_iterator.progress(); + for (; old_progress < progress; ++old_progress) { + std::cout << "."; + if (stderr_progress) + std::cerr << "."; + } + std::cout << std::flush; + if (stderr_progress) + std::cerr << std::flush; + } else { + const int progress = context_iterator.progress() / 2; + if (old_progress != progress) Logger::ProgressBar(progress); + old_progress = progress; + } + } + } + + if (!no_progress && quiet) { + for (; old_progress < 100; ++old_progress) { + std::cout << "."; + if (stderr_progress) + std::cerr << "."; + } + std::cout << std::flush; + if (stderr_progress) + std::cerr << std::flush; + } else { + Logger::Status("\rDone fixing space boundaries for " + boost::lexical_cast(num_created) + + " objects "); + } + + } + + template + void operator()(Fn fn) { + CGAL::box_self_intersection_d(boxes.begin(), boxes.end(), fn); + } +}; From b6a7ba1e1cbf37a8d95d5794ed6be1b120117dde Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 26 Jan 2020 13:58:02 +0100 Subject: [PATCH 200/235] Fix for open polyhedra --- src/ifcconvert/validation_utils.h | 5 +++++ src/ifcgeom/kernels/cgal/CgalKernel.cpp | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ifcconvert/validation_utils.h b/src/ifcconvert/validation_utils.h index eca3406563..382603371f 100644 --- a/src/ifcconvert/validation_utils.h +++ b/src/ifcconvert/validation_utils.h @@ -481,6 +481,11 @@ struct intersection_validator { } CGAL::Nef_polyhedron_3 nef = ifcopenshell::geometry::utils::create_nef_polyhedron(s); + if (nef.is_empty()) { + std::wcout << "Failed to create nef" << std::endl; + continue; + } + nef = CGAL::minkowski_sum_3(nef, cube); std::wcout << "product: " << geom_object->product() << std::endl; nefs.push_back({ geom_object->product(), nef }); diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index 190a851470..3d6e76d9c8 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -94,7 +94,8 @@ CGAL::Nef_polyhedron_3 ifcopenshell::geometry::utils::create_nef_polyhe } CGAL::Nef_polyhedron_3 ifcopenshell::geometry::utils::create_nef_polyhedron(CGAL::Polyhedron_3 &polyhedron) { - if (polyhedron.is_valid()) { + if (polyhedron.is_valid() && polyhedron.is_closed()) { + // @todo is it necessary to triangulat? CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron); CGAL::Nef_polyhedron_3 nef_polyhedron; try { From 7a8a5e2ebb3195c6f210fbb59e7e39e737d1399c Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 26 Jan 2020 17:11:02 +0100 Subject: [PATCH 201/235] Dont close polylines automatically --- src/ifcgeom/schema/mapping.cpp | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index 1e063ec52d..c27a0d3892 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -196,6 +196,8 @@ namespace { } taxonomy::item* mapping::map_impl(const IfcSchema::IfcRepresentation* inst) { + const bool use_body = !this->settings_.get(ifcopenshell::geometry::settings::INCLUDE_CURVES); + auto items = map_to_collection(this, inst->Items()); if (items == nullptr) { return nullptr; @@ -204,9 +206,9 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcRepresentation* inst) { if (flat == nullptr) { return nullptr; } - auto filtered = filter(flat, [](taxonomy::item* i) { + auto filtered = filter(flat, [&use_body](taxonomy::item* i) { // @todo just filter loops for now. - return i->kind() != taxonomy::LOOP; + return (i->kind() != taxonomy::LOOP) == use_body; }); delete items; delete flat; @@ -305,12 +307,14 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcDirection* inst) { } taxonomy::item* mapping::map_impl(const IfcSchema::IfcProduct* inst) { + const bool use_body = !this->settings_.get(ifcopenshell::geometry::settings::INCLUDE_CURVES); + auto openings = find_openings(inst); // @todo const cast auto reps = inst->data().file->traverse((IfcSchema::IfcProduct*) inst, 2)->as(); IfcSchema::IfcRepresentation* body = nullptr; for (auto& rep : *reps) { - if (rep->RepresentationIdentifier() == "Body") { + if ((rep->RepresentationIdentifier() == "Body") == use_body) { body = rep; } } @@ -321,7 +325,7 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcProduct* inst) { auto c = new taxonomy::collection; c->matrix = as(map(inst->ObjectPlacement())); - if (openings->size() && !settings_.get(settings::DISABLE_OPENING_SUBTRACTIONS)) { + if (openings->size() && !settings_.get(settings::DISABLE_OPENING_SUBTRACTIONS) && use_body) { auto ci = c->matrix.components.inverse(); IfcEntityList::ptr operands(new IfcEntityList); @@ -1113,13 +1117,15 @@ namespace { taxonomy::loop* polygon_from_points(const std::vector& ps, bool external = true) { auto loop = new taxonomy::loop(); loop->external = external; - auto previous = ps.back(); + boost::optional previous; for (auto& p : ps) { - auto e = new taxonomy::edge; - e->start = previous; - e->end = p; - previous = p; - loop->children.push_back(e); + if (previous) { + auto e = new taxonomy::edge; + e->start = *previous; + e->end = p; + loop->children.push_back(e); + } + previous = p; } return loop; } @@ -1174,7 +1180,7 @@ namespace { } std::vector ps; - ps.reserve(points.size()); + ps.reserve(points.size() + 1); std::transform(points.begin(), points.end(), std::back_inserter(ps), [&has_position, &m4](const profile_point& p) { if (has_position) { Eigen::Vector4d v(p.xy[0], p.xy[1], 0., 1.); @@ -1184,6 +1190,7 @@ namespace { return taxonomy::point3(p.xy[0], p.xy[1], 0.); } }); + ps.push_back(ps.front()); return polygon_from_points(ps); } From 1d6f20c48daabec989ff52a6820ddcd0b5cfb7db Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 26 Jan 2020 17:11:14 +0100 Subject: [PATCH 202/235] Fix wall connectivity --- src/ifcconvert/validate_wall_connectivity.cpp | 124 +++++++++++++----- src/ifcconvert/validation_utils.h | 5 + 2 files changed, 93 insertions(+), 36 deletions(-) diff --git a/src/ifcconvert/validate_wall_connectivity.cpp b/src/ifcconvert/validate_wall_connectivity.cpp index fbfb9aca66..95a9c9d274 100644 --- a/src/ifcconvert/validate_wall_connectivity.cpp +++ b/src/ifcconvert/validate_wall_connectivity.cpp @@ -1,5 +1,9 @@ #include "validation_utils.h" +#include + +using namespace ifcopenshell::geometry; + void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) { intersection_validator v(f, { "IfcWall" }, no_progress, quiet, stderr_progress); @@ -17,61 +21,109 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo ifcopenshell::geometry::Converter c("cgal", &f, settings); - v([&c](const intersection_validator::Box& a, const intersection_validator::Box& b) { - std::ostringstream ss; + auto rels = f.instances_by_type("IfcRelConnectsPathElements"); + std::map, const IfcUtil::IfcBaseClass*> rel_by_elem; + std::for_each(rels->begin(), rels->end(), [&rel_by_elem](const IfcUtil::IfcBaseClass* rel) { + auto x = ((IfcUtil::IfcBaseEntity*)rel)->get_value("RelatingElement"); + auto y = ((IfcUtil::IfcBaseEntity*)rel)->get_value("RelatedElement"); + rel_by_elem.insert({{ x,y }, rel}); + }); - ss << a.handle()->first->data().toString() << "x" << a.handle()->first->data().toString() << std::endl; + v([&c, &rel_by_elem](const intersection_validator::Box& a, const intersection_validator::Box& b) { + auto A = a.handle()->first; + auto B = b.handle()->first; + + auto rit = rel_by_elem.find({ A, B }); + if (rit == rel_by_elem.end()) { + return; + } + + auto rel = rit->second; + const bool a_is_relating = A == ((IfcUtil::IfcBaseEntity*)rel)->get_value("RelatingElement"); + auto a_type = ((IfcUtil::IfcBaseEntity*)rel)->get_value("RelatingConnectionType"); + auto b_type = ((IfcUtil::IfcBaseEntity*)rel)->get_value("RelatedConnectionType"); + if (!a_is_relating) { + std::swap(a_type, b_type); + } + +#if 0 + auto a_poly = ifcopenshell::geometry::utils::create_polyhedron(a.handle()->second); + auto b_poly = ifcopenshell::geometry::utils::create_polyhedron(b.handle()->second); + + std::wcout << "a" << std::endl; + for (auto& v : vertices(a_poly)) { + for (int i = 0; i < 3; ++i) { + std::wcout << CGAL::to_double(v->point().cartesian(i)) << " "; + } + std::wcout << std::endl; + } + + std::wcout << "b" << std::endl; + for (auto& v : vertices(b_poly)) { + for (int i = 0; i < 3; ++i) { + std::wcout << CGAL::to_double(v->point().cartesian(i)) << " "; + } + std::wcout << std::endl; + } +#endif + + std::ostringstream ss; + ss << A->data().toString() << "x" << B->data().toString() << std::endl; auto x = a.handle()->second * b.handle()->second; if (x.is_empty()) { return; } - c.convert(a.handle()->first); - cgal_shape_t x_poly; x.convert_to_polyhedron(x_poly); - for (auto& v : vertices(x_poly)) { - // project onto axes - } + auto get_axis_parameter_min_max = [&c, &x_poly](IfcUtil::IfcBaseEntity* inst) { + auto item = c.mapping()->map(inst); + auto shaperep = ((taxonomy::collection*) item)->children[0]; + auto loop = ((taxonomy::collection*) shaperep)->children[0]; - CGAL::Polygon_mesh_processing::triangulate_faces(x_poly); + if (loop->kind() != taxonomy::LOOP) { + std::wcout << "no suitable axis" << std::endl; + } else { + auto first_vertex = ((taxonomy::edge*) ((taxonomy::loop*) loop)->children.front())->start; + auto last_vertex = ((taxonomy::edge*) ((taxonomy::loop*) loop)->children.back())->end; - auto s0 = a.handle()->first->declaration().name(); - auto s1 = b.handle()->first->declaration().name(); - auto i0 = a.handle()->first->data().id(); - auto i1 = b.handle()->first->data().id(); + if (first_vertex.which() != 0 || last_vertex.which() != 0) { + std::wcout << "trims not supported" << std::endl; + } else { + auto p0 = boost::get(first_vertex); + auto p1 = boost::get(last_vertex); + + auto v0 = ((taxonomy::geom_item*)item)->matrix.components * p0.components.homogeneous(); + auto v1 = ((taxonomy::geom_item*)item)->matrix.components * p1.components.homogeneous(); - if (s0 < s1) { - std::swap(s1, s0); - std::swap(i0, i1); - } + auto P0 = Kernel_::Point_3(v0(0), v0(1), v0(2)); + auto P1 = Kernel_::Point_3(v1(0), v1(1), v1(2)); - { - auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "sb.off"; + auto D = P1 - P0; + auto len = std::sqrt(CGAL::to_double(D.squared_length())); + D /= len; - std::ofstream os(FN.c_str()); - os.precision(17); - os << x_poly; - } + std::wcout << "xx " << len << std::endl; - remove_thickness r(x_poly); + std::vector parameters; - { - auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "-sides-sb.off"; + std::transform(vertices(x_poly).begin(), vertices(x_poly).end(), std::back_inserter(parameters), [&P0, D](auto& v) { + return (v->point() - P0) * D; + }); - std::ofstream os(FN.c_str()); - os.precision(17); - os << r.polyhedron2; - } + auto pit = std::minmax_element(parameters.begin(), parameters.end()); + return std::make_pair(CGAL::to_double(*pit.first), CGAL::to_double(*pit.first)); + } + } + return std::make_pair(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); + }; - { - auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "-flat-sb.off"; + auto u0u1 = get_axis_parameter_min_max(A); + std::wcout << a_type.c_str() << " " << u0u1.first << " " << u0u1.second << std::endl; - std::ofstream os(FN.c_str()); - os.precision(17); - os << r.flattened; - } + u0u1 = get_axis_parameter_min_max(B); + std::wcout << b_type.c_str() << " " << u0u1.first << " " << u0u1.second << std::endl; }); } diff --git a/src/ifcconvert/validation_utils.h b/src/ifcconvert/validation_utils.h index 382603371f..e3c12e140f 100644 --- a/src/ifcconvert/validation_utils.h +++ b/src/ifcconvert/validation_utils.h @@ -379,6 +379,11 @@ struct remove_thickness { // @todo choose connected / connected_opposing based on largest combined area of facets? + if (longitudonal.size() == 0) { + std::wcout << "no longitudonal faces detected :(" << std::endl; + return; + } + auto connected = connected_faces(*longitudonal.begin(), thin_sides_degenerate); decltype(connected) connected_opposing; From e448312d41e8ffdb0bee0c7150d7092dd72923c1 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Mon, 27 Jan 2020 10:42:01 +0100 Subject: [PATCH 203/235] Reporting for wall connectivity --- src/ifcconvert/validate_wall_connectivity.cpp | 72 +++++++++++++------ 1 file changed, 52 insertions(+), 20 deletions(-) diff --git a/src/ifcconvert/validate_wall_connectivity.cpp b/src/ifcconvert/validate_wall_connectivity.cpp index 95a9c9d274..df522845c2 100644 --- a/src/ifcconvert/validate_wall_connectivity.cpp +++ b/src/ifcconvert/validate_wall_connectivity.cpp @@ -29,22 +29,25 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo rel_by_elem.insert({{ x,y }, rel}); }); - v([&c, &rel_by_elem](const intersection_validator::Box& a, const intersection_validator::Box& b) { + std::set rels_encounted; + + v([&c, &rel_by_elem, &rels_encounted](const intersection_validator::Box& a, const intersection_validator::Box& b) { auto A = a.handle()->first; auto B = b.handle()->first; - auto rit = rel_by_elem.find({ A, B }); - if (rit == rel_by_elem.end()) { - return; - } + const IfcUtil::IfcBaseClass* rel = nullptr; + std::string a_type, b_type; - auto rel = rit->second; - const bool a_is_relating = A == ((IfcUtil::IfcBaseEntity*)rel)->get_value("RelatingElement"); - auto a_type = ((IfcUtil::IfcBaseEntity*)rel)->get_value("RelatingConnectionType"); - auto b_type = ((IfcUtil::IfcBaseEntity*)rel)->get_value("RelatedConnectionType"); - if (!a_is_relating) { - std::swap(a_type, b_type); - } + auto rit = rel_by_elem.find({ A, B }); + if (rit != rel_by_elem.end()) { + rel = rit->second; + const bool a_is_relating = A == ((IfcUtil::IfcBaseEntity*)rel)->get_value("RelatingElement"); + a_type = ((IfcUtil::IfcBaseEntity*)rel)->get_value("RelatingConnectionType"); + b_type = ((IfcUtil::IfcBaseEntity*)rel)->get_value("RelatedConnectionType"); + if (!a_is_relating) { + std::swap(a_type, b_type); + } + } #if 0 auto a_poly = ifcopenshell::geometry::utils::create_polyhedron(a.handle()->second); @@ -104,8 +107,6 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo auto len = std::sqrt(CGAL::to_double(D.squared_length())); D /= len; - std::wcout << "xx " << len << std::endl; - std::vector parameters; std::transform(vertices(x_poly).begin(), vertices(x_poly).end(), std::back_inserter(parameters), [&P0, D](auto& v) { @@ -113,17 +114,48 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo }); auto pit = std::minmax_element(parameters.begin(), parameters.end()); - return std::make_pair(CGAL::to_double(*pit.first), CGAL::to_double(*pit.first)); + return std::make_pair(len, std::make_pair(CGAL::to_double(*pit.first), CGAL::to_double(*pit.first))); } } - return std::make_pair(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); + const auto& nan = std::numeric_limits::quiet_NaN(); + return std::make_pair(nan, std::make_pair(nan, nan)); }; - auto u0u1 = get_axis_parameter_min_max(A); - std::wcout << a_type.c_str() << " " << u0u1.first << " " << u0u1.second << std::endl; + auto qualify_connection_type = [](double l, const std::pair& p) { + if (p.first < 1.e-5) { + return "ATSTART"; + } else if (p.second > l - 1.e-5) { + return "ATEND"; + } else { + return "ATPATH"; + } + }; - u0u1 = get_axis_parameter_min_max(B); - std::wcout << b_type.c_str() << " " << u0u1.first << " " << u0u1.second << std::endl; + auto alu0u1 = get_axis_parameter_min_max(A); + auto blu0u1 = get_axis_parameter_min_max(B); + + auto atype_computed = qualify_connection_type(alu0u1.first, alu0u1.second); + auto btype_computed = qualify_connection_type(blu0u1.first, blu0u1.second); + + rels_encounted.insert(rel); + + if (a_type != atype_computed || b_type != btype_computed) { + if (rel) { + auto rel_str = rel->data().toString(); + std::wcout << "ERROR: " << rel_str.c_str() << " " << atype_computed << " " << btype_computed << std::endl; + } else { + auto A_str = A->data().toString(); + auto B_str = B->data().toString(); + std::wcout << "ERROR: no rel " << A_str.c_str() << " x " << B_str.c_str() << " " << atype_computed << " " << btype_computed << std::endl; + } + } + }); + + std::for_each(rels->begin(), rels->end(), [&rels_encounted](const IfcUtil::IfcBaseClass* rel) { + if (rels_encounted.find(rel) == rels_encounted.end()) { + auto rel_str = rel->data().toString(); + std::wcout << "ERROR: " << rel_str.c_str() << " not found" << std::endl; + } }); } From b91a34c8c6275e2a8ace2e3ca723673714059403 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 29 Jan 2020 14:57:49 +0100 Subject: [PATCH 204/235] Track time; fixes for wall connectivity check --- src/ifcconvert/IfcConvert.cpp | 13 +- src/ifcconvert/validate_space_boundaries.cpp | 114 ++++++++++++++++-- .../validate_storey_containment.cpp | 24 ++-- src/ifcconvert/validate_wall_connectivity.cpp | 67 +++++++--- src/ifcconvert/validation_utils.h | 27 ++++- src/ifcgeom/schema_agnostic/Converter.cpp | 10 ++ src/ifcgeom/schema_agnostic/Converter.h | 8 ++ 7 files changed, 225 insertions(+), 38 deletions(-) diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index f320165e5a..1cc7a0aa81 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -946,14 +946,14 @@ void write_log(bool header) { } #include +#include bool init_input_file(const std::string& filename, IfcParse::IfcFile*& ifc_file, bool no_progress, bool mmap) { - time_t start, end; + std::clock_t c_start = std::clock(); // Prevent IfcFile::Init() prints by setting output to null temporarily if (no_progress) { Logger::SetOutput(NULL, &log_stream); } - time(&start); #ifdef USE_MMAP ifc_file = new IfcParse::IfcFile(filename, mmap); #else @@ -970,10 +970,15 @@ bool init_input_file(const std::string& filename, IfcParse::IfcFile*& ifc_file, Logger::Error("Unable to parse input file '" + filename + "'"); return false; } - time(&end); + + std::clock_t c_end = std::clock(); if (no_progress) { Logger::SetOutput(&cout_, &log_stream); } - else { Logger::Status("Parsing input file took " + format_duration(start, end)); } + else { + std::stringstream ss; + ss << std::setprecision(14) << (c_end - c_start) / (double)CLOCKS_PER_SEC; + Logger::Status("total_ifc_parse_time " + ss.str()); + } return true; diff --git a/src/ifcconvert/validate_space_boundaries.cpp b/src/ifcconvert/validate_space_boundaries.cpp index e0322badfd..b555eb19d6 100644 --- a/src/ifcconvert/validate_space_boundaries.cpp +++ b/src/ifcconvert/validate_space_boundaries.cpp @@ -1,25 +1,111 @@ #include "validation_utils.h" +using namespace ifcopenshell::geometry; + +#include +#include +#include +#include + +typedef Kernel_::FT FT; +typedef Kernel_::Point_3 Point; +typedef Kernel_::Segment_3 Segment; +typedef CGAL::Polyhedron_3 Polyhedron; +typedef CGAL::AABB_face_graph_triangle_primitive Primitive; +typedef CGAL::AABB_traits Traits; +typedef CGAL::AABB_tree Tree; +typedef Tree::Point_and_primitive_id Point_and_primitive_id; + void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) { - intersection_validator v(f, { "IfcWall", "IfcSpace" }, no_progress, quiet, stderr_progress); + intersection_validator v(f, { "IfcWall", "IfcSpace" }, 1.e-5, no_progress, quiet, stderr_progress); + + auto rels = f.instances_by_type("IfcRelSpaceBoundary"); + + std::map, const IfcUtil::IfcBaseClass*> rel_by_space_elem; + + + if (rels) { + std::for_each(rels->begin(), rels->end(), [&rel_by_space_elem](const IfcUtil::IfcBaseClass* rel) { + auto x = ((IfcUtil::IfcBaseEntity*)rel)->get_value("RelatingSpace"); + try { + auto y = ((IfcUtil::IfcBaseEntity*)rel)->get_value("RelatedBuildingElement"); + rel_by_space_elem.insert({ { x,y }, rel }); + } catch (IfcParse::IfcException&) { + // RelatedBuildingElement can be NULL + } + }); + } + + std::set rels_encounted; + + IfcParse::IfcFile f2("boundaries-triangulated.ifc"); + ifcopenshell::geometry::settings settings; + + settings.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, false); + settings.set(ifcopenshell::geometry::settings::WELD_VERTICES, false); + settings.set(ifcopenshell::geometry::settings::SEW_SHELLS, true); + settings.set(ifcopenshell::geometry::settings::CONVERT_BACK_UNITS, true); + settings.set(ifcopenshell::geometry::settings::DISABLE_TRIANGULATION, true); + settings.set(ifcopenshell::geometry::settings::DISABLE_OPENING_SUBTRACTIONS, true); + + ifcopenshell::geometry::Converter c("cgal", &f2, settings); + + std::map, std::vector> elem_to_space_boundary_coords; + + for (auto& i : *f2.instances_by_type("IfcProduct")) { + auto n = ((IfcUtil::IfcBaseEntity*)i)->get_value("Name"); + auto g1 = n.substr(0, 22); + auto g2 = n.substr(23); + auto item = c.mapping()->map(i); + auto shell = (taxonomy::shell*) ((taxonomy::collection*)((taxonomy::collection*) item)->children[0])->children[0]; + for (auto& f : shell->children) { + auto face = (taxonomy::face*) f; + for (auto& w : face->children) { + auto wire = (taxonomy::loop*) w; + for (auto& e : wire->children) { + auto edge = (taxonomy::edge*) e; + auto p3 = boost::get(edge->start); + auto p4 = ((taxonomy::geom_item*)item)->matrix.components * p3.components.homogeneous(); + Kernel_::Point_3 P(p4(0), p4(1), p4(2)); + elem_to_space_boundary_coords[{g1, g2}].emplace_back(P); + } + } + } + } - v([](const intersection_validator::Box& a, const intersection_validator::Box& b) { + v([&rel_by_space_elem, &elem_to_space_boundary_coords](const intersection_validator::Box& a, const intersection_validator::Box& b) { std::ostringstream ss; // ss << id_map[a.id()]->first->data().toString() << "x" << id_map[b.id()]->first->data().toString() << std::endl; // auto x = id_map[a.id()]->second * id_map[b.id()]->second; - ss << a.handle()->first->data().toString() << "x" << a.handle()->first->data().toString() << std::endl; - auto x = a.handle()->second * b.handle()->second; - cgal_shape_t x_poly; - x.convert_to_polyhedron(x_poly); + auto A = a.handle()->first; + auto B = b.handle()->first; - CGAL::Polygon_mesh_processing::triangulate_faces(x_poly); + auto Aguid = A->get_value("GlobalId"); + auto Bguid = B->get_value("GlobalId"); - auto vs = vertices(x_poly); - if (std::distance(vs.begin(), vs.end()) == 0) { + int space_count = 0; + if (A->declaration().name() == "IfcSpace") { + space_count += 1; + } + if (B->declaration().name() == "IfcSpace") { + space_count += 1; + } + if (space_count != 1) { return; } + ss << a.handle()->first->data().toString() << "x" << a.handle()->first->data().toString() << std::endl; + auto x = a.handle()->second * b.handle()->second; + + if (x.is_empty()) { + // std::wcout << "empty" << std::endl; + return; + } + + cgal_shape_t x_poly; + x.convert_to_polyhedron(x_poly); + auto s0 = a.handle()->first->declaration().name(); auto s1 = b.handle()->first->declaration().name(); auto i0 = a.handle()->first->data().id(); @@ -30,6 +116,16 @@ void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, boo std::swap(i0, i1); } + Tree tree(faces(x_poly).first, faces(x_poly).second, x_poly); + tree.accelerate_distance_queries(); + + for (auto& p : elem_to_space_boundary_coords[{Aguid, Bguid}]) { + auto d = std::sqrt(CGAL::to_double(tree.squared_distance(p))); + std::wcout << d << std::endl; + } + + return; + { auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "sb.off"; diff --git a/src/ifcconvert/validate_storey_containment.cpp b/src/ifcconvert/validate_storey_containment.cpp index 53bbe95914..c6c4564c16 100644 --- a/src/ifcconvert/validate_storey_containment.cpp +++ b/src/ifcconvert/validate_storey_containment.cpp @@ -46,12 +46,14 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b return get_elevation(a) < get_elevation(b); }); + /* std::wcout << "Storeys "; for (auto& s : storeys_sorted) { auto n = ((IfcUtil::IfcBaseEntity*)s)->get_value("Name"); std::wcout << n.c_str() << " "; } std::wcout << std::endl; + */ std::vector elevations; std::transform(storeys_sorted.begin(), storeys_sorted.end(), std::back_inserter(elevations), get_elevation); @@ -69,13 +71,14 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b std::vector> nefs; std::transform(elevation_slices.begin(), elevation_slices.end(), std::back_inserter(nefs), [&LARGE](const std::pair& p) { - std::wcout << p.first << " - " << p.second << std::endl; + // std::wcout << p.first << " - " << p.second << std::endl; Kernel_::Point_3 p1(-LARGE, -LARGE, p.first); Kernel_::Point_3 p2(+LARGE, +LARGE, p.second); auto poly = ifcopenshell::geometry::utils::create_cube(p1, p2); return ifcopenshell::geometry::utils::create_nef_polyhedron(poly); }); + /* for (auto& n : nefs) { auto poly = ifcopenshell::geometry::utils::create_polyhedron(n); auto bounds = CGAL::Polygon_mesh_processing::bbox_3(poly); @@ -87,6 +90,7 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b } std::wcout << "---" << std::endl; } + */ if (!context_iterator.initialize()) { return; @@ -108,13 +112,15 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b break; } + /* std::stringstream ss; ss << geom_object->product()->data().toString(); auto sss = ss.str(); std::wcout << sss.c_str() << std::endl; + */ if (elem_to_storey.find(geom_object->product()) == elem_to_storey.end()) { - std::wcout << "not associated to storey" << std::endl; + // std::wcout << "not associated to storey" << std::endl; continue; } @@ -140,6 +146,7 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b vertex->point() = vertex->point().transform(trsf).transform(trsf2); } + /* { auto bounds = CGAL::Polygon_mesh_processing::bbox_3(s); for (int i = 0; i < 3; ++i) { @@ -150,11 +157,12 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b } std::wcout << "---" << std::endl; } + */ CGAL::Nef_polyhedron_3 part_nef = ifcopenshell::geometry::utils::create_nef_polyhedron(s); if (!part_nef.is_simple()) { - std::wcout << "not simple" << std::endl; + // std::wcout << "not simple" << std::endl; continue; } @@ -166,18 +174,20 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b }); } + /* std::wcout << "volumes: "; for (auto& v : intersection_volumes) { std::wcout << v << " "; } std::wcout << std::endl; + */ auto idx = std::max_element(intersection_volumes.begin(), intersection_volumes.end()) - intersection_volumes.begin(); if (storeys_sorted[idx] != elem_to_storey[geom_object->product()]) { - auto s = geom_object->product()->data().toString(); - auto s1 = storeys_sorted[idx]->data().toString(); - auto s2 = elem_to_storey[geom_object->product()]->data().toString(); - std::wcout << "Mismatch on " << s.c_str() << ": " << s1.c_str() << " vs " << s2.c_str() << std::endl; + auto s = geom_object->product()->get_value("GlobalId"); + auto s1 = ((IfcUtil::IfcBaseEntity*)storeys_sorted[idx])->get_value("GlobalId"); + auto s2 = ((IfcUtil::IfcBaseEntity*)elem_to_storey[geom_object->product()])->get_value("GlobalId"); + Logger::Error("Element " + s + " contained in " + s2 + " located on " + s1); } if (!no_progress) { diff --git a/src/ifcconvert/validate_wall_connectivity.cpp b/src/ifcconvert/validate_wall_connectivity.cpp index df522845c2..ef7aedbfe4 100644 --- a/src/ifcconvert/validate_wall_connectivity.cpp +++ b/src/ifcconvert/validate_wall_connectivity.cpp @@ -1,11 +1,14 @@ #include "validation_utils.h" +#include +#include + #include using namespace ifcopenshell::geometry; void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) { - intersection_validator v(f, { "IfcWall" }, no_progress, quiet, stderr_progress); + intersection_validator v(f, { "IfcWall" }, 1.e-3, no_progress, quiet, stderr_progress); ifcopenshell::geometry::settings settings; @@ -31,7 +34,10 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo std::set rels_encounted; - v([&c, &rel_by_elem, &rels_encounted](const intersection_validator::Box& a, const intersection_validator::Box& b) { + double total_nef_intersection_time = 0.; + double conversion_to_poly = 0.; + + v([&c, &rel_by_elem, &rels_encounted, &total_nef_intersection_time, &conversion_to_poly](const intersection_validator::Box& a, const intersection_validator::Box& b) { auto A = a.handle()->first; auto B = b.handle()->first; @@ -72,13 +78,33 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo std::ostringstream ss; ss << A->data().toString() << "x" << B->data().toString() << std::endl; + std::clock_t intersection_begin = std::clock(); auto x = a.handle()->second * b.handle()->second; + std::clock_t intersection_end = std::clock(); + + total_nef_intersection_time += (intersection_end - intersection_begin) / (double) CLOCKS_PER_SEC; + if (x.is_empty()) { return; } + std::clock_t poly_begin = std::clock(); cgal_shape_t x_poly; x.convert_to_polyhedron(x_poly); + std::clock_t poly_end = std::clock(); + conversion_to_poly += (poly_end - poly_begin) / (double)CLOCKS_PER_SEC; + + auto dza = a.bbox().zmax() - a.bbox().zmin(); + auto dzb = b.bbox().zmax() - b.bbox().zmin(); + auto bb = CGAL::Polygon_mesh_processing::bbox_3(x_poly); + if (bb.zmax() - bb.zmin() < std::min(dza, dzb) / 3.) { + return; + } + + CGAL::Polygon_mesh_processing::triangulate_faces(x_poly); + if (CGAL::Polygon_mesh_processing::area(x_poly) > 2.0) { + return; + } auto get_axis_parameter_min_max = [&c, &x_poly](IfcUtil::IfcBaseEntity* inst) { auto item = c.mapping()->map(inst); @@ -86,13 +112,13 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo auto loop = ((taxonomy::collection*) shaperep)->children[0]; if (loop->kind() != taxonomy::LOOP) { - std::wcout << "no suitable axis" << std::endl; + // std::wcout << "no suitable axis" << std::endl; } else { auto first_vertex = ((taxonomy::edge*) ((taxonomy::loop*) loop)->children.front())->start; auto last_vertex = ((taxonomy::edge*) ((taxonomy::loop*) loop)->children.back())->end; if (first_vertex.which() != 0 || last_vertex.which() != 0) { - std::wcout << "trims not supported" << std::endl; + // std::wcout << "trims not supported" << std::endl; } else { auto p0 = boost::get(first_vertex); auto p1 = boost::get(last_vertex); @@ -114,7 +140,7 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo }); auto pit = std::minmax_element(parameters.begin(), parameters.end()); - return std::make_pair(len, std::make_pair(CGAL::to_double(*pit.first), CGAL::to_double(*pit.first))); + return std::make_pair(len, std::make_pair(CGAL::to_double(*pit.first), CGAL::to_double(*pit.second))); } } const auto& nan = std::numeric_limits::quiet_NaN(); @@ -122,9 +148,9 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo }; auto qualify_connection_type = [](double l, const std::pair& p) { - if (p.first < 1.e-5) { + if (p.first < 1.e-3) { return "ATSTART"; - } else if (p.second > l - 1.e-5) { + } else if (p.second > l - 1.e-3) { return "ATEND"; } else { return "ATPATH"; @@ -141,21 +167,32 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo if (a_type != atype_computed || b_type != btype_computed) { if (rel) { - auto rel_str = rel->data().toString(); - std::wcout << "ERROR: " << rel_str.c_str() << " " << atype_computed << " " << btype_computed << std::endl; + Logger::Error(std::string("Connection type ") + atype_computed + " " + btype_computed + " for:", rel); } else { - auto A_str = A->data().toString(); - auto B_str = B->data().toString(); - std::wcout << "ERROR: no rel " << A_str.c_str() << " x " << B_str.c_str() << " " << atype_computed << " " << btype_computed << std::endl; + auto A_str = A->get_value("GlobalId"); + auto B_str = B->get_value("GlobalId"); + Logger::Error("No connection for adjacent " + A_str + " " + B_str); } } }); - std::for_each(rels->begin(), rels->end(), [&rels_encounted](const IfcUtil::IfcBaseClass* rel) { + std::for_each(rels->begin(), rels->end(), [&rels_encounted, &v](const IfcUtil::IfcBaseClass* rel) { if (rels_encounted.find(rel) == rels_encounted.end()) { - auto rel_str = rel->data().toString(); - std::wcout << "ERROR: " << rel_str.c_str() << " not found" << std::endl; + auto x = (IfcUtil::IfcBaseEntity*)((IfcUtil::IfcBaseEntity*)rel)->get_value("RelatingElement"); + auto y = (IfcUtil::IfcBaseEntity*)((IfcUtil::IfcBaseEntity*)rel)->get_value("RelatedElement"); + if (v.succesfully_processed.find(x) != v.succesfully_processed.end() && v.succesfully_processed.find(y) != v.succesfully_processed.end()) { + Logger::Error("Connection for non-adjacent walls", rel); + } } }); + + std::wcout << std::setprecision(14); + std::wcout << "total_map_time " << v.total_map_time << std::endl; + std::wcout << "total_geom_time " << v.total_geom_time << std::endl; + std::wcout << "total_nef_time " << v.total_nef_time << std::endl; + std::wcout << "total_minkowsky_time " << v.total_minkowsky_time << std::endl; + std::wcout << "total_box_time " << v.total_box_time << std::endl; + std::wcout << "total_nef_intersection_time " << total_nef_intersection_time << std::endl; + std::wcout << "total_conversion_to_poly_time " << conversion_to_poly << std::endl; } diff --git a/src/ifcconvert/validation_utils.h b/src/ifcconvert/validation_utils.h index e3c12e140f..42f367b520 100644 --- a/src/ifcconvert/validation_utils.h +++ b/src/ifcconvert/validation_utils.h @@ -421,7 +421,15 @@ struct intersection_validator { std::vector boxes; nefs_t nefs; - intersection_validator(IfcParse::IfcFile& f, std::initializer_list entities, bool no_progress, bool quiet, bool stderr_progress) { + double total_map_time = 0.; + double total_geom_time = 0.; + double total_nef_time = 0.; + double total_minkowsky_time = 0.; + double total_box_time = 0.; + + std::set succesfully_processed; + + intersection_validator(IfcParse::IfcFile& f, std::initializer_list entities, double eps, bool no_progress, bool quiet, bool stderr_progress) { ifcopenshell::geometry::settings settings; settings.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, false); @@ -441,8 +449,7 @@ struct intersection_validator { return; } - auto kernel = (ifcopenshell::geometry::kernels::CgalKernel*) context_iterator.converter().kernel(); - auto cube = kernel->precision_cube(); + auto cube = ifcopenshell::geometry::utils::create_nef_polyhedron(ifcopenshell::geometry::utils::create_cube(eps)); size_t num_created = 0; int old_progress = quiet ? 0 : -1; @@ -485,13 +492,21 @@ struct intersection_validator { vertex->point() = vertex->point().transform(trsf).transform(trsf2); } + std::clock_t nef_begin = std::clock(); CGAL::Nef_polyhedron_3 nef = ifcopenshell::geometry::utils::create_nef_polyhedron(s); + std::clock_t nef_end = std::clock(); + total_nef_time += (nef_end - nef_begin) / (double) CLOCKS_PER_SEC; if (nef.is_empty()) { std::wcout << "Failed to create nef" << std::endl; continue; } + succesfully_processed.insert(geom_object->product()); + nef = CGAL::minkowski_sum_3(nef, cube); + std::clock_t minkowski_end = std::clock(); + total_minkowsky_time += (minkowski_end - nef_end) / (double) CLOCKS_PER_SEC; + std::wcout << "product: " << geom_object->product() << std::endl; nefs.push_back({ geom_object->product(), nef }); @@ -550,10 +565,16 @@ struct intersection_validator { " objects "); } + total_geom_time = context_iterator.converter().total_geom_time; + total_map_time = context_iterator.converter().total_map_time; } template void operator()(Fn fn) { + std::clock_t box_overlap_begin = std::clock(); + CGAL::box_self_intersection_d(boxes.begin(), boxes.end(), [](auto& x, auto& y) {}); + std::clock_t box_overlap_end = std::clock(); + total_box_time += (box_overlap_end - box_overlap_begin) / (double) CLOCKS_PER_SEC; CGAL::box_self_intersection_d(boxes.begin(), boxes.end(), fn); } }; diff --git a/src/ifcgeom/schema_agnostic/Converter.cpp b/src/ifcgeom/schema_agnostic/Converter.cpp index 0a866e35a2..148aa6cdfe 100644 --- a/src/ifcgeom/schema_agnostic/Converter.cpp +++ b/src/ifcgeom/schema_agnostic/Converter.cpp @@ -44,11 +44,16 @@ ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create } */ + + std::clock_t map_start = std::clock(); + // @todo how to combine product_node and rep_item? auto product_node = (taxonomy::geom_item*) mapping_->map(product); if (product_node == nullptr) { return nullptr; } + + std::clock_t geom_start = std::clock(); auto place = taxonomy::matrix4(); std::swap(place, product_node->matrix); @@ -57,6 +62,11 @@ ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create shape = new ifcopenshell::geometry::Representation::BRep(s, representation_id_builder.str(), shapes); + std::clock_t geom_end = std::clock(); + + total_map_time += (geom_start - map_start) / (double) CLOCKS_PER_SEC; + total_geom_time += (geom_end - geom_start) / (double) CLOCKS_PER_SEC; + return new NativeElement( product->data().id(), parent_id, diff --git a/src/ifcgeom/schema_agnostic/Converter.h b/src/ifcgeom/schema_agnostic/Converter.h index 1f28e284fe..310bdc5785 100644 --- a/src/ifcgeom/schema_agnostic/Converter.h +++ b/src/ifcgeom/schema_agnostic/Converter.h @@ -76,10 +76,18 @@ namespace ifcopenshell { namespace geometry { } */ + double total_map_time = 0.; + double total_geom_time = 0.; + ifcopenshell::geometry::ConversionResults convert(IfcUtil::IfcBaseClass* item) { + std::clock_t map_start = std::clock(); auto geom_item = mapping_->map(item); + std::clock_t geom_start = std::clock(); ifcopenshell::geometry::ConversionResults results; kernel_->convert(geom_item, results); + std::clock_t geom_end = std::clock(); + total_map_time += (geom_start - map_start) / (double) CLOCKS_PER_SEC; + total_geom_time += (geom_end - geom_start) / (double) CLOCKS_PER_SEC; return results; } From a8054968956e6a515521be9b7fb275b0ee2ec122 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 29 Jan 2020 17:29:33 +0100 Subject: [PATCH 205/235] Disable polyline point removal --- src/ifcgeom/schema/mapping.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index c27a0d3892..ccf91b2e69 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -1277,12 +1277,14 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcPolyline* inst) { const double eps = precision_ * 10; const bool closed_by_proximity = polygon.size() >= 3 && (polygon.front().components - polygon.back().components).norm() < eps; + + // @todo this removes the end point, since it's identical to the beginning. if (closed_by_proximity) { - polygon.resize(polygon.size() - 1); + // polygon.resize(polygon.size() - 1); } // Remove points that are too close to one another - remove_duplicate_points_from_loop(polygon, closed_by_proximity, eps); + // remove_duplicate_points_from_loop(polygon, closed_by_proximity, eps); if (polygon.size() < 2) { return false; From cbf147b9f9b3ba2848e689f5d51273d4276567a5 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 31 Jan 2020 11:57:52 +0100 Subject: [PATCH 206/235] area overlap --- src/ifcconvert/validate_wall_connectivity.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ifcconvert/validate_wall_connectivity.cpp b/src/ifcconvert/validate_wall_connectivity.cpp index ef7aedbfe4..6429da02c3 100644 --- a/src/ifcconvert/validate_wall_connectivity.cpp +++ b/src/ifcconvert/validate_wall_connectivity.cpp @@ -102,7 +102,7 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo } CGAL::Polygon_mesh_processing::triangulate_faces(x_poly); - if (CGAL::Polygon_mesh_processing::area(x_poly) > 2.0) { + if (CGAL::Polygon_mesh_processing::area(x_poly) > 4.0) { return; } From bca78e086db96ba8955c5cdd2a794a93a25617c7 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 31 Jan 2020 11:58:14 +0100 Subject: [PATCH 207/235] Storey containment fuzziness --- src/ifcconvert/validate_storey_containment.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/ifcconvert/validate_storey_containment.cpp b/src/ifcconvert/validate_storey_containment.cpp index c6c4564c16..64596f68cf 100644 --- a/src/ifcconvert/validate_storey_containment.cpp +++ b/src/ifcconvert/validate_storey_containment.cpp @@ -68,6 +68,10 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b }); } + std::for_each(elevation_slices.begin(), elevation_slices.end(), [](std::pair& p) { + p.first -= 0.3; + p.second += 0.3; + }); std::vector> nefs; std::transform(elevation_slices.begin(), elevation_slices.end(), std::back_inserter(nefs), [&LARGE](const std::pair& p) { @@ -166,11 +170,12 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b continue; } - std::vector::iterator accumulator; + std::vector::iterator accumulator = intersection_volumes.begin(); std::for_each(nefs.begin(), nefs.end(), [&accumulator, &part_nef](const CGAL::Nef_polyhedron_3& storey_nef) { auto poly = ifcopenshell::geometry::utils::create_polyhedron(part_nef * storey_nef); CGAL::Polygon_mesh_processing::triangulate_faces(poly); - accumulator++ += CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)); + *accumulator += CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)); + accumulator++; }); } @@ -182,10 +187,13 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b std::wcout << std::endl; */ - auto idx = std::max_element(intersection_volumes.begin(), intersection_volumes.end()) - intersection_volumes.begin(); - if (storeys_sorted[idx] != elem_to_storey[geom_object->product()]) { + auto calc_idx = std::max_element(intersection_volumes.begin(), intersection_volumes.end()) - intersection_volumes.begin(); + auto calc_overlap = intersection_volumes[calc_idx]; + auto assigned_idx = std::distance(storeys_sorted.begin(), std::find(storeys_sorted.begin(), storeys_sorted.end(), elem_to_storey[geom_object->product()])); + auto assigned_overlap = intersection_volumes[assigned_idx]; + if (calc_overlap > 0 && assigned_overlap < calc_overlap * 0.9) { auto s = geom_object->product()->get_value("GlobalId"); - auto s1 = ((IfcUtil::IfcBaseEntity*)storeys_sorted[idx])->get_value("GlobalId"); + auto s1 = ((IfcUtil::IfcBaseEntity*)storeys_sorted[calc_idx])->get_value("GlobalId"); auto s2 = ((IfcUtil::IfcBaseEntity*)elem_to_storey[geom_object->product()])->get_value("GlobalId"); Logger::Error("Element " + s + " contained in " + s2 + " located on " + s1); } From 6b250b3ccf21301f989f66e159ce16006cd5f20c Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sat, 1 Feb 2020 11:15:40 +0100 Subject: [PATCH 208/235] manifold solid brep --- src/ifcgeom/schema/mapping.cpp | 8 ++++++++ src/ifcgeom/schema/mapping.i | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index ccf91b2e69..d59273fd91 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -219,12 +219,20 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcFaceBasedSurfaceModel* ins return map_to_collection(this, inst->FbsmFaces()); } +taxonomy::item* mapping::map_impl(const IfcSchema::IfcManifoldSolidBrep* inst) { + // @todo voids + return map(inst->Outer()); +} + taxonomy::item* mapping::map_impl(const IfcSchema::IfcGeometricSet* inst) { return map_to_collection(this, inst->Elements()); } taxonomy::item* mapping::map_impl(const IfcSchema::IfcConnectedFaceSet* inst) { auto shell = map_to_collection(this, inst->CfsFaces()); + if (shell == nullptr) { + return nullptr; + } shell->closed = inst->declaration().is(IfcSchema::IfcClosedShell::Class()); return shell; } diff --git a/src/ifcgeom/schema/mapping.i b/src/ifcgeom/schema/mapping.i index f743319b09..94856533f3 100644 --- a/src/ifcgeom/schema/mapping.i +++ b/src/ifcgeom/schema/mapping.i @@ -34,7 +34,7 @@ BIND(IfcMappedItem); // IfcAdvancedBrep included // IfcFacetedBrepWithVoids included // IfcAdvancedBrepWithVoids included -// BIND(IfcManifoldSolidBrep); +BIND(IfcManifoldSolidBrep); BIND(IfcGeometricSet); #ifdef SCHEMA_HAS_IfcCylindricalSurface From df6852d2ace6ac97f8f1f35282673d2121763966 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sat, 1 Feb 2020 11:16:09 +0100 Subject: [PATCH 209/235] space boundaries --- src/ifcconvert/validate_space_boundaries.cpp | 80 ++++++++++++++------ 1 file changed, 55 insertions(+), 25 deletions(-) diff --git a/src/ifcconvert/validate_space_boundaries.cpp b/src/ifcconvert/validate_space_boundaries.cpp index b555eb19d6..1d8814676c 100644 --- a/src/ifcconvert/validate_space_boundaries.cpp +++ b/src/ifcconvert/validate_space_boundaries.cpp @@ -17,7 +17,7 @@ typedef CGAL::AABB_tree Tree; typedef Tree::Point_and_primitive_id Point_and_primitive_id; void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) { - intersection_validator v(f, { "IfcWall", "IfcSpace" }, 1.e-5, no_progress, quiet, stderr_progress); + intersection_validator v(f, { "IfcWall", "IfcSpace", "IfcSlab", "IfcCovering" }, 1.e-5, no_progress, quiet, stderr_progress); auto rels = f.instances_by_type("IfcRelSpaceBoundary"); @@ -39,6 +39,10 @@ void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, boo std::set rels_encounted; IfcParse::IfcFile f2("boundaries-triangulated.ifc"); + if (!f2.good()) { + return; + } + ifcopenshell::geometry::settings settings; settings.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, false); @@ -57,6 +61,9 @@ void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, boo auto g1 = n.substr(0, 22); auto g2 = n.substr(23); auto item = c.mapping()->map(i); + if (((ifcopenshell::geometry::taxonomy::collection*) item)->children[0] == nullptr) { + continue; + } auto shell = (taxonomy::shell*) ((taxonomy::collection*)((taxonomy::collection*) item)->children[0])->children[0]; for (auto& f : shell->children) { auto face = (taxonomy::face*) f; @@ -72,8 +79,10 @@ void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, boo } } } - - v([&rel_by_space_elem, &elem_to_space_boundary_coords](const intersection_validator::Box& a, const intersection_validator::Box& b) { + + std::set< std::set > guid_pairs_visited; + + v([&rel_by_space_elem, &elem_to_space_boundary_coords, &guid_pairs_visited](const intersection_validator::Box& a, const intersection_validator::Box& b) { std::ostringstream ss; // ss << id_map[a.id()]->first->data().toString() << "x" << id_map[b.id()]->first->data().toString() << std::endl; // auto x = id_map[a.id()]->second * id_map[b.id()]->second; @@ -99,57 +108,78 @@ void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, boo auto x = a.handle()->second * b.handle()->second; if (x.is_empty()) { - // std::wcout << "empty" << std::endl; return; } + guid_pairs_visited.insert({ Aguid, Bguid }); + cgal_shape_t x_poly; x.convert_to_polyhedron(x_poly); - auto s0 = a.handle()->first->declaration().name(); - auto s1 = b.handle()->first->declaration().name(); - auto i0 = a.handle()->first->data().id(); - auto i1 = b.handle()->first->data().id(); - - if (s0 < s1) { - std::swap(s1, s0); - std::swap(i0, i1); + { + std::string fn = "computed_boundaries_" + Aguid + "_" + Bguid + ".off"; + std::ofstream computed_boundaries(fn.c_str()); + computed_boundaries.precision(17); + computed_boundaries << x_poly; } Tree tree(faces(x_poly).first, faces(x_poly).second, x_poly); tree.accelerate_distance_queries(); - for (auto& p : elem_to_space_boundary_coords[{Aguid, Bguid}]) { - auto d = std::sqrt(CGAL::to_double(tree.squared_distance(p))); - std::wcout << d << std::endl; + auto itelem = elem_to_space_boundary_coords.find({ Aguid, Bguid }); + + if (itelem == elem_to_space_boundary_coords.end()) { + Logger::Error("Missing space boundary relationship " + Aguid + " " + Bguid); + return; } - return; + const auto& coords = itelem->second; + std::vector distances; + std::transform(coords.begin(), coords.end(), std::back_inserter(distances), [&tree](const auto& p) { + return std::sqrt(CGAL::to_double(tree.squared_distance(p))); + }); - { - auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "sb.off"; + bool valid = *std::max_element(distances.begin(), distances.end()) < 0.4; - std::ofstream os(FN.c_str()); - os.precision(17); - os << x_poly; + if (!valid) { + Logger::Error("Wrong connection geometry " + Aguid + " " + Bguid); } - remove_thickness r(x_poly); + /*{ + remove_thickness r(x_poly); + std::string fn = "thin_computed_boundaries_" + Aguid + "_" + Bguid + ".off"; + std::ofstream computed_boundaries(fn.c_str()); + computed_boundaries.precision(17); + computed_boundaries << r.flattened; + }*/ + /* { auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "-sides-sb.off"; - std::ofstream os(FN.c_str()); os.precision(17); os << r.polyhedron2; } - { auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "-flat-sb.off"; - std::ofstream os(FN.c_str()); os.precision(17); os << r.flattened; } + */ }); + + auto is_wall_space_or_slab = [&f](const std::string& g) { + auto decl = f.instance_by_guid(g)->declaration(); + return decl.is("IfcWall") || decl.is("IfcSpace") || decl.is("IfcSlab"); + }; + + for (auto& i : *f2.instances_by_type("IfcProduct")) { + auto n = ((IfcUtil::IfcBaseEntity*)i)->get_value("Name"); + auto g1 = n.substr(0, 22); + auto g2 = n.substr(23); + if (is_wall_space_or_slab(g1) && is_wall_space_or_slab(g2) && guid_pairs_visited.find({ g1, g2 }) == guid_pairs_visited.end()) { + Logger::Error("Space boundary for non-bounding geometry " + g1 + " " + g2); + } + } } From 60b160461eefc9c849bc4e9562557909e5efccdd Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sat, 1 Feb 2020 11:23:01 +0100 Subject: [PATCH 210/235] Update README --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 785fb6feb6..bebcc25936 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,10 @@ +About this branch +================= + +This version splits the geometry interpretation process into two steps (a) map IFC to a smaller set of schema-agnostic definitions (`ifcopenshell::geometry::taxonomy`) (b) convert these into explicit breps or polyhedra with Open CASCADE or CGAL. + +Three validation options are added to IfcConvert for (a) storey containment (b) wall connectivity (c) space boundaries. + IfcOpenShell ============ IfcOpenShell is an open source ([LGPL]) software library for working with the Industry Foundation Classes ([IFC]) From 4aef5dbd106dfe63fbdec1c571513fe69e691a8e Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Mon, 23 Mar 2020 09:20:01 +0100 Subject: [PATCH 211/235] Small fixes --- src/ifcconvert/validation_utils.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ifcconvert/validation_utils.h b/src/ifcconvert/validation_utils.h index 42f367b520..f629461a55 100644 --- a/src/ifcconvert/validation_utils.h +++ b/src/ifcconvert/validation_utils.h @@ -68,7 +68,7 @@ struct Build_Offset : public CGAL::Modifier_base { }; template -std::list connected_faces(cgal_shape_t::Facet_handle& f, const Ts& excluded) { +std::list connected_faces(cgal_shape_t::Facet_handle f, const Ts& excluded) { std::set fs = { f }; std::function process; @@ -449,7 +449,8 @@ struct intersection_validator { return; } - auto cube = ifcopenshell::geometry::utils::create_nef_polyhedron(ifcopenshell::geometry::utils::create_cube(eps)); + auto polycube = ifcopenshell::geometry::utils::create_cube(eps); + auto cube = ifcopenshell::geometry::utils::create_nef_polyhedron(polycube); size_t num_created = 0; int old_progress = quiet ? 0 : -1; From 048ee84ae6760e85b2039785cec199137fb6a558 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 27 Mar 2020 14:06:43 +0100 Subject: [PATCH 212/235] Propagate failure on representation to product --- src/ifcgeom/schema/mapping.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index d59273fd91..549baeaf82 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -348,7 +348,13 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcProduct* inst) { n->instance = inst; c->children = { n }; } else { - c->children = { map(body) }; + auto child = map(body); + if (child) { + c->children = { child }; + } else { + delete c; + return nullptr; + } } return c; } From 3113976ee5306df0350237fa5ebc949fda853581 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Mon, 30 Mar 2020 14:31:59 +0200 Subject: [PATCH 213/235] Implement fillets and a couple of profiles --- .../kernels/opencascade/IfcGeomShapes.cpp | 29 ++- src/ifcgeom/schema/mapping.cpp | 216 +++++++++++++++++- src/ifcgeom/schema/mapping.i | 10 +- src/ifcgeom/taxonomy.h | 2 +- 4 files changed, 234 insertions(+), 23 deletions(-) diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp index f17955d9bf..f8a69b0d29 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp @@ -565,12 +565,6 @@ namespace { curve_creation_visitor_result_type operator()(const taxonomy::circle& c) { const auto& m = c.matrix.components; - /*Eigen::IOFormat fmt; - std::stringstream ss; - ss << m.format(fmt) << std::endl; - ss << m.col(3).format(fmt); - auto s = ss.str(); - std::wcout << s.c_str() << std::endl;*/ return result = Handle(Geom_Curve)(new Geom_Circle(gp_Ax2(convert_xyz2(m.col(3)), convert_xyz2(m.col(2)), convert_xyz2(m.col(0))), c.radius)); } @@ -609,17 +603,36 @@ namespace { curve = approx.Curve(); } + const bool reversed = !((taxonomy::geom_item*)e.basis)->orientation.get_value_or(true); + const bool is_conic = e.basis->kind() == taxonomy::ELLIPSE || e.basis->kind() == taxonomy::CIRCLE; + // @todo, copy over logic from previous IfcTrimmedCurve handling - if (e.start.which() == 0) { + if (e.start.which() == 0) { auto p1 = convert_xyz(boost::get(e.start)); auto p2 = convert_xyz(boost::get(e.end)); + if (reversed) { + std::swap(p1, p2); + } + E = BRepBuilderAPI_MakeEdge(curve, p1, p2).Edge(); } else { auto v1 = boost::get(e.start); auto v2 = boost::get(e.end); - E = BRepBuilderAPI_MakeEdge(curve, v1, v2).Edge(); + if (reversed) { + std::swap(v1, v2); + } + + if (is_conic && ALMOST_THE_SAME(fmod(v2 - v1, M_PI*2.), 0.)) { + E = BRepBuilderAPI_MakeEdge(curve).Edge(); + } else { + E = BRepBuilderAPI_MakeEdge(curve, v1, v2).Edge(); + } + } + + if (reversed) { + E.Reverse(); } } else { if (e.start.which() != 0) { diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index 549baeaf82..6d5d72afbd 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -17,6 +17,9 @@ * * ********************************************************************************/ +#define _USE_MATH_DEFINES +#include + #include "mapping.h" #include "../../ifcparse/IfcLogger.h" @@ -70,6 +73,8 @@ namespace { loop_to_face_upgrade(taxonomy::item* item) { taxonomy::loop* loop = dynamic_cast(item); if (loop) { + loop->external = true; + face_ = taxonomy::face(); face_->instance = loop->instance; face_->matrix = loop->matrix; @@ -1122,10 +1127,10 @@ namespace { boost::optional radius; }; - struct profile_point_with_neighbours { - std::array xy; + struct profile_point_with_edges { + Eigen::Vector2d xy; boost::optional radius; - profile_point* previous, *next; + taxonomy::edge *previous, *next; }; taxonomy::loop* polygon_from_points(const std::vector& ps, bool external = true) { @@ -1206,13 +1211,67 @@ namespace { }); ps.push_back(ps.front()); - return polygon_from_points(ps); + auto loop = polygon_from_points(ps); + + std::vector pps(points.size()); + for (int b = 0; b < points.size(); ++b) { + int c = (b - 1) % points.size(); + pps[b] = { Eigen::Vector2d(points[b].xy[0], points[b].xy[1]), points[b].radius, (taxonomy::edge*) loop->children[c], (taxonomy::edge*) loop->children[b]}; + } + + size_t i = pps.size(); + while (i--) { + const auto& p = pps[i]; + if (p.radius && *p.radius > 0.) { + // Position is a IfcAxis2Placement2D, so should remain 2d points + auto p0 = boost::get(p.previous->start).components.head<2>(); + auto p1a = boost::get(p.previous->end).components.head<2>(); + auto p2 = boost::get(p.next->end).components.head<2>(); + auto p1b = boost::get(p.next->start).components.head<2>(); + + auto ba_ = p0 - p1a; + auto bc_ = p2 - p1b; + + auto ba = ba_.normalized(); + auto bc = bc_.normalized(); + + const double angle = std::acos(ba.dot(bc)); + const double inset = *p.radius / std::tan(angle / 2.); + + boost::get(p.previous->end).components.head<2>() += ba * inset; + boost::get(p.next->start).components.head<2>() += bc * inset; + + auto e = new taxonomy::edge; + e->start = p.previous->end; + e->end = p.next->start; + + auto ab = Eigen::Vector3d(-ba(1), +ba(0), 0.); + + double sign = ab.head<2>().dot(bc) > 0 ? 1. : -1.; + + auto O = boost::get(p.previous->end).components.head<3>() + ab * *p.radius * sign; + + auto c = new taxonomy::circle; + c->matrix.components = Eigen::Affine3d(Eigen::Translation3d(O)).matrix(); + c->radius = *p.radius; + e->basis = c; + c->orientation = sign == -1.; + + loop->children.insert(std::find(loop->children.begin(), loop->children.end(), p.next), e); + } + }; + + return loop; } } taxonomy::item* mapping::map_impl(const IfcSchema::IfcRectangleProfileDef* inst) { const double x = inst->XDim() / 2.0f * length_unit_; const double y = inst->YDim() / 2.0f * length_unit_; + boost::optional radius; + if (inst->as()) { + radius = inst->as()->RoundingRadius() * length_unit_; + } // @todo const double precision_ = 1.e-5; @@ -1223,10 +1282,150 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcRectangleProfileDef* inst) } return profile_helper(this, inst, { - {{-x, -y}}, - {{+x, -y}}, - {{+x, +y}}, - {{-x, +y}}, + {{-x, -y}, radius}, + {{+x, -y}, radius}, + {{+x, +y}, radius}, + {{-x, +y}, radius}, + }); +} + +taxonomy::item* mapping::map_impl(const IfcSchema::IfcRectangleHollowProfileDef* inst) { + const double x = inst->XDim() / 2.0f * length_unit_; + const double y = inst->YDim() / 2.0f * length_unit_; + const double d = inst->WallThickness() * length_unit_; + + boost::optional radius1, radius2; + if (inst->hasOuterFilletRadius()) { + radius1 = inst->OuterFilletRadius() * length_unit_; + } + if (inst->hasInnerFilletRadius()) { + radius2 = inst->InnerFilletRadius() * length_unit_; + } + + // @todo + const double precision_ = 1.e-5; + + if (x < precision_ || y < precision_) { + Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", inst); + return nullptr; + } + + auto outer_loop = profile_helper(this, inst, { + {{-x, -y}, radius1}, + {{+x, -y}, radius1}, + {{+x, +y}, radius1}, + {{-x, +y}, radius1}, + }); + outer_loop->external = true; + + auto inner_loop = profile_helper(this, inst, { + {{-x + d, -y + d}, radius2}, + {{+x - d, -y + d}, radius2}, + {{+x - d, +y - d}, radius2}, + {{-x + d, +y - d}, radius2}, + }); + inner_loop->reverse(); + inner_loop->external = false; + + auto face = new taxonomy::face; + face->children = { outer_loop, inner_loop }; + + // @todo is this necessary; + std::swap(outer_loop->matrix, face->matrix); + inner_loop->matrix = outer_loop->matrix; + + return face; +} + +taxonomy::item* mapping::map_impl(const IfcSchema::IfcCircleProfileDef* inst) { + std::vector radii = { inst->Radius() * length_unit_ }; + + if (inst->as()) { + double t = inst->as()->WallThickness() * length_unit_; + radii.push_back(radii.front() - t); + } + + auto f = new taxonomy::face; + + for (auto it = radii.begin(); it != radii.end(); ++it) { + const double r = *it; + const bool exterior = it == radii.begin(); + + auto c = new taxonomy::circle; + c->radius = r; + + bool has_position = true; +#ifdef SCHEMA_IfcParameterizedProfileDef_Position_IS_OPTIONAL + has_position = inst->hasPosition(); +#endif + if (has_position) { + taxonomy::matrix4 m = as(map(inst->Position())); + c->matrix = m.components; + } + + auto e = new taxonomy::edge; + e->basis = c; + e->start = 0.; + e->end = 2 * M_PI; + + auto l = new taxonomy::loop; + l->children = { e }; + l->external = exterior; + + f->children.push_back(l); + } + + return f; +} + +taxonomy::item* mapping::map_impl(const IfcSchema::IfcIShapeProfileDef* inst) { + const double x1 = inst->OverallWidth() / 2.0f * length_unit_; + const double y = inst->OverallDepth() / 2.0f * length_unit_; + const double d1 = inst->WebThickness() / 2.0f * length_unit_; + const double dy1 = inst->FlangeThickness() * length_unit_; + + bool doFillet1 = inst->hasFilletRadius(); + double f1 = 0.; + if (doFillet1) { + f1 = inst->FilletRadius() * length_unit_; + } + + bool doFillet2 = doFillet1; + double x2 = x1, dy2 = dy1, f2 = f1; + + if (inst->declaration().is(IfcSchema::IfcAsymmetricIShapeProfileDef::Class())) { + IfcSchema::IfcAsymmetricIShapeProfileDef* assym = (IfcSchema::IfcAsymmetricIShapeProfileDef*) inst; + x2 = assym->TopFlangeWidth() / 2. * length_unit_; + doFillet2 = assym->hasTopFlangeFilletRadius(); + if (doFillet2) { + f2 = assym->TopFlangeFilletRadius() * length_unit_; + } + if (assym->hasTopFlangeThickness()) { + dy2 = assym->TopFlangeThickness() * length_unit_; + } + } + + // @todo + const double precision_ = 1.e-5; + + if (x1 < precision_ || x2 < precision_ || y < precision_ || d1 < precision_ || dy1 < precision_ || dy2 < precision_) { + Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", inst); + return false; + } + + return profile_helper(this, inst, { + {{-x1,-y}}, + {{x1,-y}}, + {{x1,-y + dy1}}, + {{d1,-y + dy1}, f1}, + {{d1,y - dy2}, f2}, + {{x2,y - dy2}}, + {{x2,y}}, + {{-x2,y}}, + {{-x2,y - dy2}}, + {{-d1,y - dy2}, f2}, + {{-d1,-y + dy1}, f1}, + {{-x1,-y + dy1}} }); } @@ -1389,7 +1588,6 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcTrimmedCurve* inst) { // @todo const double precision_ = 1.e-5; - const double M_PI = 3.141592653; trim_cartesian &= has_pnts[0] && has_pnts[1]; if (trim_cartesian) { diff --git a/src/ifcgeom/schema/mapping.i b/src/ifcgeom/schema/mapping.i index 94856533f3..6c81f9058a 100644 --- a/src/ifcgeom/schema/mapping.i +++ b/src/ifcgeom/schema/mapping.i @@ -74,19 +74,19 @@ BIND(IfcHalfSpaceSolid); // IfcArbitraryProfileDefWithVoids included BIND(IfcArbitraryClosedProfileDef); -// BIND(IfcRoundedRectangleProfileDef); -// BIND(IfcRectangleHollowProfileDef); +BIND(IfcRectangleHollowProfileDef); +// IfcRoundedRectangleProfileDef included BIND(IfcRectangleProfileDef); // BIND(IfcTrapeziumProfileDef) // BIND(IfcCShapeProfileDef); // IfcAsymmetricIShapeProfileDef included -// BIND(IfcIShapeProfileDef); +BIND(IfcIShapeProfileDef); // BIND(IfcLShapeProfileDef); // BIND(IfcTShapeProfileDef); // BIND(IfcUShapeProfileDef); // BIND(IfcZShapeProfileDef); -// BIND(IfcCircleHollowProfileDef); -// BIND(IfcCircleProfileDef); +// IfcCircleHollowProfileDef included +BIND(IfcCircleProfileDef); // BIND(IfcEllipseProfileDef); // BIND(IfcCenterLineProfileDef); // BIND(IfcCompositeProfileDef); diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index 696857b3db..0a0bc1bea4 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -161,7 +161,7 @@ struct trimmed_curve : public curve { trimmed_curve() : basis(nullptr), orientation(true) {} virtual void reverse() { - std::swap(start, end); + // std::swap(start, end); orientation = !orientation; } }; From 4d23a442befe59fc9cd72daa3557b93911dcbddc Mon Sep 17 00:00:00 2001 From: aothms Date: Fri, 3 Apr 2020 12:00:48 +0000 Subject: [PATCH 214/235] Eigen in nix build --- nix/build-all.py | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/nix/build-all.py b/nix/build-all.py index 5713b75ef9..65f990424e 100644 --- a/nix/build-all.py +++ b/nix/build-all.py @@ -217,26 +217,19 @@ cecho(""" - How many compiler processes may be run in parallel. dependency_tree = { 'IfcParse': ('boost', 'libxml2'), - 'IfcGeom': ('IfcParse', 'occ', 'cgal', 'voxel'), + 'IfcGeom': ('IfcParse', 'occ', 'cgal', 'voxel', 'eigen'), 'IfcConvert': ('IfcGeom', 'OpenCOLLADA', 'json'), 'OpenCOLLADA': ('libxml2', 'pcre'), 'IfcGeomServer': ('IfcGeom', ), 'IfcOpenShell-Python': ('python', 'swig', 'IfcGeom'), 'voxel': ('occ',), 'swig': ('pcre',), - 'boost': (), - 'libxml2': (), - 'python': (), - 'swig': (), 'occ': (), - 'cgal': (), - 'pcre': (), - 'json': () } def v(dep): yield dep - for d in dependency_tree[dep]: + for d in dependency_tree.get(dep, []): for x in v(d): yield x @@ -254,8 +247,8 @@ PIC = "-fPIC" if BUILD_STATIC else "" if len(tgts): targets = set(sum((list(v(target)) for target in tgts), [])) else: - targets = set(dependency_tree.keys()) - + targets = set(tuple(dependency_tree.keys()) + sum(dependency_tree.values(), ())) + print("Building:", *sorted(targets, key=lambda t: len(list(v(t))))) # Check that required tools are in PATH @@ -516,6 +509,17 @@ if "json" in targets: os.makedirs(os.path.dirname(json_install_path)) if not os.path.exists(json_install_path): urlretrieve(json_url, json_install_path) + +if "eigen" in targets: + eigen_url = "http://bitbucket.org/eigen/eigen/get/3.3.7.tar.gz" + eigen_build_path = "{DEPS_DIR}/build/Eigen-3.3.7.tar.gz".format(**locals()) + eigen_install_path = "{DEPS_DIR}/install/Eigen-3.3.7/Eigen".format(**locals()) + if not os.path.exists(eigen_build_path): + urlretrieve(eigen_url, eigen_build_path) + if not os.path.exists(eigen_install_path): + if not os.path.exists(os.path.dirname(eigen_install_path)): + os.makedirs(os.path.dirname(eigen_install_path)) + run([tar, "-xf", eigen_build_path, "--strip-components", "1", "-C", os.path.dirname(eigen_install_path), "eigen-eigen-323c052e1731/Eigen"]) if "pcre" in targets: build_dependency( @@ -722,7 +726,8 @@ cmake_args=[ "-DCMAKE_INSTALL_PREFIX=" "{DEPS_DIR}/install/ifcopenshell".format(**locals()), "-DBOOST_ROOT=" "{DEPS_DIR}/install/boost-{BOOST_VERSION}".format(**locals()), "-DGLTF_SUPPORT=" "ON", - "-DJSON_INCLUDE_DIR=" "{DEPS_DIR}/install/json".format(**locals()) + "-DJSON_INCLUDE_DIR=" "{DEPS_DIR}/install/json".format(**locals()), + "-DEIGEN_DIR=" "{DEPS_DIR}/install/Eigen-3.3.7".format(**locals()) ] if "occ" in targets: @@ -802,6 +807,7 @@ if "IfcOpenShell-Python" in targets: "-DPYTHON_LIBRARY=" +PYTHON_LIBRARY, "-DPYTHON_EXECUTABLE=" +PYTHON_EXECUTABLE, "-DPYTHON_INCLUDE_DIR=" +PYTHON_INCLUDE, + "-DEIGEN_DIR=" "{DEPS_DIR}/install/Eigen-3.3.7".format(**locals()), "-DSWIG_EXECUTABLE=" "{DEPS_DIR}/install/swig/bin/swig".format(**locals()), "-DCMAKE_INSTALL_PREFIX=" "{DEPS_DIR}/install/ifcopenshell/tmp".format(**locals()), "-DLIBXML2_INCLUDE_DIR=" "{DEPS_DIR}/install/libxml2-{LIBXML2_VERSION}/include/libxml2".format(**locals()), From 33e092c8d5443ece3548ac81a145876d21b996b6 Mon Sep 17 00:00:00 2001 From: aothms Date: Fri, 3 Apr 2020 12:01:30 +0000 Subject: [PATCH 215/235] Update occt tree --- src/ifcgeom/kernels/opencascade/IfcGeomTree.h | 23 +++++++------------ .../kernels/opencascade/OpenCascadeKernel.h | 6 ++--- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomTree.h b/src/ifcgeom/kernels/opencascade/IfcGeomTree.h index 060217a2c7..5cd590658a 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomTree.h +++ b/src/ifcgeom/kernels/opencascade/IfcGeomTree.h @@ -24,7 +24,7 @@ #include "../../../ifcgeom/schema_agnostic/IfcGeomElement.h" #include "../../../ifcgeom/schema_agnostic/IfcGeomIterator.h" #include "../../../ifcgeom/schema_agnostic/Converter.h" -#include "../../../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h" +#include "../../../ifcgeom/kernels/opencascade/OpenCascadeKernel.h" #include #include @@ -114,8 +114,7 @@ namespace ifcopenshell { namespace geometry { std::vector ts_filtered; const TopoDS_Shape& A = shapes_.find(t)->second; - OpenCascadeShape SA(A); - if (IfcGeom::Kernel::count(&SA, (int) TopAbs_SHELL) == 0) { + if (kernels::OpenCascadeKernel::count(A, TopAbs_SHELL) == 0) { return ts_filtered; } @@ -124,24 +123,21 @@ namespace ifcopenshell { namespace geometry { typename std::vector::const_iterator it = ts.begin(); for (it = ts.begin(); it != ts.end(); ++it) { const TopoDS_Shape& B = shapes_.find(*it)->second; - OpenCascadeShape SB(B); - if (IfcGeom::Kernel::count(&SB, (int) TopAbs_SHELL) == 0) { + if (kernels::OpenCascadeKernel::count(B, TopAbs_SHELL) == 0) { continue; } if (completely_within) { BRepAlgoAPI_Cut cut(B, A); if (cut.IsDone()) { - OpenCascadeShape Sc(cut.Shape()); - if (IfcGeom::Kernel::count(&Sc, (int) TopAbs_SHELL) == 0) { + if (kernels::OpenCascadeKernel::count(cut.Shape(), TopAbs_SHELL) == 0) { ts_filtered.push_back(*it); } } } else { BRepAlgoAPI_Common common(A, B); if (common.IsDone()) { - OpenCascadeShape Sc(common.Shape()); - if (IfcGeom::Kernel::count(&Sc, (int) TopAbs_SHELL) > 0) { + if (kernels::OpenCascadeKernel::count(common.Shape(), TopAbs_SHELL) > 0) { ts_filtered.push_back(*it); } } @@ -157,8 +153,7 @@ namespace ifcopenshell { namespace geometry { std::vector ts; - OpenCascadeShape Ss(s); - if (IfcGeom::Kernel::count(&Ss, (int) TopAbs_SHELL) == 0) { + if (kernels::OpenCascadeKernel::count(s, TopAbs_SHELL) == 0) { return ts; } @@ -175,15 +170,13 @@ namespace ifcopenshell { namespace geometry { for (it = ts.begin(); it != ts.end(); ++it) { const TopoDS_Shape& B = shapes_.find(*it)->second; - OpenCascadeShape SB(B); - if (IfcGeom::Kernel::count(&SB, (int) TopAbs_SHELL) == 0) { + if (kernels::OpenCascadeKernel::count(B, TopAbs_SHELL) == 0) { continue; } BRepAlgoAPI_Common common(s, B); if (common.IsDone()) { - OpenCascadeShape Sc(common.Shape());; - if (IfcGeom::Kernel::count(&Sc, (int) TopAbs_SHELL) > 0) { + if (kernels::OpenCascadeKernel::count(common.Shape(), TopAbs_SHELL) > 0) { ts_filtered.push_back(*it); } } diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h index 9f49245e58..be38bd19d8 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h @@ -227,9 +227,9 @@ namespace kernels { *this = other; } - double shape_volume(const TopoDS_Shape&); - double face_area(const TopoDS_Face&); - int count(const TopoDS_Shape& s, TopAbs_ShapeEnum t, bool unique = false); + static double shape_volume(const TopoDS_Shape&); + static double face_area(const TopoDS_Face&); + static int count(const TopoDS_Shape& s, TopAbs_ShapeEnum t, bool unique = false); bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& shape); bool create_solid_from_faces(const TopTools_ListOfShape& face_list, TopoDS_Shape& shape); From 63b9b7baa7636f1f7ee737936914c848784bf1ec Mon Sep 17 00:00:00 2001 From: aothms Date: Fri, 3 Apr 2020 12:01:58 +0000 Subject: [PATCH 216/235] Nullptr return types --- src/ifcgeom/schema/bind_convert_impl.i | 2 +- src/ifcgeom/schema/mapping.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ifcgeom/schema/bind_convert_impl.i b/src/ifcgeom/schema/bind_convert_impl.i index 32ebf485b6..8bf303533a 100644 --- a/src/ifcgeom/schema/bind_convert_impl.i +++ b/src/ifcgeom/schema/bind_convert_impl.i @@ -23,7 +23,7 @@ } catch (const std::exception& e) { \ Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l); \ } \ - return false; \ + return nullptr; \ } #include "mapping.i" diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index 6d5d72afbd..ee7fb7adb1 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -1410,7 +1410,8 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcIShapeProfileDef* inst) { if (x1 < precision_ || x2 < precision_ || y < precision_ || d1 < precision_ || dy1 < precision_ || dy2 < precision_) { Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", inst); - return false; + + return nullptr; } return profile_helper(this, inst, { @@ -1500,7 +1501,7 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcPolyline* inst) { // remove_duplicate_points_from_loop(polygon, closed_by_proximity, eps); if (polygon.size() < 2) { - return false; + return nullptr; } return polygon_from_points(polygon); @@ -1593,7 +1594,7 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcTrimmedCurve* inst) { if (trim_cartesian) { if ((pnts[0].components - pnts[1].components).norm() < (2 * precision_)) { Logger::Message(Logger::LOG_WARNING, "Skipping segment with length below tolerance level:", inst); - return false; + return nullptr; } tc->start = pnts[0]; tc->end = pnts[1]; From 47b2da60827487906272b5a11cb74901e9f345f0 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 3 Apr 2020 14:23:23 +0200 Subject: [PATCH 217/235] Fix gltf serializer compilation --- src/serializers/GltfSerializer.cpp | 27 +++++++++++++++++---------- src/serializers/GltfSerializer.h | 6 +++--- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/serializers/GltfSerializer.cpp b/src/serializers/GltfSerializer.cpp index 9c2754f2fe..99b702d82b 100644 --- a/src/serializers/GltfSerializer.cpp +++ b/src/serializers/GltfSerializer.cpp @@ -78,29 +78,32 @@ void GltfSerializer::writeHeader() { json_["materials"] = json::array(); } -int GltfSerializer::writeMaterial(const IfcGeom::Material& style) { - auto it = materials_.find(style.name()); +int GltfSerializer::writeMaterial(const ifcopenshell::geometry::taxonomy::style& style) { + // @todo is it safe to always dereference this optional? + const std::string& name = *style.name; + + auto it = materials_.find(name); if (it != materials_.end()) { return it->second; } int idx = json_["materials"].size(); - materials_[style.name()] = idx; + materials_[name] = idx; std::array base; base.fill(1.0); - if (style.hasDiffuse()) { + if (style.diffuse) { for (int i = 0; i < 3; ++i) { - base[i] = style.diffuse()[i]; + base[i] = style.diffuse->components[i]; } } - if (style.hasTransparency()) { - base[3] = 1. - style.transparency(); + if (style.transparency) { + base[3] = 1. - *style.transparency; } json_["materials"].push_back({ {"pbrMetallicRoughness", {{"baseColorFactor", base}, {"metallicFactor", 0}}} }); - if (style.hasTransparency() && style.transparency() > 1.e-9) { + if (style.transparency && *style.transparency > 1.e-9) { json_["materials"].back()["alphaMode"] = "BLEND"; } @@ -157,14 +160,17 @@ size_t write_accessor(json& j, std::ofstream& ofs, It begin, It end) { return j["accessors"].size() - 1; } -void GltfSerializer::write(const IfcGeom::TriangulationElement* o) { +void GltfSerializer::write(const ifcopenshell::geometry::TriangulationElement* o) { if (o->geometry().material_ids().empty()) { return; } node_array_.push_back(json_["nodes"].size()); - const std::vector& m = o->transformation().matrix().data(); + const double* m = o->transformation().data().components.data(); + + // @todo verify + // nb: note that this contains the Y-UP transform as well. const std::array matrix_flat = { m[0], m[ 2], -m[ 1], 0, @@ -172,6 +178,7 @@ void GltfSerializer::write(const IfcGeom::TriangulationElement* o) { m[6], m[ 8], -m[ 7], 0, m[9], m[11], -m[10], 1 }; + static const std::array identity_matrix = {1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1}; json node; diff --git a/src/serializers/GltfSerializer.h b/src/serializers/GltfSerializer.h index dc5312d9f1..4b490ab0cf 100644 --- a/src/serializers/GltfSerializer.h +++ b/src/serializers/GltfSerializer.h @@ -36,14 +36,14 @@ private: std::map materials_, meshes_; json json_, node_array_; - int writeMaterial(const IfcGeom::Material& style); + int writeMaterial(const ifcopenshell::geometry::taxonomy::style& style); public: GltfSerializer(const std::string& filename, const SerializerSettings& settings); virtual ~GltfSerializer(); bool ready(); void writeHeader(); - void write(const IfcGeom::TriangulationElement* o); - void write(const IfcGeom::NativeElement* /*o*/) {} + void write(const ifcopenshell::geometry::TriangulationElement* o); + void write(const ifcopenshell::geometry::NativeElement* /*o*/) {} void finalize(); bool isTesselated() const { return true; } void setUnitNameAndMagnitude(const std::string& /*name*/, float /*magnitude*/) {} From 5d21d26f2425d965849c8f0e106fb82747251423 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 3 Apr 2020 16:21:16 +0200 Subject: [PATCH 218/235] Fix glTF transformation --- src/serializers/GltfSerializer.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/serializers/GltfSerializer.cpp b/src/serializers/GltfSerializer.cpp index 99b702d82b..9f80d5b4f1 100644 --- a/src/serializers/GltfSerializer.cpp +++ b/src/serializers/GltfSerializer.cpp @@ -169,14 +169,12 @@ void GltfSerializer::write(const ifcopenshell::geometry::TriangulationElement* o const double* m = o->transformation().data().components.data(); - // @todo verify - - // nb: note that this contains the Y-UP transform as well. + // nb: note that this applies the Y-UP transform. const std::array matrix_flat = { - m[0], m[ 2], -m[ 1], 0, - m[3], m[ 5], -m[ 4], 0, - m[6], m[ 8], -m[ 7], 0, - m[9], m[11], -m[10], 1 + m[ 0], m[ 2], -m[ 1], m[ 3], + m[ 4], m[ 6], -m[ 5], m[ 7], + m[ 8], m[10], -m[ 9], m[11], + m[12], m[14], -m[13], m[15] }; static const std::array identity_matrix = {1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1}; From 9b391d3d477f4b4b15a4ec7334816e61bee3fa19 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 3 Apr 2020 16:24:07 +0200 Subject: [PATCH 219/235] Remove auto from lambda parameter declaration --- src/ifcconvert/validate_space_boundaries.cpp | 2 +- src/ifcconvert/validation_utils.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ifcconvert/validate_space_boundaries.cpp b/src/ifcconvert/validate_space_boundaries.cpp index 1d8814676c..94ea7bbb6a 100644 --- a/src/ifcconvert/validate_space_boundaries.cpp +++ b/src/ifcconvert/validate_space_boundaries.cpp @@ -135,7 +135,7 @@ void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, boo const auto& coords = itelem->second; std::vector distances; - std::transform(coords.begin(), coords.end(), std::back_inserter(distances), [&tree](const auto& p) { + std::transform(coords.begin(), coords.end(), std::back_inserter(distances), [&tree](const Kernel_::Point_3& p) { return std::sqrt(CGAL::to_double(tree.squared_distance(p))); }); diff --git a/src/ifcconvert/validation_utils.h b/src/ifcconvert/validation_utils.h index f629461a55..eb6e138d38 100644 --- a/src/ifcconvert/validation_utils.h +++ b/src/ifcconvert/validation_utils.h @@ -573,7 +573,7 @@ struct intersection_validator { template void operator()(Fn fn) { std::clock_t box_overlap_begin = std::clock(); - CGAL::box_self_intersection_d(boxes.begin(), boxes.end(), [](auto& x, auto& y) {}); + CGAL::box_self_intersection_d(boxes.begin(), boxes.end(), [](Box& x, Box& y) {}); std::clock_t box_overlap_end = std::clock(); total_box_time += (box_overlap_end - box_overlap_begin) / (double) CLOCKS_PER_SEC; CGAL::box_self_intersection_d(boxes.begin(), boxes.end(), fn); From bba7295edf3b6d818103ef41c47daefdff73f44b Mon Sep 17 00:00:00 2001 From: aothms Date: Fri, 3 Apr 2020 14:56:46 +0000 Subject: [PATCH 220/235] Small fixes for gcc --- nix/build-all.py | 4 +++- src/ifcconvert/validate_wall_connectivity.cpp | 2 +- src/ifcconvert/validation_utils.h | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/nix/build-all.py b/nix/build-all.py index 65f990424e..bfeb0005a7 100644 --- a/nix/build-all.py +++ b/nix/build-all.py @@ -748,7 +748,8 @@ if "cgal" in targets: "-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()) + "-DMPFR_LIBRARY_DIR=" "{DEPS_DIR}/install/mpfr-{MPFR_VERSION}/lib".format(**locals()), + "-DUSE_CGAL=ON" ]) if "OpenCOLLADA" in targets: @@ -807,6 +808,7 @@ if "IfcOpenShell-Python" in targets: "-DPYTHON_LIBRARY=" +PYTHON_LIBRARY, "-DPYTHON_EXECUTABLE=" +PYTHON_EXECUTABLE, "-DPYTHON_INCLUDE_DIR=" +PYTHON_INCLUDE, + "-DUSE_CGAL=ON", "-DEIGEN_DIR=" "{DEPS_DIR}/install/Eigen-3.3.7".format(**locals()), "-DSWIG_EXECUTABLE=" "{DEPS_DIR}/install/swig/bin/swig".format(**locals()), "-DCMAKE_INSTALL_PREFIX=" "{DEPS_DIR}/install/ifcopenshell/tmp".format(**locals()), diff --git a/src/ifcconvert/validate_wall_connectivity.cpp b/src/ifcconvert/validate_wall_connectivity.cpp index 6429da02c3..a80360c266 100644 --- a/src/ifcconvert/validate_wall_connectivity.cpp +++ b/src/ifcconvert/validate_wall_connectivity.cpp @@ -135,7 +135,7 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo std::vector parameters; - std::transform(vertices(x_poly).begin(), vertices(x_poly).end(), std::back_inserter(parameters), [&P0, D](auto& v) { + std::transform(vertices(x_poly).begin(), vertices(x_poly).end(), std::back_inserter(parameters), [&P0, D](cgal_vertex_descriptor_t& v) { return (v->point() - P0) * D; }); diff --git a/src/ifcconvert/validation_utils.h b/src/ifcconvert/validation_utils.h index eb6e138d38..bc33063eb2 100644 --- a/src/ifcconvert/validation_utils.h +++ b/src/ifcconvert/validation_utils.h @@ -15,8 +15,8 @@ template T enlarge(const T& t, double d = 1.e-5) { - T::NT min[3]; - T::NT max[3]; + typename T::NT min[3]; + typename T::NT max[3]; for (int i = 0; i < t.dimension(); ++i) { min[i] = t.min_coord(i) - d; max[i] = t.max_coord(i) + d; From 53477cc8e2a9cfb7c562e09349ca82f364bda023 Mon Sep 17 00:00:00 2001 From: aothms Date: Fri, 3 Apr 2020 15:05:50 +0000 Subject: [PATCH 221/235] Small fixes for gcc --- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index 3d6e76d9c8..391f1b26ea 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -452,13 +452,13 @@ CGAL::Polyhedron_3 ifcopenshell::geometry::utils::create_cube(double d) CGAL::Polyhedron_3 ifcopenshell::geometry::utils::create_cube(const Kernel_::Point_3& lower, const Kernel_::Point_3& upper) { cgal_face_t bottom_face; - auto& a0 = lower.cartesian(0); - auto& a1 = lower.cartesian(1); - auto& a2 = lower.cartesian(2); + auto a0 = lower.cartesian(0); + auto a1 = lower.cartesian(1); + auto a2 = lower.cartesian(2); - auto& b0 = upper.cartesian(0); - auto& b1 = upper.cartesian(1); - auto& b2 = upper.cartesian(2); + auto b0 = upper.cartesian(0); + auto b1 = upper.cartesian(1); + auto b2 = upper.cartesian(2); bottom_face.outer.push_back(Kernel_::Point_3(a0, a1, a2)); bottom_face.outer.push_back(Kernel_::Point_3(b0, a1, a2)); From 55024e1e8af5111ee06adfd75ea1b63a2b851cf0 Mon Sep 17 00:00:00 2001 From: aothms Date: Sun, 5 Apr 2020 09:41:20 +0000 Subject: [PATCH 222/235] Update cmake install directives --- cmake/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index e892f36eb5..339be1982e 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -796,6 +796,8 @@ endif() if(BUILD_CONVERT) INSTALL(TARGETS serializers ${SERIALIZER_SCHEMA_LIBRARIES} + geometry_mappings ${mapping_libraries} + geometry_kernels ${kernel_libraries} ARCHIVE DESTINATION ${LIBDIR} LIBRARY DESTINATION ${LIBDIR} RUNTIME DESTINATION ${BINDIR} From 0b659ce4f690233a46469702cf70b8f7dc4e1668 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Tue, 28 Apr 2020 13:54:41 +0200 Subject: [PATCH 223/235] Update CMakeLists.txt --- cmake/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 339be1982e..88e8d317f8 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -788,6 +788,8 @@ INSTALL(FILES ${SCHEMA_AGNOSTIC_H_FILES} ) INSTALL(TARGETS IfcGeom ${IfcGeom_libraries} + geometry_mappings ${mapping_libraries} + geometry_kernels ${kernel_libraries} ARCHIVE DESTINATION ${LIBDIR} LIBRARY DESTINATION ${LIBDIR} RUNTIME DESTINATION ${BINDIR} @@ -796,8 +798,6 @@ endif() if(BUILD_CONVERT) INSTALL(TARGETS serializers ${SERIALIZER_SCHEMA_LIBRARIES} - geometry_mappings ${mapping_libraries} - geometry_kernels ${kernel_libraries} ARCHIVE DESTINATION ${LIBDIR} LIBRARY DESTINATION ${LIBDIR} RUNTIME DESTINATION ${BINDIR} From 0fa05f7339fb9833fd600537620b9724e24e50e7 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 29 Apr 2020 10:06:23 +0200 Subject: [PATCH 224/235] Note on segfault --- src/ifcgeom/taxonomy.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index 0a0bc1bea4..bb9613c2b0 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -153,7 +153,10 @@ struct bspline_curve : public curve { }; struct trimmed_curve : public curve { + // @todo The copy constructor of point3 within the variant fails on the avx instruction + // on the default gcc in Ubuntu 18.04 and a recent AMD Ryzen. Probably due to allignment. boost::variant start, end; + // @todo somehow account for the fact that curve in IFC can be trimmed curve, polyline and composite curve as well. item* basis; bool orientation; From 185b4ef9fa8485b307de83c7bbbc6d153142d78c Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 11 Jun 2020 20:44:29 +0200 Subject: [PATCH 225/235] shell based surface model --- src/ifcgeom/schema/mapping.cpp | 4 ++++ src/ifcgeom/schema/mapping.i | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index ee7fb7adb1..715741d00c 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -224,6 +224,10 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcFaceBasedSurfaceModel* ins return map_to_collection(this, inst->FbsmFaces()); } +taxonomy::item* mapping::map_impl(const IfcSchema::IfcShellBasedSurfaceModel* inst) { + return map_to_collection(this, inst->SbsmBoundary()); +} + taxonomy::item* mapping::map_impl(const IfcSchema::IfcManifoldSolidBrep* inst) { // @todo voids return map(inst->Outer()); diff --git a/src/ifcgeom/schema/mapping.i b/src/ifcgeom/schema/mapping.i index 6c81f9058a..9ebb31fb7f 100644 --- a/src/ifcgeom/schema/mapping.i +++ b/src/ifcgeom/schema/mapping.i @@ -26,7 +26,7 @@ BIND(IfcProduct); -// BIND(IfcShellBasedSurfaceModel); +BIND(IfcShellBasedSurfaceModel); BIND(IfcFaceBasedSurfaceModel); BIND(IfcRepresentation); BIND(IfcMappedItem); From 109131961f95e59c0a1a064802e1a9b57045277d Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 11 Jun 2020 20:48:35 +0200 Subject: [PATCH 226/235] heap alloc for eigen types for alignment issues --- src/ifcconvert/validate_space_boundaries.cpp | 2 +- .../validate_storey_containment.cpp | 4 +- src/ifcconvert/validate_wall_connectivity.cpp | 4 +- src/ifcconvert/validation_utils.h | 4 +- .../kernels/cgal/CgalConversionResult.cpp | 4 +- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 11 +- .../kernels/opencascade/IfcGeomShapes.cpp | 14 +- src/ifcgeom/schema/mapping.cpp | 72 +++++---- .../schema_agnostic/ConversionResult.h | 4 +- src/ifcgeom/schema_agnostic/IfcGeomElement.h | 6 +- src/ifcgeom/taxonomy.h | 142 +++++++++++++++--- src/serializers/ColladaSerializer.cpp | 22 +-- src/serializers/GltfSerializer.cpp | 4 +- src/serializers/SvgSerializer.cpp | 2 +- .../schema_dependent/XmlSerializer.cpp | 2 +- 15 files changed, 203 insertions(+), 94 deletions(-) diff --git a/src/ifcconvert/validate_space_boundaries.cpp b/src/ifcconvert/validate_space_boundaries.cpp index 94ea7bbb6a..0f660e5901 100644 --- a/src/ifcconvert/validate_space_boundaries.cpp +++ b/src/ifcconvert/validate_space_boundaries.cpp @@ -72,7 +72,7 @@ void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, boo for (auto& e : wire->children) { auto edge = (taxonomy::edge*) e; auto p3 = boost::get(edge->start); - auto p4 = ((taxonomy::geom_item*)item)->matrix.components * p3.components.homogeneous(); + auto p4 = *((taxonomy::geom_item*)item)->matrix.components * p3.components->homogeneous(); Kernel_::Point_3 P(p4(0), p4(1), p4(2)); elem_to_space_boundary_coords[{g1, g2}].emplace_back(P); } diff --git a/src/ifcconvert/validate_storey_containment.cpp b/src/ifcconvert/validate_storey_containment.cpp index 64596f68cf..c003291230 100644 --- a/src/ifcconvert/validate_storey_containment.cpp +++ b/src/ifcconvert/validate_storey_containment.cpp @@ -132,8 +132,8 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b for (auto& g : geom_object->geometry()) { auto s = ((ifcopenshell::geometry::CgalShape*) g.Shape())->shape(); - const auto& m = g.Placement().components; - const auto& n = geom_object->transformation().data().components; + const auto& m = *g.Placement().components; + const auto& n = *geom_object->transformation().data().components; const cgal_placement_t trsf( m(0, 0), m(0, 1), m(0, 2), m(0, 3), diff --git a/src/ifcconvert/validate_wall_connectivity.cpp b/src/ifcconvert/validate_wall_connectivity.cpp index a80360c266..28de1f22e3 100644 --- a/src/ifcconvert/validate_wall_connectivity.cpp +++ b/src/ifcconvert/validate_wall_connectivity.cpp @@ -123,8 +123,8 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo auto p0 = boost::get(first_vertex); auto p1 = boost::get(last_vertex); - auto v0 = ((taxonomy::geom_item*)item)->matrix.components * p0.components.homogeneous(); - auto v1 = ((taxonomy::geom_item*)item)->matrix.components * p1.components.homogeneous(); + auto v0 = *((taxonomy::geom_item*)item)->matrix.components * p0.components->homogeneous(); + auto v1 = *((taxonomy::geom_item*)item)->matrix.components * p1.components->homogeneous(); auto P0 = Kernel_::Point_3(v0(0), v0(1), v0(2)); auto P1 = Kernel_::Point_3(v1(0), v1(1), v1(2)); diff --git a/src/ifcconvert/validation_utils.h b/src/ifcconvert/validation_utils.h index bc33063eb2..ecf4a876a4 100644 --- a/src/ifcconvert/validation_utils.h +++ b/src/ifcconvert/validation_utils.h @@ -475,8 +475,8 @@ struct intersection_validator { for (auto& g : geom_object->geometry()) { auto s = ((ifcopenshell::geometry::CgalShape*) g.Shape())->shape(); - const auto& m = g.Placement().components; - const auto& n = geom_object->transformation().data().components; + const auto& m = *g.Placement().components; + const auto& n = *geom_object->transformation().data().components; const cgal_placement_t trsf( m(0, 0), m(0, 1), m(0, 2), m(0, 3), diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index 5bbfb2537c..f0217c9c0e 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -7,8 +7,8 @@ void ifcopenshell::geometry::CgalShape::Triangulate(const settings& settings, co // Copy is made because triangulate_faces() does not accept a const argument cgal_shape_t s = shape_; - if (!place.components.isIdentity()) { - const auto& m = place.components; + if (!place.components->isIdentity()) { + const auto& m = *place.components; // @todo check const cgal_placement_t trsf( diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index 391f1b26ea..972476b3e4 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -183,17 +183,18 @@ bool CgalKernel::convert(const taxonomy::face* face, cgal_face_t& result) { } namespace { + // @todo obsolete? bool convert_curve(CgalKernel* kernel, const taxonomy::item* curve, cgal_wire_t& builder) { if (curve->kind() == taxonomy::EDGE) { auto e = (taxonomy::edge*) curve; if (true || e->basis == nullptr) { if (builder.empty()) { const auto& p = boost::get(e->start); - cgal_point_t pnt(p.components(0), p.components(1), p.components(2)); + cgal_point_t pnt((*p.components)(0), (*p.components)(1), (*p.components)(2)); builder.push_back(pnt); } const auto& p = boost::get(e->end); - cgal_point_t pnt(p.components(0), p.components(1), p.components(2)); + cgal_point_t pnt((*p.components)(0), (*p.components)(1), (*p.components)(2)); builder.push_back(pnt); } else if (e->basis->kind() == taxonomy::CIRCLE) { // @todo @@ -308,7 +309,7 @@ bool CgalKernel::convert(const taxonomy::extrusion* extrusion, cgal_shape_t &sha } // std::cout << "Face vertices: " << face.outer.size() << std::endl; - auto fs = extrusion->direction.components; + auto fs = *extrusion->direction.components; cgal_direction_t dir(fs(0), fs(1), fs(2)); // std::cout << "Direction: " << dir << std::endl; @@ -584,7 +585,7 @@ bool CgalKernel::preprocess_boolean_operand(const IfcUtil::IfcBaseClass* log_ref namespace { bool convert_placement(const ifcopenshell::geometry::taxonomy::matrix4& place, cgal_placement_t& trsf) { - const auto& m = place.components; + const auto& m = *place.components; // @todo check trsf = cgal_placement_t( @@ -623,7 +624,7 @@ bool CgalKernel::convert_impl(const taxonomy::boolean_result* br, ifcopenshell:: for (auto it = cr.begin(); it != cr.end(); ++it) { const cgal_shape_t& entity_shape_unlocated(((CgalShape*)it->Shape())->shape()); cgal_shape_t entity_shape(entity_shape_unlocated); - if (!it->Placement().components.isIdentity()) { + if (!it->Placement().components->isIdentity()) { cgal_placement_t trsf; convert_placement(it->Placement(), trsf); for (auto &vertex : vertices(entity_shape)) { diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp index f8a69b0d29..f8ab8d2e41 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp @@ -134,8 +134,8 @@ bool OpenCascadeKernel::convert(const taxonomy::extrusion* extrusion, TopoDS_Sha auto trsf = gtrsf.Trsf(); */ - auto fs = extrusion->direction.components.data(); - gp_Dir dir(fs[0], fs[1], fs[2]); + const auto& fs = *extrusion->direction.components; + gp_Dir dir(fs(0), fs(1), fs(2)); shape.Nullify(); @@ -559,17 +559,17 @@ namespace { } curve_creation_visitor_result_type operator()(const taxonomy::line& l) { - const auto& m = l.matrix.components; + const auto& m = *l.matrix.components; return result = Handle(Geom_Curve)(new Geom_Line(convert_xyz2(m.col(3)), convert_xyz2(m.col(0)))); } curve_creation_visitor_result_type operator()(const taxonomy::circle& c) { - const auto& m = c.matrix.components; + const auto& m = *c.matrix.components; return result = Handle(Geom_Curve)(new Geom_Circle(gp_Ax2(convert_xyz2(m.col(3)), convert_xyz2(m.col(2)), convert_xyz2(m.col(0))), c.radius)); } curve_creation_visitor_result_type operator()(const taxonomy::ellipse& e) { - const auto& m = e.matrix.components; + const auto& m = *e.matrix.components; return result = Handle(Geom_Curve)(new Geom_Ellipse(gp_Ax2(convert_xyz2(m.col(3)), convert_xyz2(m.col(2)), convert_xyz2(m.col(0))), e.radius, e.radius2)); } @@ -2251,7 +2251,7 @@ bool OpenCascadeKernel::flatten_shape_list(const ifcopenshell::geometry::Convers } TopoDS_Shape OpenCascadeKernel::apply_transformation(const TopoDS_Shape& s, const taxonomy::matrix4& t) { - if (t.components.isIdentity()) { + if (t.components->isIdentity()) { return s; } else { gp_GTrsf trsf; @@ -2294,7 +2294,7 @@ bool OpenCascadeKernel::convert_impl(const taxonomy::face* face, ifcopenshell::g } // @todo boundary - const auto& m = ((taxonomy::geom_item*)face->basis)->matrix.components; + const auto& m = *((taxonomy::geom_item*)face->basis)->matrix.components; gp_Pln pln(convert_xyz2(m.col(3)), convert_xyz2(m.col(2))); const gp_Pnt pnt = pln.Location().Translated(face->orientation.get_value_or(false) ? -pln.Axis().Direction() : pln.Axis().Direction()); TopoDS_Shape shape = BRepPrimAPI_MakeHalfSpace(BRepBuilderAPI_MakeFace(pln), pnt).Solid(); diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index 715741d00c..3c038fb791 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -343,14 +343,14 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcProduct* inst) { c->matrix = as(map(inst->ObjectPlacement())); if (openings->size() && !settings_.get(settings::DISABLE_OPENING_SUBTRACTIONS) && use_body) { - auto ci = c->matrix.components.inverse(); + auto ci = c->matrix.components->inverse(); IfcEntityList::ptr operands(new IfcEntityList); operands->push(body); operands->push(openings); auto n = map_to_collection(this, operands); std::for_each(n->children.begin() + 1, n->children.end(), [&ci](taxonomy::item* i) { - ((taxonomy::geom_item*)i)->matrix.components = ci * ((taxonomy::geom_item*)i)->matrix.components; + *((taxonomy::geom_item*)i)->matrix.components = ci * *((taxonomy::geom_item*)i)->matrix.components; }); n->operation = taxonomy::boolean_result::SUBTRACTION; // @todo one indirection too many @@ -372,7 +372,7 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcAxis2Placement3D* inst) { Eigen::Vector3d o, axis(0, 0, 1), refDirection, X(1, 0, 0); { taxonomy::point3 v = as(map(inst->Location())); - o = v.components; + o = *v.components; } const bool hasAxis = inst->hasAxis(); const bool hasRef = inst->hasRefDirection(); @@ -383,12 +383,12 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcAxis2Placement3D* inst) { if (hasAxis) { taxonomy::direction3 v = as(map(inst->Axis())); - axis = v.components; + axis = *v.components; } if (hasRef) { taxonomy::direction3 v = as(map(inst->RefDirection())); - refDirection = v.components; + refDirection = *v.components; } else { if (acos(axis.dot(X)) > 1.e-5) { refDirection = { 1., 0., 0. }; @@ -406,12 +406,12 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcAxis2Placement2D* inst) { Eigen::Vector3d P, axis(0, 0, 1), V(1, 0, 0); { taxonomy::point3 v = as(map(inst->Location())); - P = v.components; + P = *v.components; } const bool hasRef = inst->hasRefDirection(); if (hasRef) { taxonomy::direction3 v = as(map(inst->RefDirection())); - V = v.components; + V = *v.components; } return new taxonomy::matrix4(P, axis, V); } @@ -444,7 +444,7 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcLocalPlacement* inst) { if (relplacement->declaration().is(IfcSchema::IfcAxis2Placement3D::Class())) { taxonomy::matrix4 trsf2 = as(map(relplacement)); // @todo check - m4->components = trsf2.components * m4->components; + *m4->components = *trsf2.components * *m4->components; } if (current->hasPlacementRelTo()) { IfcSchema::IfcObjectPlacement* parent = current->PlacementRelTo(); @@ -489,14 +489,14 @@ IfcSchema::IfcProduct::list::ptr mapping::products_represented_by(const IfcSchem if (maps->size() == 1) { IfcSchema::IfcRepresentationMap* rmap = *maps->begin(); taxonomy::matrix4 origin = as(map(rmap->MappingOrigin())); - if (origin.components.isIdentity()) { + if (origin.components->isIdentity()) { IfcSchema::IfcMappedItem::list::ptr items = rmap->MapUsage(); for (IfcSchema::IfcMappedItem::list::it it = items->begin(); it != items->end(); ++it) { IfcSchema::IfcMappedItem* item = *it; if (item->StyledByItem()->size() != 0) continue; taxonomy::matrix4 target = as(map(item->MappingTarget())); - if (target.components.isIdentity()) { + if (target.components->isIdentity()) { continue; } @@ -770,10 +770,10 @@ IfcSchema::IfcRepresentation* mapping::representation_mapped_to(const IfcSchema: if (item->StyledByItem()->size() == 0) { IfcSchema::IfcMappedItem* mapped_item = item->as(); taxonomy::matrix4 target = as(map(mapped_item->MappingTarget())); - if (target.components.isIdentity()) { + if (target.components->isIdentity()) { IfcSchema::IfcRepresentationMap* rmap = mapped_item->MappingSource(); taxonomy::matrix4 origin = as(map(rmap->MappingOrigin())); - if (origin.components.isIdentity()) { + if (origin.components->isIdentity()) { representation_mapped_to = rmap->MappedRepresentation(); } } @@ -927,7 +927,7 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcStyledItem* inst) { double rgb[3]; if (process_colour(shading->SurfaceColour(), rgb)) { surface_style->diffuse.emplace(); - (*surface_style->diffuse).components << rgb[0], rgb[1], rgb[2]; + (*(*surface_style->diffuse).components) << rgb[0], rgb[1], rgb[2]; } if (auto rendering_style = shading->as()) { @@ -1194,7 +1194,7 @@ namespace { #endif if (has_position) { taxonomy::matrix4 m = as(self->map(inst->Position())); - m4 = m.components; + m4 = *m.components; } // @todo precision @@ -1228,10 +1228,10 @@ namespace { const auto& p = pps[i]; if (p.radius && *p.radius > 0.) { // Position is a IfcAxis2Placement2D, so should remain 2d points - auto p0 = boost::get(p.previous->start).components.head<2>(); - auto p1a = boost::get(p.previous->end).components.head<2>(); - auto p2 = boost::get(p.next->end).components.head<2>(); - auto p1b = boost::get(p.next->start).components.head<2>(); + auto p0 = boost::get(p.previous->start).components->head<2>(); + auto p1a = boost::get(p.previous->end).components->head<2>(); + auto p2 = boost::get(p.next->end).components->head<2>(); + auto p1b = boost::get(p.next->start).components->head<2>(); auto ba_ = p0 - p1a; auto bc_ = p2 - p1b; @@ -1242,8 +1242,8 @@ namespace { const double angle = std::acos(ba.dot(bc)); const double inset = *p.radius / std::tan(angle / 2.); - boost::get(p.previous->end).components.head<2>() += ba * inset; - boost::get(p.next->start).components.head<2>() += bc * inset; + boost::get(p.previous->end).components->head<2>() += ba * inset; + boost::get(p.next->start).components->head<2>() += bc * inset; auto e = new taxonomy::edge; e->start = p.previous->end; @@ -1253,10 +1253,10 @@ namespace { double sign = ab.head<2>().dot(bc) > 0 ? 1. : -1.; - auto O = boost::get(p.previous->end).components.head<3>() + ab * *p.radius * sign; + auto O = boost::get(p.previous->end).components->head<3>() + ab * *p.radius * sign; auto c = new taxonomy::circle; - c->matrix.components = Eigen::Affine3d(Eigen::Translation3d(O)).matrix(); + *c->matrix.components = Eigen::Affine3d(Eigen::Translation3d(O)).matrix(); c->radius = *p.radius; e->basis = c; c->orientation = sign == -1.; @@ -1364,7 +1364,7 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcCircleProfileDef* inst) { #endif if (has_position) { taxonomy::matrix4 m = as(map(inst->Position())); - c->matrix = m.components; + c->matrix = *m.components; } auto e = new taxonomy::edge; @@ -1465,7 +1465,7 @@ namespace { for (int i = 1; i <= n; ++i) { // wrap around to the first point in case of a closed loop int j = (i % polygon.size()) + 1; - double dist = (polygon.at(i - 1).components - polygon.at(j - 1).components).squaredNorm(); + double dist = (*polygon.at(i - 1).components - *polygon.at(j - 1).components).squaredNorm(); if (dist < tol) { // do not remove the first or last point to // maintain connectivity with other wires @@ -1494,7 +1494,7 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcPolyline* inst) { }); const double eps = precision_ * 10; - const bool closed_by_proximity = polygon.size() >= 3 && (polygon.front().components - polygon.back().components).norm() < eps; + const bool closed_by_proximity = polygon.size() >= 3 && (*polygon.front().components - *polygon.back().components).norm() < eps; // @todo this removes the end point, since it's identical to the beginning. if (closed_by_proximity) { @@ -1517,18 +1517,26 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcMappedItem* inst) { IfcSchema::IfcRepresentationMap* rmap = inst->MappingSource(); IfcSchema::IfcAxis2Placement* placement = rmap->MappingOrigin(); taxonomy::matrix4 trsf2 = as(map(placement)); - gtrsf.components = gtrsf.components * trsf2.components; + *gtrsf.components = *gtrsf.components * *trsf2.components; // @todo immutable for caching? // @todo allow for multiple levels of matrix? auto shapes = map(rmap->MappedRepresentation()); - for (auto& c : ((taxonomy::collection*)shapes)->children) { - auto item = ((taxonomy::geom_item*)c); - item->matrix.components = gtrsf.components * item->matrix.components; - // @todo previously style was also copied. + if (shapes == nullptr) { + return shapes; } - return shapes; + auto collection = new taxonomy::collection; + collection->children.push_back(shapes); + collection->matrix = *gtrsf.components; + + if (shapes != nullptr) { + for (auto& c : ((taxonomy::collection*)shapes)->children) { + // @todo previously style was also copied. + } + } + + return collection; } taxonomy::item* mapping::map_impl(const IfcSchema::IfcCompositeCurve* inst) { @@ -1596,7 +1604,7 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcTrimmedCurve* inst) { trim_cartesian &= has_pnts[0] && has_pnts[1]; if (trim_cartesian) { - if ((pnts[0].components - pnts[1].components).norm() < (2 * precision_)) { + if ((*pnts[0].components - *pnts[1].components).norm() < (2 * precision_)) { Logger::Message(Logger::LOG_WARNING, "Skipping segment with length below tolerance level:", inst); return nullptr; } diff --git a/src/ifcgeom/schema_agnostic/ConversionResult.h b/src/ifcgeom/schema_agnostic/ConversionResult.h index 0ccae1ccf0..d82cdd952b 100644 --- a/src/ifcgeom/schema_agnostic/ConversionResult.h +++ b/src/ifcgeom/schema_agnostic/ConversionResult.h @@ -75,11 +75,11 @@ namespace ifcopenshell { namespace geometry { : id(id), shape(shape->clone()) {} void append(const ifcopenshell::geometry::taxonomy::matrix4& trsf) { // @todo verify order - placement.components = placement.components * trsf.components; + *placement.components = *placement.components * *trsf.components; } void prepend(const ifcopenshell::geometry::taxonomy::matrix4& trsf) { // @todo verify order - placement.components = trsf.components * placement.components; + *placement.components = *trsf.components * *placement.components; } const ConversionResultShape* Shape() const { return shape; } const ifcopenshell::geometry::taxonomy::matrix4& Placement() const { return placement; } diff --git a/src/ifcgeom/schema_agnostic/IfcGeomElement.h b/src/ifcgeom/schema_agnostic/IfcGeomElement.h index a21db0ede1..3c1229844e 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomElement.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomElement.h @@ -49,14 +49,12 @@ namespace ifcopenshell { namespace geometry { // internally in IfcOpenShell everything is measured in meters. if (settings.get(settings::CONVERT_BACK_UNITS)) { for (int i = 0; i <= 2; ++i) { - matrix_.components(3, i) /= settings.unit_magnitude(); + (*matrix_.components)(3, i) /= settings.unit_magnitude(); } } } const ifcopenshell::geometry::taxonomy::matrix4& data() const { return matrix_; } const element_settings& settings() const { return settings_; } - - EIGEN_MAKE_ALIGNED_OPERATOR_NEW }; class Element { @@ -136,8 +134,6 @@ namespace ifcopenshell { namespace geometry { } virtual ~Element() {} - - EIGEN_MAKE_ALIGNED_OPERATOR_NEW }; class NativeElement : public Element { diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index bb9613c2b0..22d4738cb2 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -31,50 +31,90 @@ struct item { const IfcUtil::IfcBaseClass* instance; virtual item* clone() const = 0; virtual kinds kind() const = 0; + virtual void print(std::ostream&, int indent=0) const = 0; virtual void reverse() { throw taxonomy::topology_error(); } item(const IfcUtil::IfcBaseClass* instance = nullptr) : instance(instance) {} - - EIGEN_MAKE_ALIGNED_OPERATOR_NEW }; -struct matrix4 : public item { +template +struct eigen_base { + T* components; + + eigen_base() { + components = new T; + } + + eigen_base(const eigen_base& other) { + this->components = new T(*other.components); + } + + eigen_base(const T& other) { + this->components = new T(other); + } + + eigen_base& operator=(const eigen_base& other) { + if (this != &other) { + this->components = new T(*other.components); + } + return *this; + } + + void print_impl(std::ostream& o, const std::string& class_name, int indent = 0) const { + o << std::string(indent, ' ') << class_name; + for (size_t i = 0; i < 16; ++i) { + o << " " << (*components)(i); + } + o << std::endl; + } + + ~eigen_base() { + delete this->components; + } +}; + +struct matrix4 : public item, public eigen_base { enum tag_t { IDENTITY, AFFINE_WO_SCALE, AFFINE_W_UNIFORM_SCALE, AFFINE_W_NONUNIFORM_SCALE, OTHER }; tag_t tag; - - Eigen::Matrix4d components; - matrix4() : components(Eigen::Matrix4d::Identity()), tag(IDENTITY) {} - matrix4(const Eigen::Matrix4d& c) : components(c), tag(OTHER) {} + matrix4() : eigen_base(Eigen::Matrix4d::Identity()), tag(IDENTITY) {} + matrix4(const Eigen::Matrix4d& c) : eigen_base(c), tag(OTHER) {} matrix4(const Eigen::Vector3d& o, const Eigen::Vector3d& z, const Eigen::Vector3d& x) : tag(AFFINE_WO_SCALE) { auto X = x.normalized(); auto Y = z.cross(x).normalized(); auto Z = z.normalized(); - components << + components = new Eigen::Matrix4d; + (*components) << X(0), Y(0), Z(0), o(0), X(1), Y(1), Z(1), o(1), X(2), Y(2), Z(2), o(2), 0, 0, 0, 1.; } + void print(std::ostream& o, int indent = 0) const { + print_impl(o, "matrix4", indent); + } + virtual item* clone() const { return new matrix4(*this); } virtual kinds kind() const { return MATRIX4; } }; -struct colour : public item { - Eigen::Vector3d components; +struct colour : public item, public eigen_base { + void print(std::ostream& o, int indent = 0) const { + print_impl(o, "colour", indent); + } virtual item* clone() const { return new colour(*this); } virtual kinds kind() const { return COLOUR; } - colour() : components(Eigen::Vector3d::Zero()) {} - colour(double r, double g, double b) { components << r, g, b; } + colour() : eigen_base(Eigen::Vector3d::Zero()) {} + colour(double r, double g, double b) { (*components) << r, g, b; } - const double& r() const { return components[0]; } - const double& g() const { return components[1]; } - const double& b() const { return components[2]; } + const double& r() const { return (*components)[0]; } + const double& g() const { return (*components)[1]; } + const double& b() const { return (*components)[2]; } }; struct style : public item { @@ -84,6 +124,22 @@ struct style : public item { boost::optional specular; boost::optional specularity, transparency; + void print(std::ostream& o, int indent = 0) const { + o << std::string(indent, ' ') << "style" << std::endl; + if (name) { + o << std::string(indent, ' ') << " " << "name" << (*name) << std::endl; + } + if (diffuse) { + o << std::string(indent, ' ') << " " << "diffuse" << (*name) << std::endl; + diffuse->print(o, indent + 5 + 7); + } + if (diffuse) { + o << std::string(indent, ' ') << " " << "specular" << (*name) << std::endl; + diffuse->print(o, indent + 5 + 8); + } + // @todo + } + virtual item* clone() const { return new style(*this); } virtual kinds kind() const { return STYLE; } @@ -105,17 +161,19 @@ struct geom_item : public item { }; template -struct cartesian_base : public geom_item { - Eigen::Vector3d components; - - cartesian_base() : components(Eigen::Vector3d::Zero()) {} - cartesian_base(double x, double y, double z = 0.) { components << x, y, z; } +struct cartesian_base : public geom_item, public eigen_base { + cartesian_base() : eigen_base(Eigen::Vector3d::Zero()) {} + cartesian_base(double x, double y, double z = 0.) : eigen_base(Eigen::Vector3d(x, y, z)) {} }; struct point3 : public cartesian_base<3> { virtual item* clone() const { return new point3(*this); } virtual kinds kind() const { return POINT3; } + void print(std::ostream& o, int indent = 0) const { + print_impl(o, "point3", indent); + } + point3(double x = 0., double y = 0., double z = 0.) : cartesian_base(x, y, z) {} }; @@ -123,6 +181,10 @@ struct direction3 : public cartesian_base<3> { virtual item* clone() const { return new direction3(*this); } virtual kinds kind() const { return DIRECTION3; } + void print(std::ostream& o, int indent = 0) const { + print_impl(o, "direction3", indent); + } + direction3(double x = 0., double y = 0., double z = 0.) : cartesian_base(x, y, z) {} }; @@ -131,6 +193,10 @@ struct curve : public geom_item {}; struct line : public curve { virtual item* clone() const { return new line(*this); } virtual kinds kind() const { return LINE; } + + void print(std::ostream& o, int indent = 0) const { + o << "not implemented"; + } }; struct circle : public curve { @@ -138,6 +204,10 @@ struct circle : public curve { virtual item* clone() const { return new circle(*this); } virtual kinds kind() const { return CIRCLE; } + + void print(std::ostream& o, int indent = 0) const { + o << "not implemented"; + } }; struct ellipse : public circle { @@ -145,11 +215,19 @@ struct ellipse : public circle { virtual item* clone() const { return new ellipse(*this); } virtual kinds kind() const { return ELLIPSE; } + + void print(std::ostream& o, int indent = 0) const { + o << "not implemented"; + } }; struct bspline_curve : public curve { virtual item* clone() const { return new bspline_curve(*this); } virtual kinds kind() const { return BSPLINE_CURVE; } + + void print(std::ostream& o, int indent = 0) const { + o << "not implemented"; + } }; struct trimmed_curve : public curve { @@ -167,6 +245,13 @@ struct trimmed_curve : public curve { // std::swap(start, end); orientation = !orientation; } + + void print(std::ostream& o, int indent = 0) const { + o << std::string(indent, ' ') << "trimmed_curve" << std::endl; + if (basis) { + basis->print(o, indent + 4); + } + } }; struct edge : public trimmed_curve { @@ -199,6 +284,13 @@ struct collection : public geom_item { child->reverse(); } } + + void print(std::ostream& o, int indent = 0) const { + o << std::string(indent, ' ') << "collection" << std::endl; + for (auto& c : children) { + c->print(o, indent + 4); + } + } }; struct shell : public collection { @@ -213,6 +305,10 @@ struct surface : public geom_item {}; struct plane : public surface { virtual item* clone() const { return new plane(*this); } virtual kinds kind() const { return PLANE; } + + void print(std::ostream& o, int indent = 0) const { + o << "not implemented"; + } }; struct face : public collection { @@ -244,6 +340,12 @@ struct extrusion : public sweep { virtual kinds kind() const { return EXTRUSION; } extrusion(matrix4 m, face basis, direction3 dir, double d) : sweep(m, basis), direction(dir), depth(d) {} + + void print(std::ostream& o, int indent = 0) const { + o << std::string(indent, ' ') << "extrusion " << depth << std::endl; + direction.print(o, indent + 4); + basis.print(o, indent + 4); + } }; struct node : public collection { diff --git a/src/serializers/ColladaSerializer.cpp b/src/serializers/ColladaSerializer.cpp index 4267ed7f3b..19df0e2959 100644 --- a/src/serializers/ColladaSerializer.cpp +++ b/src/serializers/ColladaSerializer.cpp @@ -197,14 +197,14 @@ void ColladaSerializer::ColladaExporter::ColladaScene::add( // If this is not the first parent, get the relative placement if (parentNodes.size() > 0) { - auto m4 = ifcopenshell::geometry::taxonomy::matrix4(matrixStack.top().data().components * transformation.data().components); + auto m4 = ifcopenshell::geometry::taxonomy::matrix4(*matrixStack.top().data().components * *transformation.data().components); relative_trsf = new ifcopenshell::geometry::Transformation(transformation.settings(), m4); transformation_towrite = relative_trsf; } // @todo verify - const double* m = transformation_towrite->data().components.data(); + const double* m = transformation_towrite->data().components->data(); double matrix_array[4][4] = { { m[0], m[4], m[8], m[12] }, @@ -251,14 +251,14 @@ void ColladaSerializer::ColladaExporter::ColladaScene::addParent(const ifcopensh // If this is not the first parent, get the relative placement if (parentNodes.size() > 0) { - auto m4 = ifcopenshell::geometry::taxonomy::matrix4(matrixStack.top().data().components * parent_trsf.data().components); + auto m4 = ifcopenshell::geometry::taxonomy::matrix4(*matrixStack.top().data().components * *parent_trsf.data().components); relative_trsf = new ifcopenshell::geometry::Transformation(parent_trsf.settings(), m4); transformation_towrite = relative_trsf; } // @todo verify - const double* parentMatrix = transformation_towrite->data().components.data(); + const double* parentMatrix = transformation_towrite->data().components->data(); double matrix_array[4][4] = { { (double)parentMatrix[0], (double)parentMatrix[3], (double)parentMatrix[6], (double)parentMatrix[9] }, @@ -280,7 +280,7 @@ void ColladaSerializer::ColladaExporter::ColladaScene::addParent(const ifcopensh current_node->addMatrix(matrix_array); // Add the node to the parent stack - matrixStack.push(ifcopenshell::geometry::Transformation(parent_trsf.settings(), ifcopenshell::geometry::taxonomy::matrix4(parent_trsf.data().components.inverse()))); + matrixStack.push(ifcopenshell::geometry::Transformation(parent_trsf.settings(), ifcopenshell::geometry::taxonomy::matrix4(parent_trsf.data().components->inverse()))); parentNodes.push(current_node); serializer->parentStackId.push(parent.id()); } @@ -320,11 +320,11 @@ void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write COLLADASW::EffectProfile effect(mSW); effect.setShaderType(COLLADASW::EffectProfile::LAMBERT); if (material.diffuse) { - auto diffuse = material.diffuse.get().components; + const auto& diffuse = *material.diffuse.get().components; effect.setDiffuse(COLLADASW::ColorOrTexture(COLLADASW::Color(diffuse[0],diffuse[1],diffuse[2]))); } if (material.specular) { - auto specular = material.specular.get().components; + const auto& specular = *material.specular.get().components; effect.setSpecular(COLLADASW::ColorOrTexture(COLLADASW::Color(specular[0],specular[1],specular[2]))); } if (material.specularity) { @@ -348,9 +348,11 @@ void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::close void ColladaSerializer::ColladaExporter::ColladaMaterials::add(const ifcopenshell::geometry::taxonomy::style& material) { if (!contains(material)) { - // @todo original_name - std::string material_name = *(serializer->settings().get(SerializerSettings::USE_MATERIAL_NAMES) - ? material.name : material.name); + // @todo original_name? + + // @todo apparently material.name is unitialized in some cases now. + + std::string material_name = material.name.get_value_or("missing-material"); if (material_name.empty()) { material_name = "missing-material-" + *material.name; diff --git a/src/serializers/GltfSerializer.cpp b/src/serializers/GltfSerializer.cpp index 9f80d5b4f1..77454d82b4 100644 --- a/src/serializers/GltfSerializer.cpp +++ b/src/serializers/GltfSerializer.cpp @@ -94,7 +94,7 @@ int GltfSerializer::writeMaterial(const ifcopenshell::geometry::taxonomy::style& base.fill(1.0); if (style.diffuse) { for (int i = 0; i < 3; ++i) { - base[i] = style.diffuse->components[i]; + base[i] = (*style.diffuse->components)[i]; } } if (style.transparency) { @@ -167,7 +167,7 @@ void GltfSerializer::write(const ifcopenshell::geometry::TriangulationElement* o node_array_.push_back(json_["nodes"].size()); - const double* m = o->transformation().data().components.data(); + const double* m = o->transformation().data().components->data(); // nb: note that this applies the Y-UP transform. const std::array matrix_flat = { diff --git a/src/serializers/SvgSerializer.cpp b/src/serializers/SvgSerializer.cpp index 85cda03eda..40fd128216 100644 --- a/src/serializers/SvgSerializer.cpp +++ b/src/serializers/SvgSerializer.cpp @@ -490,7 +490,7 @@ void SvgSerializer::setFile(IfcParse::IfcFile* f) { auto item = mapping_->map(*product->get("ObjectPlacement")); if (item) { auto matrix = (ifcopenshell::geometry::taxonomy::matrix4*) item; - const double& Z = matrix->components(3, 2); + const double& Z = (*matrix->components)(3, 2); setSectionHeight(Z + 1.); Logger::Warning("No building storeys encountered, used for reference:", product); return; diff --git a/src/serializers/schema_dependent/XmlSerializer.cpp b/src/serializers/schema_dependent/XmlSerializer.cpp index ddc174b027..2b388b6c68 100644 --- a/src/serializers/schema_dependent/XmlSerializer.cpp +++ b/src/serializers/schema_dependent/XmlSerializer.cpp @@ -131,7 +131,7 @@ boost::optional format_attribute(ifcopenshell::geometry::abstract_m std::stringstream stream; for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { - const double trsf_value = matrix->components(j, i); + const double trsf_value = (*matrix->components)(j, i); stream << trsf_value; if (i < 3 && j < 3) { stream << " "; From 52a3d627e26051fe872b216b55718aab8f280d10 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 11 Jun 2020 20:49:44 +0200 Subject: [PATCH 227/235] mapped item implementation --- src/ifcgeom/schema/mapping.cpp | 139 ++++++++++++++++++++++++++++----- src/ifcgeom/schema/mapping.i | 4 +- 2 files changed, 122 insertions(+), 21 deletions(-) diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index 3c038fb791..7094848e6f 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -184,11 +184,26 @@ namespace { return flat; } + template + bool apply_predicate_to_collection(taxonomy::item* i, Fn fn) { + if (i->kind() == taxonomy::COLLECTION) { + auto c = (taxonomy::collection*) i; + for (auto& child : c->children) { + if (apply_predicate_to_collection(child, fn)) { + return true; + } + } + } else { + return fn(i); + } + } + + // @nb traverses nested collections template taxonomy::collection* filter(taxonomy::collection* collection, Fn fn) { auto filtered = new taxonomy::collection; for (auto& child : collection->children) { - if (fn(child)) { + if (apply_predicate_to_collection(child, fn)) { filtered->children.push_back(child); } } @@ -207,16 +222,23 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcRepresentation* inst) { if (items == nullptr) { return nullptr; } + + /* + // Don't blindly flatten, as we're culling away IfcMappedItem transformations + auto flat = flatten(items); if (flat == nullptr) { return nullptr; } - auto filtered = filter(flat, [&use_body](taxonomy::item* i) { + */ + + auto filtered = filter(items, [&use_body](taxonomy::item* i) { // @todo just filter loops for now. return (i->kind() != taxonomy::LOOP) == use_body; }); + delete items; - delete flat; + return filtered; } @@ -416,24 +438,92 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcAxis2Placement2D* inst) { return new taxonomy::matrix4(P, axis, V); } -taxonomy::item* mapping::map_impl(const IfcSchema::IfcCartesianTransformationOperator2DnonUniform* inst) { - // @todo - return new taxonomy::matrix4(); -} - -taxonomy::item* mapping::map_impl(const IfcSchema::IfcCartesianTransformationOperator3DnonUniform* inst) { - // @todo - return new taxonomy::matrix4(); -} - taxonomy::item* mapping::map_impl(const IfcSchema::IfcCartesianTransformationOperator2D* inst) { - // @todo - return new taxonomy::matrix4(); + auto m = new taxonomy::matrix4; + + Eigen::Vector4d origin, axis1(1.0, 0.0, 0.0, 0.0), axis2(0.0, 1.0, 0.0, 0.0), axis3(0.0, 0.0, 1.0, 0.0); + + taxonomy::point3 O = as(map(inst->LocalOrigin())); + origin << *O.components, 1.0; + + if (inst->hasAxis1()) { + taxonomy::direction3 ax1 = as(map(inst->Axis1())); + axis1 << *ax1.components, 0.0; + } + if (inst->hasAxis2()) { + taxonomy::direction3 ax2 = as(map(inst->Axis1())); + axis2 << *ax2.components, 0.0; + } + + double scale1, scale2; + scale1 = scale2 = 1.0; + + if (inst->hasScale()) { + scale1 = inst->Scale(); + } + if (inst->as()) { + auto nu = inst->as(); + scale2 = nu->hasScale2() ? nu->Scale2() : scale1; + } + + *m->components << + axis1 * scale1, + axis2 * scale2, + axis3, + origin; + + m->components->transposeInPlace(); + + return m; } taxonomy::item* mapping::map_impl(const IfcSchema::IfcCartesianTransformationOperator3D* inst) { - // @todo - return new taxonomy::matrix4(); + auto m = new taxonomy::matrix4; + + Eigen::Vector4d origin; + Eigen::Vector4d axis1(1., 0., 0., 0.); + Eigen::Vector4d axis2(0., 1., 0., 0.); + Eigen::Vector4d axis3(0., 0., 1., 0.); + + taxonomy::point3 O = as(map(inst->LocalOrigin())); + origin << *O.components, 1.0; + + if (inst->hasAxis1()) { + taxonomy::direction3 ax1 = as(map(inst->Axis1())); + axis1 << *ax1.components, 0.0; + } + if (inst->hasAxis2()) { + taxonomy::direction3 ax2 = as(map(inst->Axis2())); + axis2 << *ax2.components, 0.0; + } + if (inst->hasAxis3()) { + taxonomy::direction3 ax3 = as(map(inst->Axis3())); + axis3 << *ax3.components, 0.0; + } + + double scale1, scale2, scale3; + scale1 = scale2 = scale3 = 1.; + + if (inst->hasScale()) { + scale1 = inst->Scale(); + } + if (inst->as()) { + auto nu = inst->as(); + scale2 = nu->hasScale2() ? nu->Scale2() : scale1; + scale3 = nu->hasScale3() ? nu->Scale3() : scale1; + } + + *m->components << + axis1 * scale1, + axis2 * scale2, + axis3 * scale3, + origin; + + m->components->transposeInPlace(); + + // @todo tag identity? + + return m; } taxonomy::item* mapping::map_impl(const IfcSchema::IfcLocalPlacement* inst) { @@ -1545,8 +1635,19 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcCompositeCurve* inst) { for (auto& segment : *segments) { auto crv = map(segment->ParentCurve()); if (crv) { - ((taxonomy::geom_item*)crv)->orientation = segment->SameSense(); - loop->children.push_back(crv); + if (crv->kind() == taxonomy::EDGE) { + ((taxonomy::geom_item*)crv)->orientation = segment->SameSense(); + loop->children.push_back(crv); + } else if (crv->kind() == taxonomy::LOOP) { + if (!segment->SameSense()) { + crv->reverse(); + } + auto curve_segments = ((taxonomy::loop*)crv)->children_as(); + for (auto& s : curve_segments) { + loop->children.push_back(s); + } + // @todo delete crv without children + } } } IfcEntityList::ptr profile = inst->data().getInverse(&IfcSchema::IfcProfileDef::Class(), -1); diff --git a/src/ifcgeom/schema/mapping.i b/src/ifcgeom/schema/mapping.i index 9ebb31fb7f..382ee65f3b 100644 --- a/src/ifcgeom/schema/mapping.i +++ b/src/ifcgeom/schema/mapping.i @@ -122,9 +122,9 @@ BIND(IfcDirection); BIND(IfcAxis2Placement2D); BIND(IfcAxis2Placement3D); // BIND(IfcAxis1Placement); -BIND(IfcCartesianTransformationOperator2DnonUniform); -BIND(IfcCartesianTransformationOperator3DnonUniform); +// IfcCartesianTransformationOperator2DnonUniform included BIND(IfcCartesianTransformationOperator2D); +// IfcCartesianTransformationOperator3DnonUniform included BIND(IfcCartesianTransformationOperator3D); BIND(IfcLocalPlacement); // BIND(IfcVector); From 018f1ea1d423baf6e4d59a717451bee35f814dd0 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 11 Jun 2020 20:49:53 +0200 Subject: [PATCH 228/235] fix radius --- src/ifcgeom/schema/mapping.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index 7094848e6f..74bc6ffbe5 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -1765,7 +1765,7 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcTrimmedCurve* inst) { taxonomy::item* mapping::map_impl(const IfcSchema::IfcCircle* inst) { auto c = new taxonomy::circle; c->matrix = as(map(inst->Position())); - c->radius = inst->Radius(); + c->radius = inst->Radius() * length_unit_; return c; } From 939d1a6c4f6748cb5ce9a48d8601b26409e2badc Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 11 Jun 2020 20:50:13 +0200 Subject: [PATCH 229/235] implement triangulation transformation in eigen --- .../OpenCascadeConversionResult.cpp | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp index f96af5cdf7..1d02b90c11 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp @@ -7,18 +7,30 @@ #include +namespace { + // We bypass the conversion to gp_GTrsf, because it does not work + void taxonomy_transform(const Eigen::Matrix4d* m, gp_XYZ& xyz) { + Eigen::Vector4d v(xyz.X(), xyz.Y(), xyz.Z(), 1.0); + auto v2 = (*m * v).eval(); + xyz.ChangeData()[0] = v2(0); + xyz.ChangeData()[1] = v2(1); + xyz.ChangeData()[2] = v2(2); + } +} + void ifcopenshell::geometry::OpenCascadeShape::Triangulate(const settings& settings, const ifcopenshell::geometry::taxonomy::matrix4& place, Representation::Triangulation* t, int surface_style_id) const { - // @todo check - gp_GTrsf trsf; - gp_Trsf tr; - const auto& m = place.components; - tr.SetValues( - m(0, 0), m(0, 1), m(0, 2), m(0, 3), - m(1, 0), m(1, 1), m(1, 2), m(1, 3), - m(2, 0), m(2, 1), m(2, 2), m(2, 3) + // @todo remove duplication with OpenCascadeKernel::convert(const taxonomy::matrix4* matrix, gp_GTrsf& trsf); + // above can be static? + + const auto& m = *place.components; + + // A 3x3 matrix to rotate the vertex normals + gp_Mat rotation_matrix( + m(0, 0), m(0, 1), m(0, 2), + m(1, 0), m(1, 1), m(1, 2), + m(2, 0), m(2, 1), m(2, 2) ); - trsf = tr; // Triangulate the shape try { @@ -41,9 +53,6 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(const settings& setti 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, int> edgecount; @@ -61,7 +70,7 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(const settings& setti for (int i = 1; i <= nodes.Length(); ++i) { coords.push_back(nodes(i).Transformed(loc).XYZ()); - trsf.Transforms(*coords.rbegin()); + taxonomy_transform(place.components, *coords.rbegin()); const gp_XYZ& last = *coords.rbegin(); dict[i] = t->addVertex(surface_style_id, last.X(), last.Y(), last.Z()); From b85e03374a205eb1092534067adf3733f31eab8e Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 11 Jun 2020 20:50:50 +0200 Subject: [PATCH 230/235] Workaround singularity issues in gp_GTrsf --- .../kernels/opencascade/IfcGeomShapes.cpp | 66 ++++++++++--------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp index f8ab8d2e41..9d86771058 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp @@ -512,32 +512,9 @@ bool OpenCascadeKernel::convert(const taxonomy::face* face, TopoDS_Shape& result #include namespace { - /* A compile-time for loop over the curve kinds */ - template - struct dispatch_curve_creation { - static bool dispatch(const ifcopenshell::geometry::taxonomy::item* item, T& visitor) { - // @todo it should be possible to eliminate this dynamic_cast when there is a static equivalent to kind() - const ifcopenshell::geometry::taxonomy::curves::type* v = dynamic_cast*>(item); - if (v) { - visitor(*v); - return true; - } else { - return dispatch_curve_creation::dispatch(item, visitor); - } - } - }; - - template - struct dispatch_curve_creation { - static bool dispatch(const ifcopenshell::geometry::taxonomy::item* item, T& visitor) { - Logger::Error("No conversion for " + std::to_string(item->kind())); - return false; - } - }; - template T convert_xyz(const U& u) { - const auto& vs = u.components; + const auto& vs = *u.components; return T(vs(0), vs(1), vs(2)); } @@ -936,14 +913,41 @@ bool OpenCascadeKernel::convert_impl(const taxonomy::shell *shell, ifcopenshell: bool OpenCascadeKernel::convert(const taxonomy::matrix4* matrix, gp_GTrsf& trsf) { // @todo check - gp_Trsf tr; - const auto& m = matrix->components; - tr.SetValues( - m(0, 0), m(0, 1), m(0, 2), m(0, 3), - m(1, 0), m(1, 1), m(1, 2), m(1, 3), - m(2, 0), m(2, 1), m(2, 2), m(2, 3) + const auto& m = *matrix->components; + gp_Mat mat( + m(0, 0), m(0, 1), m(0, 2), + m(1, 0), m(1, 1), m(1, 2), + m(2, 0), m(2, 1), m(2, 2) ); - trsf = tr; + + if (matrix->instance && matrix->instance->declaration().name() == "IfcCartesianTransformationOperator3DnonUniform") { + std::wcout << "non uniform" << std::endl; + } + + // @nb SetVectorialPart() sets gp_GTrsf.scale to 0.0, causing an non-invertable + // matrix later on which cannot be in TopLoc_Location. + + std::array ms{ { + mat.Column(1).Modulus(), + mat.Column(2).Modulus(), + mat.Column(3).Modulus() + } }; + std::sort(ms.begin(), ms.end()); + + if (std::fabs(ms.front() - ms.back()) < 1.e-7) { + gp_Trsf tr; + tr.SetValues( + m(0, 0), m(0, 1), m(0, 2), m(0, 3), + m(1, 0), m(1, 1), m(1, 2), m(1, 3), + m(2, 0), m(2, 1), m(2, 2), m(2, 3) + ); + trsf = tr; + } else { + trsf.SetVectorialPart(mat); + trsf.SetTranslationPart(gp_XYZ(m(0, 3), m(1, 3), m(2, 3))); + trsf.SetForm(); + } + return true; } From 7f60ea9c52ca2b5805af2bb1a5438e710a226fb2 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 11 Jun 2020 20:51:08 +0200 Subject: [PATCH 231/235] cgal curve implementations --- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 184 +++++++++++++++++++++++- 1 file changed, 180 insertions(+), 4 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index 972476b3e4..a99c09dccb 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -16,6 +16,8 @@ * along with this program. If not, see . * * * ********************************************************************************/ +#define _USE_MATH_DEFINES +#include #include "CgalKernel.h" @@ -214,6 +216,169 @@ namespace { } } +namespace { + typedef std::pair parameter_range; + + static const parameter_range unbounded = { + -std::numeric_limits::infinity(), + +std::numeric_limits::infinity() + }; + + void evaluate_curve(const taxonomy::line& c, double u, taxonomy::point3& p) { + Eigen::Vector4d xy{ u, 0, 0, 1. }; + *p.components = (*c.matrix.components * xy).head<3>(); + } + + void evaluate_curve(const taxonomy::circle& c, double u, taxonomy::point3& p) { + Eigen::Vector4d xy{ c.radius * std::cos(u), c.radius * std::sin(u), 0, 1. }; + *p.components = (*c.matrix.components * xy).head<3>(); + } + + void evaluate_curve(const taxonomy::ellipse& c, double u, taxonomy::point3& p) { + Eigen::Vector4d xy{ c.radius * std::cos(u), c.radius2 * std::sin(u), 0, 1. }; + *p.components = (*c.matrix.components * xy).head<3>(); + } + + // ---- + + void project_onto_curve(const taxonomy::line& c, const taxonomy::point3& p, double& u) { + u = (c.matrix.components->inverse() * p.components->homogeneous())(0); + } + + void project_onto_curve(const taxonomy::circle& c, const taxonomy::point3& p, double& u) { + Eigen::Vector2d xy = (c.matrix.components->inverse() * p.components->homogeneous()).head<2>(); + u = std::atan2(xy(1), xy(0)); + } + + void project_onto_curve(const taxonomy::ellipse& c, const taxonomy::point3& p, double& u) { + Eigen::Vector2d xy = (c.matrix.components->inverse() * p.components->homogeneous()).head<2>(); + u = std::atan2(xy(1), xy(0)); + } + + struct point_projection_visitor_ { + taxonomy::point3 p; + double u; + + void operator()(const taxonomy::line& c) { + project_onto_curve(c, p, u); + } + + void operator()(const taxonomy::circle& c) { + project_onto_curve(c, p, u); + } + + void operator()(const taxonomy::ellipse& c) { + project_onto_curve(c, p, u); + } + + void operator()(const taxonomy::item& c) { + throw std::runtime_error("Point projection not implemented on this geometry type"); + } + }; + + struct point_projection_visitor { + taxonomy::item* curve; + double u; + + void operator()(const taxonomy::point3& p) { + point_projection_visitor_ v{ p }; + dispatch_curve_creation::dispatch(curve, v); + u = v.u; + } + + void operator()(const double& u) { + this->u = u; + } + }; + + struct cgal_curve_creation_visitor { + static const int FULL_CIRCLE_NUM_SEGMENTS = 32; + parameter_range param; + + std::vector points; + + cgal_curve_creation_visitor() : param(unbounded) {} + cgal_curve_creation_visitor(const parameter_range& p) : param(p) {} + + void operator()(const taxonomy::line& l) { + if (param == unbounded) { + throw std::runtime_error("Cannot represent infinite line segment"); + } + taxonomy::point3 start, end; + evaluate_curve(l, param.first, start); + evaluate_curve(l, param.second, end); + points.push_back(start); + points.push_back(end); + } + + template + void evaluate_conic(const T& t) { + double a, b; + if (param == unbounded) { + a = 0.; + b = 2 * M_PI; + } else { + std::tie(a, b) = param; + } + int num_segments = (int)std::ceil(std::fabs(a - b) / (2 * M_PI) * FULL_CIRCLE_NUM_SEGMENTS); + double du = (b - a) / num_segments; + taxonomy::point3 P; + // @nb for loop is not inclusive of the both end points + evaluate_curve(t, a, P); + points.push_back(P); + for (int i = 1; i < num_segments; ++i) { + double u = a + du * i; + evaluate_curve(t, u, P); + points.push_back(P); + } + evaluate_curve(t, b, P); + points.push_back(P); + } + + void operator()(const taxonomy::circle& c) { + evaluate_conic(c); + } + + void operator()(const taxonomy::ellipse& e) { + evaluate_conic(e); + } + + void operator()(const taxonomy::trimmed_curve& e) { + point_projection_visitor v1, v2; + boost::apply_visitor(v1, e.start); + boost::apply_visitor(v2, e.end); + + cgal_curve_creation_visitor v({ v1.u, v2.u }); + + dispatch_curve_creation::dispatch(e.basis, v); + this->points = v.points; + } + + void operator()(const taxonomy::item& e) { + throw std::runtime_error("Not supported"); + } + }; + + void convert_curve(taxonomy::item* i, std::vector& points) { + cgal_curve_creation_visitor v; + dispatch_curve_creation::dispatch(i, v); + points = v.points; + } + + // @nb mutates a + void extend_wire(std::vector& a, const std::vector& b) { + if (a.empty()) { + a = b; + } + if (b.empty()) { + return; + } + double d = (*a.back().components - *b.front().components).norm(); + size_t offset = d < 1.e-5 ? 1 : 0; + a.insert(a.end(), b.begin() + offset, b.end()); + } +} + bool CgalKernel::convert(const taxonomy::loop* loop, cgal_wire_t& result) { // @todo only implement polygonal loops @@ -222,16 +387,27 @@ bool CgalKernel::convert(const taxonomy::loop* loop, cgal_wire_t& result) { for (auto& e : edges) { if (e->basis) { - Logger::Error("Only polyhedra supported :("); - return false; + std::vector edge; + convert_curve(e->basis, points); + extend_wire(points, edge); + } else { + extend_wire(points, { + boost::get(e->start), + boost::get(e->end) + }); } - points.push_back(boost::get(e->start)); + } + + if (points.size() >= 2) { + // the edges -> conversion left us with a duplicate global begin,end point. + double d = (*points.back().components - *points.front().components).norm(); + points.erase(points.end() - 1); } // Parse and store the points in a sequence cgal_wire_t polygon = std::vector(); for (auto& p : points) { - cgal_point_t pnt(p.components(0), p.components(1), p.components(2)); + cgal_point_t pnt((*p.components)(0), (*p.components)(1), (*p.components)(2)); polygon.push_back(pnt); } From eacea738f9b0f568d048c433245fc49377aca9fa Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 11 Jun 2020 20:51:22 +0200 Subject: [PATCH 232/235] move dispatch curve creation --- .../kernel_agnostic/AbstractKernel.cpp | 23 --------- src/ifcgeom/kernel_agnostic/AbstractKernel.h | 47 +++++++++++++++++++ 2 files changed, 47 insertions(+), 23 deletions(-) diff --git a/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp index 62cebcabfb..a7e5a5699b 100644 --- a/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp +++ b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp @@ -7,29 +7,6 @@ #include "../../ifcgeom/kernels/cgal/CgalKernel.h" -namespace { - /* A compile-time for loop over the taxonomy kinds */ - template - struct dispatch_conversion { - static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel* kernel, const ifcopenshell::geometry::taxonomy::item* item, ifcopenshell::geometry::ConversionResults& results) { - if (N == item->kind()) { - auto concrete_item = static_cast*>(item); - return kernel->convert_impl(concrete_item, results); - } else { - return dispatch_conversion::dispatch(kernel, item, results); - } - } - }; - - template <> - struct dispatch_conversion { - static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel*, const ifcopenshell::geometry::taxonomy::item* item, ifcopenshell::geometry::ConversionResults&) { - Logger::Error("No conversion for " + std::to_string(item->kind())); - return false; - } - }; -} - bool ifcopenshell::geometry::kernels::AbstractKernel::convert(const taxonomy::item* item, ifcopenshell::geometry::ConversionResults& results) { try { return dispatch_conversion<0>::dispatch(this, item, results); diff --git a/src/ifcgeom/kernel_agnostic/AbstractKernel.h b/src/ifcgeom/kernel_agnostic/AbstractKernel.h index 735fbde202..5eb2172194 100644 --- a/src/ifcgeom/kernel_agnostic/AbstractKernel.h +++ b/src/ifcgeom/kernel_agnostic/AbstractKernel.h @@ -71,4 +71,51 @@ namespace ifcopenshell { namespace geometry { namespace kernels { } } + +namespace { + /* A compile-time for loop over the taxonomy kinds */ + template + struct dispatch_conversion { + static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel* kernel, const ifcopenshell::geometry::taxonomy::item* item, ifcopenshell::geometry::ConversionResults& results) { + if (N == item->kind()) { + auto concrete_item = static_cast*>(item); + return kernel->convert_impl(concrete_item, results); + } else { + return dispatch_conversion::dispatch(kernel, item, results); + } + } + }; + + template <> + struct dispatch_conversion { + static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel*, const ifcopenshell::geometry::taxonomy::item* item, ifcopenshell::geometry::ConversionResults&) { + Logger::Error("No conversion for " + std::to_string(item->kind())); + return false; + } + }; + + /* A compile-time for loop over the curve kinds */ + template + struct dispatch_curve_creation { + static bool dispatch(const ifcopenshell::geometry::taxonomy::item* item, T& visitor) { + // @todo it should be possible to eliminate this dynamic_cast when there is a static equivalent to kind() + const ifcopenshell::geometry::taxonomy::curves::type* v = dynamic_cast*>(item); + if (v) { + visitor(*v); + return true; + } else { + return dispatch_curve_creation::dispatch(item, visitor); + } + } + }; + + template + struct dispatch_curve_creation { + static bool dispatch(const ifcopenshell::geometry::taxonomy::item* item, T&) { + Logger::Error("No conversion for " + std::to_string(item->kind())); + return false; + } + }; +} + #endif \ No newline at end of file From 6aafff2c40394a56765b67e0169f95644bb4db08 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 21 Jun 2020 15:15:49 +0200 Subject: [PATCH 233/235] taxonomy printing and different trimmed curve orientation handling --- .../kernels/opencascade/IfcGeomShapes.cpp | 13 ++++++++ src/ifcgeom/schema/mapping.cpp | 5 +-- src/ifcgeom/schema_agnostic/Converter.cpp | 10 +++++- src/ifcgeom/taxonomy.h | 32 +++++++++++++++---- 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp index 9d86771058..ce6e606e2c 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp @@ -848,6 +848,19 @@ bool OpenCascadeKernel::convert(const taxonomy::loop* loop, TopoDS_Wire& wire) { for (auto& segment : segments) { auto segment_wire = boost::get(convert_curve(this, segment)); + +#ifdef IFOPSH_DEBUG + std::ostringstream o; + segment->print(o); + TopoDS_Vertex v0, v1; + TopExp::Vertices(segment_wire, v0, v1); + gp_Pnt p0 = BRep_Tool::Pnt(v0); + gp_Pnt p1 = BRep_Tool::Pnt(v1); + o << "p0 " << p0.X() << " " << p0.Y() << " " << p0.Z() << std::endl; + o << "p1 " << p1.X() << " " << p1.Y() << " " << p1.Z() << std::endl; + auto o_str = o.str(); + std::wcout << o_str.c_str() << std::endl; +#endif if (!segment->orientation) { segment_wire.Reverse(); diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index 74bc6ffbe5..77d57a6d02 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -1668,13 +1668,14 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcTrimmedCurve* inst) { IfcEntityList::ptr trims1 = inst->Trim1(); IfcEntityList::ptr trims2 = inst->Trim2(); - unsigned sense_agreement = inst->SenseAgreement() ? 0 : 1; + // reversed orientation handling happens in geometry kernel + unsigned sense_agreement = 0; // inst->SenseAgreement() ? 0 : 1; double flts[2]; taxonomy::point3 pnts[2]; bool has_flts[2] = { false,false }; bool has_pnts[2] = { false,false }; - tc->orientation = sense_agreement != 0; + tc->orientation = inst->SenseAgreement(); for (IfcEntityList::it it = trims1->begin(); it != trims1->end(); it++) { IfcUtil::IfcBaseClass* i = *it; diff --git a/src/ifcgeom/schema_agnostic/Converter.cpp b/src/ifcgeom/schema_agnostic/Converter.cpp index 148aa6cdfe..b037ad6c29 100644 --- a/src/ifcgeom/schema_agnostic/Converter.cpp +++ b/src/ifcgeom/schema_agnostic/Converter.cpp @@ -58,7 +58,15 @@ ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create auto place = taxonomy::matrix4(); std::swap(place, product_node->matrix); - kernel_->convert(product_node, shapes); + try { + kernel_->convert(product_node, shapes); + } catch (...) { + std::ostringstream oss; + product_node->print(oss); + std::string s = oss.str(); + std::wcout << s.c_str() << std::endl; + return nullptr; + } shape = new ifcopenshell::geometry::Representation::BRep(s, representation_id_builder.str(), shapes); diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index 22d4738cb2..98a8da2ca7 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -62,7 +62,8 @@ struct eigen_base { void print_impl(std::ostream& o, const std::string& class_name, int indent = 0) const { o << std::string(indent, ' ') << class_name; - for (size_t i = 0; i < 16; ++i) { + int n = T::RowsAtCompileTime * T::ColsAtCompileTime; + for (size_t i = 0; i < n; ++i) { o << " " << (*components)(i); } o << std::endl; @@ -188,14 +189,19 @@ struct direction3 : public cartesian_base<3> { direction3(double x = 0., double y = 0., double z = 0.) : cartesian_base(x, y, z) {} }; -struct curve : public geom_item {}; +struct curve : public geom_item { + void print_impl(std::ostream& o, const std::string& classname, int indent = 0) const { + o << std::string(indent, ' ') << classname << std::endl; + this->matrix.print(o, indent + 4); + } +}; struct line : public curve { virtual item* clone() const { return new line(*this); } virtual kinds kind() const { return LINE; } void print(std::ostream& o, int indent = 0) const { - o << "not implemented"; + print_impl(o, "line", indent); } }; @@ -206,7 +212,7 @@ struct circle : public curve { virtual kinds kind() const { return CIRCLE; } void print(std::ostream& o, int indent = 0) const { - o << "not implemented"; + print_impl(o, "circle", indent); } }; @@ -217,7 +223,7 @@ struct ellipse : public circle { virtual kinds kind() const { return ELLIPSE; } void print(std::ostream& o, int indent = 0) const { - o << "not implemented"; + print_impl(o, "ellipse", indent); } }; @@ -226,7 +232,7 @@ struct bspline_curve : public curve { virtual kinds kind() const { return BSPLINE_CURVE; } void print(std::ostream& o, int indent = 0) const { - o << "not implemented"; + o << std::string(indent, ' ') << "bspline curve" << std::endl; } }; @@ -251,6 +257,20 @@ struct trimmed_curve : public curve { if (basis) { basis->print(o, indent + 4); } + + const boost::variant const * start_end[2] = { &start, &end }; + for (int i = 0; i < 2; ++i) { + o << std::string(indent + 4, ' ') << (i == 0 ? "start" : "end") << std::endl; + if (start_end[i]->which() == 0) { + boost::get(*start_end[i]).print(o, indent + 4); + } else if (start_end[i]->which() == 1) { + o << std::string(indent + 4, ' ') << "parameter " << boost::get(*start_end[i]) << std::endl; + } + } + + if (this->instance) { + o << std::string(indent, ' ') << this->instance->data().toString() << std::endl; + } } }; From 0e2bac5e3b4b60564ac24fa05f33cafd2b66caad Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 8 Jul 2020 12:07:10 +0200 Subject: [PATCH 234/235] Shape reuse based on std::less --- src/ifcgeom/schema_agnostic/Converter.cpp | 25 ++- src/ifcgeom/schema_agnostic/Converter.h | 2 + src/ifcgeom/taxonomy.cpp | 220 ++++++++++++++++++++++ src/ifcgeom/taxonomy.h | 17 +- 4 files changed, 254 insertions(+), 10 deletions(-) create mode 100644 src/ifcgeom/taxonomy.cpp diff --git a/src/ifcgeom/schema_agnostic/Converter.cpp b/src/ifcgeom/schema_agnostic/Converter.cpp index b037ad6c29..3fd94452e2 100644 --- a/src/ifcgeom/schema_agnostic/Converter.cpp +++ b/src/ifcgeom/schema_agnostic/Converter.cpp @@ -54,18 +54,29 @@ ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create } std::clock_t geom_start = std::clock(); - - auto place = taxonomy::matrix4(); - std::swap(place, product_node->matrix); - try { - kernel_->convert(product_node, shapes); - } catch (...) { + if (false) { std::ostringstream oss; product_node->print(oss); std::string s = oss.str(); std::wcout << s.c_str() << std::endl; - return nullptr; + } + + auto place = taxonomy::matrix4(); + std::swap(place, product_node->matrix); + + auto it = cache_.find(product_node); + if (it == cache_.end()) { + try { + kernel_->convert(product_node, shapes); + } catch (...) { + return nullptr; + } + cache_.insert(it, { product_node, shapes }); + } else { + Logger::Notice("Reusing geometry for", product); + Logger::Notice("Found", it->first->instance); + shapes = it->second; } shape = new ifcopenshell::geometry::Representation::BRep(s, representation_id_builder.str(), shapes); diff --git a/src/ifcgeom/schema_agnostic/Converter.h b/src/ifcgeom/schema_agnostic/Converter.h index 310bdc5785..676bb15e3f 100644 --- a/src/ifcgeom/schema_agnostic/Converter.h +++ b/src/ifcgeom/schema_agnostic/Converter.h @@ -18,6 +18,8 @@ namespace ifcopenshell { namespace geometry { abstract_mapping* mapping_; kernels::AbstractKernel* kernel_; ifcopenshell::geometry::settings settings_; + std::map cache_; + public: kernels::AbstractKernel* kernel() { return kernel_; } diff --git a/src/ifcgeom/taxonomy.cpp b/src/ifcgeom/taxonomy.cpp new file mode 100644 index 0000000000..b44f8858ed --- /dev/null +++ b/src/ifcgeom/taxonomy.cpp @@ -0,0 +1,220 @@ +#include "taxonomy.h" + +using namespace ifcopenshell::geometry::taxonomy; + +namespace { + template + bool compare(const eigen_base& t, const eigen_base& u) { + auto t_begin = t.components->data(); + auto t_end = t.components->data() + t.components->size(); + + auto u_begin = u.components->data(); + auto u_end = u.components->data() + u.components->size(); + + return std::lexicographical_compare(t_begin, t_end, u_begin, u_end); + } + + bool compare(const line& a, const line& b) { + return compare(a.matrix, b.matrix); + } + + bool compare(const plane& a, const plane& b) { + return compare(a.matrix, b.matrix); + } + + bool compare(const circle& a, const circle& b) { + if (a.radius == b.radius) { + return compare(a.matrix, b.matrix); + } + return a.radius < b.radius; + } + + bool compare(const ellipse& a, const ellipse& b) { + if (a.radius == b.radius && a.radius2 == b.radius2) { + return compare(a.matrix, b.matrix); + } + return + std::tie(a.radius, a.radius2) < + std::tie(b.radius, b.radius2); + } + + bool compare(const bspline_curve&, const bspline_curve&) { + throw std::runtime_error("not implemented"); + } + + template + typename std::enable_if::value, int>::type less_to_order(const T& a, const T& b) { + const bool a_lt_b = compare(a, b); + const bool b_lt_a = compare(b, a); + return a_lt_b ? + -1 : (!b_lt_a ? 0 : 1); + } + + template + typename std::enable_if::value, int>::type less_to_order(const T& a, const T& b) { + const bool a_lt_b = a < b; + const bool b_lt_a = b < a; + return a_lt_b ? + -1 : (!b_lt_a ? 0 : 1); + } + + template + int less_to_order_optional(const boost::optional& a, const boost::optional& b) { + if (a && b) { + return less_to_order(*a, *b); + } else if (!a && !b) { + return 0; + } else if (a) { + return 1; + } else { + return -1; + } + } + + int compare(const boost::variant& a, const boost::variant& b) { + bool a_lt_b, b_lt_a; + if (a.which() == 0) { + a_lt_b = compare(boost::get(a), boost::get(b)); + b_lt_a = compare(boost::get(b), boost::get(a)); + } else { + a_lt_b = std::less()(boost::get(a), boost::get(b)); + b_lt_a = std::less()(boost::get(b), boost::get(a)); + } + return a_lt_b ? + -1 : (!b_lt_a ? 0 : 1); + } + + bool compare(const trimmed_curve& a, const trimmed_curve& b); + + bool compare(const collection& a, const collection& b); + + bool compare(const extrusion& a, const extrusion& b) { + const int order[3] = { + less_to_order(a.basis, b.basis), + less_to_order(a.direction, b.direction), + a.depth < b.depth ? -1 : (a.depth == b.depth ? 0 : 1) + }; + auto it = std::find_if(std::begin(order), std::end(order), [](int x) { return x; }); + if (it == std::end(order)) return false; + return *it == -1; + } + + bool compare(const style& a, const style& b) { + const int order[5] = { + less_to_order_optional(a.name, b.name), + less_to_order_optional(a.diffuse, b.diffuse), + less_to_order_optional(a.specular, b.specular), + less_to_order_optional(a.specularity, b.specularity), + less_to_order_optional(a.transparency, b.transparency) + }; + auto it = std::find_if(std::begin(order), std::end(order), [](int x) { return x; }); + if (it == std::end(order)) return false; + return *it == -1; + } + + /* A compile-time for loop over the taxonomy kinds */ + template + struct dispatch_comparison { + static bool dispatch(const item* a, const item* b) { + if (N == a->kind() && N == b->kind()) { + auto A = static_cast*>(a); + auto B = static_cast*>(b); + return compare(*A, *B); + } else { + return dispatch_comparison::dispatch(a, b); + } + } + }; + + template <> + struct dispatch_comparison { + static bool dispatch(const item*, const item*) { + return false; + } + }; +} + +bool ifcopenshell::geometry::taxonomy::less(const item* a, const item* b) { + if (a == b) { + return false; + } + + int a_kind = a->kind(); + int b_kind = b->kind(); + + if (a_kind != b_kind) { + return a_kind < b_kind; + } + + return dispatch_comparison<0>::dispatch(a, b); +} + + +namespace { + bool compare(const trimmed_curve& a, const trimmed_curve& b) { + int a_which_start = a.start.which(); + int a_which_end = a.end.which(); + int b_which_start = b.start.which(); + int b_which_end = b.end.which(); + if (std::tie(a.orientation, a_which_start, a_which_end) == + std::tie(b.orientation, b_which_start, b_which_end)) { + + int start_state = compare(a.start, b.start); + + if (start_state == 0) { + + int end_state = compare(a.end, b.end); + + if (end_state == 0) { + + int a_has_basis = !!a.basis; + int b_has_basis = !!a.basis; + + if (a_has_basis == b_has_basis) { + + if (!a_has_basis) { + // Finally, equality + return false; + } else { + return less(a.basis, b.basis); + } + + } else { + return a_has_basis < b_has_basis; + } + + } else { + return end_state == -1; + } + + } else { + return start_state == -1; + } + + } else { + return + std::tie(a.orientation, a_which_start, a_which_end) < + std::tie(b.orientation, b_which_start, b_which_end); + } + } + + bool compare(const collection& a, const collection& b) { + if (a.children.size() == b.children.size()) { + auto at = a.children.begin(); + auto bt = b.children.begin(); + for (; at != a.children.end(); ++at, ++bt) { + const bool a_lt_b = less(*at, *bt); + const bool b_lt_a = less(*bt, *at); + if (!a_lt_b && !b_lt_a) { + // Elements equal. + continue; + } + return a_lt_b; + } + // Vectors equal. + return false; + } else { + return a.children.size() < b.children.size(); + } + } +} \ No newline at end of file diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index 98a8da2ca7..5c78592078 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -37,6 +37,14 @@ struct item { item(const IfcUtil::IfcBaseClass* instance = nullptr) : instance(instance) {} }; +bool less(const item*, const item*); + +struct less_functor { + bool operator()(const item* a, const item* b) const { + return less(a, b); + } +}; + template struct eigen_base { T* components; @@ -258,7 +266,7 @@ struct trimmed_curve : public curve { basis->print(o, indent + 4); } - const boost::variant const * start_end[2] = { &start, &end }; + const boost::variant * const start_end[2] = { &start, &end }; for (int i = 0; i < 2; ++i) { o << std::string(indent + 4, ' ') << (i == 0 ? "start" : "end") << std::endl; if (start_end[i]->which() == 0) { @@ -307,6 +315,9 @@ struct collection : public geom_item { void print(std::ostream& o, int indent = 0) const { o << std::string(indent, ' ') << "collection" << std::endl; + if (!matrix.components->isIdentity()) { + matrix.print(o, indent + 4); + } for (auto& c : children) { c->print(o, indent + 4); } @@ -326,7 +337,7 @@ struct plane : public surface { virtual item* clone() const { return new plane(*this); } virtual kinds kind() const { return PLANE; } - void print(std::ostream& o, int indent = 0) const { + void print(std::ostream& o, int) const { o << "not implemented"; } }; @@ -386,7 +397,7 @@ struct boolean_result : public collection { }; namespace impl { - typedef std::tuple KindsTuple; + typedef std::tuple KindsTuple; typedef std::tuple CurvesTuple; } From 6d59e6ea90c710c34d8f864de5062e4e2dba8e7c Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 9 Jul 2020 22:09:54 +0200 Subject: [PATCH 235/235] Fixes for transform and mapped item reuse in taxonomy --- src/ifcgeom/abstract_mapping.h | 5 - src/ifcgeom/schema/mapping.cpp | 48 ++----- src/ifcgeom/schema/mapping.h | 2 +- src/ifcgeom/schema_agnostic/Converter.cpp | 131 +++++++++++------- src/ifcgeom/schema_agnostic/Converter.h | 7 +- src/ifcgeom/schema_agnostic/IfcGeomIterator.h | 72 +++++++--- src/ifcgeom/taxonomy.cpp | 6 +- 7 files changed, 162 insertions(+), 109 deletions(-) diff --git a/src/ifcgeom/abstract_mapping.h b/src/ifcgeom/abstract_mapping.h index 97f6254f6c..9a39fb55d0 100644 --- a/src/ifcgeom/abstract_mapping.h +++ b/src/ifcgeom/abstract_mapping.h @@ -15,15 +15,10 @@ namespace ifcopenshell { namespace geometry { - class Element; - class NativeElement; - struct geometry_conversion_task { int index; IfcUtil::IfcBaseEntity* representation; IfcEntityList::ptr products; - std::vector breps; - std::vector elements; }; typedef boost::function filter_t; diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index 77d57a6d02..046bb399ec 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -513,12 +513,14 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcCartesianTransformationOpe scale3 = nu->hasScale3() ? nu->Scale3() : scale1; } - *m->components << + Eigen::Matrix4d tmp; + tmp << axis1 * scale1, axis2 * scale2, axis3 * scale3, origin; + *m->components = tmp.inverse(); m->components->transposeInPlace(); // @todo tag identity? @@ -560,7 +562,7 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcLocalPlacement* inst) { return m4; } -IfcSchema::IfcProduct::list::ptr mapping::products_represented_by(const IfcSchema::IfcRepresentation* representation) { +IfcSchema::IfcProduct::list::ptr mapping::products_represented_by(const IfcSchema::IfcRepresentation* representation, bool only_direct) { IfcSchema::IfcProduct::list::ptr products(new IfcSchema::IfcProduct::list); IfcSchema::IfcProductRepresentation::list::ptr prodreps = representation->OfProductRepresentation(); @@ -575,6 +577,10 @@ IfcSchema::IfcProduct::list::ptr mapping::products_represented_by(const IfcSchem products->push((*it)->data().getInverse((&IfcSchema::IfcProduct::Class()), -1)->as()); } + if (only_direct) { + return products; + } + IfcSchema::IfcRepresentationMap::list::ptr maps = representation->RepresentationMap(); if (maps->size() == 1) { IfcSchema::IfcRepresentationMap* rmap = *maps->begin(); @@ -777,46 +783,16 @@ void mapping::get_representations(std::vector& tasks, int task_index = 0; for (auto representation : *representations) { + // There used to be a whole lot of magic in here to pair multiple products with, + // representations but this is now handled at a later stage where equivalent + // taxonomy::items (sorted based on std::less) are grouped. - // Init. the list of filtered IfcProducts for this representation - - // Include only the desired products for processing. - IfcSchema::IfcProduct::list::ptr ifcproducts = filter_products(products_represented_by(representation), filters); + IfcSchema::IfcProduct::list::ptr ifcproducts = filter_products(products_represented_by(representation, true), filters); if (ifcproducts->size() == 0) { continue; } - auto geometry_reuse_ok_for_current_representation_ = reuse_ok_(s, ifcproducts); - - IfcSchema::IfcRepresentationMap::list::ptr maps = representation->RepresentationMap(); - - if (!geometry_reuse_ok_for_current_representation_ && maps->size() == 1) { - // unfiltered_products contains products represented by this representation by means of mapped items. - // For example because of openings applied to products, reuse might not be acceptable and then the - // products will be processed by means of their immediate representation and not the mapped representation. - - // IfcRepresentationMaps are also used for IfcTypeProducts, so an additional check is performed whether the map - // is indeed used by IfcMappedItems. - IfcSchema::IfcRepresentationMap* map = *maps->begin(); - if (map->MapUsage()->size() > 0) { - continue; - } - } - - // Check if this represenation has (or will be) processed as part its mapped representation - bool representation_processed_as_mapped_item = false; - IfcSchema::IfcRepresentation* rep_mapped_to = representation_mapped_to(representation); - if (rep_mapped_to) { - representation_processed_as_mapped_item = geometry_reuse_ok_for_current_representation_ && ( - ok_mapped_representations->contains(rep_mapped_to) || reuse_ok_(s, filter_products(products_represented_by(rep_mapped_to), filters))); - } - - if (representation_processed_as_mapped_item) { - ok_mapped_representations->push(rep_mapped_to); - continue; - } - // @todo, fix this properly by considering the mapped geometry types in the representation. if (representation->hasRepresentationIdentifier() && representation->RepresentationIdentifier() == "Body") { geometry_conversion_task task; diff --git a/src/ifcgeom/schema/mapping.h b/src/ifcgeom/schema/mapping.h index 597826cf33..232ee8e848 100644 --- a/src/ifcgeom/schema/mapping.h +++ b/src/ifcgeom/schema/mapping.h @@ -31,7 +31,7 @@ namespace geometry { const IfcSchema::IfcMaterial* get_single_material_association(const IfcSchema::IfcProduct* product); IfcSchema::IfcRepresentation* representation_mapped_to(const IfcSchema::IfcRepresentation* representation); - IfcSchema::IfcProduct::list::ptr products_represented_by(const IfcSchema::IfcRepresentation* representation); + IfcSchema::IfcProduct::list::ptr products_represented_by(const IfcSchema::IfcRepresentation* representation, bool only_direct=false); bool reuse_ok_(settings& s, const IfcSchema::IfcProduct::list::ptr& products); IfcEntityList::ptr find_openings(const IfcSchema::IfcProduct* product); IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity* product, bool include_openings); diff --git a/src/ifcgeom/schema_agnostic/Converter.cpp b/src/ifcgeom/schema_agnostic/Converter.cpp index 3fd94452e2..8b1a87de12 100644 --- a/src/ifcgeom/schema_agnostic/Converter.cpp +++ b/src/ifcgeom/schema_agnostic/Converter.cpp @@ -9,15 +9,14 @@ ifcopenshell::geometry::Converter::Converter(const std::string& geometry_library mapping_ = impl::mapping_implementations().construct(file, settings_); } -ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create_brep_for_representation_and_product( - IfcUtil::IfcBaseEntity* representation, IfcUtil::IfcBaseEntity* product) { - - std::stringstream representation_id_builder; - +ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create_brep_for_representation_and_product(taxonomy::item* product_node, const taxonomy::matrix4& place) { + auto product = (IfcUtil::IfcBaseEntity*) product_node->instance; const std::string product_type = product->declaration().name(); // @todo element_settings s(settings_, 1.0 /*getValue(GV_LENGTH_UNIT) */, product_type); + std::stringstream representation_id_builder; + int parent_id = -1; try { IfcUtil::IfcBaseEntity* parent_object = mapping_->get_decomposing_entity(product); @@ -30,62 +29,34 @@ ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create const std::string guid = product->get_value("GlobalId"); const std::string name = product->get_value_or("Name", ""); - - representation_id_builder << representation->data().id(); - ifcopenshell::geometry::Representation::BRep* shape; - ifcopenshell::geometry::ConversionResults shapes; + // @todo should be rep id. + representation_id_builder << product->data().id(); - /* - auto rep_item = mapping_->map(representation); - // @todo should map() throw an exception instead? - if (rep_item == nullptr) { - return nullptr; - } - */ + brep_ptr shape; - - std::clock_t map_start = std::clock(); - - // @todo how to combine product_node and rep_item? - auto product_node = (taxonomy::geom_item*) mapping_->map(product); - if (product_node == nullptr) { - return nullptr; - } - - std::clock_t geom_start = std::clock(); - - if (false) { - std::ostringstream oss; - product_node->print(oss); - std::string s = oss.str(); - std::wcout << s.c_str() << std::endl; - } - - auto place = taxonomy::matrix4(); - std::swap(place, product_node->matrix); - - auto it = cache_.find(product_node); + auto it = cache_.end(); // cache_.find(product_node); if (it == cache_.end()) { try { + ifcopenshell::geometry::ConversionResults shapes; + + std::clock_t geom_start = std::clock(); kernel_->convert(product_node, shapes); + std::clock_t geom_end = std::clock(); + + total_geom_time += (geom_end - geom_start) / (double)CLOCKS_PER_SEC; + + shape = brep_ptr(new ifcopenshell::geometry::Representation::BRep(s, representation_id_builder.str(), shapes)); } catch (...) { return nullptr; } - cache_.insert(it, { product_node, shapes }); + cache_.insert(it, { product_node, shape }); } else { Logger::Notice("Reusing geometry for", product); Logger::Notice("Found", it->first->instance); - shapes = it->second; + shape = it->second; } - shape = new ifcopenshell::geometry::Representation::BRep(s, representation_id_builder.str(), shapes); - - std::clock_t geom_end = std::clock(); - - total_map_time += (geom_start - map_start) / (double) CLOCKS_PER_SEC; - total_geom_time += (geom_end - geom_start) / (double) CLOCKS_PER_SEC; - return new NativeElement( product->data().id(), parent_id, @@ -96,9 +67,32 @@ ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create "", place, // product_node->matrix, - boost::shared_ptr(shape), + shape, product ); +} + +ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create_brep_for_representation_and_product( + // @todo representation is not used yet. + IfcUtil::IfcBaseEntity*, IfcUtil::IfcBaseEntity* product) { + + std::clock_t map_start = std::clock(); + + // @todo how to combine product_node and rep_item? + auto product_node = (taxonomy::geom_item*) mapping_->map(product); + if (product_node == nullptr) { + return nullptr; + } + + std::clock_t map_end = std::clock(); + + auto place = taxonomy::matrix4(); + std::swap(place, product_node->matrix); + + total_map_time += (map_end - map_start) / (double)CLOCKS_PER_SEC; + + return create_brep_for_representation_and_product(product_node, place); + /* std::stringstream representation_id_builder; @@ -240,6 +234,47 @@ ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create */ } +ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create_brep_for_processed_representation( + IfcUtil::IfcBaseEntity* product, const taxonomy::matrix4& place, ifcopenshell::geometry::NativeElement* brep) { + + int parent_id = -1; + try { + IfcUtil::IfcBaseEntity* parent_object = mapping_->get_decomposing_entity(product); + if (parent_object) { + parent_id = parent_object->data().id(); + } + } catch (const std::exception& e) { + Logger::Error(e); + } + + const std::string guid = product->get_value("GlobalId"); + const std::string name = product->get_value_or("Name", ""); + + /* + 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( + product->data().id(), + parent_id, + name, + product_type, + guid, + // @todo + "", + place, + brep->geometry_pointer(), + product + ); +} + ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create_brep_for_processed_representation( IfcUtil::IfcBaseEntity* /* representation */, IfcUtil::IfcBaseEntity* product, ifcopenshell::geometry::NativeElement* brep) diff --git a/src/ifcgeom/schema_agnostic/Converter.h b/src/ifcgeom/schema_agnostic/Converter.h index 676bb15e3f..5a1118f3d3 100644 --- a/src/ifcgeom/schema_agnostic/Converter.h +++ b/src/ifcgeom/schema_agnostic/Converter.h @@ -14,11 +14,13 @@ namespace ifcopenshell { namespace geometry { class NativeElement; class Converter { + public: + typedef boost::shared_ptr brep_ptr; private: abstract_mapping* mapping_; kernels::AbstractKernel* kernel_; ifcopenshell::geometry::settings settings_; - std::map cache_; + std::map cache_; public: kernels::AbstractKernel* kernel() { return kernel_; } @@ -96,6 +98,9 @@ namespace ifcopenshell { namespace geometry { ifcopenshell::geometry::NativeElement* create_brep_for_representation_and_product(IfcUtil::IfcBaseEntity* representation, IfcUtil::IfcBaseEntity* product); ifcopenshell::geometry::NativeElement* create_brep_for_processed_representation(IfcUtil::IfcBaseEntity* representation, IfcUtil::IfcBaseEntity* product, ifcopenshell::geometry::NativeElement* brep); + ifcopenshell::geometry::NativeElement* create_brep_for_representation_and_product(taxonomy::item*, const taxonomy::matrix4&); + ifcopenshell::geometry::NativeElement* create_brep_for_processed_representation(IfcUtil::IfcBaseEntity*, const taxonomy::matrix4&, ifcopenshell::geometry::NativeElement*); + /* static int count(const ifcopenshell::geometry::ConversionResultShape*, int, bool unique=false); static int surface_genus(const ifcopenshell::geometry::ConversionResultShape*); diff --git a/src/ifcgeom/schema_agnostic/IfcGeomIterator.h b/src/ifcgeom/schema_agnostic/IfcGeomIterator.h index 2a9420c426..076fef099d 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomIterator.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomIterator.h @@ -105,6 +105,17 @@ #undef max #endif +namespace ifcopenshell { namespace geometry { + +struct geometry_conversion_result { + taxonomy::item* item; + std::vector> products; + std::vector breps; + std::vector elements; +}; + +} } + namespace { ifcopenshell::geometry::Element* process_based_on_settings( const ifcopenshell::geometry::settings& settings, @@ -137,11 +148,12 @@ namespace { void create_element( ifcopenshell::geometry::Converter* converter, const ifcopenshell::geometry::settings& settings, - ifcopenshell::geometry::geometry_conversion_task* rep) + ifcopenshell::geometry::geometry_conversion_result* rep) { - IfcUtil::IfcBaseEntity* representation = rep->representation; - IfcUtil::IfcBaseEntity* product = (IfcUtil::IfcBaseEntity*) *rep->products->begin(); - auto brep = converter->create_brep_for_representation_and_product(representation, product); + ifcopenshell::geometry::taxonomy::item* representation = rep->item; + auto place = rep->products.front().second; + auto brep = converter->create_brep_for_representation_and_product(representation, place); + if (!brep) { return; } @@ -154,10 +166,11 @@ namespace { rep->breps = { brep }; rep->elements = { elem }; - for (auto it = rep->products->begin() + 1; it != rep->products->end(); ++it) { - auto brep2 = converter->create_brep_for_processed_representation(representation, (IfcUtil::IfcBaseEntity*) *it, brep); + for (auto it = rep->products.begin() + 1; it != rep->products.end(); ++it) { + const auto& p = *it; + auto brep2 = converter->create_brep_for_processed_representation(p.first, p.second, brep); if (brep2) { - auto elem2 = process_based_on_settings(settings, brep, dynamic_cast(elem)); + auto elem2 = process_based_on_settings(settings, brep2, dynamic_cast(elem)); if (elem2) { rep->breps.push_back(brep2); rep->elements.push_back(elem2); @@ -174,8 +187,8 @@ namespace ifcopenshell { namespace geometry { int num_threads_; std::atomic progress_; - std::vector tasks_; - std::vector::iterator task_iterator_; + std::vector tasks_; + std::vector::iterator task_iterator_; std::vector all_processed_elements_; std::vector all_processed_native_elements_; @@ -210,7 +223,34 @@ namespace ifcopenshell { namespace geometry { bool initialize() { converter_ = new Converter(geometry_library_, ifc_file, settings_); - converter_->mapping()->get_representations(tasks_, filters_, settings_); + std::vector reps; + converter_->mapping()->get_representations(reps, filters_, settings_); + std::vector products; + for (auto& r : reps) { + std::copy(r.products->begin(), r.products->end(), std::back_inserter(products)); + } + std::vector items; + std::map placements; + std::transform(products.begin(), products.end(), std::back_inserter(items), [this, &placements](IfcUtil::IfcBaseClass* p) { + auto item = converter_->mapping()->map(p); + // Product placements do not affect item reuse and should temporarily be swapped to identity + std::swap(placements[item], ((taxonomy::geom_item*)item)->matrix); + return item; + }); + std::sort(items.begin(), items.end(), taxonomy::less); + auto it = items.begin(); + while (it < items.end()) { + auto jt = std::upper_bound(it, items.end(), *it, taxonomy::less); + geometry_conversion_result r; + r.item = *it; + std::transform(it, jt, std::back_inserter(r.products), [&r, &placements](taxonomy::item* product_node) { + return std::make_pair((IfcUtil::IfcBaseEntity*) product_node->instance, placements[product_node]); + }); + tasks_.push_back(r); + it = jt; + } + + Logger::Notice("Created " + boost::lexical_cast(tasks_.size()) + " tasks for " + boost::lexical_cast(products.size()) + " products"); if (tasks_.size() == 0) { Logger::Warning("No representations encountered, aborting"); @@ -386,8 +426,8 @@ namespace ifcopenshell { namespace geometry { ++done; } - IfcUtil::IfcBaseClass* create_shape_model_for_next_entity() { - geometry_conversion_task* task = nullptr; + const IfcUtil::IfcBaseClass* create_shape_model_for_next_entity() { + geometry_conversion_result* task = nullptr; while (task_iterator_ != tasks_.end()) { task = &*task_iterator_++; create_element(converter_, settings_, task); @@ -400,7 +440,7 @@ namespace ifcopenshell { namespace geometry { if (task) { all_processed_elements_.insert(all_processed_elements_.end(), task->elements.begin(), task->elements.end()); all_processed_native_elements_.insert(all_processed_native_elements_.end(), task->breps.begin(), task->breps.end()); - return (*task->products)[0]; + return task->item->instance; } else { return nullptr; } @@ -410,7 +450,7 @@ namespace ifcopenshell { namespace geometry { /// Moves to the next shape representation, create its geometry, and returns the associated product. /// Use get() to retrieve the created geometry. - IfcUtil::IfcBaseClass* next() { + const IfcUtil::IfcBaseClass* next() { if (num_threads_ != 1) { task_result_index_++; if (task_result_index_ == all_processed_elements_.size()) { @@ -555,8 +595,8 @@ namespace ifcopenshell { namespace geometry { */ } - IfcUtil::IfcBaseClass* create() { - IfcUtil::IfcBaseClass* product = nullptr; + const IfcUtil::IfcBaseClass* create() { + const IfcUtil::IfcBaseClass* product = nullptr; try { product = create_shape_model_for_next_entity(); } catch (const std::exception& e) { diff --git a/src/ifcgeom/taxonomy.cpp b/src/ifcgeom/taxonomy.cpp index b44f8858ed..cf33e1c96a 100644 --- a/src/ifcgeom/taxonomy.cpp +++ b/src/ifcgeom/taxonomy.cpp @@ -89,6 +89,8 @@ namespace { bool compare(const collection& a, const collection& b); bool compare(const extrusion& a, const extrusion& b) { + // @todo extrusions can also have non-identity matrices right? perhaps it's time + // for a dedicated transform node and not on the abstract geom_item. const int order[3] = { less_to_order(a.basis, b.basis), less_to_order(a.direction, b.direction), @@ -211,8 +213,8 @@ namespace { } return a_lt_b; } - // Vectors equal. - return false; + // Vectors equal, compare matrix (in case of mapped items). + return compare(a.matrix, b.matrix); } else { return a.children.size() < b.children.size(); }