222 строки
7.2 KiB
C++
222 строки
7.2 KiB
C++
/******************************************************************************
|
|
*
|
|
* Project: Arc GIS Server Client Driver
|
|
* Purpose: Implementation of Dataset and RasterBand classes for WMS
|
|
* and other similar services.
|
|
* Author: Alexander Lisovenko
|
|
*
|
|
******************************************************************************
|
|
* Copyright (c) 2014-2020, NextGIS <info@nextgis.com>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
****************************************************************************/
|
|
|
|
#include "wmsdriver.h"
|
|
#include "minidriver_arcgis_server.h"
|
|
|
|
#include <algorithm>
|
|
|
|
WMSMiniDriver_AGS::WMSMiniDriver_AGS()
|
|
{
|
|
}
|
|
|
|
WMSMiniDriver_AGS::~WMSMiniDriver_AGS()
|
|
{
|
|
}
|
|
|
|
static double GetBBoxCoord(const GDALWMSImageRequestInfo &iri, char what)
|
|
{
|
|
switch (what)
|
|
{
|
|
case 'x':
|
|
return std::min(iri.m_x0, iri.m_x1);
|
|
case 'y':
|
|
return std::min(iri.m_y0, iri.m_y1);
|
|
case 'X':
|
|
return std::max(iri.m_x0, iri.m_x1);
|
|
case 'Y':
|
|
return std::max(iri.m_y0, iri.m_y1);
|
|
}
|
|
return 0.0;
|
|
}
|
|
|
|
char **WMSMiniDriver_AGS::GetMetadataDomainList(void)
|
|
{
|
|
return CSLAddString(nullptr, "LocationInfo");
|
|
}
|
|
|
|
CPLErr WMSMiniDriver_AGS::Initialize(CPLXMLNode *config,
|
|
CPL_UNUSED char **papszOpenOptions)
|
|
{
|
|
// Bounding box, if specified, has to be xyXY.
|
|
m_bbox_order = CPLGetXMLValue(config, "BBoxOrder", "xyXY");
|
|
if (m_bbox_order.size() < 4 || m_bbox_order.find("xyXY") != 0)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"GDALWMS: ArcGIS BBoxOrder value has to be xyXY");
|
|
return CE_Failure;
|
|
}
|
|
|
|
m_base_url = CPLGetXMLValue(config, "ServerURL",
|
|
CPLGetXMLValue(config, "ServerUrl", ""));
|
|
if (m_base_url.empty())
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"GDALWMS: ArcGIS Server mini-driver: ServerURL missing.");
|
|
return CE_Failure;
|
|
}
|
|
|
|
m_image_format = CPLGetXMLValue(config, "ImageFormat", "png");
|
|
m_time_range = CPLGetXMLValue(config, "TimeRange", "");
|
|
m_transparent = CPLGetXMLValue(config, "Transparent", "");
|
|
m_transparent.tolower();
|
|
m_layers = CPLGetXMLValue(config, "Layers", "");
|
|
|
|
const char *irs = CPLGetXMLValue(config, "SRS", "102100");
|
|
|
|
if (irs != nullptr)
|
|
{
|
|
if (STARTS_WITH_CI(
|
|
irs, "EPSG:")) // If we have EPSG code just convert it to WKT.
|
|
{
|
|
m_oSRS = ProjToSRS(irs);
|
|
m_irs = irs + 5;
|
|
}
|
|
else // If we have AGS code - try if it's EPSG.
|
|
{
|
|
m_irs = irs;
|
|
m_oSRS = ProjToSRS("EPSG:" + m_irs);
|
|
}
|
|
// TODO: If we have AGS JSON.
|
|
}
|
|
m_identification_tolerance =
|
|
CPLGetXMLValue(config, "IdentificationTolerance", "2");
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
void WMSMiniDriver_AGS::GetCapabilities(WMSMiniDriverCapabilities *caps)
|
|
{
|
|
caps->m_has_getinfo = 1;
|
|
}
|
|
|
|
CPLErr WMSMiniDriver_AGS::TiledImageRequest(
|
|
WMSHTTPRequest &request, const GDALWMSImageRequestInfo &iri,
|
|
CPL_UNUSED const GDALWMSTiledImageRequestInfo &tiri)
|
|
{
|
|
CPLString &url = request.URL;
|
|
url = m_base_url;
|
|
|
|
// Assume map service if exportImage is not explicitly requested.
|
|
if ((url.ifind("/export?") == std::string::npos) &&
|
|
(url.ifind("/exportImage?") == std::string::npos))
|
|
{
|
|
url += "/export?";
|
|
}
|
|
|
|
URLPrepare(url);
|
|
url += "f=image";
|
|
char *pszEscapedValue = CPLEscapeString(m_layers, -1, CPLES_URL);
|
|
url += CPLOPrintf("&bbox=%.8f%%2C%.8f%%2C%.8f%%2C%.8f",
|
|
GetBBoxCoord(iri, m_bbox_order[0]),
|
|
GetBBoxCoord(iri, m_bbox_order[1]),
|
|
GetBBoxCoord(iri, m_bbox_order[2]),
|
|
GetBBoxCoord(iri, m_bbox_order[3])) +
|
|
CPLOPrintf("&size=%d%%2C%d", iri.m_sx, iri.m_sy) +
|
|
CPLOPrintf("&imageSR=%s", m_irs.c_str()) +
|
|
CPLOPrintf("&bboxSR=%s", m_irs.c_str()) +
|
|
CPLOPrintf("&format=%s", m_image_format.c_str()) +
|
|
CPLOPrintf("&layers=%s", pszEscapedValue);
|
|
CPLFree(pszEscapedValue);
|
|
|
|
if (!m_transparent.empty())
|
|
{
|
|
url += "&transparent=" + m_transparent;
|
|
}
|
|
else
|
|
{
|
|
url += "&transparent=false";
|
|
}
|
|
|
|
if (!m_time_range.empty())
|
|
{
|
|
pszEscapedValue = CPLEscapeString(m_time_range, -1, CPLES_URL);
|
|
url += CPLOPrintf("&time=%s", pszEscapedValue);
|
|
CPLFree(pszEscapedValue);
|
|
}
|
|
else
|
|
{
|
|
url += "&time=";
|
|
}
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
void WMSMiniDriver_AGS::GetTiledImageInfo(
|
|
CPLString &url, const GDALWMSImageRequestInfo &iri,
|
|
CPL_UNUSED const GDALWMSTiledImageRequestInfo &tiri, int nXInBlock,
|
|
int nYInBlock)
|
|
{
|
|
url = m_base_url;
|
|
|
|
if (m_base_url.ifind("/identify?") == std::string::npos)
|
|
{
|
|
url += "/identify?";
|
|
}
|
|
|
|
URLPrepare(url);
|
|
// Constant part.
|
|
url += "f=json&geometryType=esriGeometryPoint&returnGeometry=false"
|
|
"&layerdefs=&time=&layerTimeOptions=&maxAllowableOffset=";
|
|
|
|
double fX = GetBBoxCoord(iri, 'x') +
|
|
nXInBlock * (GetBBoxCoord(iri, 'X') - GetBBoxCoord(iri, 'x')) /
|
|
iri.m_sx;
|
|
double fY = GetBBoxCoord(iri, 'y') +
|
|
(iri.m_sy - nYInBlock) *
|
|
(GetBBoxCoord(iri, 'Y') - GetBBoxCoord(iri, 'y')) /
|
|
iri.m_sy;
|
|
|
|
url += "&geometry=" + std::to_string(fX) + "%2C" + std::to_string(fY) +
|
|
"&sr=" + m_irs;
|
|
|
|
CPLString layers("visible");
|
|
if (m_layers.find("show") != std::string::npos)
|
|
{
|
|
layers = m_layers;
|
|
layers.replace(layers.find("show"), 4, "all");
|
|
}
|
|
|
|
if (m_layers.find("hide") != std::string::npos ||
|
|
m_layers.find("include") != std::string::npos ||
|
|
m_layers.find("exclude") != std::string::npos)
|
|
{
|
|
layers = "top";
|
|
}
|
|
|
|
url += "&layers=" + layers;
|
|
url += "&tolerance=" + m_identification_tolerance;
|
|
url += CPLOPrintf("&mapExtent=%.8f%%2C%.8f%%2C%.8f%%2C%.8f",
|
|
GetBBoxCoord(iri, m_bbox_order[0]),
|
|
GetBBoxCoord(iri, m_bbox_order[1]),
|
|
GetBBoxCoord(iri, m_bbox_order[2]),
|
|
GetBBoxCoord(iri, m_bbox_order[3])) +
|
|
CPLOPrintf("&imageDisplay=%d%%2C%d%%2C96", iri.m_sx, iri.m_sy);
|
|
}
|