gdal/frmts/wms/minidriver_arcgis_server.cpp

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);
}