Skip to content

Commit

Permalink
Merge pull request jklimke#94 from catenda/citygml3-texture
Browse files Browse the repository at this point in the history
CityGML 3.0 texture support
  • Loading branch information
jklimke authored Jul 8, 2024
2 parents da57819 + c97c94b commit 297389d
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 2 deletions.
1 change: 1 addition & 0 deletions sources/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ SET(SOURCES
src/parser/externalreferenceparser.cpp
src/parser/materialelementparser.cpp
src/parser/textureelementparser.cpp
src/parser/textureassociationelementparser.cpp
src/parser/georeferencedtextureelementparser.cpp
src/parser/geometryelementparser.cpp
src/parser/polygonelementparser.cpp
Expand Down
4 changes: 4 additions & 0 deletions sources/include/parser/nodetypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -392,10 +392,13 @@ namespace citygml {
NODETYPE( APP, GeoreferencedTexture )
NODETYPE( APP, ImageURI )
NODETYPE( APP, TextureMap )
NODETYPE( APP, TextureParameterization )
NODETYPE( APP, TextureAssociation )
NODETYPE( APP, Target )
NODETYPE( APP, TexCoordList )
NODETYPE( APP, TexCoordGen )
NODETYPE( APP, TextureCoordinates )
NODETYPE( APP, Ring )
NODETYPE( APP, WorldToTexture )
NODETYPE( APP, TextureType )
NODETYPE( APP, Repeat )
Expand All @@ -409,6 +412,7 @@ namespace citygml {
NODETYPE( APP, X3DMaterial )
NODETYPE( APP, Material )
NODETYPE( APP, SurfaceDataMember )
NODETYPE( APP, SurfaceData )
NODETYPE( APP, Shininess )
NODETYPE( APP, Transparency )
NODETYPE( APP, SpecularColor )
Expand Down
45 changes: 45 additions & 0 deletions sources/include/parser/textureassociationelementparser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#pragma once

#include <parser/gmlobjectparser.h>
#include <citygml/vecs.hpp>

#include <functional>
#include <memory>
#include <string>
#include <vector>

namespace citygml {

class Texture;
class TextureTargetDefinition;
class TextureCoordinates;

// Parser for CityGML 3.0 TextureAssociation elements
class TextureAssociationElementParser : public GMLObjectElementParser {
public:
TextureAssociationElementParser(CityGMLDocumentParser& documentParser, CityGMLFactory& factory, std::shared_ptr<CityGMLLogger> logger, std::shared_ptr<Texture> texture);

// ElementParser interface
virtual std::string elementParserName() const override;
virtual bool handlesElement(const NodeType::XMLNode &node) const override;

protected:
// CityGMLElementParser interface
virtual bool parseElementStartTag(const NodeType::XMLNode& node, Attributes& attributes) override;
virtual bool parseElementEndTag(const NodeType::XMLNode& node, const std::string& characters) override;
virtual bool parseChildElementStartTag(const NodeType::XMLNode& node, Attributes& attributes) override;
virtual bool parseChildElementEndTag(const NodeType::XMLNode& node, const std::string& characters) override;

// GMLObjectElementParser interface
virtual Object* getObject() override;

private:
std::shared_ptr<Texture> m_model;
std::shared_ptr<TextureTargetDefinition> m_currentTexTargetDef;
std::string m_lastTargetDefinitionID;
std::string m_ringId;
std::string m_texCoordGmlId;
std::vector<TVec2f> m_texCoordData;
};

}
4 changes: 2 additions & 2 deletions sources/src/parser/appearanceelementparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ namespace citygml {
{
if (node == NodeType::APP_ThemeNode) {
return true;
} else if (node == NodeType::APP_SurfaceDataMemberNode) {
} else if (node == NodeType::APP_SurfaceDataMemberNode || node == NodeType::APP_SurfaceDataNode) {

if (attributes.hasXLinkAttribute()) {
// surfaceDataMemberNode links to an existing surfaceData member
Expand Down Expand Up @@ -112,7 +112,7 @@ namespace citygml {
}
m_theme = characters;
return true;
} else if (node == NodeType::APP_SurfaceDataMemberNode) {
} else if (node == NodeType::APP_SurfaceDataMemberNode || node == NodeType::APP_SurfaceDataNode) {
return true;
}
return GMLObjectElementParser::parseChildElementEndTag(node, characters);
Expand Down
8 changes: 8 additions & 0 deletions sources/src/parser/nodetypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -422,9 +422,12 @@ namespace citygml {
INITIALIZE_NODE( APP, GeoreferencedTexture )
INITIALIZE_NODE( APP, ImageURI )
INITIALIZE_NODE( APP, TextureMap )
INITIALIZE_NODE( APP, TextureParameterization )
INITIALIZE_NODE( APP, TextureAssociation )
INITIALIZE_NODE( APP, Target )
INITIALIZE_NODE( APP, TexCoordList )
INITIALIZE_NODE( APP, TextureCoordinates )
INITIALIZE_NODE( APP, Ring )
INITIALIZE_NODE( APP, TextureType )
INITIALIZE_NODE( APP, Repeat )
INITIALIZE_NODE( APP, WrapMode )
Expand All @@ -438,6 +441,7 @@ namespace citygml {
INITIALIZE_NODE( APP, Material )
INITIALIZE_NODE( APP, AppearanceMember )
INITIALIZE_NODE( APP, SurfaceDataMember )
INITIALIZE_NODE( APP, SurfaceData )
INITIALIZE_NODE( APP, Shininess )
INITIALIZE_NODE( APP, Transparency )
INITIALIZE_NODE( APP, SpecularColor )
Expand Down Expand Up @@ -839,9 +843,12 @@ namespace citygml {
DEFINE_NODE( APP, GeoreferencedTexture )
DEFINE_NODE( APP, ImageURI )
DEFINE_NODE( APP, TextureMap )
DEFINE_NODE( APP, TextureParameterization )
DEFINE_NODE( APP, TextureAssociation )
DEFINE_NODE( APP, Target )
DEFINE_NODE( APP, TexCoordList )
DEFINE_NODE( APP, TextureCoordinates )
DEFINE_NODE( APP, Ring )
DEFINE_NODE( APP, TextureType )
DEFINE_NODE( APP, Repeat )
DEFINE_NODE( APP, WrapMode )
Expand All @@ -855,6 +862,7 @@ namespace citygml {
DEFINE_NODE( APP, Material )
DEFINE_NODE( APP, AppearanceMember )
DEFINE_NODE( APP, SurfaceDataMember )
DEFINE_NODE( APP, SurfaceData )
DEFINE_NODE( APP, Shininess )
DEFINE_NODE( APP, Transparency )
DEFINE_NODE( APP, SpecularColor )
Expand Down
119 changes: 119 additions & 0 deletions sources/src/parser/textureassociationelementparser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
#include "parser/textureassociationelementparser.h"

#include <unordered_map>

#include "parser/nodetypes.h"
#include "parser/attributes.h"
#include "parser/documentlocation.h"
#include "parser/parserutils.hpp"
#include "parser/skipelementparser.h"

#include <citygml/cityobject.h>
#include <citygml/citygmlfactory.h>
#include <citygml/citygmllogger.h>
#include <citygml/texture.h>
#include <citygml/texturetargetdefinition.h>
#include <citygml/texturecoordinates.h>

#include <stdexcept>

namespace citygml {

TextureAssociationElementParser::TextureAssociationElementParser(CityGMLDocumentParser& documentParser, CityGMLFactory& factory, std::shared_ptr<CityGMLLogger> logger, std::shared_ptr<Texture> texture)
: GMLObjectElementParser(documentParser, factory, logger)
{
m_model = texture;
if (m_model == nullptr) {
throw std::runtime_error("TextureAssociationElementParser constructed without a valid Texture.");
}
}

std::string TextureAssociationElementParser::elementParserName() const
{
return "TextureAssociationElementParser";
}

bool TextureAssociationElementParser::handlesElement(const NodeType::XMLNode& node) const
{
return node == NodeType::APP_TextureAssociationNode;
}

bool TextureAssociationElementParser::parseElementStartTag(const NodeType::XMLNode& node, Attributes& attributes)
{
if (node != NodeType::APP_TextureAssociationNode) {
CITYGML_LOG_ERROR(m_logger, "Expected start tag <" << NodeType::APP_TextureAssociationNode.name() << "> got " << node << " at " << getDocumentLocation());
throw std::runtime_error("Unexpected start tag found.");
}

return true;
}

bool TextureAssociationElementParser::parseElementEndTag(const NodeType::XMLNode&, const std::string&)
{
return true;
}

bool TextureAssociationElementParser::parseChildElementStartTag(const NodeType::XMLNode& node, Attributes& attributes)
{
if (node == NodeType::APP_TextureParameterizationNode
|| node == NodeType::APP_TexCoordListNode
|| node == NodeType::APP_RingNode) {
return true;
} else if (node == NodeType::APP_TargetNode) {
if (!m_lastTargetDefinitionID.empty()) {
CITYGML_LOG_WARN(m_logger, "Multiple texture target definitions detected at: " << getDocumentLocation());
}
m_lastTargetDefinitionID = attributes.getCityGMLIDAttribute();
return true;
} else if (node == NodeType::APP_TextureCoordinatesNode) {
if (!m_texCoordGmlId.empty()) {
CITYGML_LOG_WARN(m_logger, "Multiple texture coordinates definitions detected at: " << getDocumentLocation());
}
m_texCoordGmlId = attributes.getCityGMLIDAttribute();
return true;
}

return GMLObjectElementParser::parseChildElementStartTag(node, attributes);
}

bool TextureAssociationElementParser::parseChildElementEndTag(const NodeType::XMLNode& node, const std::string& characters)
{
if (node == NodeType::APP_TextureParameterizationNode) {
// Do nothing (target and texture coords are set in child elements)
} else if (node == NodeType::APP_TexCoordListNode) {
std::shared_ptr<TextureCoordinates> texCoords = std::make_shared<TextureCoordinates>(m_texCoordGmlId, m_ringId);
texCoords->setCoords(m_texCoordData);
if (m_currentTexTargetDef != nullptr) {
m_currentTexTargetDef->addTexCoordinates(texCoords);
} else {
CITYGML_LOG_WARN(m_logger, "TexCoordList node finished before texture target definition was set at " << getDocumentLocation());
}

} else if (node == NodeType::APP_TextureCoordinatesNode) {

if (m_texCoordData.empty()) {
m_texCoordData = parseVecList<TVec2f>(characters, m_logger, getDocumentLocation());
} else {
CITYGML_LOG_WARN(m_logger, "Unexpected end tag <" << NodeType::APP_TextureCoordinatesNode << " at: " << getDocumentLocation());
}
} else if (node == NodeType::APP_TargetNode) {
if (m_currentTexTargetDef == nullptr) {
const std::string uri = parseReference(characters, m_logger, getDocumentLocation());
m_currentTexTargetDef = m_factory.createTextureTargetDefinition(uri, m_model, m_lastTargetDefinitionID);
m_lastTargetDefinitionID = "";
} else {
CITYGML_LOG_WARN(m_logger, "Unexpected end tag <" << NodeType::APP_TargetNode << " at: " << getDocumentLocation());
}
} else if (node == NodeType::APP_RingNode) {
m_ringId = parseReference(characters, m_logger, getDocumentLocation());
} else {
return GMLObjectElementParser::parseChildElementEndTag(node, characters);
}
return true;
}

Object* TextureAssociationElementParser::getObject()
{
return m_model.get();
}
}
7 changes: 7 additions & 0 deletions sources/src/parser/textureelementparser.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "parser/textureelementparser.h"

#include "parser/textureassociationelementparser.h"

#include <unordered_map>

#include "parser/nodetypes.h"
Expand Down Expand Up @@ -84,6 +86,9 @@ namespace citygml {
m_currentTexCoords = std::make_shared<TextureCoordinates>(attributes.getCityGMLIDAttribute(), parseReference(attributes.getAttribute("ring"), m_logger, getDocumentLocation()));
}
return true;
} else if (node == NodeType::APP_TextureParameterizationNode) {
setParserForNextElement(new TextureAssociationElementParser(m_documentParser, m_factory, m_logger, m_model));
return true;
}

return GMLObjectElementParser::parseChildElementStartTag(node, attributes);
Expand All @@ -101,6 +106,8 @@ namespace citygml {
} else if (node == NodeType::APP_TextureTypeNode) {

m_model->setAttribute(node.name(), characters);
} else if (node == NodeType::APP_TextureParameterizationNode) {
// Do nothing (target and texture coords are set in child element)
} else if (node == NodeType::APP_WrapModeNode) {

if (!m_model->setWrapModeFromString(characters)) {
Expand Down

0 comments on commit 297389d

Please sign in to comment.