-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[GEOS-8596] WMS-T "nearest match" support for time dimension (#2764)
[GEOS-8596] WMS-T "nearest match" support for time dimension
- Loading branch information
Showing
29 changed files
with
1,820 additions
and
120 deletions.
There are no files selected for viewing
Binary file modified
BIN
-25.8 KB
(35%)
doc/en/user/source/data/webadmin/img/data_layers_dimension_editor_time.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
118 changes: 118 additions & 0 deletions
118
src/main/src/main/java/org/geoserver/catalog/AcceptableRange.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,118 @@ | |||
/* (c) 2018 Open Source Geospatial Foundation - all rights reserved | |||
* This code is licensed under the GPL 2.0 license, available at the root | |||
* application directory. | |||
*/ | |||
package org.geoserver.catalog; | |||
|
|||
import org.geoserver.ows.kvp.TimeParser; | |||
import org.geotools.util.DateRange; | |||
import org.geotools.util.Range; | |||
|
|||
import java.text.ParseException; | |||
import java.util.Calendar; | |||
import java.util.Date; | |||
|
|||
/** | |||
* Represents the parsed acceptable range. For elevation it's simple numbers, for dates it's a number of milliseconds. | |||
*/ | |||
public class AcceptableRange { | |||
|
|||
/** | |||
* Parses the acceptable range | |||
* | |||
* @param spec The specification from the UI | |||
* @param dataType The target data type (e.g. {@link Date} | |||
* @return An {@link AcceptableRange} object, or null if the spec was null or empty | |||
*/ | |||
public static AcceptableRange getAcceptableRange(String spec, Class dataType) throws ParseException { | |||
if (spec == null || spec.trim().isEmpty()) { | |||
return null; | |||
} | |||
|
|||
String[] split = spec.split("/"); | |||
if (split.length > 2) { | |||
throw new IllegalArgumentException("Invalid acceptable range specification, must be either a single " + | |||
"value, or two values split by a forward slash"); | |||
} | |||
Number before = parseValue(split[0], dataType); | |||
Number after = before; | |||
if (split.length == 2) { | |||
after = parseValue(split[1], dataType); | |||
} | |||
// avoid complications in case the search range is empty | |||
if (before.doubleValue() == 0 && after.doubleValue() == 0) { | |||
return null; | |||
} | |||
return new AcceptableRange(before, after, dataType); | |||
} | |||
|
|||
private static Number parseValue(String s, Class dataType) throws ParseException { | |||
if (Date.class.isAssignableFrom(dataType)) { | |||
return TimeParser.parsePeriod(s); | |||
} | |||
// TODO: add support for Number, e.g., elevation | |||
throw new IllegalArgumentException("Unsupported value type " + dataType); | |||
} | |||
|
|||
private Number before; | |||
private Number after; | |||
private Class dataType; | |||
|
|||
public AcceptableRange(Number before, Number after, Class dataType) { | |||
this.before = before; | |||
this.after = after; | |||
this.dataType = dataType; | |||
} | |||
|
|||
public Range getSearchRange(Object value) { | |||
if (value instanceof Range) { | |||
Range range = (Range) value; | |||
Range before = getSearchRangeOnSingleValue(range.getMinValue()); | |||
Range after = getSearchRangeOnSingleValue(range.getMaxValue()); | |||
return before.union(after); | |||
} else { | |||
return getSearchRangeOnSingleValue(value); | |||
} | |||
|
|||
} | |||
|
|||
public Range getSearchRangeOnSingleValue(Object value) { | |||
if (Date.class.isAssignableFrom(dataType)) { | |||
Date center = (Date) value; | |||
Calendar cal = Calendar.getInstance(); | |||
cal.setTime(center); | |||
cal.setTimeInMillis(cal.getTimeInMillis() - before.longValue()); | |||
Date min = cal.getTime(); | |||
cal.setTime(center); | |||
cal.setTimeInMillis(cal.getTimeInMillis() + after.longValue()); | |||
Date max = cal.getTime(); | |||
return new DateRange(min, max); | |||
} | |||
// TODO: add support for Number, e.g., elevation | |||
throw new IllegalArgumentException("Unsupported value type " + dataType); | |||
} | |||
|
|||
/** | |||
* Before offset | |||
* @return | |||
*/ | |||
public Number getBefore() { | |||
return before; | |||
} | |||
|
|||
/** | |||
* After offset | |||
* @return | |||
*/ | |||
public Number getAfter() { | |||
return after; | |||
} | |||
|
|||
/** | |||
* The range data type | |||
* @return | |||
*/ | |||
public Class getDataType() { | |||
return dataType; | |||
} | |||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
src/main/src/test/java/org/geoserver/catalog/AcceptableRangeTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,53 @@ | |||
/* (c) 2018 Open Source Geospatial Foundation - all rights reserved | |||
* This code is licensed under the GPL 2.0 license, available at the root | |||
* application directory. | |||
*/ | |||
package org.geoserver.catalog; | |||
|
|||
import org.geotools.util.DateRange; | |||
import org.junit.Test; | |||
|
|||
import java.util.Date; | |||
|
|||
import static junit.framework.TestCase.assertEquals; | |||
|
|||
public class AcceptableRangeTest { | |||
|
|||
public static final long DAY_IN_MS = 1000 * 60 * 60 * 24; | |||
|
|||
@Test | |||
public void testSymmetricTimeRange() throws Exception { | |||
AcceptableRange range = AcceptableRange.getAcceptableRange("P1D", Date.class); | |||
assertEquals(DAY_IN_MS, range.getBefore()); | |||
assertEquals(DAY_IN_MS, range.getAfter()); | |||
|
|||
Date value = new Date(); | |||
DateRange searchRange = (DateRange) range.getSearchRange(value); | |||
assertEquals(DAY_IN_MS, value.getTime() - searchRange.getMinValue().getTime()); | |||
assertEquals(DAY_IN_MS, searchRange.getMaxValue().getTime() - value.getTime()); | |||
} | |||
|
|||
@Test | |||
public void testPastTimeRange() throws Exception { | |||
AcceptableRange range = AcceptableRange.getAcceptableRange("P1D/P0D", Date.class); | |||
assertEquals(DAY_IN_MS, range.getBefore()); | |||
assertEquals(0l, range.getAfter()); | |||
|
|||
Date value = new Date(); | |||
DateRange searchRange = (DateRange) range.getSearchRange(value); | |||
assertEquals(DAY_IN_MS, value.getTime() - searchRange.getMinValue().getTime()); | |||
assertEquals(0l, searchRange.getMaxValue().getTime() - value.getTime()); | |||
} | |||
|
|||
@Test | |||
public void testFutureTimeRange() throws Exception { | |||
AcceptableRange range = AcceptableRange.getAcceptableRange("P0D/P1D", Date.class); | |||
assertEquals(0l, range.getBefore()); | |||
assertEquals(DAY_IN_MS, range.getAfter()); | |||
|
|||
Date value = new Date(); | |||
DateRange searchRange = (DateRange) range.getSearchRange(value); | |||
assertEquals(0l, value.getTime() - searchRange.getMinValue().getTime()); | |||
assertEquals(DAY_IN_MS, searchRange.getMaxValue().getTime() - value.getTime()); | |||
} | |||
} |
Oops, something went wrong.