[Git][debian-gis-team/libcitygml][upstream] New upstream version 2.5.0

Bas Couwenberg (@sebastic) gitlab at salsa.debian.org
Tue Feb 14 14:25:04 GMT 2023



Bas Couwenberg pushed to branch upstream at Debian GIS Project / libcitygml


Commits:
2ccb9baf by Bas Couwenberg at 2023-02-14T15:02:32+01:00
New upstream version 2.5.0
- - - - -


28 changed files:

- .travis.yml
- CMakeLists.txt
- README.md
- + data/FZK-Haus-LoD0-KIT-IAI-KHH-B36-V1.gml
- sources/CMakeLists.txt
- sources/include/citygml/appearancemanager.h
- sources/include/citygml/citygml.h
- sources/include/citygml/citymodel.h
- sources/include/citygml/cityobject.h
- sources/include/citygml/geometry.h
- sources/include/citygml/polygon.h
- sources/include/citygml/tesselator.h
- + sources/include/citygml/tesselatorbase.h
- sources/include/parser/citygmldocumentparser.h
- sources/include/parser/cityobjectelementparser.h
- sources/include/parser/nodetypes.h
- sources/src/citygml/citymodel.cpp
- sources/src/citygml/cityobject.cpp
- sources/src/citygml/geometry.cpp
- sources/src/citygml/polygon.cpp
- sources/src/citygml/tesselator.cpp
- + sources/src/citygml/tesselatorbase.cpp
- sources/src/parser/citygmldocumentparser.cpp
- sources/src/parser/cityobjectelementparser.cpp
- sources/src/parser/nodetypes.cpp
- sources/src/parser/parserxercesc.cpp
- test/CMakeLists.txt
- test/citygmltest.cpp


Changes:

=====================================
.travis.yml
=====================================
@@ -12,7 +12,7 @@ before_install:
   - echo $LANG
   - echo $LC_ALL
   - if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi
-script: mkdir build && cd build && cmake ../ && make && ./bin/citygmltest ../data/berlin_open_data_sample_data.citygml && ./bin/citygmltest ../data/b1_lod2_s.gml 
+script: mkdir build && cd build && cmake ../ && make && ./bin/citygmltest ../data/berlin_open_data_sample_data.citygml && ./bin/citygmltest ../data/b1_lod2_s.gml && ./bin/citygmltest ../data/FZK-Haus-LoD0-KIT-IAI-KHH-B36-V1.gml 
 addons:
   apt:
     sources:


=====================================
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 )
 


=====================================
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
 =====================
@@ -37,6 +41,7 @@ Overview over the testing data within the "data" directory:
 | data/b1_lod2_cs_w_sem.gml             | https://www.citygml.org/samplefiles/building/             | [https://www.citygml.org](https://www.citygml.org/samplefiles/)                                           |
 | data/b1_lod2_s.gml                    | https://www.citygml.org/samplefiles/building/             | [https://www.citygml.org](https://www.citygml.org/samplefiles/)                                           |
 | data/berlin_open_data_sample_data.gml | Berlin Partner für Wirtschaft und Technologie GmbH        | [Berlin Partner Download Portal](http://www.businesslocationcenter.de/berlin3d-downloadportal/?lang=en)   |
+| data/FZK-Haus-LoD0-KIT-IAI-KHH-B36-V1.gml | Institute for Automation and Applied Computer Science (IAI) / Karlsruhe Institute of Technology (KIT) | https://www.citygmlwiki.org/index.php?title=FZK_Haus |
 
 
 


=====================================
data/FZK-Haus-LoD0-KIT-IAI-KHH-B36-V1.gml
=====================================
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Generated by:                                    --><!-- IFC -> cityGML Converter                         --><!-- (C) - Institute for Applied Computer Science     --><!-- Forschungszentrum Karlsruhe                      --><!-- Not for commercial use                           --><!-- Generated by: IfcExplorer--><!-- cityGML Schema: 1.0.0                            --><!-- Level of Detail 1--><!-- Creation Date: Tuesday, 23 November 2010 - 10:37:59--><!-- Edited Manually in Oxygen 8.2 --><!-- Modified by GMLOffset.xslt at Mon Dec 6 2010 --><!-- Version 2 Building located in the area of KIT Campus North)--><!-- Modified by GMLOffset.xslt at Wed Dec 8 2010 --><!-- Modified by GMLOffset.xslt at Wed Mar 29 2017 --><core:CityModel xsi:schemaLocation="http://www.opengis.net/citygml/2.0 http://schemas.opengis.net/citygml/2.0/cityGMLBase.xsd  http://www.opengis.net/citygml/appearance/2.0 http://schemas.opengis.net/citygml/appearance/2.0/appearance.xsd http://www.opengis.net/citygml/building/2.0 http://schemas.opengis.net/citygml/building/2.0/building.xsd http://www.opengis.net/citygml/generics/2.0 http://schemas.opengis.net/citygml/generics/2.0/generics.xsd" xmlns:core="http://www.opengis.net/citygml/2.0" xmlns="http://www.opengis.net/citygml/profiles/base/2.0" xmlns:bldg="http://www.opengis.net/citygml/building/2.0" xmlns:gen="http://www.opengis.net/citygml/generics/2.0" xmlns:grp="http://www.opengis.net/citygml/cityobjectgroup/2.0" xmlns:app="http://www.opengis.net/citygml/appearance/2.0" xmlns:gml="http://www.opengis.net/gml" xmlns:xAL="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <!-- Manually edited by KHH 23.01.2017, Address added, roof edge added -->
+  <gml:name>AC14-FZK-Haus</gml:name>
+  <gml:boundedBy>
+    <gml:Envelope srsDimension="3" srsName="urn:adv:crs:ETRS89_UTM32*DE_DHHN92_NH">
+      <gml:lowerCorner srsDimension="3">457842 5439083 111.8 </gml:lowerCorner>
+      <gml:upperCorner srsDimension="3">457854 5439093 118.317669 </gml:upperCorner>
+    </gml:Envelope>
+  </gml:boundedBy>
+  <core:cityObjectMember>
+    <bldg:Building gml:id="UUID_d281adfc-4901-0f52-540b-4cc1a9325f82">
+      <gml:description>FZK-Haus (Forschungszentrum Karlsruhe, now KIT), created by Karl-Heinz
+        Haefele </gml:description>
+      <gml:name>AC14-FZK-Haus</gml:name>
+      <core:creationDate>2017-01-23</core:creationDate>
+      <core:relativeToTerrain>entirelyAboveTerrain</core:relativeToTerrain>
+      <gen:measureAttribute name="GrossPlannedArea">
+        <gen:value uom="m2">120.00</gen:value>
+      </gen:measureAttribute>
+      <gen:stringAttribute name="ConstructionMethod">
+        <gen:value>New Building</gen:value>
+      </gen:stringAttribute>
+      <gen:stringAttribute name="IsLandmarked">
+        <gen:value>NO</gen:value>
+      </gen:stringAttribute>
+      <bldg:class codeSpace="http://www.sig3d.org/codelists/citygml/2.0/building/2.0/_AbstractBuilding_class.xml">1000</bldg:class>
+      <bldg:function codeSpace="http://www.sig3d.org/codelists/citygml/2.0/building/2.0/_AbstractBuilding_function.xml">1000</bldg:function>
+      <bldg:usage codeSpace="http://www.sig3d.org/codelists/citygml/2.0/building/2.0/_AbstractBuilding_usage.xml">1000</bldg:usage>
+      <bldg:yearOfConstruction>2020</bldg:yearOfConstruction>
+      <bldg:roofType codeSpace="http://www.sig3d.org/codelists/citygml/2.0/building/2.0/_AbstractBuilding_roofType.xml">1030</bldg:roofType>
+      <bldg:measuredHeight uom="m">6.52</bldg:measuredHeight>
+      <bldg:storeysAboveGround>2</bldg:storeysAboveGround>
+      <bldg:storeysBelowGround>0</bldg:storeysBelowGround>
+      <bldg:lod0FootPrint>
+        <gml:MultiSurface>
+          <gml:surfaceMember>
+            <gml:Polygon>
+              <gml:exterior>
+                <gml:LinearRing>
+                  <gml:posList srsDimension="3">457842 5439083 111.8 457842 5439093 111.8 457854 5439093 111.8 457854 5439083 111.8 457842 5439083 111.8 </gml:posList>
+                </gml:LinearRing>
+              </gml:exterior>
+            </gml:Polygon>
+          </gml:surfaceMember>
+        </gml:MultiSurface>
+      </bldg:lod0FootPrint>
+      <bldg:lod0RoofEdge>
+        <gml:MultiSurface>
+          <gml:surfaceMember>
+            <gml:Polygon>
+              <gml:exterior>
+                <gml:LinearRing>
+                  <gml:posList srsDimension="3">457841.5 5439082.5 111.8 457841.5 5439093.5 111.8 457854.5 5439093.5 111.8 457854.5 5439082.5 111.8 457841.5 5439082.5 111.8 </gml:posList>
+                </gml:LinearRing>
+              </gml:exterior>
+            </gml:Polygon>
+          </gml:surfaceMember>
+        </gml:MultiSurface>
+      </bldg:lod0RoofEdge>
+      <bldg:address>
+        <core:Address>
+          <core:xalAddress>
+            <xAL:AddressDetails>
+              <xAL:Locality Type="Town">
+                <xAL:LocalityName>Eggenstein-Leopoldshafen</xAL:LocalityName>
+                <xAL:Thoroughfare Type="Street">
+                  <xAL:ThoroughfareNumber>4711</xAL:ThoroughfareNumber>
+                  <xAL:ThoroughfareName>Spöcker Straße</xAL:ThoroughfareName>
+                </xAL:Thoroughfare>
+                <xAL:PostalCode>
+                  <xAL:PostalCodeNumber>76344</xAL:PostalCodeNumber>
+                </xAL:PostalCode>
+              </xAL:Locality>
+            </xAL:AddressDetails>
+          </core:xalAddress>
+        </core:Address>
+      </bldg:address>
+    </bldg:Building>
+  </core:cityObjectMember>
+</core:CityModel>
\ No newline at end of file


=====================================
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")


=====================================
sources/include/citygml/appearancemanager.h
=====================================
@@ -8,8 +8,6 @@
 #include <citygml/object.h>
 #include <citygml/vecs.hpp>
 
-class Tesselator;
-
 namespace citygml {
 
     class CityGMLLogger;


=====================================
sources/include/citygml/citygml.h
=====================================
@@ -31,9 +31,7 @@
 #include <citygml/vecs.hpp>
 #include <citygml/cityobject.h>
 #include <citygml/envelope.h>
-
-
-class Tesselator;
+#include <citygml/tesselatorbase.h>
 
 namespace citygml
 {
@@ -88,8 +86,8 @@ namespace citygml
         std::string srcSRS;
     };
 
-    LIBCITYGML_EXPORT std::shared_ptr<const CityModel> load( std::istream& stream, const ParserParams& params, std::shared_ptr<CityGMLLogger> logger = nullptr);
+    LIBCITYGML_EXPORT std::shared_ptr<const CityModel> load( std::istream& stream, const ParserParams& params, std::unique_ptr<TesselatorBase> tesselator, std::shared_ptr<CityGMLLogger> logger = nullptr);
 
-    LIBCITYGML_EXPORT std::shared_ptr<const CityModel> load( const std::string& fileName, const ParserParams& params, std::shared_ptr<CityGMLLogger> logger = nullptr);
+    LIBCITYGML_EXPORT std::shared_ptr<const CityModel> load( const std::string& fileName, const ParserParams& params, std::unique_ptr<TesselatorBase> tesselator, std::shared_ptr<CityGMLLogger> logger = nullptr);
 
 }


=====================================
sources/include/citygml/citymodel.h
=====================================
@@ -8,6 +8,8 @@
 #include <citygml/cityobject.h>
 #include <citygml/featureobject.h>
 
+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<CityGMLLogger> logger);
+        void finish(TesselatorBase* tesselator, bool optimize, bool tesselate, std::shared_ptr<CityGMLLogger> logger);
 
         std::vector<std::string> themes() const;
         void setThemes(std::vector<std::string> themes);


=====================================
sources/include/citygml/cityobject.h
=====================================
@@ -8,7 +8,7 @@
 #include <citygml/enum_type_bitmask.h>
 #include <citygml/rectifiedgridcoverage.h>
 #include <citygml/externalreference.h>
-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<citygml::CityGMLLogger> logger);
+        void finish(TesselatorBase* tesselator, bool optimize, std::shared_ptr<citygml::CityGMLLogger> logger);
 
         virtual ~CityObject();
 


=====================================
sources/include/citygml/geometry.h
=====================================
@@ -7,7 +7,7 @@
 #include <citygml/citygml_api.h>
 #include <citygml/appearancetarget.h>
 
-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<CityGMLLogger> logger);
+        void finish(TesselatorBase* tesselator, bool optimize, std::shared_ptr<CityGMLLogger> logger);
 
         ~Geometry();
 


=====================================
sources/include/citygml/polygon.h
=====================================
@@ -11,7 +11,7 @@
 #include <citygml/linearring.h>
 #include <citygml/geometry.h>
 
-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<CityGMLLogger> logger);
+        void finish(TesselatorBase* tesselator , bool optimize, std::shared_ptr<CityGMLLogger> logger);
 
         std::shared_ptr<LinearRing> 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<CityGMLLogger> logger);
+        void computeIndices(TesselatorBase* tesselator, std::shared_ptr<CityGMLLogger> logger);
         void createSimpleIndices(std::shared_ptr<CityGMLLogger> logger);
-        void createIndicesWithTesselation(Tesselator& tesselator, std::shared_ptr<CityGMLLogger> logger);
+        void createIndicesWithTesselation(TesselatorBase* tesselator, std::shared_ptr<CityGMLLogger> logger);
         void removeDuplicateVerticesInRings(std::shared_ptr<CityGMLLogger> logger);
         std::vector<TVec2f> getTexCoordsForRingAndTheme(const LinearRing& ring, const std::string& theme, bool front);
         std::vector<std::vector<TVec2f> > getTexCoordListsForRing(const LinearRing& ring, const std::vector<std::string>& themesFront, const std::vector<std::string>& themesBack);


=====================================
sources/include/citygml/tesselator.h
=====================================
@@ -31,40 +31,30 @@
 #endif
 
 #include <citygml/citygml_api.h>
+#include <citygml/tesselatorbase.h>
 #include <citygml/vecs.hpp>
-#include <vector>
-#include <list>
-#include <memory>
 
 namespace citygml {
     class CityGMLLogger;
 }
 
 // GLU based polygon tesselator
-class LIBCITYGML_EXPORT Tesselator
+class LIBCITYGML_EXPORT Tesselator: public TesselatorBase
 {
 public:
-    Tesselator( std::shared_ptr<citygml::CityGMLLogger> logger );
+    Tesselator( std::shared_ptr<citygml::CityGMLLogger> 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<TVec3d>&, std::vector<std::vector<TVec2f> > textureCoordinatesLists);
+    void addContour(const std::vector<TVec3d>&, std::vector<std::vector<TVec2f> > textureCoordinatesLists) override;
 
     // Let's tesselate!
-    void compute();
-
-    // Tesselation result access
-    const std::vector<TVec3d> getVertices() const;
-    const std::vector<std::vector<TVec2f> >& getTexCoords() const { return _texCoordsLists; }
-    const std::vector<unsigned int>& getIndices() const;
-
-    void setKeepVertices(bool val);
-    bool keepVertices() const;
+    void compute() override;
 
 private:
     typedef void (APIENTRY *GLU_TESS_CALLBACK)();
@@ -77,16 +67,7 @@ private:
 private:
     GLUtesselator *_tobj;
     GLenum  _curMode;
-
-    std::list<TVec3d> _vertices;
-    std::vector<std::vector<TVec2f> > _texCoordsLists;
-    std::list<unsigned int> _indices;
-    std::vector<unsigned int> _outIndices;
-
-    std::vector<unsigned int> _curIndices;
-    std::shared_ptr<citygml::CityGMLLogger> _logger;
-
-    bool _keepVertices;
+    GLenum _windingRule;
 };
 
 #endif // __TESSELATOR_H__


=====================================
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 <citygml/citygml_api.h>
+#include <citygml/vecs.hpp>
+#include <vector>
+#include <memory>
+
+namespace citygml {
+    class CityGMLLogger;
+}
+
+// base class for polygon tesselator
+class LIBCITYGML_EXPORT TesselatorBase
+{
+public:
+    TesselatorBase( std::shared_ptr<citygml::CityGMLLogger> logger );
+    virtual ~TesselatorBase();
+
+    void setLogger(std::shared_ptr<citygml::CityGMLLogger> 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<TVec3d>&, std::vector<std::vector<TVec2f> > textureCoordinatesLists);
+
+    // Let's tesselate!
+    virtual void compute() = 0;
+
+    // Tesselation result access
+    const std::vector<TVec3d>& getVertices() const;
+    const std::vector<std::vector<TVec2f> >& getTexCoords() const { return _texCoordsLists; }
+    const std::vector<unsigned int>& getIndices() const;
+
+    void setKeepVertices(bool val);
+    bool keepVertices() const;
+
+protected:
+    std::vector<TVec3d> _vertices;
+    std::vector<std::vector<TVec2f> > _texCoordsLists;
+    std::vector<unsigned int> _indices;
+    std::vector<unsigned int> _outIndices;
+
+    std::vector<unsigned int> _curIndices;
+    std::shared_ptr<citygml::CityGMLLogger> _logger;
+
+    bool _keepVertices;
+};
+
+#endif // __TESSELATORBASE_H__


=====================================
sources/include/parser/citygmldocumentparser.h
=====================================
@@ -15,7 +15,7 @@ namespace citygml {
 
     class CityGMLDocumentParser {
     public:
-        CityGMLDocumentParser(const ParserParams& params, std::shared_ptr<CityGMLLogger> logger);
+        CityGMLDocumentParser(const ParserParams& params, std::shared_ptr<CityGMLLogger> logger, std::unique_ptr<TesselatorBase> tesselator);
 
         std::shared_ptr<const CityModel> getModel();
 
@@ -80,6 +80,8 @@ namespace citygml {
         std::shared_ptr<CityModel> m_rootModel;
         ParserParams m_parserParams;
 
+        std::unique_ptr<TesselatorBase> m_tesselator;
+
         bool m_currentElementUnknownOrUnexpected;
         int m_unknownElementOrUnexpectedElementDepth;
         std::string m_unknownElementOrUnexpectedElementName;


=====================================
sources/include/parser/cityobjectelementparser.h
=====================================
@@ -50,6 +50,7 @@ namespace citygml {
         static bool attributesSetInitialized;
 
         void parseGeometryForLODLevel(int lod);
+        void parseGeometryForLODLevel(int lod, CityObject::CityObjectsType parentType);
         void parseImplicitGeometryForLODLevel(int lod);
         void parseGeometryPropertyElementForLODLevel(int lod, const std::string& id);
     };


=====================================
sources/include/parser/nodetypes.h
=====================================
@@ -178,7 +178,9 @@ namespace citygml {
         NODETYPE( BLDG, RoomInstallation)
         NODETYPE( BLDG, Opening)
         NODETYPE( BLDG, RoofType)
-
+        
+        NODETYPE( BLDG, Lod0FootPrint )
+        NODETYPE( BLDG, Lod0RoofEdge )
         NODETYPE( BLDG, Lod1Solid )
         NODETYPE( BLDG, Lod2Solid )
         NODETYPE( BLDG, Lod3Solid )


=====================================
sources/src/citygml/citymodel.cpp
=====================================
@@ -115,11 +115,11 @@ namespace citygml
     }
 
 
-    void CityModel::finish(Tesselator& tesselator, bool optimize, bool tesselate, std::shared_ptr<CityGMLLogger> logger)
+    void CityModel::finish(TesselatorBase* tesselator, bool optimize, bool tesselate, std::shared_ptr<CityGMLLogger> logger)
     {
         // Finish all cityobjcts
         for (auto& cityObj : m_roots) {
-            cityObj->finish(tesselator, optimize, tesselate, logger);
+            cityObj->finish(tesselator, optimize, logger);
         }
 
         // Build city objects map


=====================================
sources/src/citygml/cityobject.cpp
=====================================
@@ -114,20 +114,20 @@ namespace citygml {
         m_externalReference = std::unique_ptr<ExternalReference>(externalReference);
     }
 
-    void CityObject::finish(Tesselator& tesselator, bool optimize, bool tesselate, std::shared_ptr<CityGMLLogger> logger)
+    void CityObject::finish(TesselatorBase* tesselator, bool optimize, std::shared_ptr<CityGMLLogger> logger)
     {
         for (std::unique_ptr<Geometry>& geom : m_geometries) {
-            geom->finish(tesselator, optimize, tesselate, logger);
+            geom->finish(tesselator, optimize, logger);
         }
 
         for (std::unique_ptr<ImplicitGeometry>& 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<CityObject>& child : m_children) {
-            child->finish(tesselator, optimize, tesselate, logger);
+            child->finish(tesselator, optimize, logger);
         }
     }
 


=====================================
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<CityGMLLogger> logger)
+    void Geometry::finish(TesselatorBase* tesselator, bool optimize, std::shared_ptr<CityGMLLogger> logger)
     {
         // only need to finish geometry once
         if (m_finished) {
@@ -148,12 +148,12 @@ namespace citygml {
 
         for (std::shared_ptr<Geometry>&  child : m_childGeometries) {
             child->addTargetDefinitionsOf(*this);
-            child->finish(tesselator, optimize, tesselate, logger);
+            child->finish(tesselator, optimize, logger);
         }
 
         for (std::shared_ptr<Polygon>& polygon : m_polygons) {
             polygon->addTargetDefinitionsOf(*this);
-            polygon->finish(tesselator, optimize, tesselate, logger);
+            polygon->finish(tesselator, optimize, logger);
         }
 
     }


=====================================
sources/src/citygml/polygon.cpp
=====================================
@@ -2,7 +2,7 @@
 #include <citygml/appearance.h>
 #include <citygml/texture.h>
 #include <citygml/texturecoordinates.h>
-#include <citygml/tesselator.h>
+#include <citygml/tesselatorbase.h>
 #include <citygml/citygmllogger.h>
 #include <citygml/texturetargetdefinition.h>
 #include <citygml/materialtargetdefinition.h>
@@ -171,19 +171,19 @@ namespace citygml {
         return texCoordsLists;
     }
 
-    void Polygon::createIndicesWithTesselation(Tesselator& tesselator, std::shared_ptr<CityGMLLogger> logger)
+    void Polygon::createIndicesWithTesselation(TesselatorBase* tesselator, std::shared_ptr<CityGMLLogger> logger)
     {
         TVec3d normal = computeNormal();
 
         std::vector<std::string> themesFront = getAllTextureThemes(true);
         std::vector<std::string> 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<std::vector<TVec2f> >& texCoordLists = tesselator.getTexCoords();
+        const std::vector<std::vector<TVec2f> >& 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<CityGMLLogger> logger )
+    void Polygon::computeIndices(TesselatorBase* tesselator, std::shared_ptr<CityGMLLogger> 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<CityGMLLogger> logger)
+    void Polygon::finish(TesselatorBase* tesselator, bool optimize, std::shared_ptr<CityGMLLogger> 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);
         }
     }


=====================================
sources/src/citygml/tesselator.cpp
=====================================
@@ -34,11 +34,9 @@
 #include <assert.h>
 #include <algorithm>
 
-Tesselator::Tesselator(std::shared_ptr<citygml::CityGMLLogger> logger )
+Tesselator::Tesselator(std::shared_ptr<citygml::CityGMLLogger> 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<citygml::CityGMLLogger> 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<TVec3d> Tesselator::getVertices() const
-{
-    return std::vector<TVec3d>(_vertices.begin(), _vertices.end());
-}
-
-const std::vector<unsigned int>& Tesselator::getIndices() const
-{
-    return _outIndices;
-}
-
-void Tesselator::setKeepVertices(bool value)
-{
-    _keepVertices = value;
-}
-
-bool Tesselator::keepVertices() const
-{
-    return _keepVertices;
-}
-
 void Tesselator::addContour(const std::vector<TVec3d>& pts, std::vector<std::vector<TVec2f> > textureCoordinatesLists )
 {
-    unsigned int len = pts.size();
-    if ( len < 3 ) return;
-
-    for (size_t i = 0; i < textureCoordinatesLists.size(); i++) {
-
-        std::vector<TVec2f>& 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<TVec2f> 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 )


=====================================
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 <citygml/tesselatorbase.h>
+#ifndef WIN32
+#	include <stdint.h>
+#endif
+
+#include <citygml/citygml.h>
+#include <citygml/citygmllogger.h>
+
+#include <iostream>
+#include <assert.h>
+#include <algorithm>
+
+TesselatorBase::TesselatorBase(std::shared_ptr<citygml::CityGMLLogger> 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<citygml::CityGMLLogger> logger)
+{
+    _logger = logger;
+}
+
+const std::vector<TVec3d>& TesselatorBase::getVertices() const
+{
+    return _vertices;
+}
+
+const std::vector<unsigned int>& TesselatorBase::getIndices() const
+{
+    return _outIndices;
+}
+
+void TesselatorBase::setKeepVertices(bool value)
+{
+    _keepVertices = value;
+}
+
+bool TesselatorBase::keepVertices() const
+{
+    return _keepVertices;
+}
+
+void TesselatorBase::addContour(const std::vector<TVec3d>& pts, std::vector<std::vector<TVec2f> > textureCoordinatesLists )
+{
+    unsigned int len = pts.size();
+    if ( len < 3 ) return;
+
+    for (size_t i = 0; i < textureCoordinatesLists.size(); i++) {
+
+        std::vector<TVec2f>& 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<TVec2f> 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
+}


=====================================
sources/src/parser/citygmldocumentparser.cpp
=====================================
@@ -8,17 +8,18 @@
 #include <citygml/citygmllogger.h>
 #include <citygml/citygmlfactory.h>
 #include <citygml/citymodel.h>
-#include <citygml/tesselator.h>
+#include <citygml/tesselatorbase.h>
 
 #include <stdexcept>
 
 namespace citygml {
 
-    CityGMLDocumentParser::CityGMLDocumentParser(const ParserParams& params, std::shared_ptr<CityGMLLogger> logger)
+    CityGMLDocumentParser::CityGMLDocumentParser(const ParserParams& params, std::shared_ptr<CityGMLLogger> logger, std::unique_ptr<TesselatorBase> tesselator)
     {
         m_logger = logger;
         m_factory = std::unique_ptr<CityGMLFactory>(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());
 


=====================================
sources/src/parser/cityobjectelementparser.cpp
=====================================
@@ -319,6 +319,12 @@ namespace citygml {
                    || node == NodeType::WTR_Lod0MultiSurfaceNode) {
             
             parseGeometryForLODLevel(0);
+        } else if (node == NodeType::BLDG_Lod0FootPrintNode) {
+            // for Lod0 footprint, we must explicitly set the City Object Type, because the parent type is "Building", and it doesn't allow to discriminate between the ground and roof surface
+            parseGeometryForLODLevel(0, CityObject::CityObjectsType::COT_GroundSurface);
+        } else if (node == NodeType::BLDG_Lod0RoofEdgeNode) {
+            // for Lod0 roof edge, we must explicitly set the City Object Type, because the parent type is "Building", and it doesn't allow to discriminate between the ground and roof surface
+            parseGeometryForLODLevel(0, CityObject::CityObjectsType::COT_RoofSurface);
         } else if (node == NodeType::BLDG_Lod1MultiCurveNode
                    || node == NodeType::BLDG_Lod1MultiSurfaceNode
                    || node == NodeType::BLDG_Lod1SolidNode
@@ -480,6 +486,8 @@ namespace citygml {
                     || node == NodeType::BLDG_OpeningNode
                     || node == NodeType::APP_AppearanceNode
                     || node == NodeType::APP_AppearanceMemberNode
+                    || node == NodeType::BLDG_Lod0FootPrintNode
+                    || node == NodeType::BLDG_Lod0RoofEdgeNode
                     || node == NodeType::BLDG_Lod1MultiCurveNode
                     || node == NodeType::BLDG_Lod1MultiSurfaceNode
                     || node == NodeType::BLDG_Lod1SolidNode
@@ -584,13 +592,18 @@ namespace citygml {
     {
         return m_model;
     }
-
-    void CityObjectElementParser::parseGeometryForLODLevel(int lod)
+    
+    void CityObjectElementParser::parseGeometryForLODLevel(int lod, CityObject::CityObjectsType parentType)
     {
-        setParserForNextElement(new GeometryElementParser(m_documentParser, m_factory, m_logger, lod, m_model->getType(), [this](Geometry* geom) {
+        setParserForNextElement(new GeometryElementParser(m_documentParser, m_factory, m_logger, lod, parentType, [this](Geometry* geom) {
             m_model->addGeometry(geom);
         }));
     }
+    
+    void CityObjectElementParser::parseGeometryForLODLevel(int lod)
+    {
+        parseGeometryForLODLevel(lod, m_model->getType());
+    }
 
     void CityObjectElementParser::parseImplicitGeometryForLODLevel(int lod)
     {


=====================================
sources/src/parser/nodetypes.cpp
=====================================
@@ -175,7 +175,9 @@ namespace citygml {
                 INITIALIZE_NODE( GML, Surface )
                 INITIALIZE_NODE( GML, PolygonPatch)
                 INITIALIZE_NODE( GML, LineString)
-
+                
+                INITIALIZE_NODE( BLDG, Lod0FootPrint )
+                INITIALIZE_NODE( BLDG, Lod0RoofEdge )
                 INITIALIZE_NODE( BLDG, Lod1Solid )
                 INITIALIZE_NODE( BLDG, Lod2Solid )
                 INITIALIZE_NODE( BLDG, Lod3Solid )
@@ -548,7 +550,9 @@ namespace citygml {
     DEFINE_NODE( GML, PosList )
     DEFINE_NODE( GML, OrientableSurface )
     DEFINE_NODE( GML, LinearRing )
-
+    
+    DEFINE_NODE( BLDG, Lod0FootPrint )
+    DEFINE_NODE( BLDG, Lod0RoofEdge )
     DEFINE_NODE( BLDG, Lod1Solid )
     DEFINE_NODE( BLDG, Lod2Solid )
     DEFINE_NODE( BLDG, Lod3Solid )


=====================================
sources/src/parser/parserxercesc.cpp
=====================================
@@ -23,6 +23,7 @@
 #include <mutex>
 
 #include <citygml/citygml_api.h>
+#include "citygml/tesselatorbase.h"
 #include "parser/citygmldocumentparser.h"
 #include "parser/documentlocation.h"
 #include "parser/attributes.h"
@@ -116,8 +117,8 @@ protected:
 class CityGMLHandlerXerces : public xercesc::DefaultHandler, public citygml::CityGMLDocumentParser
 {
 public:
-    CityGMLHandlerXerces( const ParserParams& params, const std::string& fileName, std::shared_ptr<CityGMLLogger> logger)
-        : citygml::CityGMLDocumentParser(params, logger), m_documentLocation(DocumentLocationXercesAdapter(fileName)) {}
+    CityGMLHandlerXerces( const ParserParams& params, const std::string& fileName, std::shared_ptr<CityGMLLogger> logger, std::unique_ptr<TesselatorBase> tesselator)
+        : citygml::CityGMLDocumentParser(params, logger, std::move(tesselator)), m_documentLocation(DocumentLocationXercesAdapter(fileName)) {}
 
 
     // ContentHandler interface
@@ -269,11 +270,11 @@ namespace citygml
 
     }
 
-    std::shared_ptr<const CityModel> parse(xercesc::InputSource& stream, const ParserParams& params, std::shared_ptr<CityGMLLogger> logger, std::string filename = "") {
+    std::shared_ptr<const CityModel> parse(xercesc::InputSource& stream, const ParserParams& params, std::shared_ptr<CityGMLLogger> logger, std::unique_ptr<TesselatorBase> 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<const CityModel> load(std::istream& stream, const ParserParams& params, std::shared_ptr<CityGMLLogger> logger)
+    std::shared_ptr<const CityModel> load(std::istream& stream, const ParserParams& params, std::unique_ptr<TesselatorBase> tesselator, std::shared_ptr<CityGMLLogger> logger)
     {
         if (!logger) {
             logger = std::make_shared<StdLogger>();
+            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<const CityModel> load( const std::string& fname, const ParserParams& params , std::shared_ptr<CityGMLLogger> logger)
+    std::shared_ptr<const CityModel> load( const std::string& fname, const ParserParams& params, std::unique_ptr<TesselatorBase> tesselator, std::shared_ptr<CityGMLLogger> logger)
     {
         if (!logger) {
             logger = std::make_shared<StdLogger>();
+            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());


=====================================
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")


=====================================
test/citygmltest.cpp
=====================================
@@ -21,8 +21,13 @@
 #include <citygml/citygml.h>
 #include <citygml/citymodel.h>
 #include <citygml/cityobject.h>
+#include <citygml/geometry.h>
 
-void analyzeObject( const citygml::CityObject*, unsigned int );
+#ifdef LIBCITYGML_USE_OPENGL
+#include <citygml/tesselator.h>
+#endif //LIBCITYGML_USE_OPENGL
+
+void analyzeObject( const citygml::CityObject&, unsigned int );
 
 void usage()
 {
@@ -79,8 +84,13 @@ int main( int argc, char **argv )
 #else
 
     std::shared_ptr<const citygml::CityModel> city;
+#ifdef LIBCITYGML_USE_OPENGL
+    std::unique_ptr<TesselatorBase> tesselator = std::unique_ptr<TesselatorBase>(new Tesselator(nullptr));
+#else
+    std::unique_ptr<TesselatorBase> 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,36 +103,35 @@ 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 )
     {
         std::cout << std::endl << "Objects hierarchy:" << std::endl;
-//        const citygml::ConstCityObjects& roots = city->getRootCityObjects();
-
-//        for ( unsigned int i = 0; i < roots.size(); i++ ) analyzeObject( roots[ i ], 2 );
+        const citygml::ConstCityObjects& roots = city->getRootCityObjects();
+        for ( unsigned int i = 0; i < roots.size(); i++ ) analyzeObject( *(roots[ i ]), 2 );
     }
 
     std::cout << "Done." << std::endl;
@@ -130,11 +139,49 @@ int main( int argc, char **argv )
     return EXIT_SUCCESS;
 }
 
-void analyzeObject( const citygml::CityObject* object, unsigned int indent )
+void printIndent(unsigned int indent) {
+  for ( unsigned int i = 0; i < indent; i++ ) std::cout << " ";
+}
+
+void printGeometry( const citygml::Geometry& geometry, unsigned int indent ) 
 {
-//    for ( unsigned int i = 0; i < indent; i++ ) std::cout << " ";
-//        std::cout << "Object " << citygml::getCityObjectsClassName( object->getType() ) << ": " << object->getId() << std::endl;
+  printIndent(indent);
+  std::cout << "Geometry for LOD" << geometry.getLOD() << ", type: " << geometry.getTypeAsString() << std::endl;
+  
+  if(geometry.getLineStringCount() > 0)
+  {
+    printIndent(indent+1);
+    std::cout << "Linestrings:" << geometry.getLineStringCount() << std::endl;
+  }
+  
+  if(geometry.getPolygonsCount() > 0)
+  {
+    printIndent(indent+1);
+    std::cout << "Polygons:" << geometry.getPolygonsCount() << std::endl;
+  }
+  
+  if(geometry.getGeometriesCount() >0)
+  {
+    printIndent(indent+1);
+    std::cout << "SubGeometries:" << std::endl;
+    for( unsigned int i = 0; i < geometry.getGeometriesCount(); i++ )
+    {
+      printGeometry(geometry.getGeometry(i), indent+1);
+    }
+  }
+}
 
-//    for ( unsigned int i = 0; i < object->getChildCount(); i++ )
-//        analyzeObject( object->getChild(i), indent+1 );
+void analyzeObject( const citygml::CityObject& object, unsigned int indent )
+{
+   printIndent(indent);
+   std::cout << "Object " << object.getTypeAsString() << ": " << object.getId() << std::endl;
+   
+   
+   for ( unsigned int i = 0; i < object.getGeometriesCount(); i++ ) 
+   {
+       printGeometry( object.getGeometry(i), indent+1 );
+   }
+
+   for ( unsigned int i = 0; i < object.getChildCityObjectsCount(); i++ )
+       analyzeObject( object.getChildCityObject(i), indent+1 );
 }



View it on GitLab: https://salsa.debian.org/debian-gis-team/libcitygml/-/commit/2ccb9baf02bc5ef33e8406cb9fc133684a7a06e1

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/libcitygml/-/commit/2ccb9baf02bc5ef33e8406cb9fc133684a7a06e1
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20230214/2eaa64e7/attachment-0001.htm>


More information about the Pkg-grass-devel mailing list