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 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "wmsdriver.h"
15 : #include "minidriver_arcgis_server.h"
16 :
17 : #include <algorithm>
18 :
19 2 : WMSMiniDriver_AGS::WMSMiniDriver_AGS()
20 : {
21 2 : }
22 :
23 4 : WMSMiniDriver_AGS::~WMSMiniDriver_AGS()
24 : {
25 4 : }
26 :
27 8 : static double GetBBoxCoord(const GDALWMSImageRequestInfo &iri, char what)
28 : {
29 8 : switch (what)
30 : {
31 2 : case 'x':
32 2 : return std::min(iri.m_x0, iri.m_x1);
33 2 : case 'y':
34 2 : return std::min(iri.m_y0, iri.m_y1);
35 2 : case 'X':
36 2 : return std::max(iri.m_x0, iri.m_x1);
37 2 : case 'Y':
38 2 : return std::max(iri.m_y0, iri.m_y1);
39 : }
40 0 : return 0.0;
41 : }
42 :
43 0 : char **WMSMiniDriver_AGS::GetMetadataDomainList(void)
44 : {
45 0 : return CSLAddString(nullptr, "LocationInfo");
46 : }
47 :
48 2 : CPLErr WMSMiniDriver_AGS::Initialize(CPLXMLNode *config,
49 : CPL_UNUSED char **papszOpenOptions)
50 : {
51 : // Bounding box, if specified, has to be xyXY.
52 2 : m_bbox_order = CPLGetXMLValue(config, "BBoxOrder", "xyXY");
53 2 : if (m_bbox_order.size() < 4 || m_bbox_order.find("xyXY") != 0)
54 : {
55 0 : CPLError(CE_Failure, CPLE_AppDefined,
56 : "GDALWMS: ArcGIS BBoxOrder value has to be xyXY");
57 0 : return CE_Failure;
58 : }
59 :
60 : m_base_url = CPLGetXMLValue(config, "ServerURL",
61 2 : CPLGetXMLValue(config, "ServerUrl", ""));
62 2 : if (m_base_url.empty())
63 : {
64 0 : CPLError(CE_Failure, CPLE_AppDefined,
65 : "GDALWMS: ArcGIS Server mini-driver: ServerURL missing.");
66 0 : return CE_Failure;
67 : }
68 :
69 2 : m_image_format = CPLGetXMLValue(config, "ImageFormat", "png");
70 2 : m_time_range = CPLGetXMLValue(config, "TimeRange", "");
71 : m_transparent =
72 2 : CPLString(CPLGetXMLValue(config, "Transparent", "")).tolower();
73 2 : m_layers = CPLGetXMLValue(config, "Layers", "");
74 :
75 2 : const char *irs = CPLGetXMLValue(config, "SRS", "102100");
76 :
77 2 : if (irs != nullptr)
78 : {
79 2 : if (STARTS_WITH_CI(
80 : irs, "EPSG:")) // If we have EPSG code just convert it to WKT.
81 : {
82 2 : m_oSRS = ProjToSRS(irs);
83 2 : m_irs = irs + 5;
84 : }
85 : else // If we have AGS code - try if it's EPSG.
86 : {
87 0 : m_irs = irs;
88 0 : m_oSRS = ProjToSRS("EPSG:" + m_irs);
89 : }
90 : // TODO: If we have AGS JSON.
91 : }
92 : m_identification_tolerance =
93 2 : CPLGetXMLValue(config, "IdentificationTolerance", "2");
94 :
95 2 : return CE_None;
96 : }
97 :
98 2 : void WMSMiniDriver_AGS::GetCapabilities(WMSMiniDriverCapabilities *caps)
99 : {
100 2 : caps->m_has_getinfo = 1;
101 2 : }
102 :
103 2 : CPLErr WMSMiniDriver_AGS::TiledImageRequest(
104 : WMSHTTPRequest &request, const GDALWMSImageRequestInfo &iri,
105 : CPL_UNUSED const GDALWMSTiledImageRequestInfo &tiri)
106 : {
107 2 : CPLString &url = request.URL;
108 2 : url = m_base_url;
109 :
110 : // Assume map service if exportImage is not explicitly requested.
111 3 : if ((url.ifind("/export?") == std::string::npos) &&
112 1 : (url.ifind("/exportImage?") == std::string::npos))
113 : {
114 1 : url += "/export?";
115 : }
116 :
117 2 : URLPrepare(url);
118 2 : url += "f=image";
119 2 : char *pszEscapedValue = CPLEscapeString(m_layers, -1, CPLES_URL);
120 2 : url += CPLOPrintf("&bbox=%.8f%%2C%.8f%%2C%.8f%%2C%.8f",
121 2 : GetBBoxCoord(iri, m_bbox_order[0]),
122 2 : GetBBoxCoord(iri, m_bbox_order[1]),
123 2 : GetBBoxCoord(iri, m_bbox_order[2]),
124 6 : GetBBoxCoord(iri, m_bbox_order[3])) +
125 8 : CPLOPrintf("&size=%d%%2C%d", iri.m_sx, iri.m_sy) +
126 8 : CPLOPrintf("&imageSR=%s", m_irs.c_str()) +
127 8 : CPLOPrintf("&bboxSR=%s", m_irs.c_str()) +
128 8 : CPLOPrintf("&format=%s", m_image_format.c_str()) +
129 6 : CPLOPrintf("&layers=%s", pszEscapedValue);
130 2 : CPLFree(pszEscapedValue);
131 :
132 2 : if (!m_transparent.empty())
133 : {
134 0 : url += "&transparent=" + m_transparent;
135 : }
136 : else
137 : {
138 2 : url += "&transparent=false";
139 : }
140 :
141 2 : if (!m_time_range.empty())
142 : {
143 0 : pszEscapedValue = CPLEscapeString(m_time_range, -1, CPLES_URL);
144 0 : url += CPLOPrintf("&time=%s", pszEscapedValue);
145 0 : CPLFree(pszEscapedValue);
146 : }
147 : else
148 : {
149 2 : url += "&time=";
150 : }
151 :
152 2 : return CE_None;
153 : }
154 :
155 0 : void WMSMiniDriver_AGS::GetTiledImageInfo(
156 : CPLString &url, const GDALWMSImageRequestInfo &iri,
157 : CPL_UNUSED const GDALWMSTiledImageRequestInfo &tiri, int nXInBlock,
158 : int nYInBlock)
159 : {
160 0 : url = m_base_url;
161 :
162 0 : if (m_base_url.ifind("/identify?") == std::string::npos)
163 : {
164 0 : url += "/identify?";
165 : }
166 :
167 0 : URLPrepare(url);
168 : // Constant part.
169 : url += "f=json&geometryType=esriGeometryPoint&returnGeometry=false"
170 0 : "&layerdefs=&time=&layerTimeOptions=&maxAllowableOffset=";
171 :
172 0 : double fX = GetBBoxCoord(iri, 'x') +
173 0 : nXInBlock * (GetBBoxCoord(iri, 'X') - GetBBoxCoord(iri, 'x')) /
174 0 : iri.m_sx;
175 0 : double fY = GetBBoxCoord(iri, 'y') +
176 0 : (iri.m_sy - nYInBlock) *
177 0 : (GetBBoxCoord(iri, 'Y') - GetBBoxCoord(iri, 'y')) /
178 0 : iri.m_sy;
179 :
180 0 : url += "&geometry=" + std::to_string(fX) + "%2C" + std::to_string(fY) +
181 0 : "&sr=" + m_irs;
182 :
183 0 : CPLString layers("visible");
184 0 : if (m_layers.find("show") != std::string::npos)
185 : {
186 0 : layers = m_layers;
187 0 : layers.replace(layers.find("show"), 4, "all");
188 : }
189 :
190 0 : if (m_layers.find("hide") != std::string::npos ||
191 0 : m_layers.find("include") != std::string::npos ||
192 0 : m_layers.find("exclude") != std::string::npos)
193 : {
194 0 : layers = "top";
195 : }
196 :
197 0 : url += "&layers=" + layers;
198 0 : url += "&tolerance=" + m_identification_tolerance;
199 0 : url += CPLOPrintf("&mapExtent=%.8f%%2C%.8f%%2C%.8f%%2C%.8f",
200 0 : GetBBoxCoord(iri, m_bbox_order[0]),
201 0 : GetBBoxCoord(iri, m_bbox_order[1]),
202 0 : GetBBoxCoord(iri, m_bbox_order[2]),
203 0 : GetBBoxCoord(iri, m_bbox_order[3])) +
204 0 : CPLOPrintf("&imageDisplay=%d%%2C%d%%2C96", iri.m_sx, iri.m_sy);
205 0 : }
|