From 3e80d3646c86b9c1a03ace793c3cd5437b2f2935 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 29 Aug 2018 12:54:25 +0200 Subject: [PATCH] Work on ifcxml parsere --- cmake/CMakeLists.txt | 11 ++++- nix/build-all.py | 4 ++ src/ifcconvert/IfcConvert.cpp | 8 ++++ src/ifcparse/IfcFile.h | 10 +++++ src/ifcparse/IfcParse.cpp | 83 +++++++++++++++++++++-------------- src/ifcparse/IfcParse.h | 1 + win/run-cmake.bat | 4 ++ 7 files changed, 86 insertions(+), 35 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 9a52a319d4..41ce284157 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -23,6 +23,7 @@ project (IfcOpenShell) OPTION(UNICODE_SUPPORT "Build IfcOpenShell with Unicode support (requires ICU)." ON) OPTION(COLLADA_SUPPORT "Build IfcConvert with COLLADA support (requires OpenCOLLADA)." ON) +OPTION(IFCXML_SUPPORT "Build IfcParse with ifcXML support (requires libxml2)." ON) OPTION(ENABLE_BUILD_OPTIMIZATIONS "Enable certain compiler and linker optimizations on RelWithDebInfo and Release builds." OFF) OPTION(IFCCONVERT_DOUBLE_PRECISION "IfcConvert: Use double precision floating-point numbers." ON) OPTION(BUILD_IFCPYTHON "Build IfcPython." ON) @@ -88,6 +89,8 @@ UNIFY_ENVVARS_AND_CACHE(ICU_INCLUDE_DIR) UNIFY_ENVVARS_AND_CACHE(ICU_LIBRARY_DIR) UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_INCLUDE_DIR) UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_LIBRARY_DIR) +UNIFY_ENVVARS_AND_CACHE(LIBXML2_INCLUDE_DIR) +UNIFY_ENVVARS_AND_CACHE(LIBXML2_LIBRARIES) UNIFY_ENVVARS_AND_CACHE(PCRE_LIBRARY_DIR) UNIFY_ENVVARS_AND_CACHE(PYTHON_EXECUTABLE) IF(WIN32) @@ -136,6 +139,10 @@ if(USE_MMAP) add_definitions(-DUSE_MMAP) endif() +if (IFCXML_SUPPORT) + add_definitions(-DWITH_IFCXML) +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}") @@ -437,7 +444,7 @@ if (IFCCONVERT_DOUBLE_PRECISION) endif() INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS} - ${ICU_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} + ${ICU_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ${LIBXML2_INCLUDE_DIR} ) function(files_for_ifc_version IFC_VERSION RESULT_NAME) @@ -571,7 +578,7 @@ set(IFCPARSE_FILES ${IFCPARSE_CPP_FILES} ${IFCPARSE_H_FILES}) add_library(IfcParse ${IFCPARSE_FILES}) set_target_properties(IfcParse PROPERTIES COMPILE_FLAGS -DIFC_PARSE_EXPORTS) -TARGET_LINK_LIBRARIES(IfcParse ${Boost_LIBRARIES} ${BCRYPT_LIBRARIES}) +TARGET_LINK_LIBRARIES(IfcParse ${Boost_LIBRARIES} ${BCRYPT_LIBRARIES} ${LIBXML2_LIBRARIES}) IF(UNICODE_SUPPORT) TARGET_LINK_LIBRARIES(IfcParse ${ICU_LIBRARIES}) diff --git a/nix/build-all.py b/nix/build-all.py index 3c8f81bf52..c0991dd38a 100644 --- a/nix/build-all.py +++ b/nix/build-all.py @@ -559,6 +559,8 @@ run_cmake("", cmake_args=[ "-DICU_INCLUDE_DIR=" "%s/install/icu-%s/include" % (DEPS_DIR, ICU_VERSION), "-DICU_LIBRARY_DIR=" "%s/install/icu-%s/lib" % (DEPS_DIR, ICU_VERSION), "-DPCRE_LIBRARY_DIR=" "%s/install/pcre-%s/lib" % (DEPS_DIR, PCRE_VERSION), + "-DLIBXML2_INCLUDE_DIR=" "%s/install/libxml2-%s/include/libxml2" % (DEPS_DIR, LIBXML_VERSION), + "-DLIBXML2_LIBRARIES=" "%s/install/libxml2-%s/lib/libxml2.a" % (DEPS_DIR, LIBXML_VERSION), "-DBUILD_IFCPYTHON=" "OFF", "-DUSE_MMAP=" "OFF", "-DCMAKE_INSTALL_PREFIX=" "%s/install/ifcopenshell" % (DEPS_DIR,)], cmake_dir=CMAKE_DIR, cwd=executables_dir) @@ -596,6 +598,8 @@ for PYTHON_VERSION, _, TAG in PYTHON_VERSION_CONFS(): "-DOPENCOLLADA_LIBRARY_DIR=%s/install/OpenCOLLADA/lib/opencollada" % (DEPS_DIR,), "-DICU_INCLUDE_DIR=%s/install/icu-%s/include" % (DEPS_DIR, ICU_VERSION), "-DICU_LIBRARY_DIR=%s/install/icu-%s/lib" % (DEPS_DIR, ICU_VERSION), + "-DLIBXML2_INCLUDE_DIR=%s/install/libxml2-%s/include/libxml2" % (DEPS_DIR, LIBXML_VERSION), + "-DLIBXML2_LIBRARIES=%s/install/libxml2-%s/lib/libxml2.a" % (DEPS_DIR, LIBXML_VERSION), "-DPYTHON_LIBRARY=%s" % (PYTHON_LIBRARY,), "-DPYTHON_EXECUTABLE=%s" % (PYTHON_EXECUTABLE,), "-DPYTHON_INCLUDE_DIR=%s" % (PYTHON_INCLUDE,), diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 8d8ad7293b..fede5d3014 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -779,6 +779,8 @@ void write_log(bool header) { } } +#include + bool init_input_file(const std::string& filename, IfcParse::IfcFile*& ifc_file, bool no_progress, bool mmap) { // Prevent IfcFile::Init() prints by setting output to null temporarily @@ -788,6 +790,12 @@ bool init_input_file(const std::string& filename, IfcParse::IfcFile*& ifc_file, ifc_file = new IfcParse::IfcFile(filename, mmap); #else (void)mmap; + +#ifdef WITH_IFCXML + if (boost::ends_with(boost::to_lower_copy(filename), ".ifcxml")) { + ifc_file = IfcParse::parse_ifcxml(filename); + } else +#endif ifc_file = new IfcParse::IfcFile(filename); if (!ifc_file->good()) { #endif diff --git a/src/ifcparse/IfcFile.h b/src/ifcparse/IfcFile.h index 789716073b..e093d706b9 100644 --- a/src/ifcparse/IfcFile.h +++ b/src/ifcparse/IfcFile.h @@ -86,6 +86,7 @@ private: void initialize_(IfcParse::IfcSpfStream* f); + void build_inverses_(IfcUtil::IfcBaseClass*); public: IfcParse::IfcSpfLexer* tokens; IfcParse::IfcSpfStream* stream; @@ -191,6 +192,11 @@ public: const IfcParse::schema_definition* schema() const { return schema_; } std::pair getUnit(const std::string& unit_type); + + bool parsing_complete() const { return parsing_complete_; } + bool& parsing_complete() { return parsing_complete_; } + + void build_inverses(); }; template @@ -207,6 +213,10 @@ public: } }; +#ifdef WITH_IFCXML +IFC_PARSE_API IfcFile* parse_ifcxml(const std::string& filename); +#endif + } #endif diff --git a/src/ifcparse/IfcParse.cpp b/src/ifcparse/IfcParse.cpp index f8b3a6d25d..c1b1c21190 100644 --- a/src/ifcparse/IfcParse.cpp +++ b/src/ifcparse/IfcParse.cpp @@ -1016,13 +1016,18 @@ IfcEntityInstanceData::IfcEntityInstanceData(const IfcEntityInstanceData& e) { } } +static IfcParse::NullArgument static_null_attribute; Argument* IfcEntityInstanceData::getArgument(unsigned int i) const { if (attributes_ == 0) { load(); } if (i < getArgumentCount()) { - return attributes_[i]; + if (attributes_[i] == nullptr) { + return &static_null_attribute; + } else { + return attributes_[i]; + } } else { throw IfcParse::IfcException("Attribute index out of range"); } @@ -1284,8 +1289,8 @@ IfcFile::IfcFile(IfcParse::IfcSpfStream* s) { } IfcFile::IfcFile(const IfcParse::schema_definition* schema) - : parsing_complete_(false) - , good_(false) + : parsing_complete_(true) + , good_(true) , schema_(schema) , ifcroot_type_(schema_->declaration_by_name("IfcRoot")) , MaxId(0) @@ -1521,18 +1526,20 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity) { // Obtain all forward references by a depth-first // traversal and add them to the file. - try { - IfcEntityList::ptr entity_attributes = traverse(entity, 1); - for (IfcEntityList::it it = entity_attributes->begin(); it != entity_attributes->end(); ++it) { - if (*it != entity) { - entity_entity_map_t::iterator mit2 = entity_file_map.find(*it); - if (mit2 == entity_file_map.end()) { - entity_file_map.insert(entity_entity_map_t::value_type(*it, addEntity(*it))); + if (parsing_complete_) { + try { + IfcEntityList::ptr entity_attributes = traverse(entity, 1); + for (IfcEntityList::it it = entity_attributes->begin(); it != entity_attributes->end(); ++it) { + if (*it != entity) { + entity_entity_map_t::iterator mit2 = entity_file_map.find(*it); + if (mit2 == entity_file_map.end()) { + entity_file_map.insert(entity_entity_map_t::value_type(*it, addEntity(*it))); + } } } + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Failed to visit forward references of", entity); } - } catch (...) { - Logger::Message(Logger::LOG_ERROR, "Failed to visit forward references of", entity); } // See whether the instance is already part of a file @@ -1642,6 +1649,7 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity) { we->set_id(FreshId()); } + // @todo entity_file_map: use weak_ptr entity_file_map.insert(entity_entity_map_t::value_type(entity, new_entity)); } @@ -1709,27 +1717,8 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity) { byid[new_id] = new_entity; } - if (ty->as_entity()) { - // The mapping by reference is updated. - IfcEntityList::ptr entity_attributes(new IfcEntityList); - try { - entity_attributes = traverse(new_entity, 1); - } catch (const std::exception& e) { - Logger::Error(e); - } - - for (IfcEntityList::it it = entity_attributes->begin(); it != entity_attributes->end(); ++it) { - IfcUtil::IfcBaseClass* entity_attribute = *it; - if (*it == new_entity) continue; - try { - if (entity_attribute->declaration().as_entity()) { - unsigned entity_attribute_id = entity_attribute->data().id(); - byref[entity_attribute_id].push_back(new_entity->data().id()); - } - } catch (const std::exception& e) { - Logger::Error(e); - } - } + if (parsing_complete_ && ty->as_entity()) { + build_inverses_(new_entity); } return new_entity; @@ -2097,3 +2086,31 @@ std::pair IfcFile::getUnit(const std::string& un return return_value; } + +void IfcParse::IfcFile::build_inverses_(IfcUtil::IfcBaseClass* inst) { + IfcEntityList::ptr entity_attributes(new IfcEntityList); + try { + entity_attributes = traverse(inst, 1); + } catch (const std::exception& e) { + Logger::Error(e); + } + + for (IfcEntityList::it it = entity_attributes->begin(); it != entity_attributes->end(); ++it) { + IfcUtil::IfcBaseClass* entity_attribute = *it; + if (*it == inst) continue; + try { + if (entity_attribute->declaration().as_entity()) { + unsigned entity_attribute_id = entity_attribute->data().id(); + byref[entity_attribute_id].push_back(inst->data().id()); + } + } catch (const std::exception& e) { + Logger::Error(e); + } + } +} + +void IfcParse::IfcFile::build_inverses() { + for (auto& pair : *this) { + build_inverses_(pair.second); + } +} \ No newline at end of file diff --git a/src/ifcparse/IfcParse.h b/src/ifcparse/IfcParse.h index e002a6f969..384e7c4465 100644 --- a/src/ifcparse/IfcParse.h +++ b/src/ifcparse/IfcParse.h @@ -165,6 +165,7 @@ namespace IfcParse { public: ArgumentList() : size_(0), list_(0) {} + ArgumentList(size_t n) : size_(n), list_(new Argument*[size_]) {} ~ArgumentList(); void read(IfcSpfLexer* t, std::vector& ids); diff --git a/win/run-cmake.bat b/win/run-cmake.bat index c72996a699..e46ad6ccd0 100755 --- a/win/run-cmake.bat +++ b/win/run-cmake.bat @@ -70,6 +70,8 @@ if not defined OCC_INCLUDE_DIR set OCC_INCLUDE_DIR=%INSTALL_DIR%\oce\include\oce if not defined OCC_LIBRARY_DIR set OCC_LIBRARY_DIR=%INSTALL_DIR%\oce\Win%ARCH_BITS%\lib set OPENCOLLADA_INCLUDE_DIR=%INSTALL_DIR%\OpenCOLLADA\include\opencollada set OPENCOLLADA_LIBRARY_DIR=%INSTALL_DIR%\OpenCOLLADA\lib\opencollada +set LIBXML2_INCLUDE_DIR=%DEPS_DIR%\OpenCOLLADA\Externals\LibXML\include +set LIBXML2_LIBRARIES=%INSTALL_DIR%\OpenCOLLADA\lib\opencollada\xml.lib if not defined PY_VER_MAJOR_MINOR set PY_VER_MAJOR_MINOR=34 if not defined PYTHONHOME set PYTHONHOME=%INSTALL_DIR%\Python%PY_VER_MAJOR_MINOR% set PYTHON_INCLUDE_DIR=%PYTHONHOME%\include @@ -93,6 +95,8 @@ echo OCC_INCLUDE_DIR = %OCC_INCLUDE_DIR% echo OCC_LIBRARY_DIR = %OCC_LIBRARY_DIR% echo OPENCOLLADA_INCLUDE_DIR = %OPENCOLLADA_INCLUDE_DIR% echo OPENCOLLADA_LIBRARY_DIR = %OPENCOLLADA_LIBRARY_DIR% +echo LIBXML2_INCLUDE_DIR = %LIBXML2_INCLUDE_DIR% +echo LIBXML2_LIBRARIES = %LIBXML2_LIBRARIES% echo PYTHONHOME = %PYTHONHOME% echo PYTHON_INCLUDE_DIR = %PYTHON_INCLUDE_DIR% echo PYTHON_LIBRARY = %PYTHON_LIBRARY%