Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft: WCS Coverage for multidimensional layers #332

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 80 additions & 16 deletions adagucserverEC/CXMLGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <iostream>
#include <algorithm>
#include <vector>
#include <sstream>
#include <string>
#include "CXMLGen.h"
#include "CDBFactory.h"
Expand All @@ -38,6 +39,35 @@ int CXMLGen::WCSDescribeCoverage(CServerParams *srvParam, CT::string *XMLDocumen

bool compareStringCase(const std::string &s1, const std::string &s2) { return strcmp(s1.c_str(), s2.c_str()) <= 0; }

// Function to parse a string to double if numeric
double parseNumeric(std::string const &str, bool &isNumeric) {
auto result = double();
auto i = std::istringstream(str);
i >> result;
isNumeric = !i.fail() && i.eof();
return result;
}

// Sort values that can either be numeric of a string
bool multitypeSort(const CT::string &a, const CT::string &b) {
// Try to convert strings to numbers
float aNum, bNum;
bool isANum, isBNum;

isANum = false;
aNum = parseNumeric(a.c_str(), isANum);

isBNum = false;
bNum = parseNumeric(b.c_str(), isBNum);

// Do numerical comparison or alphabetical comparison according to type
if (isANum && isBNum) {
return aNum < bNum;
} else {
return a < b;
}
}

int CXMLGen::getFileNameForLayer(WMSLayer *myWMSLayer) {
#ifdef CXMLGEN_DEBUG
CDBDebug("getFileNameForLayer");
Expand Down Expand Up @@ -1492,6 +1522,53 @@ int CXMLGen::getWCS_1_0_0_Capabilities(CT::string *XMLDoc, std::vector<WMSLayer
return 0;
}

void CXMLGen::generateRangeSet(CT::string *XMLDoc, WMSLayer *layer) {
/*
From the documentation:
The optional and repeatable axisDescription/AxisDescription element is for compound observations.
It describes an additional parameter (that is, an independent variable besides space and time),
and the valid values of this parameter, which GetCoverage requests can use to select subsets of a
coverage offering.
*/
XMLDoc->concat(" <rangeSet>\n"
" <RangeSet>\n"
" <name>dimensions</name>\n"
" <label>dimensions</label>\n");
// Dims
for (size_t d = 0; d < layer->dimList.size(); d++) {
WMSLayer::Dim *dim = layer->dimList[d];
if (dim->name.indexOf("time") != -1) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to show for time the min/max and resolution?

When I do describecoverage on a KNMI Radar file there is no time dimension in the describecoverage. I think we have to accomodate for a webclient, for a webclient it would be useful to have this information to generate a UI.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The resolution in the same way that we show in the getCapabilities description?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes!

continue;
}
// Sort the values to make sure they are in the right order
CT::string *valueSplit = dim->values.splitToArray(",");
std::vector<CT::string> valuesVector(valueSplit, valueSplit + valueSplit->count);
std::sort(valuesVector.begin(), valuesVector.end(), multitypeSort);

XMLDoc->printconcat(" <axisDescription>\n"
" <AxisDescription>\n"
" <name>\"%s\"</name>\n"
" <label>\"%s\"</label>\n",
dim->name.c_str(), dim->name.c_str());
// At least two values (to have a min and a max)
if (valueSplit->count >= 2) {
XMLDoc->printconcat(" <values>\n"
" <interval>\n"
" <min>\"%s\"</min>\n"
" <max>\"%s\"</max>\n"
" </interval>\n"
" </values>\n",
valuesVector[0].c_str(), valuesVector.back().c_str());
}
XMLDoc->printconcat(" </AxisDescription>\n"
" </axisDescription>\n");
delete[] valueSplit;
}

XMLDoc->concat(" </RangeSet>\n"
" </rangeSet>\n");
}

int CXMLGen::getWCS_1_0_0_DescribeCoverage(CT::string *XMLDoc, std::vector<WMSLayer *> *myWMSLayerList) {

XMLDoc->copy("<?xml version='1.0' encoding=\"ISO-8859-1\" ?>\n"
Expand Down Expand Up @@ -1614,22 +1691,9 @@ int CXMLGen::getWCS_1_0_0_DescribeCoverage(CT::string *XMLDoc, std::vector<WMSLa
}
XMLDoc->concat(" </temporalDomain>\n");
}
XMLDoc->concat(" </domainSet>\n"
" <rangeSet>\n"
" <RangeSet>\n"
" <name>bands</name>\n"
" <label>bands</label>\n"
" <axisDescription>\n"
" <AxisDescription>\n"
" <name>bands</name>\n"
" <label>Bands/Channels/Samples</label>\n"
" <values>\n"
" <singleValue>1</singleValue>\n"
" </values>\n"
" </AxisDescription>\n"
" </axisDescription>\n"
" </RangeSet>\n"
" </rangeSet>\n");
XMLDoc->concat(" </domainSet>\n");
// Generate the XML code for RangeSet, including dimensions (AxisDescriptions)
generateRangeSet(XMLDoc, layer);
// Supported CRSs
XMLDoc->concat(" <supportedCRSs>\n");

Expand Down
1 change: 1 addition & 0 deletions adagucserverEC/CXMLGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ class CXMLGen {
int getWCS_1_0_0_Capabilities(CT::string *XMLDoc, std::vector<WMSLayer *> *myWMSLayerList);
int getWCS_1_0_0_DescribeCoverage(CT::string *XMLDoc, std::vector<WMSLayer *> *myWMSLayerList);
int getStylesForLayer(WMSLayer *myWMSLayer);
void generateRangeSet(CT::string *XMLDoc, WMSLayer *layer);
// int getStylesForLayer2(WMSLayer * myWMSLayer);
CServerParams *srvParam;
CT::string serviceInfo;
Expand Down
16 changes: 16 additions & 0 deletions tests/AdagucTests/TestWCS.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,22 @@ def test_WCSDescribeCoverage_Actuele10mindata(self):
self.assertTrue(AdagucTestTools().compareGetCapabilitiesXML(
self.testresultspath + filename, self.expectedoutputsspath + filename))

def test_WCSDescribeCoverage_Multidimdata(self):
"""
Check if WCS DescribeCoverage shows information for multidimensional data
"""
AdagucTestTools().cleanTempDir()
# This file has the following dimensions: lon,lat,member,height, and time.
filename = "test_WCSDescribeCoverage_Multidimdata.xml"
status, data, headers = AdagucTestTools().runADAGUCServer(
"source=netcdf_5dims/netcdf_5dims_seq2/nc_5D_20170101001500-20170101002500.nc&SERVICE=WCS&request=describecoverage&coverage=data",
env=self.env, maxLogFileSize=16384) # Silence log flood warning, datafile has lots of variables, each giving log output
AdagucTestTools().writetofile(self.testresultspath + filename, data.getvalue())
self.assertEqual(status, 0)
self.assertTrue(AdagucTestTools().compareGetCapabilitiesXML(
self.testresultspath + filename, self.expectedoutputsspath + filename))


def test_WCSGetCoverageAAIGRID_testdatanc(self):
"""
Check if WCS GetCoverage for testdata.nc as AAIGRID file is OK
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
<?xml version='1.0' encoding="ISO-8859-1" ?>
<CoverageDescription
version="1.0.0"
updateSequence="0"
xmlns="http://www.opengis.net/wcs"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:gml="http://www.opengis.net/gml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/wcs http://schemas.opengis.net/wcs/1.0.0/describeCoverage.xsd">
<CoverageOffering>
<description>data</description>
<name>data</name>
<label>data</label>
<uom>km</uom>
<lonLatEnvelope srsName="urn:ogc:def:crs:OGC:1.3:CRS84">
<gml:pos>-180.494446 -90.488892</gml:pos>
<gml:pos>179.505554 89.511108</gml:pos>
</lonLatEnvelope>
<domainSet>
<spatialDomain>
<gml:Envelope srsName="EPSG:3411">
<gml:pos>-399240949.703125 -399607437.540235</gml:pos>
<gml:pos>399487065.269510 398879979.546019</gml:pos>
</gml:Envelope>
<gml:Envelope srsName="EPSG:3412">
<gml:pos>-2868126705.493384 -2870740092.047709</gml:pos>
<gml:pos>2869855924.003487 2865475278.583282</gml:pos>
</gml:Envelope>
<gml:Envelope srsName="EPSG:3575">
<gml:pos>-12712149.336113 -12731583.256617</gml:pos>
<gml:pos>12735505.704073 12723911.899582</gml:pos>
</gml:Envelope>
<gml:Envelope srsName="EPSG:3857">
<gml:pos>-19201993.871211 -22228632.557364</gml:pos>
<gml:pos>19982466.888021 34805382.412607</gml:pos>
</gml:Envelope>
<gml:Envelope srsName="EPSG:4258">
<gml:pos>-180.494446 -90.488892</gml:pos>
<gml:pos>179.505554 89.511108</gml:pos>
</gml:Envelope>
<gml:Envelope srsName="EPSG:4326">
<gml:pos>-180.494446 -90.488892</gml:pos>
<gml:pos>179.505554 89.511108</gml:pos>
</gml:Envelope>
<gml:Envelope srsName="CRS:84">
<gml:pos>-180.494446 -90.488892</gml:pos>
<gml:pos>179.505554 89.511108</gml:pos>
</gml:Envelope>
<gml:Envelope srsName="EPSG:25831">
<gml:pos>-15931605.907041 -19720315.591565</gml:pos>
<gml:pos>17051580.684528 19828593.536145</gml:pos>
</gml:Envelope>
<gml:Envelope srsName="EPSG:25832">
<gml:pos>-14709787.414601 -19720736.728277</gml:pos>
<gml:pos>17177711.901099 47405035.658741</gml:pos>
</gml:Envelope>
<gml:Envelope srsName="EPSG:28992">
<gml:pos>-352494887.244074 -527708138.497395</gml:pos>
<gml:pos>319428390.883462 521690003.576207</gml:pos>
</gml:Envelope>
<gml:Envelope srsName="EPSG:7399">
<gml:pos>-17284159.484400 -8898366.230070</gml:pos>
<gml:pos>17986681.325950 9020047.848074</gml:pos>
</gml:Envelope>
<gml:Envelope srsName="EPSG:50001">
<gml:pos>-2000000.000000 -2000000.000000</gml:pos>
<gml:pos>10000000.000000 8500000.000000</gml:pos>
</gml:Envelope>
<gml:Envelope srsName="EPSG:54030">
<gml:pos>-16294244.470419 -8493172.970167</gml:pos>
<gml:pos>16956530.805045 8610630.466538</gml:pos>
</gml:Envelope>
<gml:Envelope srsName="EPSG:32661">
<gml:pos>-407173329.856895 -406795071.401436</gml:pos>
<gml:pos>411420024.012517 411546161.390658</gml:pos>
</gml:Envelope>
<gml:Envelope srsName="EPSG:40000">
<gml:pos>-411643188.990840 -411262647.285147</gml:pos>
<gml:pos>411891372.245993 412018271.016759</gml:pos>
</gml:Envelope>
<gml:Envelope srsName="EPSG:900913">
<gml:pos>-19201993.871211 -22228632.557364</gml:pos>
<gml:pos>19982466.888021 34805382.412607</gml:pos>
</gml:Envelope>
<gml:Envelope srsName="EPSG:3067">
<gml:pos>-15931605.907041 -19720315.591565</gml:pos>
<gml:pos>17051580.684528 19828593.536145</gml:pos>
</gml:Envelope>
<gml:Envelope srsName="EPSG:4326">
<gml:pos>-180.494446 89.511108</gml:pos>
<gml:pos>179.505554 -90.488892</gml:pos>
</gml:Envelope>
<gml:RectifiedGrid dimension="2">
<gml:limits>
<gml:GridEnvelope>
<gml:low>0 0</gml:low>
<gml:high>359 179</gml:high>
</gml:GridEnvelope>
</gml:limits>
<gml:axisName>x</gml:axisName>
<gml:axisName>y</gml:axisName>
<gml:origin>
<gml:pos>-180.494446 89.511108</gml:pos>
</gml:origin>
<gml:offsetVector>1.000000 0</gml:offsetVector>
<gml:offsetVector>0 -1.000000</gml:offsetVector>
</gml:RectifiedGrid>
</spatialDomain>
<temporalDomain>
<gml:timePosition>2017-01-01T00:15:00Z</gml:timePosition>
<gml:timePosition>2017-01-01T00:20:00Z</gml:timePosition>
<gml:timePosition>2017-01-01T00:25:00Z</gml:timePosition>
</temporalDomain>
</domainSet>
<rangeSet>
<RangeSet>
<name>dimensions</name>
<label>dimensions</label>
<axisDescription>
<AxisDescription>
<name>"member"</name>
<label>"member"</label>
<values>
<interval>
<min>"member1"</min>
maartenplieger marked this conversation as resolved.
Show resolved Hide resolved
<max>"member6"</max>
</interval>
</values>
</AxisDescription>
</axisDescription>
<axisDescription>
<AxisDescription>
<name>"elevation"</name>
<label>"elevation"</label>
<values>
<interval>
<min>"1000.0"</min>
<max>"9000.0"</max>
</interval>
</values>
</AxisDescription>
</axisDescription>
</RangeSet>
</rangeSet>
<supportedCRSs>
<requestResponseCRSs>EPSG:3411</requestResponseCRSs>
<requestResponseCRSs>EPSG:3412</requestResponseCRSs>
<requestResponseCRSs>EPSG:3575</requestResponseCRSs>
<requestResponseCRSs>EPSG:3857</requestResponseCRSs>
<requestResponseCRSs>EPSG:4258</requestResponseCRSs>
<requestResponseCRSs>EPSG:4326</requestResponseCRSs>
<requestResponseCRSs>CRS:84</requestResponseCRSs>
<requestResponseCRSs>EPSG:25831</requestResponseCRSs>
<requestResponseCRSs>EPSG:25832</requestResponseCRSs>
<requestResponseCRSs>EPSG:28992</requestResponseCRSs>
<requestResponseCRSs>EPSG:7399</requestResponseCRSs>
<requestResponseCRSs>EPSG:50001</requestResponseCRSs>
<requestResponseCRSs>EPSG:54030</requestResponseCRSs>
<requestResponseCRSs>EPSG:32661</requestResponseCRSs>
<requestResponseCRSs>EPSG:40000</requestResponseCRSs>
<requestResponseCRSs>EPSG:900913</requestResponseCRSs>
<requestResponseCRSs>EPSG:3067</requestResponseCRSs>
<requestResponseCRSs>EPSG:4326</requestResponseCRSs>
<nativeCRSs>EPSG:4326</nativeCRSs>
</supportedCRSs>
<supportedFormats nativeFormat="NetCDF4">
<formats>GeoTIFF</formats>
<formats>AAIGRID</formats>
<formats>netcdf</formats>
<formats>NetCDF3</formats>
<formats>NetCDF4</formats>
<formats>aaigrid</formats>
<formats>geotiff</formats>
</supportedFormats>
<supportedInterpolations default="nearest neighbor">
<interpolationMethod>nearest neighbor</interpolationMethod>
</supportedInterpolations>
</CoverageOffering>
</CoverageDescription>
Original file line number Diff line number Diff line change
Expand Up @@ -108,17 +108,8 @@
</domainSet>
<rangeSet>
<RangeSet>
<name>bands</name>
<label>bands</label>
<axisDescription>
<AxisDescription>
<name>bands</name>
<label>Bands/Channels/Samples</label>
<values>
<singleValue>1</singleValue>
</values>
</AxisDescription>
</axisDescription>
<name>dimensions</name>
<label>dimensions</label>
</RangeSet>
</rangeSet>
<supportedCRSs>
Expand Down Expand Up @@ -255,17 +246,8 @@
</domainSet>
<rangeSet>
<RangeSet>
<name>bands</name>
<label>bands</label>
<axisDescription>
<AxisDescription>
<name>bands</name>
<label>Bands/Channels/Samples</label>
<values>
<singleValue>1</singleValue>
</values>
</AxisDescription>
</axisDescription>
<name>dimensions</name>
<label>dimensions</label>
</RangeSet>
</rangeSet>
<supportedCRSs>
Expand Down Expand Up @@ -402,17 +384,8 @@
</domainSet>
<rangeSet>
<RangeSet>
<name>bands</name>
<label>bands</label>
<axisDescription>
<AxisDescription>
<name>bands</name>
<label>Bands/Channels/Samples</label>
<values>
<singleValue>1</singleValue>
</values>
</AxisDescription>
</axisDescription>
<name>dimensions</name>
<label>dimensions</label>
</RangeSet>
</rangeSet>
<supportedCRSs>
Expand Down
Loading