Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Arc GIS Server Client Driver
4 : * Purpose: Implementation of Dataset and RasterBand classes for WMS
5 : * and other similar services.
6 : * Author: Alexander Lisovenko
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2014-2020, NextGIS <info@nextgis.com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "wmsdriver.h"
31 : #include "minidriver_arcgis_server.h"
32 :
33 : #include <algorithm>
34 :
35 2 : WMSMiniDriver_AGS::WMSMiniDriver_AGS()
36 : {
37 2 : }
38 :
39 4 : WMSMiniDriver_AGS::~WMSMiniDriver_AGS()
40 : {
41 4 : }
42 :
43 8 : static double GetBBoxCoord(const GDALWMSImageRequestInfo &iri, char what)
44 : {
45 8 : switch (what)
46 : {
47 2 : case 'x':
48 2 : return std::min(iri.m_x0, iri.m_x1);
49 2 : case 'y':
50 2 : return std::min(iri.m_y0, iri.m_y1);
51 2 : case 'X':
52 2 : return std::max(iri.m_x0, iri.m_x1);
53 2 : case 'Y':
54 2 : return std::max(iri.m_y0, iri.m_y1);
55 : }
56 0 : return 0.0;
57 : }
58 :
59 0 : char **WMSMiniDriver_AGS::GetMetadataDomainList(void)
60 : {
61 0 : return CSLAddString(nullptr, "LocationInfo");
62 : }
63 :
64 2 : CPLErr WMSMiniDriver_AGS::Initialize(CPLXMLNode *config,
65 : CPL_UNUSED char **papszOpenOptions)
66 : {
67 : // Bounding box, if specified, has to be xyXY.
68 2 : m_bbox_order = CPLGetXMLValue(config, "BBoxOrder", "xyXY");
69 2 : if (m_bbox_order.size() < 4 || m_bbox_order.find("xyXY") != 0)
70 : {
71 0 : CPLError(CE_Failure, CPLE_AppDefined,
72 : "GDALWMS: ArcGIS BBoxOrder value has to be xyXY");
73 0 : return CE_Failure;
74 : }
75 :
76 : m_base_url = CPLGetXMLValue(config, "ServerURL",
77 2 : CPLGetXMLValue(config, "ServerUrl", ""));
78 2 : if (m_base_url.empty())
79 : {
80 0 : CPLError(CE_Failure, CPLE_AppDefined,
81 : "GDALWMS: ArcGIS Server mini-driver: ServerURL missing.");
82 0 : return CE_Failure;
83 : }
84 :
85 2 : m_image_format = CPLGetXMLValue(config, "ImageFormat", "png");
86 2 : m_time_range = CPLGetXMLValue(config, "TimeRange", "");
87 2 : m_transparent = CPLGetXMLValue(config, "Transparent", "");
88 2 : m_transparent.tolower();
89 2 : m_layers = CPLGetXMLValue(config, "Layers", "");
90 :
91 2 : const char *irs = CPLGetXMLValue(config, "SRS", "102100");
92 :
93 2 : if (irs != nullptr)
94 : {
95 2 : if (STARTS_WITH_CI(
96 : irs, "EPSG:")) // If we have EPSG code just convert it to WKT.
97 : {
98 2 : m_oSRS = ProjToSRS(irs);
99 2 : m_irs = irs + 5;
100 : }
101 : else // If we have AGS code - try if it's EPSG.
102 : {
103 0 : m_irs = irs;
104 0 : m_oSRS = ProjToSRS("EPSG:" + m_irs);
105 : }
106 : // TODO: If we have AGS JSON.
107 : }
108 : m_identification_tolerance =
109 2 : CPLGetXMLValue(config, "IdentificationTolerance", "2");
110 :
111 2 : return CE_None;
112 : }
113 :
114 2 : void WMSMiniDriver_AGS::GetCapabilities(WMSMiniDriverCapabilities *caps)
115 : {
116 2 : caps->m_has_getinfo = 1;
117 2 : }
118 :
119 2 : CPLErr WMSMiniDriver_AGS::TiledImageRequest(
120 : WMSHTTPRequest &request, const GDALWMSImageRequestInfo &iri,
121 : CPL_UNUSED const GDALWMSTiledImageRequestInfo &tiri)
122 : {
123 2 : CPLString &url = request.URL;
124 2 : url = m_base_url;
125 :
126 : // Assume map service if exportImage is not explicitly requested.
127 3 : if ((url.ifind("/export?") == std::string::npos) &&
128 1 : (url.ifind("/exportImage?") == std::string::npos))
129 : {
130 1 : url += "/export?";
131 : }
132 :
133 2 : URLPrepare(url);
134 2 : url += "f=image";
135 2 : char *pszEscapedValue = CPLEscapeString(m_layers, -1, CPLES_URL);
136 2 : url += CPLOPrintf("&bbox=%.8f%%2C%.8f%%2C%.8f%%2C%.8f",
137 2 : GetBBoxCoord(iri, m_bbox_order[0]),
138 2 : GetBBoxCoord(iri, m_bbox_order[1]),
139 2 : GetBBoxCoord(iri, m_bbox_order[2]),
140 6 : GetBBoxCoord(iri, m_bbox_order[3])) +
141 8 : CPLOPrintf("&size=%d%%2C%d", iri.m_sx, iri.m_sy) +
142 8 : CPLOPrintf("&imageSR=%s", m_irs.c_str()) +
143 8 : CPLOPrintf("&bboxSR=%s", m_irs.c_str()) +
144 8 : CPLOPrintf("&format=%s", m_image_format.c_str()) +
145 6 : CPLOPrintf("&layers=%s", pszEscapedValue);
146 2 : CPLFree(pszEscapedValue);
147 :
148 2 : if (!m_transparent.empty())
149 : {
150 0 : url += "&transparent=" + m_transparent;
151 : }
152 : else
153 : {
154 2 : url += "&transparent=false";
155 : }
156 :
157 2 : if (!m_time_range.empty())
158 : {
159 0 : pszEscapedValue = CPLEscapeString(m_time_range, -1, CPLES_URL);
160 0 : url += CPLOPrintf("&time=%s", pszEscapedValue);
161 0 : CPLFree(pszEscapedValue);
162 : }
163 : else
164 : {
165 2 : url += "&time=";
166 : }
167 :
168 2 : return CE_None;
169 : }
170 :
171 0 : void WMSMiniDriver_AGS::GetTiledImageInfo(
172 : CPLString &url, const GDALWMSImageRequestInfo &iri,
173 : CPL_UNUSED const GDALWMSTiledImageRequestInfo &tiri, int nXInBlock,
174 : int nYInBlock)
175 : {
176 0 : url = m_base_url;
177 :
178 0 : if (m_base_url.ifind("/identify?") == std::string::npos)
179 : {
180 0 : url += "/identify?";
181 : }
182 :
183 0 : URLPrepare(url);
184 : // Constant part.
185 : url += "f=json&geometryType=esriGeometryPoint&returnGeometry=false"
186 0 : "&layerdefs=&time=&layerTimeOptions=&maxAllowableOffset=";
187 :
188 0 : double fX = GetBBoxCoord(iri, 'x') +
189 0 : nXInBlock * (GetBBoxCoord(iri, 'X') - GetBBoxCoord(iri, 'x')) /
190 0 : iri.m_sx;
191 0 : double fY = GetBBoxCoord(iri, 'y') +
192 0 : (iri.m_sy - nYInBlock) *
193 0 : (GetBBoxCoord(iri, 'Y') - GetBBoxCoord(iri, 'y')) /
194 0 : iri.m_sy;
195 :
196 0 : url += "&geometry=" + std::to_string(fX) + "%2C" + std::to_string(fY) +
197 0 : "&sr=" + m_irs;
198 :
199 0 : CPLString layers("visible");
200 0 : if (m_layers.find("show") != std::string::npos)
201 : {
202 0 : layers = m_layers;
203 0 : layers.replace(layers.find("show"), 4, "all");
204 : }
205 :
206 0 : if (m_layers.find("hide") != std::string::npos ||
207 0 : m_layers.find("include") != std::string::npos ||
208 0 : m_layers.find("exclude") != std::string::npos)
209 : {
210 0 : layers = "top";
211 : }
212 :
213 0 : url += "&layers=" + layers;
214 0 : url += "&tolerance=" + m_identification_tolerance;
215 0 : url += CPLOPrintf("&mapExtent=%.8f%%2C%.8f%%2C%.8f%%2C%.8f",
216 0 : GetBBoxCoord(iri, m_bbox_order[0]),
217 0 : GetBBoxCoord(iri, m_bbox_order[1]),
218 0 : GetBBoxCoord(iri, m_bbox_order[2]),
219 0 : GetBBoxCoord(iri, m_bbox_order[3])) +
220 0 : CPLOPrintf("&imageDisplay=%d%%2C%d%%2C96", iri.m_sx, iri.m_sy);
221 0 : }
|