EVOLUTION-MANAGER
Edit File: ili2reader.cpp
/****************************************************************************** * $Id: ili2reader.cpp 27741 2014-09-26 19:20:02Z goatbar $ * * Project: Interlis 2 Reader * Purpose: Implementation of ILI2Reader class. * Author: Markus Schnider, Sourcepole AG * ****************************************************************************** * Copyright (c) 2004, Pirmin Kalberer, Sourcepole AG * Copyright (c) 2008-2012, Even Rouault <even dot rouault at mines-paris dot org> * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************/ #include "ogr_ili2.h" #include "cpl_conv.h" #include "cpl_string.h" #include "ilihelper.h" #include "ili2reader.h" #include "ili2readerp.h" //from trstring.cpp/gmlreaderp.h char *tr_strdup( const XMLCh * ); using namespace std; CPL_CVSID("$Id: ili2reader.cpp 27741 2014-09-26 19:20:02Z goatbar $"); // // constants // static const char *ILI2_TID = "TID"; static const char *ILI2_REF = "REF"; static const int ILI2_STRING_TYPE = 0; static const int ILI2_COORD_TYPE = 1; static const int ILI2_ARC_TYPE = 2; static const int ILI2_POLYLINE_TYPE = 4; static const int ILI2_BOUNDARY_TYPE = 8; static const int ILI2_AREA_TYPE = 16; // also SURFACE static const int ILI2_GEOMCOLL_TYPE = 32; static const char *ILI2_COORD = "COORD"; static const char *ILI2_ARC = "ARC"; static const char *ILI2_POLYLINE = "POLYLINE"; static const char *ILI2_BOUNDARY = "BOUNDARY"; static const char *ILI2_AREA = "AREA"; static const char *ILI2_SURFACE = "SURFACE"; // // helper functions // int cmpStr(string s1, string s2) { string::const_iterator p1 = s1.begin(); string::const_iterator p2 = s2.begin(); while (p1 != s1.end() && p2 != s2.end()) { if (toupper(*p1) != toupper(*p2)) return (toupper(*p1) < toupper(*p2)) ? -1 : 1; ++p1; ++p2; } return (s2.size() == s1.size()) ? 0 : (s1.size() < s2.size()) ? -1 : 1; } string ltrim(string tmpstr) { unsigned int i = 0; while (i < tmpstr.length() && (tmpstr[i] == ' ' || tmpstr[i] == '\t' || tmpstr[i] == '\r' || tmpstr[i] == '\n')) ++i; return i > 0 ? tmpstr.substr(i, tmpstr.length()-i) : tmpstr; } string rtrim(string tmpstr) { if (tmpstr.length() == 0) return tmpstr; unsigned int i = tmpstr.length() - 1; while (tmpstr[i] == ' ' || tmpstr[i] == '\t' || tmpstr[i] == '\r' || tmpstr[i] == '\n') --i; return i < tmpstr.length() - 1 ? tmpstr.substr(0, i+1) : tmpstr; } string trim(string tmpstr) { tmpstr = ltrim(tmpstr); tmpstr = rtrim(tmpstr); return tmpstr; } int getGeometryTypeOfElem(DOMElement* elem) { int type = ILI2_STRING_TYPE; char* pszTagName = XMLString::transcode(elem->getTagName()); if (elem && elem->getNodeType() == DOMNode::ELEMENT_NODE) { if (cmpStr(ILI2_COORD, pszTagName) == 0) { type = ILI2_COORD_TYPE; } else if (cmpStr(ILI2_ARC, pszTagName) == 0) { type = ILI2_ARC_TYPE; } else if (cmpStr(ILI2_POLYLINE, pszTagName) == 0) { type = ILI2_POLYLINE_TYPE; } else if (cmpStr(ILI2_BOUNDARY, pszTagName) == 0) { type = ILI2_BOUNDARY_TYPE; } else if (cmpStr(ILI2_AREA, pszTagName) == 0) { type = ILI2_AREA_TYPE; } else if (cmpStr(ILI2_SURFACE, pszTagName) == 0) { type = ILI2_AREA_TYPE; } } XMLString::release(&pszTagName); return type; } char *getObjValue(DOMElement *elem) { DOMElement *textElem = (DOMElement *)elem->getFirstChild(); if ((textElem != NULL) && (textElem->getNodeType() == DOMNode::TEXT_NODE)) { char* pszNodeValue = tr_strdup(textElem->getNodeValue()); return pszNodeValue; } return NULL; } char *getREFValue(DOMElement *elem) { XMLCh* pszIli2_ref = XMLString::transcode(ILI2_REF); char* pszREFValue = tr_strdup(elem->getAttribute(pszIli2_ref)); XMLString::release(&pszIli2_ref); return pszREFValue; } OGRPoint *getPoint(DOMElement *elem) { // elem -> COORD (or ARC) OGRPoint *pt = new OGRPoint(); DOMElement *coordElem = (DOMElement *)elem->getFirstChild(); while (coordElem != NULL) { char* pszTagName = XMLString::transcode(coordElem->getTagName()); char* pszObjValue = getObjValue(coordElem); if (cmpStr("C1", pszTagName) == 0) pt->setX(atof(pszObjValue)); else if (cmpStr("C2", pszTagName) == 0) pt->setY(atof(pszObjValue)); else if (cmpStr("C3", pszTagName) == 0) pt->setZ(atof(pszObjValue)); CPLFree(pszObjValue); XMLString::release(&pszTagName); coordElem = (DOMElement *)coordElem->getNextSibling(); } pt->flattenTo2D(); return pt; } OGRLineString *ILI2Reader::getArc(DOMElement *elem) { // elem -> ARC OGRLineString *ls = new OGRLineString(); // previous point -> start point OGRPoint *ptStart = getPoint((DOMElement *)elem->getPreviousSibling()); // COORD or ARC // end point OGRPoint *ptEnd = new OGRPoint(); // point on the arc OGRPoint *ptOnArc = new OGRPoint(); // double radius = 0; // radius DOMElement *arcElem = (DOMElement *)elem->getFirstChild(); while (arcElem != NULL) { char* pszTagName = XMLString::transcode(arcElem->getTagName()); char* pszObjValue = getObjValue(arcElem); if (cmpStr("C1", pszTagName) == 0) ptEnd->setX(atof(pszObjValue)); else if (cmpStr("C2", pszTagName) == 0) ptEnd->setY(atof(pszObjValue)); else if (cmpStr("C3", pszTagName) == 0) ptEnd->setZ(atof(pszObjValue)); else if (cmpStr("A1", pszTagName) == 0) ptOnArc->setX(atof(pszObjValue)); else if (cmpStr("A2", pszTagName) == 0) ptOnArc->setY(atof(pszObjValue)); else if (cmpStr("A3", pszTagName) == 0) ptOnArc->setZ(atof(pszObjValue)); else if (cmpStr("R", pszTagName) == 0) { // radius = atof(pszObjValue); } CPLFree(pszObjValue); XMLString::release(&pszTagName); arcElem = (DOMElement *)arcElem->getNextSibling(); } ptEnd->flattenTo2D(); ptOnArc->flattenTo2D(); interpolateArc(ls, ptStart, ptOnArc, ptEnd, arcIncr); delete ptStart; delete ptOnArc; delete ptEnd; return ls; } OGRLineString *getLineString(DOMElement *elem, int bAsLinearRing) { // elem -> POLYLINE OGRLineString *ls; if (bAsLinearRing) ls = new OGRLinearRing(); else ls = new OGRLineString(); DOMElement *lineElem = (DOMElement *)elem->getFirstChild(); while (lineElem != NULL) { char* pszTagName = XMLString::transcode(lineElem->getTagName()); if (cmpStr(ILI2_COORD, pszTagName) == 0) { OGRPoint* poPoint = getPoint(lineElem); ls->addPoint(poPoint); delete poPoint; } else if (cmpStr(ILI2_ARC, pszTagName) == 0) { // end point OGRPoint *ptEnd = new OGRPoint(); // point on the arc OGRPoint *ptOnArc = new OGRPoint(); // radius // double radius = 0; DOMElement *arcElem = (DOMElement *)lineElem->getFirstChild(); while (arcElem != NULL) { char* pszTagName = XMLString::transcode(arcElem->getTagName()); char* pszObjValue = getObjValue(arcElem); if (cmpStr("C1", pszTagName) == 0) ptEnd->setX(atof(pszObjValue)); else if (cmpStr("C2", pszTagName) == 0) ptEnd->setY(atof(pszObjValue)); else if (cmpStr("C3", pszTagName) == 0) ptEnd->setZ(atof(pszObjValue)); else if (cmpStr("A1", pszTagName) == 0) ptOnArc->setX(atof(pszObjValue)); else if (cmpStr("A2", pszTagName) == 0) ptOnArc->setY(atof(pszObjValue)); else if (cmpStr("A3", pszTagName) == 0) ptOnArc->setZ(atof(pszObjValue)); else if (cmpStr("R", pszTagName) == 0) { // radius = atof(pszObjValue); } CPLFree(pszObjValue); XMLString::release(&pszTagName); arcElem = (DOMElement *)arcElem->getNextSibling(); } ptEnd->flattenTo2D(); ptOnArc->flattenTo2D(); OGRPoint *ptStart = getPoint((DOMElement *)lineElem->getPreviousSibling()); // COORD or ARC interpolateArc(ls, ptStart, ptOnArc, ptEnd, PI/180); delete ptStart; delete ptEnd; delete ptOnArc; } /* else { // TODO: StructureValue in Polyline not yet supported } */ XMLString::release(&pszTagName); lineElem = (DOMElement *)lineElem->getNextSibling(); } return ls; } OGRLinearRing *getBoundary(DOMElement *elem) { DOMElement *lineElem = (DOMElement *)elem->getFirstChild(); if (lineElem != NULL) { char* pszTagName = XMLString::transcode(lineElem->getTagName()); if (cmpStr(ILI2_POLYLINE, pszTagName) == 0) { XMLString::release(&pszTagName); return (OGRLinearRing*) getLineString(lineElem, TRUE); } XMLString::release(&pszTagName); } return new OGRLinearRing(); } OGRPolygon *getPolygon(DOMElement *elem) { OGRPolygon *pg = new OGRPolygon(); DOMElement *boundaryElem = (DOMElement *)elem->getFirstChild(); // outer boundary while (boundaryElem != NULL) { char* pszTagName = XMLString::transcode(boundaryElem->getTagName()); if (cmpStr(ILI2_BOUNDARY, pszTagName) == 0) pg->addRingDirectly(getBoundary(boundaryElem)); XMLString::release(&pszTagName); boundaryElem = (DOMElement *)boundaryElem->getNextSibling(); // inner boundaries } return pg; } OGRGeometry *ILI2Reader::getGeometry(DOMElement *elem, int type) { OGRGeometryCollection *gm = new OGRGeometryCollection(); DOMElement *childElem = elem; while (childElem != NULL) { char* pszTagName = XMLString::transcode(childElem->getTagName()); switch (type) { case ILI2_COORD_TYPE : if (cmpStr(ILI2_COORD, pszTagName) == 0) { delete gm; XMLString::release(&pszTagName); return getPoint(childElem); } break; case ILI2_ARC_TYPE : // is it possible here? It have to be a ARC or COORD before (getPreviousSibling) if (cmpStr(ILI2_ARC, pszTagName) == 0) { delete gm; XMLString::release(&pszTagName); return getArc(childElem); } break; case ILI2_POLYLINE_TYPE : if (cmpStr(ILI2_POLYLINE, pszTagName) == 0) { delete gm; XMLString::release(&pszTagName); return getLineString(childElem, FALSE); } break; case ILI2_BOUNDARY_TYPE : if (cmpStr(ILI2_BOUNDARY, pszTagName) == 0) { delete gm; XMLString::release(&pszTagName); return getLineString(childElem, FALSE); } break; case ILI2_AREA_TYPE : if ((cmpStr(ILI2_AREA, pszTagName) == 0) || (cmpStr(ILI2_SURFACE, pszTagName) == 0)) { delete gm; XMLString::release(&pszTagName); return getPolygon(childElem); } break; default : if (type >= ILI2_GEOMCOLL_TYPE) { int subType = getGeometryTypeOfElem(childElem); //???? gm->addGeometryDirectly(getGeometry(childElem, subType)); } break; } XMLString::release(&pszTagName); // GEOMCOLL childElem = (DOMElement *)childElem->getNextSibling(); } return gm; } int ILI2Reader::ReadModel(ImdReader *poImdReader, const char *modelFilename) { poImdReader->ReadModel(modelFilename); for (FeatureDefnInfos::const_iterator it = poImdReader->featureDefnInfos.begin(); it != poImdReader->featureDefnInfos.end(); ++it) { OGRLayer* layer = new OGRILI2Layer(it->poTableDefn, it->poGeomFieldInfos, NULL); m_listLayer.push_back(layer); } return 0; } //Detect field name of value element char* fieldName(DOMElement* elem) { DOMNode *node = elem; if (getGeometryTypeOfElem(elem)) { int depth = 0; // Depth of value elem node for (node = elem; node; node = node->getParentNode()) ++depth; //Field name is on level 4 node = elem; for (int d = 0; d<depth-4; ++d) node = node->getParentNode(); } char* pszNodeName = tr_strdup(node->getNodeName()); return pszNodeName; } void ILI2Reader::setFieldDefn(OGRFeatureDefn *featureDef, DOMElement* elem) { int type = 0; //recursively search children for (DOMElement *childElem = (DOMElement *)elem->getFirstChild(); type == 0 && childElem && childElem->getNodeType() == DOMNode::ELEMENT_NODE; childElem = (DOMElement*)childElem->getNextSibling()) { type = getGeometryTypeOfElem(childElem); if (type == 0) { if (childElem->getFirstChild() && childElem->getFirstChild()->getNodeType() == DOMNode::ELEMENT_NODE) { setFieldDefn(featureDef, childElem); } else { char *fName = fieldName(childElem); if (featureDef->GetFieldIndex(fName) == -1) { CPLDebug( "OGR_ILI", "AddFieldDefn: %s",fName ); OGRFieldDefn oFieldDefn(fName, OFTString); featureDef->AddFieldDefn(&oFieldDefn); } CPLFree(fName); } } } } void ILI2Reader::SetFieldValues(OGRFeature *feature, DOMElement* elem) { int type = 0; //recursively search children for (DOMElement *childElem = (DOMElement *)elem->getFirstChild(); type == 0 && childElem && childElem->getNodeType() == DOMNode::ELEMENT_NODE; childElem = (DOMElement*)childElem->getNextSibling()) { type = getGeometryTypeOfElem(childElem); if (type == 0) { if (childElem->getFirstChild() && childElem->getFirstChild()->getNodeType() == DOMNode::ELEMENT_NODE) { SetFieldValues(feature, childElem); } else { char *fName = fieldName(childElem); int fIndex = feature->GetFieldIndex(fName); if (fIndex != -1) { char * objVal = getObjValue(childElem); if (objVal == NULL) objVal = getREFValue(childElem); // only to try feature->SetField(fIndex, objVal); CPLFree(objVal); } else { CPLDebug( "OGR_ILI","Attribute '%s' not found", fName); m_missAttrs.push_back(fName); } CPLFree(fName); } } else { char *fName = fieldName(childElem); int fIndex = feature->GetGeomFieldIndex(fName); feature->SetGeomFieldDirectly(fIndex, getGeometry(childElem, type)); CPLFree(fName); } } } // // ILI2Reader // IILI2Reader::~IILI2Reader() { } ILI2Reader::ILI2Reader() { m_poILI2Handler = NULL; m_poSAXReader = NULL; m_bReadStarted = FALSE; m_pszFilename = NULL; SetupParser(); } ILI2Reader::~ILI2Reader() { CPLFree( m_pszFilename ); CleanupParser(); list<OGRLayer *>::const_iterator layerIt = m_listLayer.begin(); while (layerIt != m_listLayer.end()) { OGRILI2Layer *tmpLayer = (OGRILI2Layer *)*layerIt; delete tmpLayer; layerIt++; } } void ILI2Reader::SetArcDegrees(double arcDegrees) { arcIncr = arcDegrees*PI/180; } void ILI2Reader::SetSourceFile( const char *pszFilename ) { CPLFree( m_pszFilename ); m_pszFilename = CPLStrdup( pszFilename ); } int ILI2Reader::SetupParser() { static int bXercesInitialized = FALSE; if( !bXercesInitialized ) { try { XMLPlatformUtils::Initialize(); } catch (const XMLException& toCatch) { char* msg = tr_strdup(toCatch.getMessage()); CPLError( CE_Failure, CPLE_AppDefined, "Unable to initalize Xerces C++ based ILI2 reader. " "Error message:\n%s\n", msg ); CPLFree(msg); return FALSE; } bXercesInitialized = TRUE; } // Cleanup any old parser. if( m_poSAXReader != NULL ) CleanupParser(); // Create and initialize parser. m_poSAXReader = XMLReaderFactory::createXMLReader(); m_poILI2Handler = new ILI2Handler( this ); m_poSAXReader->setContentHandler( m_poILI2Handler ); m_poSAXReader->setErrorHandler( m_poILI2Handler ); m_poSAXReader->setLexicalHandler( m_poILI2Handler ); m_poSAXReader->setEntityResolver( m_poILI2Handler ); m_poSAXReader->setDTDHandler( m_poILI2Handler ); /* No Validation #if (OGR_ILI2_VALIDATION) m_poSAXReader->setFeature( XMLString::transcode("http://xml.org/sax/features/validation"), true); m_poSAXReader->setFeature( XMLString::transcode("http://xml.org/sax/features/namespaces"), true); m_poSAXReader->setFeature( XMLUni::fgSAX2CoreNameSpaces, true ); m_poSAXReader->setFeature( XMLUni::fgXercesSchema, true ); // m_poSAXReader->setDoSchema(true); // m_poSAXReader->setValidationSchemaFullChecking(true); #else */ XMLCh *tmpCh = XMLString::transcode("http://xml.org/sax/features/validation"); m_poSAXReader->setFeature(tmpCh, false); XMLString::release(&tmpCh); tmpCh = XMLString::transcode("http://xml.org/sax/features/namespaces"); m_poSAXReader->setFeature(tmpCh, false); XMLString::release(&tmpCh); //#endif m_bReadStarted = FALSE; return TRUE; } void ILI2Reader::CleanupParser() { if( m_poSAXReader == NULL ) return; delete m_poSAXReader; m_poSAXReader = NULL; delete m_poILI2Handler; m_poILI2Handler = NULL; m_bReadStarted = FALSE; } int ILI2Reader::SaveClasses( const char *pszFile = NULL ) { // Add logic later to determine reasonable default schema file. if( pszFile == NULL ) return FALSE; // parse and create layers and features try { CPLDebug( "OGR_ILI", "Parsing %s", pszFile); m_poSAXReader->parse(pszFile); } catch (const SAXException& toCatch) { char* msg = tr_strdup(toCatch.getMessage()); CPLError( CE_Failure, CPLE_AppDefined, "Parsing failed: %s\n", msg ); CPLFree(msg); return FALSE; } if (m_missAttrs.size() != 0) { m_missAttrs.sort(); m_missAttrs.unique(); string attrs = ""; list<string>::const_iterator it; for (it = m_missAttrs.begin(); it != m_missAttrs.end(); ++it) attrs += *it + ", "; CPLError( CE_Warning, CPLE_NotSupported, "Failed to add new definition to existing layers, attributes not saved: %s", attrs.c_str() ); } return TRUE; } list<OGRLayer *> ILI2Reader::GetLayers() { return m_listLayer; } int ILI2Reader::GetLayerCount() { return m_listLayer.size(); } OGRLayer* ILI2Reader::GetLayer(const char* pszName) { for (list<OGRLayer *>::reverse_iterator layerIt = m_listLayer.rbegin(); layerIt != m_listLayer.rend(); ++layerIt) { OGRFeatureDefn *fDef = (*layerIt)->GetLayerDefn(); if (cmpStr(fDef->GetName(), pszName) == 0) { return *layerIt; } } return NULL; } int ILI2Reader::AddFeature(DOMElement *elem) { bool newLayer = true; OGRLayer *curLayer = 0; char *pszName = tr_strdup(elem->getTagName()); //CPLDebug( "OGR_ILI", "Reading layer: %s", pszName ); // test if this layer exist curLayer = GetLayer(pszName); newLayer = (curLayer == NULL); // add a layer if (newLayer) { CPLDebug( "OGR_ILI", "Adding layer: %s", pszName ); OGRFeatureDefn* poFeatureDefn = new OGRFeatureDefn(pszName); poFeatureDefn->SetGeomType( wkbUnknown ); GeomFieldInfos oGeomFieldInfos; curLayer = new OGRILI2Layer(poFeatureDefn, oGeomFieldInfos, NULL); m_listLayer.push_back(curLayer); } // the feature and field definition OGRFeatureDefn *featureDef = curLayer->GetLayerDefn(); if (newLayer) { // add TID field OGRFieldDefn ofieldDefn (ILI2_TID, OFTString); featureDef->AddFieldDefn(&ofieldDefn); setFieldDefn(featureDef, elem); } // add the features OGRFeature *feature = new OGRFeature(featureDef); // assign TID int fIndex = feature->GetFieldIndex(ILI2_TID); if (fIndex != -1) { XMLCh *pszIli2_tid = XMLString::transcode(ILI2_TID); char *fChVal = tr_strdup(elem->getAttribute(pszIli2_tid)); feature->SetField(fIndex, fChVal); XMLString::release(&pszIli2_tid); CPLFree(fChVal); } else { CPLDebug( "OGR_ILI","'%s' not found", ILI2_TID); } SetFieldValues(feature, elem); curLayer->SetFeature(feature); CPLFree(pszName); return 0; } IILI2Reader *CreateILI2Reader() { return new ILI2Reader(); } void DestroyILI2Reader(IILI2Reader* reader) { if (reader) delete reader; }