/src/gdal/frmts/wcs/gmlcoverage.cpp
Line | Count | Source |
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 | | CPLErr WCSParseGMLCoverage(CPLXMLNode *psXML, int *pnXSize, int *pnYSize, |
34 | | GDALGeoTransform >, char **ppszProjection) |
35 | | |
36 | 0 | { |
37 | 0 | CPLStripXMLNamespace(psXML, nullptr, TRUE); |
38 | | |
39 | | /* -------------------------------------------------------------------- */ |
40 | | /* Isolate RectifiedGrid. Eventually we will need to support */ |
41 | | /* other georeferencing objects. */ |
42 | | /* -------------------------------------------------------------------- */ |
43 | 0 | CPLXMLNode *psRG = CPLSearchXMLNode(psXML, "=RectifiedGrid"); |
44 | 0 | CPLXMLNode *psOriginPoint = nullptr; |
45 | 0 | const char *pszOffset1 = nullptr; |
46 | 0 | const char *pszOffset2 = nullptr; |
47 | |
|
48 | 0 | if (psRG != nullptr) |
49 | 0 | { |
50 | 0 | psOriginPoint = CPLGetXMLNode(psRG, "origin.Point"); |
51 | 0 | if (psOriginPoint == nullptr) |
52 | 0 | psOriginPoint = CPLGetXMLNode(psRG, "origin"); |
53 | |
|
54 | 0 | CPLXMLNode *psOffset1 = CPLGetXMLNode(psRG, "offsetVector"); |
55 | 0 | if (psOffset1 != nullptr) |
56 | 0 | { |
57 | 0 | pszOffset1 = CPLGetXMLValue(psOffset1, "", nullptr); |
58 | 0 | pszOffset2 = |
59 | 0 | CPLGetXMLValue(psOffset1->psNext, "=offsetVector", nullptr); |
60 | 0 | } |
61 | 0 | } |
62 | | |
63 | | /* -------------------------------------------------------------------- */ |
64 | | /* If we are missing any of the origin or 2 offsets then give up. */ |
65 | | /* -------------------------------------------------------------------- */ |
66 | 0 | if (psRG == nullptr || psOriginPoint == nullptr || pszOffset1 == nullptr || |
67 | 0 | pszOffset2 == nullptr) |
68 | 0 | { |
69 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
70 | 0 | "Unable to find GML RectifiedGrid, origin or offset vectors"); |
71 | 0 | return CE_Failure; |
72 | 0 | } |
73 | | |
74 | | /* -------------------------------------------------------------------- */ |
75 | | /* Search for the GridEnvelope and derive the raster size. */ |
76 | | /* -------------------------------------------------------------------- */ |
77 | 0 | char **papszLow = |
78 | 0 | CSLTokenizeString(CPLGetXMLValue(psRG, "limits.GridEnvelope.low", "")); |
79 | 0 | char **papszHigh = |
80 | 0 | CSLTokenizeString(CPLGetXMLValue(psRG, "limits.GridEnvelope.high", "")); |
81 | |
|
82 | 0 | if (CSLCount(papszLow) < 2 || CSLCount(papszHigh) < 2) |
83 | 0 | { |
84 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
85 | 0 | "Unable to find or parse GridEnvelope.low/high."); |
86 | 0 | CSLDestroy(papszLow); |
87 | 0 | CSLDestroy(papszHigh); |
88 | 0 | return CE_Failure; |
89 | 0 | } |
90 | | |
91 | 0 | if (pnXSize != nullptr) |
92 | 0 | *pnXSize = atoi(papszHigh[0]) - atoi(papszLow[0]) + 1; |
93 | 0 | if (pnYSize != nullptr) |
94 | 0 | *pnYSize = atoi(papszHigh[1]) - atoi(papszLow[1]) + 1; |
95 | |
|
96 | 0 | CSLDestroy(papszLow); |
97 | 0 | CSLDestroy(papszHigh); |
98 | | |
99 | | /* -------------------------------------------------------------------- */ |
100 | | /* Extract origin location. */ |
101 | | /* -------------------------------------------------------------------- */ |
102 | 0 | OGRPoint *poOriginGeometry = nullptr; |
103 | 0 | std::unique_ptr<OGRGeometry> poGeom; |
104 | 0 | const char *pszSRSName = nullptr; |
105 | |
|
106 | 0 | { |
107 | 0 | 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 | 0 | if (psOriginPoint->eType == CXT_Element && |
112 | 0 | EQUAL(psOriginPoint->pszValue, "origin")) |
113 | 0 | { |
114 | 0 | strcpy(psOriginPoint->pszValue, "Point"); |
115 | 0 | bOldWrap = true; |
116 | 0 | } |
117 | 0 | poGeom.reset( |
118 | 0 | OGRGeometry::FromHandle(OGR_G_CreateFromGMLTree(psOriginPoint))); |
119 | |
|
120 | 0 | if (poGeom != nullptr && |
121 | 0 | wkbFlatten(poGeom->getGeometryType()) == wkbPoint) |
122 | 0 | { |
123 | 0 | poOriginGeometry = poGeom->toPoint(); |
124 | 0 | } |
125 | |
|
126 | 0 | if (bOldWrap) |
127 | 0 | strcpy(psOriginPoint->pszValue, "origin"); |
128 | | |
129 | | // SRS? |
130 | 0 | pszSRSName = CPLGetXMLValue(psOriginPoint, "srsName", nullptr); |
131 | 0 | } |
132 | | |
133 | | /* -------------------------------------------------------------------- */ |
134 | | /* Extract offset(s) */ |
135 | | /* -------------------------------------------------------------------- */ |
136 | 0 | bool bSuccess = false; |
137 | |
|
138 | 0 | char **papszOffset1Tokens = |
139 | 0 | CSLTokenizeStringComplex(pszOffset1, " ,", FALSE, FALSE); |
140 | 0 | char **papszOffset2Tokens = |
141 | 0 | CSLTokenizeStringComplex(pszOffset2, " ,", FALSE, FALSE); |
142 | |
|
143 | 0 | if (CSLCount(papszOffset1Tokens) >= 2 && |
144 | 0 | CSLCount(papszOffset2Tokens) >= 2 && poOriginGeometry != nullptr) |
145 | 0 | { |
146 | 0 | gt.xorig = poOriginGeometry->getX(); |
147 | 0 | gt.xscale = CPLAtof(papszOffset1Tokens[0]); |
148 | 0 | gt.xrot = CPLAtof(papszOffset1Tokens[1]); |
149 | 0 | gt.yorig = poOriginGeometry->getY(); |
150 | 0 | gt.yrot = CPLAtof(papszOffset2Tokens[0]); |
151 | 0 | gt.yscale = CPLAtof(papszOffset2Tokens[1]); |
152 | | |
153 | | // offset from center of pixel. |
154 | 0 | gt.xorig -= gt.xscale * 0.5; |
155 | 0 | gt.xorig -= gt.xrot * 0.5; |
156 | 0 | gt.yorig -= gt.yrot * 0.5; |
157 | 0 | gt.yorig -= gt.yscale * 0.5; |
158 | |
|
159 | 0 | bSuccess = true; |
160 | 0 | } |
161 | |
|
162 | 0 | CSLDestroy(papszOffset1Tokens); |
163 | 0 | CSLDestroy(papszOffset2Tokens); |
164 | | |
165 | | /* -------------------------------------------------------------------- */ |
166 | | /* If we have gotten a geotransform, then try to interpret the */ |
167 | | /* srsName. */ |
168 | | /* -------------------------------------------------------------------- */ |
169 | 0 | if (bSuccess && pszSRSName != nullptr && |
170 | 0 | (*ppszProjection == nullptr || strlen(*ppszProjection) == 0)) |
171 | 0 | { |
172 | 0 | if (STARTS_WITH_CI(pszSRSName, "epsg:")) |
173 | 0 | { |
174 | 0 | OGRSpatialReference oSRS; |
175 | 0 | if (oSRS.SetFromUserInput(pszSRSName) == OGRERR_NONE) |
176 | 0 | oSRS.exportToWkt(ppszProjection); |
177 | 0 | } |
178 | 0 | else if (STARTS_WITH_CI(pszSRSName, "urn:ogc:def:crs:")) |
179 | 0 | { |
180 | 0 | OGRSpatialReference oSRS; |
181 | 0 | if (oSRS.importFromURN(pszSRSName) == OGRERR_NONE) |
182 | 0 | oSRS.exportToWkt(ppszProjection); |
183 | 0 | } |
184 | 0 | else |
185 | 0 | *ppszProjection = CPLStrdup(pszSRSName); |
186 | 0 | } |
187 | |
|
188 | 0 | if (*ppszProjection) |
189 | 0 | CPLDebug("GDALJP2Metadata", "Got projection from GML box: %s", |
190 | 0 | *ppszProjection); |
191 | |
|
192 | 0 | return CE_None; |
193 | 0 | } |