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 c6966187..d517b6f5 100644 --- a/README.md +++ b/README.md @@ -22,9 +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. 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 ===================== 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..76de3760 100644 --- a/sources/include/citygml/citygml.h +++ b/sources/include/citygml/citygml.h @@ -31,9 +31,7 @@ #include #include #include - - -class Tesselator; +#include namespace citygml { @@ -88,8 +86,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..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 @@ -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..ebced493 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 = pts.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[pos + i][0]), &_indices[pos + 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..662ca331 100644 --- a/sources/src/parser/citygmldocumentparser.cpp +++ b/sources/src/parser/citygmldocumentparser.cpp @@ -8,17 +8,18 @@ #include #include #include -#include +#include #include 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..0e78c607 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,13 @@ 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(); + if(tesselator) { + tesselator->setLogger(logger); + } } if (!initXerces(logger)) { @@ -317,13 +321,16 @@ 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(); + if(tesselator) { + tesselator->setLogger(logger); + } } if (!initXerces(logger)) { @@ -336,7 +343,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..8a0f519c 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 ) @@ -18,7 +20,11 @@ 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) set(BIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/bin") diff --git a/test/citygmltest.cpp b/test/citygmltest.cpp index c6168b56..37466a65 100644 --- a/test/citygmltest.cpp +++ b/test/citygmltest.cpp @@ -23,6 +23,10 @@ #include #include +#ifdef LIBCITYGML_USE_OPENGL +#include +#endif //LIBCITYGML_USE_OPENGL + void analyzeObject( const citygml::CityObject&, unsigned int ); void usage() @@ -80,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){ } @@ -94,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 ) {