Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: GDAL 4 : * Purpose: Generic support for GML Coverage descriptions. 5 : * Author: Frank Warmerdam, warmerdam@pobox.com 6 : * 7 : ****************************************************************************** 8 : * Copyright (c) 2006, Frank Warmerdam <warmerdam@pobox.com> 9 : * 10 : * SPDX-License-Identifier: MIT 11 : ****************************************************************************/ 12 : 13 : #include "cpl_port.h" 14 : #include "gdal_priv.h" 15 : 16 : #include <cstdlib> 17 : #include <cstring> 18 : 19 : #include "cpl_conv.h" 20 : #include "cpl_error.h" 21 : #include "cpl_minixml.h" 22 : #include "cpl_string.h" 23 : #include "ogr_api.h" 24 : #include "ogr_core.h" 25 : #include "ogr_geometry.h" 26 : #include "ogr_spatialref.h" 27 : #include "gmlcoverage.h" 28 : 29 : /************************************************************************/ 30 : /* ParseGMLCoverageDesc() */ 31 : /************************************************************************/ 32 : 33 15 : CPLErr WCSParseGMLCoverage(CPLXMLNode *psXML, int *pnXSize, int *pnYSize, 34 : double *padfGeoTransform, char **ppszProjection) 35 : 36 : { 37 15 : CPLStripXMLNamespace(psXML, nullptr, TRUE); 38 : 39 : /* -------------------------------------------------------------------- */ 40 : /* Isolate RectifiedGrid. Eventually we will need to support */ 41 : /* other georeferencing objects. */ 42 : /* -------------------------------------------------------------------- */ 43 15 : CPLXMLNode *psRG = CPLSearchXMLNode(psXML, "=RectifiedGrid"); 44 15 : CPLXMLNode *psOriginPoint = nullptr; 45 15 : const char *pszOffset1 = nullptr; 46 15 : const char *pszOffset2 = nullptr; 47 : 48 15 : if (psRG != nullptr) 49 : { 50 15 : psOriginPoint = CPLGetXMLNode(psRG, "origin.Point"); 51 15 : if (psOriginPoint == nullptr) 52 15 : psOriginPoint = CPLGetXMLNode(psRG, "origin"); 53 : 54 15 : CPLXMLNode *psOffset1 = CPLGetXMLNode(psRG, "offsetVector"); 55 15 : if (psOffset1 != nullptr) 56 : { 57 15 : pszOffset1 = CPLGetXMLValue(psOffset1, "", nullptr); 58 : pszOffset2 = 59 15 : CPLGetXMLValue(psOffset1->psNext, "=offsetVector", nullptr); 60 : } 61 : } 62 : 63 : /* -------------------------------------------------------------------- */ 64 : /* If we are missing any of the origin or 2 offsets then give up. */ 65 : /* -------------------------------------------------------------------- */ 66 15 : if (psRG == nullptr || psOriginPoint == nullptr || pszOffset1 == nullptr || 67 : pszOffset2 == nullptr) 68 : { 69 0 : CPLError(CE_Failure, CPLE_AppDefined, 70 : "Unable to find GML RectifiedGrid, origin or offset vectors"); 71 0 : return CE_Failure; 72 : } 73 : 74 : /* -------------------------------------------------------------------- */ 75 : /* Search for the GridEnvelope and derive the raster size. */ 76 : /* -------------------------------------------------------------------- */ 77 : char **papszLow = 78 15 : CSLTokenizeString(CPLGetXMLValue(psRG, "limits.GridEnvelope.low", "")); 79 : char **papszHigh = 80 15 : CSLTokenizeString(CPLGetXMLValue(psRG, "limits.GridEnvelope.high", "")); 81 : 82 15 : if (CSLCount(papszLow) < 2 || CSLCount(papszHigh) < 2) 83 : { 84 0 : CPLError(CE_Failure, CPLE_AppDefined, 85 : "Unable to find or parse GridEnvelope.low/high."); 86 0 : CSLDestroy(papszLow); 87 0 : CSLDestroy(papszHigh); 88 0 : return CE_Failure; 89 : } 90 : 91 15 : if (pnXSize != nullptr) 92 15 : *pnXSize = atoi(papszHigh[0]) - atoi(papszLow[0]) + 1; 93 15 : if (pnYSize != nullptr) 94 15 : *pnYSize = atoi(papszHigh[1]) - atoi(papszLow[1]) + 1; 95 : 96 15 : CSLDestroy(papszLow); 97 15 : CSLDestroy(papszHigh); 98 : 99 : /* -------------------------------------------------------------------- */ 100 : /* Extract origin location. */ 101 : /* -------------------------------------------------------------------- */ 102 15 : OGRPoint *poOriginGeometry = nullptr; 103 0 : std::unique_ptr<OGRGeometry> poGeom; 104 15 : const char *pszSRSName = nullptr; 105 : 106 : { 107 15 : bool bOldWrap = false; 108 : 109 : // Old coverages (i.e. WCS) just have <pos> under <origin>, so we 110 : // may need to temporarily force <origin> to <Point>. 111 15 : if (psOriginPoint->eType == CXT_Element && 112 15 : EQUAL(psOriginPoint->pszValue, "origin")) 113 : { 114 15 : strcpy(psOriginPoint->pszValue, "Point"); 115 15 : bOldWrap = true; 116 : } 117 15 : poGeom.reset( 118 : OGRGeometry::FromHandle(OGR_G_CreateFromGMLTree(psOriginPoint))); 119 : 120 30 : if (poGeom != nullptr && 121 15 : wkbFlatten(poGeom->getGeometryType()) == wkbPoint) 122 : { 123 15 : poOriginGeometry = poGeom->toPoint(); 124 : } 125 : 126 15 : if (bOldWrap) 127 15 : strcpy(psOriginPoint->pszValue, "origin"); 128 : 129 : // SRS? 130 15 : pszSRSName = CPLGetXMLValue(psOriginPoint, "srsName", nullptr); 131 : } 132 : 133 : /* -------------------------------------------------------------------- */ 134 : /* Extract offset(s) */ 135 : /* -------------------------------------------------------------------- */ 136 15 : bool bSuccess = false; 137 : 138 : char **papszOffset1Tokens = 139 15 : CSLTokenizeStringComplex(pszOffset1, " ,", FALSE, FALSE); 140 : char **papszOffset2Tokens = 141 15 : CSLTokenizeStringComplex(pszOffset2, " ,", FALSE, FALSE); 142 : 143 15 : if (CSLCount(papszOffset1Tokens) >= 2 && 144 15 : CSLCount(papszOffset2Tokens) >= 2 && poOriginGeometry != nullptr) 145 : { 146 15 : padfGeoTransform[0] = poOriginGeometry->getX(); 147 15 : padfGeoTransform[1] = CPLAtof(papszOffset1Tokens[0]); 148 15 : padfGeoTransform[2] = CPLAtof(papszOffset1Tokens[1]); 149 15 : padfGeoTransform[3] = poOriginGeometry->getY(); 150 15 : padfGeoTransform[4] = CPLAtof(papszOffset2Tokens[0]); 151 15 : padfGeoTransform[5] = CPLAtof(papszOffset2Tokens[1]); 152 : 153 : // offset from center of pixel. 154 15 : padfGeoTransform[0] -= padfGeoTransform[1] * 0.5; 155 15 : padfGeoTransform[0] -= padfGeoTransform[2] * 0.5; 156 15 : padfGeoTransform[3] -= padfGeoTransform[4] * 0.5; 157 15 : padfGeoTransform[3] -= padfGeoTransform[5] * 0.5; 158 : 159 15 : bSuccess = true; 160 : } 161 : 162 15 : CSLDestroy(papszOffset1Tokens); 163 15 : CSLDestroy(papszOffset2Tokens); 164 : 165 : /* -------------------------------------------------------------------- */ 166 : /* If we have gotten a geotransform, then try to interpret the */ 167 : /* srsName. */ 168 : /* -------------------------------------------------------------------- */ 169 15 : if (bSuccess && pszSRSName != nullptr && 170 0 : (*ppszProjection == nullptr || strlen(*ppszProjection) == 0)) 171 : { 172 0 : if (STARTS_WITH_CI(pszSRSName, "epsg:")) 173 : { 174 0 : OGRSpatialReference oSRS; 175 0 : if (oSRS.SetFromUserInput(pszSRSName) == OGRERR_NONE) 176 0 : oSRS.exportToWkt(ppszProjection); 177 : } 178 0 : else if (STARTS_WITH_CI(pszSRSName, "urn:ogc:def:crs:")) 179 : { 180 0 : OGRSpatialReference oSRS; 181 0 : if (oSRS.importFromURN(pszSRSName) == OGRERR_NONE) 182 0 : oSRS.exportToWkt(ppszProjection); 183 : } 184 : else 185 0 : *ppszProjection = CPLStrdup(pszSRSName); 186 : } 187 : 188 15 : if (*ppszProjection) 189 0 : CPLDebug("GDALJP2Metadata", "Got projection from GML box: %s", 190 : *ppszProjection); 191 : 192 15 : return CE_None; 193 : }