void GeoCoordinateTransformer::transform(Geometry& obj, GeoTransform& transformation) {

        if (!transformation.valid()) {
            CITYGML_LOG_WARN(m_logger, "No valid spatial reference system is given for Geometry with id '" << obj.getId() << "'. Child Polygons are not transformed"
                                       << "(unless they are shared with another geometry for which a spatial reference system is defined)");
            return;
        }

        for (unsigned int i = 0; i < obj.getPolygonsCount(); i++) {

            const auto poly = obj.getPolygon(i);

            auto it = m_transformedPolygonsSourceURNMap.find(poly.get());

            if (it == m_transformedPolygonsSourceURNMap.end()) {

                for (TVec3d& vertex : poly->getVertices()) {
                    transformation.transform(vertex);
                }

                m_transformedPolygonsSourceURNMap[poly.get()] = transformation.sourceURN();

            } else if (it->second != transformation.sourceURN()) {
                CITYGML_LOG_WARN(m_logger, "Polygon with id '" << poly->getId() << "' was already transformed from " << it->second << " to " << m_destinationSRS
                                 << ". But the spatial reference system of Geometry object with id '" << obj.getId() << "' that also contains the polygon is different "
                                 << "(" << transformation.sourceURN() << "). Ignoring new source SRS.");
            }
        }

        for (unsigned int i = 0; i < obj.getLineStringCount(); i++) {

            const auto lineString = obj.getLineString(i);

            auto it = m_transformedLineStringsSourceURNMap.find(lineString.get());

            if (it == m_transformedLineStringsSourceURNMap.end()) {

                if (lineString->getDimensions() == 2) {
                    for (TVec2d& vertex : lineString->getVertices2D()) {
                        transformation.transform(vertex);
                    }
                } else if (lineString->getDimensions() == 3) {
                    for (TVec3d& vertex : lineString->getVertices3D()) {
                        transformation.transform(vertex);
                    }
                }

                m_transformedLineStringsSourceURNMap[lineString.get()] = transformation.sourceURN();

            } else if (it->second != transformation.sourceURN()) {
                CITYGML_LOG_WARN(m_logger, "LineString with id '" << lineString->getId() << "' was already transformed from " << it->second << " to " << m_destinationSRS
                                 << ". But the spatial reference system of Geometry object with id '" << obj.getId() << "' that also contains the LineString is different "
                                 << "(" << transformation.sourceURN() << "). Ignoring new source SRS.");
            }
        }

        for (unsigned int i = 0; i < obj.getGeometriesCount(); i++) {
            transform(obj.getGeometry(i), transformation);
        }
    }
    void  GeoCoordinateTransformer::transformRecursive_helper(CityObject& obj, GeoTransform& transformation) {

        if (obj.getEnvelope().validBounds()) {

            if (transformation.valid()) {
                TVec3d lowerBound = obj.getEnvelope().getLowerBound();
                TVec3d upperBound = obj.getEnvelope().getUpperBound();

                transformation.transform(lowerBound);
                transformation.transform(upperBound);

                Envelope* newEnvelope = new Envelope(m_destinationSRS);
                newEnvelope->setLowerBound(lowerBound);
                newEnvelope->setUpperBound(upperBound);

                obj.setEnvelope(newEnvelope);
            } else {
                CITYGML_LOG_WARN(m_logger, "No valid spatial reference system is given for CityObject with id '" << obj.getId() << "'. Envelope (Bounding Box) is not transformed.");
            }
        }

        for (unsigned int i = 0; i < obj.getChildCityObjectsCount(); i++) {
            transformRecursive(obj.getChildCityObject(i), transformation);
        }

        for (unsigned int i = 0; i < obj.getImplicitGeometryCount(); i++) {
            transformRecursive(obj.getImplicitGeometry(i), transformation);
        }

        for (unsigned int i = 0; i < obj.getGeometriesCount(); i++) {
            transform(obj.getGeometry(i), transformation);
        }
    }
    void  GeoCoordinateTransformer::transformRecursive_helper(ImplicitGeometry& obj, GeoTransform& transformation) {

        TVec3d referencePoint = obj.getReferencePoint();
        if (transformation.valid()) {
            transformation.transform(referencePoint);
            obj.setReferencePoint(referencePoint);
            obj.setSRSName(m_destinationSRS);
        } else {
            CITYGML_LOG_WARN(m_logger, "No valid spatial reference system is given for ImplicitGeometry with id '" << obj.getId() << "'. Reference Point is not transformed.");
        }

        // Do not transform the geometry of an ImplicitGeometry object. Implicit Geometries share Geometry objects but each implicit geometry
        // defines its own transformation on the vertices of the shared geometry. Hence those vertices are in a local coordinate system. Read
        // the citygml documentation for more details.
        //for (unsigned int i = 0; i < obj.getGeometriesCount(); i++) {
        //  transform(obj.getGeometry(i), transformation);
        //}
    }