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