From 2fc76400c4931b290cd54577aff29b9f81022afe Mon Sep 17 00:00:00 2001 From: topheg Date: Wed, 2 Nov 2022 09:33:46 +0100 Subject: [PATCH 1/7] Make use of OpenGL optional --- CMakeLists.txt | 3 + README.md | 2 + sources/CMakeLists.txt | 40 +++++- sources/include/citygml/appearancemanager.h | 2 - sources/include/citygml/citygml.h | 9 +- sources/include/citygml/citymodel.h | 4 +- sources/include/citygml/cityobject.h | 4 +- sources/include/citygml/geometry.h | 4 +- sources/include/citygml/polygon.h | 8 +- sources/include/citygml/tesselator.h | 33 +---- sources/include/citygml/tesselatorbase.h | 69 ++++++++++ .../include/parser/citygmldocumentparser.h | 4 +- sources/src/citygml/citymodel.cpp | 4 +- sources/src/citygml/cityobject.cpp | 8 +- sources/src/citygml/geometry.cpp | 6 +- sources/src/citygml/polygon.cpp | 26 ++-- sources/src/citygml/tesselator.cpp | 83 ++--------- sources/src/citygml/tesselatorbase.cpp | 129 ++++++++++++++++++ sources/src/parser/citygmldocumentparser.cpp | 15 +- sources/src/parser/parserxercesc.cpp | 19 +-- test/CMakeLists.txt | 7 +- test/citygmltest.cpp | 48 ++++--- 22 files changed, 345 insertions(+), 182 deletions(-) create mode 100644 sources/include/citygml/tesselatorbase.h create mode 100644 sources/src/citygml/tesselatorbase.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 99ab3c4c..f5da939f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -135,6 +135,9 @@ IF( MSVC AND LIBCITYGML_STATIC_CRT ) ENDFOREACH( flag_var ) ENDIF( MSVC AND LIBCITYGML_STATIC_CRT ) + +OPTION(LIBCITYGML_USE_OPENGL "Set to OFF to prevent use of GL libraries. Tesselator won't be compiled." ON) + # core ADD_SUBDIRECTORY( sources ) diff --git a/README.md b/README.md index 188123dd..7ce93ef8 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ Dependencies: The XercesC xml parsing library is the only requirement compiling and using libcitygml. Please use a version > 3.1 compiled with an SDK that is compatible with C++11. +OpenGL is required if you want to use the tesselator provided in the project. Otherwise, you can provide another implementation by inheriting TesselatorBase, or not use tesselation. + GDAL is required if coordinate transformations should be applied during paring. OpenSceneGraph is required for building the plugin. diff --git a/sources/CMakeLists.txt b/sources/CMakeLists.txt index 520afe4f..17d06cff 100644 --- a/sources/CMakeLists.txt +++ b/sources/CMakeLists.txt @@ -6,7 +6,11 @@ ENDIF (NOT DEFINED CMAKE_MODULE_PATH) SET( target citygml ) -FIND_PACKAGE( OpenGL REQUIRED ) +IF( LIBCITYGML_USE_OPENGL) + FIND_PACKAGE( OpenGL REQUIRED ) +ELSE( LIBCITYGML_USE_OPENGL ) + SET( GLU_INCLUDE_PATH "" ) +ENDIF( LIBCITYGML_USE_OPENGL ) FIND_PACKAGE( Xerces REQUIRED ) # gdal library @@ -53,7 +57,7 @@ INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/include SET(SOURCES src/citygml/attributesmap.cpp src/citygml/citymodel.cpp - src/citygml/tesselator.cpp + src/citygml/tesselatorbase.cpp src/citygml/object.cpp src/citygml/featureobject.cpp src/citygml/appearance.cpp @@ -112,9 +116,12 @@ SET(SOURCES src/parser/implicitgeometryelementparser.cpp src/parser/addressparser.cpp ) + if(UNIX) if (APPLE) - set_source_files_properties(src/citygml/tesselator.cpp PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations") # for warnings: 'glu*' is deprecated... + if (LIBCITYGML_USE_OPENGL) + set_source_files_properties(src/citygml/tesselator.cpp PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations") # for warnings: 'glu*' is deprecated... + endif (LIBCITYGML_USE_OPENGL) endif (APPLE) endif(UNIX) @@ -139,7 +146,7 @@ SET(PUBLIC_HEADER include/citygml/citygml.h include/citygml/transformmatrix.h include/citygml/implictgeometry.h - include/citygml/tesselator.h + include/citygml/tesselatorbase.h include/citygml/texture.h include/citygml/appearancetargetdefinition.h include/citygml/texturetargetdefinition.h @@ -153,12 +160,24 @@ SET(PUBLIC_HEADER include/citygml/externalreference.h ) + +if(LIBCITYGML_USE_OPENGL) + SET(SOURCES + ${SOURCES} + src/citygml/tesselator.cpp + ) + + SET(PUBLIC_HEADER + ${PUBLIC_HEADER} + include/citygml/tesselator.h + ) +endif(LIBCITYGML_USE_OPENGL) + SET(HEADERS ${PUBLIC_HEADER} ${CMAKE_MODULE_PATH}/citygml_api.h.in - include/citygml/tesselator.h include/citygml/utils.h include/citygml/appearancemanager.h include/citygml/polygonmanager.h @@ -205,7 +224,10 @@ generate_export_header(citygml EXPORT_MACRO_NAME LIBCITYGML_EXPORT EXPORT_FILE_NAME ${EXPORT_HEADER_FILE_NAME}) -TARGET_LINK_LIBRARIES( ${target} PUBLIC ${XERCESC_LIBRARIES} ${OPENGL_LIBRARIES} ) +TARGET_LINK_LIBRARIES( ${target} PUBLIC ${XERCESC_LIBRARIES} ) +if(LIBCITYGML_USE_OPENGL) + TARGET_LINK_LIBRARIES( ${target} PUBLIC ${OPENGL_LIBRARIES} ) +endif(LIBCITYGML_USE_OPENGL) if(LIBCITYGML_USE_GDAL) TARGET_LINK_LIBRARIES( ${target} PUBLIC ${GDAL_LIBRARY} ) endif(LIBCITYGML_USE_GDAL) @@ -284,7 +306,11 @@ else() set(LIBCITYGML_POSTFIX "") endif() -set(PKG_CONFIG_REQUIRES "xerces-c glu") +set(PKG_CONFIG_REQUIRES "xerces-c") + +if(LIBCITYGML_USE_OPENGL) + set(PKG_CONFIG_REQUIRES "${PKG_CONFIG_REQUIRES} glu") + endif(LIBCITYGML_USE_OPENGL) if (LIBCITYGML_USE_GDAL) set(PKG_CONFIG_REQUIRES "${PKG_CONFIG_REQUIRES} gdal") diff --git a/sources/include/citygml/appearancemanager.h b/sources/include/citygml/appearancemanager.h index 4c4e9731..73b46192 100644 --- a/sources/include/citygml/appearancemanager.h +++ b/sources/include/citygml/appearancemanager.h @@ -8,8 +8,6 @@ #include #include -class Tesselator; - namespace citygml { class CityGMLLogger; diff --git a/sources/include/citygml/citygml.h b/sources/include/citygml/citygml.h index 6e9be843..932889bc 100644 --- a/sources/include/citygml/citygml.h +++ b/sources/include/citygml/citygml.h @@ -31,10 +31,7 @@ #include #include #include - - -class Tesselator; - +class TesselatorBase; namespace citygml { class CityModel; @@ -88,8 +85,8 @@ namespace citygml std::string srcSRS; }; - LIBCITYGML_EXPORT std::shared_ptr load( std::istream& stream, const ParserParams& params, std::shared_ptr logger = nullptr); + LIBCITYGML_EXPORT std::shared_ptr load( std::istream& stream, const ParserParams& params, std::unique_ptr tesselator, std::shared_ptr logger = nullptr); - LIBCITYGML_EXPORT std::shared_ptr load( const std::string& fileName, const ParserParams& params, std::shared_ptr logger = nullptr); + LIBCITYGML_EXPORT std::shared_ptr load( const std::string& fileName, const ParserParams& params, std::unique_ptr tesselator, std::shared_ptr logger = nullptr); } diff --git a/sources/include/citygml/citymodel.h b/sources/include/citygml/citymodel.h index 02752654..469e2b27 100644 --- a/sources/include/citygml/citymodel.h +++ b/sources/include/citygml/citymodel.h @@ -8,6 +8,8 @@ #include #include +class TesselatorBase; + namespace citygml { class AppearanceManager; @@ -39,7 +41,7 @@ namespace citygml { const std::string& getSRSName() const; - void finish(Tesselator& tesselator, bool optimize, bool tesselate, std::shared_ptr logger); + void finish(TesselatorBase* tesselator, bool optimize, bool tesselate, std::shared_ptr logger); std::vector themes() const; void setThemes(std::vector themes); diff --git a/sources/include/citygml/cityobject.h b/sources/include/citygml/cityobject.h index fb791e3c..63b57f2e 100644 --- a/sources/include/citygml/cityobject.h +++ b/sources/include/citygml/cityobject.h @@ -8,7 +8,7 @@ #include #include #include -class Tesselator; +class TesselatorBase; namespace citygml { @@ -119,7 +119,7 @@ namespace citygml { ExternalReference const* externalReference() const; void setExternalReference(ExternalReference * externalReference); - void finish(Tesselator& tesselator, bool optimize, bool tesselate, std::shared_ptr logger); + void finish(TesselatorBase* tesselator, bool optimize, std::shared_ptr logger); virtual ~CityObject(); diff --git a/sources/include/citygml/geometry.h b/sources/include/citygml/geometry.h index 523099ad..a66b5f81 100644 --- a/sources/include/citygml/geometry.h +++ b/sources/include/citygml/geometry.h @@ -7,7 +7,7 @@ #include #include -class Tesselator; +class TesselatorBase; namespace citygml { @@ -73,7 +73,7 @@ namespace citygml { * @param tesselator the tesselator to be used for tesselation * @param mergePolygons determines wether all polygons are merged into one */ - void finish(Tesselator& tesselator, bool optimize, bool tesselate, std::shared_ptr logger); + void finish(TesselatorBase* tesselator, bool optimize, std::shared_ptr logger); ~Geometry(); diff --git a/sources/include/citygml/polygon.h b/sources/include/citygml/polygon.h index 146f3943..aabe610e 100644 --- a/sources/include/citygml/polygon.h +++ b/sources/include/citygml/polygon.h @@ -11,7 +11,7 @@ #include #include -class Tesselator; +class TesselatorBase; namespace citygml { @@ -82,7 +82,7 @@ namespace citygml { void addRing( LinearRing* ); - void finish(Tesselator& tesselator , bool optimize, bool tesselate, std::shared_ptr logger); + void finish(TesselatorBase* tesselator , bool optimize, std::shared_ptr logger); std::shared_ptr exteriorRing(){ return m_exteriorRing; @@ -112,9 +112,9 @@ namespace citygml { * @param tesselate if true the tesselator will be used to tesselate the linear rings * @param tesselator the Tesselator object */ - void computeIndices(Tesselator& tesselator, std::shared_ptr logger); + void computeIndices(TesselatorBase* tesselator, std::shared_ptr logger); void createSimpleIndices(std::shared_ptr logger); - void createIndicesWithTesselation(Tesselator& tesselator, std::shared_ptr logger); + void createIndicesWithTesselation(TesselatorBase* tesselator, std::shared_ptr logger); void removeDuplicateVerticesInRings(std::shared_ptr logger); std::vector getTexCoordsForRingAndTheme(const LinearRing& ring, const std::string& theme, bool front); std::vector > getTexCoordListsForRing(const LinearRing& ring, const std::vector& themesFront, const std::vector& themesBack); diff --git a/sources/include/citygml/tesselator.h b/sources/include/citygml/tesselator.h index e6b6e866..2a2737f2 100644 --- a/sources/include/citygml/tesselator.h +++ b/sources/include/citygml/tesselator.h @@ -31,40 +31,30 @@ #endif #include +#include #include -#include -#include -#include namespace citygml { class CityGMLLogger; } // GLU based polygon tesselator -class LIBCITYGML_EXPORT Tesselator +class LIBCITYGML_EXPORT Tesselator: public TesselatorBase { public: - Tesselator( std::shared_ptr logger ); + Tesselator( std::shared_ptr logger, GLenum winding_rule = GLU_TESS_WINDING_ODD); ~Tesselator(); - void init(const TVec3d& normal, GLenum winding_rule = GLU_TESS_WINDING_ODD ); + void init(const TVec3d& normal) override; /** * @brief Add a new contour - add the exterior ring first, then interiors * @param textureCoordinatesLists a list of texture coordinates lists for the countour. Each list contains one texture coordinate for each vertex. */ - void addContour(const std::vector&, std::vector > textureCoordinatesLists); + void addContour(const std::vector&, std::vector > textureCoordinatesLists) override; // Let's tesselate! - void compute(); - - // Tesselation result access - const std::vector getVertices() const; - const std::vector >& getTexCoords() const { return _texCoordsLists; } - const std::vector& getIndices() const; - - void setKeepVertices(bool val); - bool keepVertices() const; + void compute() override; private: typedef void (APIENTRY *GLU_TESS_CALLBACK)(); @@ -77,16 +67,7 @@ class LIBCITYGML_EXPORT Tesselator private: GLUtesselator *_tobj; GLenum _curMode; - - std::list _vertices; - std::vector > _texCoordsLists; - std::list _indices; - std::vector _outIndices; - - std::vector _curIndices; - std::shared_ptr _logger; - - bool _keepVertices; + GLenum _windingRule; }; #endif // __TESSELATOR_H__ diff --git a/sources/include/citygml/tesselatorbase.h b/sources/include/citygml/tesselatorbase.h new file mode 100644 index 00000000..ac3906b9 --- /dev/null +++ b/sources/include/citygml/tesselatorbase.h @@ -0,0 +1,69 @@ +/* -*-c++-*- libcitygml - Copyright (c) 2010 Joachim Pouderoux, BRGM +* +* This file is part of libcitygml library +* http://code.google.com/p/libcitygml +* +* libcitygml is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation, either version 2.1 of the License, or +* (at your option) any later version. +* +* libcitygml 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 +* GNU Lesser General Public License for more details. +*/ + +#ifndef __TESSELATORBASE_H__ +#define __TESSELATORBASE_H__ + +#include +#include +#include +#include + +namespace citygml { + class CityGMLLogger; +} + +// base class for polygon tesselator +class LIBCITYGML_EXPORT TesselatorBase +{ +public: + TesselatorBase( std::shared_ptr logger ); + virtual ~TesselatorBase(); + + void setLogger(std::shared_ptr logger); + + virtual void init(const TVec3d& normal) = 0; + + /** + * @brief Add a new contour - add the exterior ring first, then interiors + * @param textureCoordinatesLists a list of texture coordinates lists for the countour. Each list contains one texture coordinate for each vertex. + */ + virtual void addContour(const std::vector&, std::vector > textureCoordinatesLists); + + // Let's tesselate! + virtual void compute() = 0; + + // Tesselation result access + const std::vector& getVertices() const; + const std::vector >& getTexCoords() const { return _texCoordsLists; } + const std::vector& getIndices() const; + + void setKeepVertices(bool val); + bool keepVertices() const; + +protected: + std::vector _vertices; + std::vector > _texCoordsLists; + std::vector _indices; + std::vector _outIndices; + + std::vector _curIndices; + std::shared_ptr _logger; + + bool _keepVertices; +}; + +#endif // __TESSELATORBASE_H__ diff --git a/sources/include/parser/citygmldocumentparser.h b/sources/include/parser/citygmldocumentparser.h index e0169aff..68d0c2f5 100644 --- a/sources/include/parser/citygmldocumentparser.h +++ b/sources/include/parser/citygmldocumentparser.h @@ -15,7 +15,7 @@ namespace citygml { class CityGMLDocumentParser { public: - CityGMLDocumentParser(const ParserParams& params, std::shared_ptr logger); + CityGMLDocumentParser(const ParserParams& params, std::shared_ptr logger, std::unique_ptr tesselator); std::shared_ptr getModel(); @@ -80,6 +80,8 @@ namespace citygml { std::shared_ptr m_rootModel; ParserParams m_parserParams; + std::unique_ptr m_tesselator; + bool m_currentElementUnknownOrUnexpected; int m_unknownElementOrUnexpectedElementDepth; std::string m_unknownElementOrUnexpectedElementName; diff --git a/sources/src/citygml/citymodel.cpp b/sources/src/citygml/citymodel.cpp index 8e861b2a..3ca108ad 100644 --- a/sources/src/citygml/citymodel.cpp +++ b/sources/src/citygml/citymodel.cpp @@ -115,11 +115,11 @@ namespace citygml } - void CityModel::finish(Tesselator& tesselator, bool optimize, bool tesselate, std::shared_ptr logger) + void CityModel::finish(TesselatorBase* tesselator, bool optimize, bool tesselate, std::shared_ptr logger) { // Finish all cityobjcts for (auto& cityObj : m_roots) { - cityObj->finish(tesselator, optimize, tesselate, logger); + cityObj->finish(tesselator, optimize, logger); } // Build city objects map diff --git a/sources/src/citygml/cityobject.cpp b/sources/src/citygml/cityobject.cpp index 703baf2b..658a4391 100644 --- a/sources/src/citygml/cityobject.cpp +++ b/sources/src/citygml/cityobject.cpp @@ -114,20 +114,20 @@ namespace citygml { m_externalReference = std::unique_ptr(externalReference); } - void CityObject::finish(Tesselator& tesselator, bool optimize, bool tesselate, std::shared_ptr logger) + void CityObject::finish(TesselatorBase* tesselator, bool optimize, std::shared_ptr logger) { for (std::unique_ptr& geom : m_geometries) { - geom->finish(tesselator, optimize, tesselate, logger); + geom->finish(tesselator, optimize, logger); } for (std::unique_ptr& implictGeom : m_implicitGeometries) { for (int i = 0; i < implictGeom->getGeometriesCount(); i++) { - implictGeom->getGeometry(i).finish(tesselator, optimize, tesselate, logger); + implictGeom->getGeometry(i).finish(tesselator, optimize, logger); } } for (std::unique_ptr& child : m_children) { - child->finish(tesselator, optimize, tesselate, logger); + child->finish(tesselator, optimize, logger); } } diff --git a/sources/src/citygml/geometry.cpp b/sources/src/citygml/geometry.cpp index 490b7576..43d0c8e7 100644 --- a/sources/src/citygml/geometry.cpp +++ b/sources/src/citygml/geometry.cpp @@ -137,7 +137,7 @@ namespace citygml { m_lineStrings.push_back(l); } - void Geometry::finish(Tesselator& tesselator, bool optimize, bool tesselate, std::shared_ptr logger) + void Geometry::finish(TesselatorBase* tesselator, bool optimize, std::shared_ptr logger) { // only need to finish geometry once if (m_finished) { @@ -148,12 +148,12 @@ namespace citygml { for (std::shared_ptr& child : m_childGeometries) { child->addTargetDefinitionsOf(*this); - child->finish(tesselator, optimize, tesselate, logger); + child->finish(tesselator, optimize, logger); } for (std::shared_ptr& polygon : m_polygons) { polygon->addTargetDefinitionsOf(*this); - polygon->finish(tesselator, optimize, tesselate, logger); + polygon->finish(tesselator, optimize, logger); } } diff --git a/sources/src/citygml/polygon.cpp b/sources/src/citygml/polygon.cpp index 8644d411..c70b26da 100644 --- a/sources/src/citygml/polygon.cpp +++ b/sources/src/citygml/polygon.cpp @@ -171,19 +171,19 @@ namespace citygml { return texCoordsLists; } - void Polygon::createIndicesWithTesselation(Tesselator& tesselator, std::shared_ptr logger) + void Polygon::createIndicesWithTesselation(TesselatorBase* tesselator, std::shared_ptr logger) { TVec3d normal = computeNormal(); std::vector themesFront = getAllTextureThemes(true); std::vector themesBack = getAllTextureThemes(false); - tesselator.init(normal); + tesselator->init(normal); if (m_exteriorRing != nullptr) { - tesselator.addContour( m_exteriorRing->getVertices(), getTexCoordListsForRing(*m_exteriorRing, themesFront, themesBack)); - if (!tesselator.keepVertices()) + tesselator->addContour( m_exteriorRing->getVertices(), getTexCoordListsForRing(*m_exteriorRing, themesFront, themesBack)); + if (!tesselator->keepVertices()) { m_exteriorRing->forgetVertices(); } @@ -191,22 +191,22 @@ namespace citygml { for ( auto& ring : m_interiorRings ) { - tesselator.addContour( ring->getVertices(), getTexCoordListsForRing(*ring, themesFront, themesBack) ); - if (!tesselator.keepVertices()) + tesselator->addContour( ring->getVertices(), getTexCoordListsForRing(*ring, themesFront, themesBack) ); + if (!tesselator->keepVertices()) { ring->forgetVertices(); } } - tesselator.compute(); - m_vertices = tesselator.getVertices(); - m_indices = tesselator.getIndices(); + tesselator->compute(); + m_vertices = tesselator->getVertices(); + m_indices = tesselator->getIndices(); if (m_vertices.empty()) { return; } - const std::vector >& texCoordLists = tesselator.getTexCoords(); + const std::vector >& texCoordLists = tesselator->getTexCoords(); for (size_t i = 0; i < themesFront.size(); i++) { assert(texCoordLists.at(i).size() == m_vertices.size()); @@ -219,7 +219,7 @@ namespace citygml { } } - void Polygon::computeIndices(Tesselator& tesselator, std::shared_ptr logger ) + void Polygon::computeIndices(TesselatorBase* tesselator, std::shared_ptr logger ) { m_indices.clear(); m_vertices.clear(); @@ -231,7 +231,7 @@ namespace citygml { } } - void Polygon::finish(Tesselator& tesselator, bool optimize, bool tesselate, std::shared_ptr logger) + void Polygon::finish(TesselatorBase* tesselator, bool optimize, std::shared_ptr logger) { if (m_finished) { // This may happen as Polygons can be shared between geometries @@ -244,7 +244,7 @@ namespace citygml { removeDuplicateVerticesInRings(logger); } - if (tesselate) { + if (tesselator != nullptr) { computeIndices(tesselator, logger); } } diff --git a/sources/src/citygml/tesselator.cpp b/sources/src/citygml/tesselator.cpp index f8bc68a4..c778ad50 100644 --- a/sources/src/citygml/tesselator.cpp +++ b/sources/src/citygml/tesselator.cpp @@ -34,11 +34,9 @@ #include #include -Tesselator::Tesselator(std::shared_ptr logger ) +Tesselator::Tesselator(std::shared_ptr logger, GLenum winding_rule): TesselatorBase(logger), _windingRule(winding_rule) { - _logger = logger; _tobj = gluNewTess(); - _keepVertices = false; gluTessCallback( _tobj, GLU_TESS_VERTEX_DATA, (GLU_TESS_CALLBACK)&vertexDataCallback ); gluTessCallback( _tobj, GLU_TESS_BEGIN_DATA, (GLU_TESS_CALLBACK)&beginCallback ); @@ -47,18 +45,13 @@ Tesselator::Tesselator(std::shared_ptr logger ) gluTessCallback( _tobj, GLU_TESS_ERROR_DATA, (GLU_TESS_CALLBACK)&errorCallback ); } -void Tesselator::init( const TVec3d& normal, GLenum winding_rule ) +void Tesselator::init( const TVec3d& normal) { + TesselatorBase::init(normal); gluTessBeginPolygon( _tobj, this ); - gluTessProperty( _tobj, GLU_TESS_WINDING_RULE, winding_rule ); + gluTessProperty( _tobj, GLU_TESS_WINDING_RULE, _windingRule); gluTessNormal( _tobj, normal.x, normal.y, normal.z ); - - _vertices.clear(); - _indices.clear(); - _curIndices.clear(); - _texCoordsLists.clear(); - _outIndices.clear(); } Tesselator::~Tesselator() @@ -71,80 +64,20 @@ void Tesselator::compute() gluTessEndPolygon( _tobj ); } -const std::vector Tesselator::getVertices() const -{ - return std::vector(_vertices.begin(), _vertices.end()); -} - -const std::vector& Tesselator::getIndices() const -{ - return _outIndices; -} - -void Tesselator::setKeepVertices(bool value) -{ - _keepVertices = value; -} - -bool Tesselator::keepVertices() const -{ - return _keepVertices; -} - void Tesselator::addContour(const std::vector& pts, std::vector > textureCoordinatesLists ) { - unsigned int len = pts.size(); - if ( len < 3 ) return; - - for (size_t i = 0; i < textureCoordinatesLists.size(); i++) { - - std::vector& texCoords = textureCoordinatesLists.at(i); - - - - if (texCoords.size() != pts.size()) { - if (!texCoords.empty()) { - CITYGML_LOG_ERROR(_logger, "Invalid call to 'addContour'. The number of texture coordinates in list " << i << " (" << texCoords.size() << ") " - "does not match the number of vertices (" << pts.size() << "). The texture coordinates list will be resized which may cause invalid texture coordinates."); - } - - texCoords.resize(pts.size(), TVec2f(0.f, 0.f)); - } - } - - for (size_t i = 0; i < std::max(_texCoordsLists.size(), textureCoordinatesLists.size()); i++) { - - if (i >= _texCoordsLists.size()) { - std::vector texCoords(_vertices.size(), TVec2f(0.f, 0.f)); - texCoords.insert(texCoords.end(), textureCoordinatesLists.at(i).begin(), textureCoordinatesLists.at(i).end()); - _texCoordsLists.push_back(texCoords); - } else if (i >= textureCoordinatesLists.size()) { - _texCoordsLists.at(i).resize(_texCoordsLists.at(i).size() + pts.size(), TVec2f(0.f, 0.f)); - } else { - _texCoordsLists.at(i).insert(_texCoordsLists.at(i).end(), textureCoordinatesLists.at(i).begin(), textureCoordinatesLists.at(i).end()); - } - - } - - unsigned int pos = _vertices.size(); + TesselatorBase::addContour(pts, textureCoordinatesLists); gluTessBeginContour( _tobj ); + unsigned int len = _vertices.size(); + assert(_indices.size() == _vertices.size()); for ( unsigned int i = 0; i < len; i++ ) { - _vertices.push_back( pts[i] ); - _indices.push_back(pos + i); - - gluTessVertex( _tobj, &(_vertices.back()[0]), &_indices.back() ); + gluTessVertex( _tobj, &(_vertices[i][0]), &_indices[i] ); } gluTessEndContour( _tobj ); - -#ifndef NDEBUG - for (size_t i = 0; i < _texCoordsLists.size(); i++) { - assert(_texCoordsLists.at(i).size() == _vertices.size()); - } -#endif } void CALLBACK Tesselator::beginCallback( GLenum which, void* userData ) diff --git a/sources/src/citygml/tesselatorbase.cpp b/sources/src/citygml/tesselatorbase.cpp new file mode 100644 index 00000000..2ae3fa18 --- /dev/null +++ b/sources/src/citygml/tesselatorbase.cpp @@ -0,0 +1,129 @@ +/* -*-c++-*- libcitygml - Copyright (c) 2010 Joachim Pouderoux, BRGM +* +* Contributors: +* - Manuel Garnier, BRGM - better normal computation +* +* This file is part of libcitygml library +* http://code.google.com/p/libcitygml +* +* libcitygml is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation, either version 2.1 of the License, or +* (at your option) any later version. +* +* libcitygml 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 +* GNU Lesser General Public License for more details. +*/ + +#ifdef WIN32 +#define WINDOWS_LEAN_AND_MEAN +#define NOMINMAX +#endif + +#include +#ifndef WIN32 +# include +#endif + +#include +#include + +#include +#include +#include + +TesselatorBase::TesselatorBase(std::shared_ptr logger ) +{ + _logger = logger; + _keepVertices = false; +} + +void TesselatorBase::init( const TVec3d& normal) +{ + _vertices.clear(); + _indices.clear(); + _curIndices.clear(); + _texCoordsLists.clear(); + _outIndices.clear(); +} + +TesselatorBase::~TesselatorBase() +{ +} + +void TesselatorBase::setLogger(std::shared_ptr logger) +{ + _logger = logger; +} + +const std::vector& TesselatorBase::getVertices() const +{ + return _vertices; +} + +const std::vector& TesselatorBase::getIndices() const +{ + return _outIndices; +} + +void TesselatorBase::setKeepVertices(bool value) +{ + _keepVertices = value; +} + +bool TesselatorBase::keepVertices() const +{ + return _keepVertices; +} + +void TesselatorBase::addContour(const std::vector& pts, std::vector > textureCoordinatesLists ) +{ + unsigned int len = pts.size(); + if ( len < 3 ) return; + + for (size_t i = 0; i < textureCoordinatesLists.size(); i++) { + + std::vector& texCoords = textureCoordinatesLists.at(i); + + + + if (texCoords.size() != pts.size()) { + if (!texCoords.empty()) { + CITYGML_LOG_ERROR(_logger, "Invalid call to 'addContour'. The number of texture coordinates in list " << i << " (" << texCoords.size() << ") " + "does not match the number of vertices (" << pts.size() << "). The texture coordinates list will be resized which may cause invalid texture coordinates."); + } + + texCoords.resize(pts.size(), TVec2f(0.f, 0.f)); + } + } + + for (size_t i = 0; i < std::max(_texCoordsLists.size(), textureCoordinatesLists.size()); i++) { + + if (i >= _texCoordsLists.size()) { + std::vector texCoords(_vertices.size(), TVec2f(0.f, 0.f)); + texCoords.insert(texCoords.end(), textureCoordinatesLists.at(i).begin(), textureCoordinatesLists.at(i).end()); + _texCoordsLists.push_back(texCoords); + } else if (i >= textureCoordinatesLists.size()) { + _texCoordsLists.at(i).resize(_texCoordsLists.at(i).size() + pts.size(), TVec2f(0.f, 0.f)); + } else { + _texCoordsLists.at(i).insert(_texCoordsLists.at(i).end(), textureCoordinatesLists.at(i).begin(), textureCoordinatesLists.at(i).end()); + } + + } + + unsigned int pos = _vertices.size(); + + for ( unsigned int i = 0; i < len; i++ ) + { + _vertices.push_back( pts[i] ); + _indices.push_back(pos + i); + } + +#ifndef NDEBUG + for (size_t i = 0; i < _texCoordsLists.size(); i++) { + assert(_texCoordsLists.at(i).size() == _vertices.size()); + } +#endif +} diff --git a/sources/src/parser/citygmldocumentparser.cpp b/sources/src/parser/citygmldocumentparser.cpp index 3450f72e..10a1f289 100644 --- a/sources/src/parser/citygmldocumentparser.cpp +++ b/sources/src/parser/citygmldocumentparser.cpp @@ -14,11 +14,12 @@ namespace citygml { - CityGMLDocumentParser::CityGMLDocumentParser(const ParserParams& params, std::shared_ptr logger) + CityGMLDocumentParser::CityGMLDocumentParser(const ParserParams& params, std::shared_ptr logger, std::unique_ptr tesselator) { m_logger = logger; m_factory = std::unique_ptr(new CityGMLFactory(logger)); m_parserParams = params; + m_tesselator = std::move(tesselator); m_activeParser = nullptr; m_currentElementUnknownOrUnexpected = false; m_unknownElementOrUnexpectedElementDepth = 0; @@ -122,12 +123,14 @@ namespace citygml { m_factory->closeFactory(); if (m_rootModel != nullptr) { - Tesselator tesselator(m_logger); - tesselator.setKeepVertices(m_parserParams.keepVertices); - CITYGML_LOG_INFO(m_logger, "Start postprocessing of the citymodel."); - m_rootModel->finish(tesselator, m_parserParams.optimize, m_parserParams.tesselate, m_logger); - CITYGML_LOG_INFO(m_logger, "Finished postprocessing of the citymodel."); + if(m_tesselator != nullptr) { + m_tesselator->setKeepVertices(m_parserParams.keepVertices); + + CITYGML_LOG_INFO(m_logger, "Start postprocessing of the citymodel."); + m_rootModel->finish(m_tesselator.get(), m_parserParams.optimize, m_parserParams.tesselate, m_logger); + CITYGML_LOG_INFO(m_logger, "Finished postprocessing of the citymodel."); + } m_rootModel->setThemes(m_factory->getAllThemes()); diff --git a/sources/src/parser/parserxercesc.cpp b/sources/src/parser/parserxercesc.cpp index 2d3dd6f8..fc352739 100644 --- a/sources/src/parser/parserxercesc.cpp +++ b/sources/src/parser/parserxercesc.cpp @@ -23,6 +23,7 @@ #include #include +#include "citygml/tesselatorbase.h" #include "parser/citygmldocumentparser.h" #include "parser/documentlocation.h" #include "parser/attributes.h" @@ -116,8 +117,8 @@ class AttributesXercesAdapter : public citygml::Attributes { class CityGMLHandlerXerces : public xercesc::DefaultHandler, public citygml::CityGMLDocumentParser { public: - CityGMLHandlerXerces( const ParserParams& params, const std::string& fileName, std::shared_ptr logger) - : citygml::CityGMLDocumentParser(params, logger), m_documentLocation(DocumentLocationXercesAdapter(fileName)) {} + CityGMLHandlerXerces( const ParserParams& params, const std::string& fileName, std::shared_ptr logger, std::unique_ptr tesselator) + : citygml::CityGMLDocumentParser(params, logger, std::move(tesselator)), m_documentLocation(DocumentLocationXercesAdapter(fileName)) {} // ContentHandler interface @@ -269,11 +270,11 @@ namespace citygml } - std::shared_ptr parse(xercesc::InputSource& stream, const ParserParams& params, std::shared_ptr logger, std::string filename = "") { + std::shared_ptr parse(xercesc::InputSource& stream, const ParserParams& params, std::shared_ptr logger, std::unique_ptr tesselator, std::string filename = "") { - CityGMLHandlerXerces handler( params, filename, logger ); + CityGMLHandlerXerces handler( params, filename, logger, std::move(tesselator) ); xercesc::SAX2XMLReader* parser = xercesc::XMLReaderFactory::createXMLReader(); parser->setFeature(xercesc::XMLUni::fgSAX2CoreNameSpaces, false); @@ -306,10 +307,11 @@ namespace citygml return handler.getModel(); } - std::shared_ptr load(std::istream& stream, const ParserParams& params, std::shared_ptr logger) + std::shared_ptr load(std::istream& stream, const ParserParams& params, std::unique_ptr tesselator, std::shared_ptr logger) { if (!logger) { logger = std::make_shared(); + tesselator->setLogger(logger); } if (!initXerces(logger)) { @@ -317,13 +319,14 @@ namespace citygml } StdBinInputSource streamSource(stream); - return parse(streamSource, params, logger); + return parse(streamSource, params, logger, std::move(tesselator)); } - std::shared_ptr load( const std::string& fname, const ParserParams& params , std::shared_ptr logger) + std::shared_ptr load( const std::string& fname, const ParserParams& params, std::unique_ptr tesselator, std::shared_ptr logger) { if (!logger) { logger = std::make_shared(); + tesselator->setLogger(logger); } if (!initXerces(logger)) { @@ -336,7 +339,7 @@ namespace citygml try { #endif xercesc::LocalFileInputSource fileSource(fileName.get()); - return parse(fileSource, params, logger, fname); + return parse(fileSource, params, logger, std::move(tesselator), fname); #ifdef NDEBUG } catch (xercesc::XMLException& e) { CITYGML_LOG_ERROR(logger, "Error parsing file " << fname << ": " << e.getMessage()); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 31026369..7f8ecbc2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -2,7 +2,9 @@ IF(WIN32) SET(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} /NODEFAULTLIB:MSVCRT") ENDIF() -FIND_PACKAGE( OpenGL REQUIRED ) +IF( LIBCITYGML_USE_OPENGL) + FIND_PACKAGE( OpenGL REQUIRED ) +ENDIF( LIBCITYGML_USE_OPENGL ) FIND_PACKAGE( Xerces REQUIRED ) IF( LIBCITYGML_DYNAMIC ) @@ -19,6 +21,9 @@ SET( PRG_SRCS citygmltest.cpp ) ADD_EXECUTABLE( citygmltest ${PRG_SRCS} ) TARGET_LINK_LIBRARIES( citygmltest citygml ${XERCESC_LIBRARY} ${OPENGL_LIBRARIES} ) +IF(LIBCITYGML_USE_OPENGL) + TARGET_COMPILE_DEFINITIONS( citygmltest PUBLIC LIBCITYGML_USE_OPENGL) +ENDIF(LIBCITYGML_USE_OPENGL) if(NOT DEFINED BIN_INSTALL_DIR) set(BIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/bin") diff --git a/test/citygmltest.cpp b/test/citygmltest.cpp index e723d93f..2ef0c3fe 100644 --- a/test/citygmltest.cpp +++ b/test/citygmltest.cpp @@ -21,6 +21,11 @@ #include #include #include +#include +#include +#ifdef LIBCITYGML_USE_OPENGL +#include +#endif //LIBCITYGML_USE_OPENGL void analyzeObject( const citygml::CityObject*, unsigned int ); @@ -79,8 +84,13 @@ int main( int argc, char **argv ) #else std::shared_ptr city; +#ifdef LIBCITYGML_USE_OPENGL + std::unique_ptr tesselator = std::unique_ptr(new Tesselator(nullptr)); +#else + std::unique_ptr tesselator = nullptr; +#endif // LIBCITYGML_USE_OPENGL try{ - city = citygml::load( argv[fargc], params ); + city = citygml::load( argv[fargc], params, std::move(tesselator) ); }catch(const std::runtime_error& e){ } @@ -93,29 +103,29 @@ int main( int argc, char **argv ) std::cout << "Done in " << difftime( end, start ) << " seconds." << std::endl; - /* + std::cout << "Analyzing the city objects..." << std::endl; + + const auto& cityObjects = city->getRootCityObjects(); - citygml::CityObjectsMap::const_iterator it = cityObjectsMap.begin(); + citygml::ConstCityObjects::const_iterator it = cityObjects.begin(); - for ( ; it != cityObjectsMap.end(); ++it ) + for ( ; it != cityObjects.end(); ++it ) { - const citygml::CityObjects& v = it->second; - - std::cout << ( log ? " Analyzing " : " Found " ) << v.size() << " " << citygml::getCityObjectsClassName( it->first ) << ( ( v.size() > 1 ) ? "s" : "" ) << "..." << std::endl; - - if ( log ) - { - for ( unsigned int i = 0; i < v.size(); i++ ) - { - std::cout << " + found object " << v[i]->getId(); - if ( v[i]->getChildCount() > 0 ) std::cout << " with " << v[i]->getChildCount() << " children"; - std::cout << " with " << v[i]->size() << " geometr" << ( ( v[i]->size() > 1 ) ? "ies" : "y" ); - std::cout << std::endl; - } - } + const citygml::CityObject& v = **it; + + //std::cout << ( log ? " Analyzing " : " Found " ) << v.size() << " " << v.getTypeAsString() << ( ( v.size() > 1 ) ? "s" : "" ) << "..." << std::endl; + + // if ( log ) + // { + // std::cout << " + found object " << v.getId(); + // if ( v.getChildCityObjectsCount() > 0 ) std::cout << " with " << v.getChildCityObjectsCount() << " children"; + // std::cout << " with " << v.getGeometriesCount() << " geometr" << ( ( v.getGeometriesCount() > 1 ) ? "ies" : "y" ); + // std::cout << " with " << v.getImplicitGeometryCount() << " implicit geometr" << ( ( v.getImplicitGeometryCount() > 1 ) ? "ies" : "y" ); + // std::cout << std::endl; + // } } - */ + if ( log ) { From 256dc9275fbf4280f4a4db1a000280982e499643 Mon Sep 17 00:00:00 2001 From: topheg Date: Wed, 2 Nov 2022 10:33:19 +0100 Subject: [PATCH 2/7] Add cmake options to the build documentation in the README --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7ce93ef8..02150216 100644 --- a/README.md +++ b/README.md @@ -22,11 +22,13 @@ Dependencies: The XercesC xml parsing library is the only requirement compiling and using libcitygml. Please use a version > 3.1 compiled with an SDK that is compatible with C++11. -OpenGL is required if you want to use the tesselator provided in the project. Otherwise, you can provide another implementation by inheriting TesselatorBase, or not use tesselation. +OpenGL is required if you want to use the tesselator provided in the project. Otherwise, you can provide another implementation by inheriting TesselatorBase, or not use tesselation. Set the cmake option "LIBCITYGML_USE_OPENGL" to OFF to disable the use of OpenGL. GDAL is required if coordinate transformations should be applied during paring. +Set the cmake option "LIBCITYGML_USE_GDAL" to OFF to disable the use of GDAL. -OpenSceneGraph is required for building the plugin. +OpenSceneGraph is required to build the plugin. +Set the cmake option "LIBCITYGML_OSGPLUGIN" to ON to enable the build of the plugin. Test Data Attribution ===================== From b0d26c58982ecae57cd914ca22dee505f51c96ec Mon Sep 17 00:00:00 2001 From: topheg Date: Tue, 8 Nov 2022 12:06:19 +0100 Subject: [PATCH 3/7] Fix nullptr exception when setting default logger --- sources/src/parser/parserxercesc.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sources/src/parser/parserxercesc.cpp b/sources/src/parser/parserxercesc.cpp index fc352739..0e78c607 100644 --- a/sources/src/parser/parserxercesc.cpp +++ b/sources/src/parser/parserxercesc.cpp @@ -311,7 +311,9 @@ namespace citygml { if (!logger) { logger = std::make_shared(); - tesselator->setLogger(logger); + if(tesselator) { + tesselator->setLogger(logger); + } } if (!initXerces(logger)) { @@ -326,7 +328,9 @@ namespace citygml { if (!logger) { logger = std::make_shared(); - tesselator->setLogger(logger); + if(tesselator) { + tesselator->setLogger(logger); + } } if (!initXerces(logger)) { From a4d2e233554a5a6e40720c9d1b20ef3edb0ec813 Mon Sep 17 00:00:00 2001 From: topheg Date: Wed, 16 Nov 2022 16:40:45 +0100 Subject: [PATCH 4/7] Fix header inclusion for TesselatorBase --- sources/include/citygml/citygml.h | 3 ++- test/citygmltest.cpp | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sources/include/citygml/citygml.h b/sources/include/citygml/citygml.h index 932889bc..76de3760 100644 --- a/sources/include/citygml/citygml.h +++ b/sources/include/citygml/citygml.h @@ -31,7 +31,8 @@ #include #include #include -class TesselatorBase; +#include + namespace citygml { class CityModel; diff --git a/test/citygmltest.cpp b/test/citygmltest.cpp index 2ef0c3fe..634002c7 100644 --- a/test/citygmltest.cpp +++ b/test/citygmltest.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #ifdef LIBCITYGML_USE_OPENGL #include #endif //LIBCITYGML_USE_OPENGL From a21878550cd561a3e70dc223055e850da5ca478e Mon Sep 17 00:00:00 2001 From: topheg Date: Thu, 17 Nov 2022 17:13:46 +0100 Subject: [PATCH 5/7] Check flag before linking on opengl for tests --- test/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7f8ecbc2..8a0f519c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -20,9 +20,10 @@ SET( PRG_SRCS citygmltest.cpp ) ADD_EXECUTABLE( citygmltest ${PRG_SRCS} ) -TARGET_LINK_LIBRARIES( citygmltest citygml ${XERCESC_LIBRARY} ${OPENGL_LIBRARIES} ) +TARGET_LINK_LIBRARIES( citygmltest citygml ${XERCESC_LIBRARY}) IF(LIBCITYGML_USE_OPENGL) TARGET_COMPILE_DEFINITIONS( citygmltest PUBLIC LIBCITYGML_USE_OPENGL) + TARGET_LINK_LIBRARIES( citygmltest citygml ${OPENGL_LIBRARIES} ) ENDIF(LIBCITYGML_USE_OPENGL) if(NOT DEFINED BIN_INSTALL_DIR) From 377e4d9df7e10a08d8f837aa09fd3d4f61f44e28 Mon Sep 17 00:00:00 2001 From: topheg Date: Thu, 1 Dec 2022 14:47:54 +0100 Subject: [PATCH 6/7] Fix bug with inner rings tesselation --- sources/src/citygml/tesselator.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sources/src/citygml/tesselator.cpp b/sources/src/citygml/tesselator.cpp index c778ad50..ebced493 100644 --- a/sources/src/citygml/tesselator.cpp +++ b/sources/src/citygml/tesselator.cpp @@ -66,15 +66,15 @@ void Tesselator::compute() void Tesselator::addContour(const std::vector& pts, std::vector > textureCoordinatesLists ) { + unsigned int pos = _vertices.size(); TesselatorBase::addContour(pts, textureCoordinatesLists); gluTessBeginContour( _tobj ); - unsigned int len = _vertices.size(); - assert(_indices.size() == _vertices.size()); + unsigned int len = pts.size(); for ( unsigned int i = 0; i < len; i++ ) { - gluTessVertex( _tobj, &(_vertices[i][0]), &_indices[i] ); + gluTessVertex( _tobj, &(_vertices[pos + i][0]), &_indices[pos + i] ); } gluTessEndContour( _tobj ); From b414dc7d6619c10c3c0c4aad0ad9705a184aadd4 Mon Sep 17 00:00:00 2001 From: topheg Date: Wed, 14 Dec 2022 18:14:26 +0100 Subject: [PATCH 7/7] Fix wrong includes --- sources/src/citygml/polygon.cpp | 2 +- sources/src/parser/citygmldocumentparser.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sources/src/citygml/polygon.cpp b/sources/src/citygml/polygon.cpp index c70b26da..3998aa83 100644 --- a/sources/src/citygml/polygon.cpp +++ b/sources/src/citygml/polygon.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/sources/src/parser/citygmldocumentparser.cpp b/sources/src/parser/citygmldocumentparser.cpp index 10a1f289..662ca331 100644 --- a/sources/src/parser/citygmldocumentparser.cpp +++ b/sources/src/parser/citygmldocumentparser.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include