Skip to content

Commit 61d0873

Browse files
committed
Add Raster reclassify, extrema, getMinValue, and getMaxValue methods
1 parent d05ec98 commit 61d0873

File tree

4 files changed

+120
-2
lines changed

4 files changed

+120
-2
lines changed

doc/api/raster.rst

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ Properties
9494
`Array` of :class:`raster.Bands`
9595
Get an array of Bands
9696

97+
.. attribute:: Raster.extrema
98+
99+
`Object` with min and max arrays with min and max values for each band
100+
Get the minimum and maximum values for each band.
101+
97102
Methods
98103
-------
99104

@@ -119,6 +124,18 @@ Methods
119124

120125
Get a value for each band from the Raster.
121126

127+
.. function:: Raster.getMinimumValue(band)
128+
129+
:arg namd: `Number` The band
130+
131+
Get the minimum value for the given band
132+
133+
.. function:: Raster.getMaximumValue(band)
134+
135+
:arg namd: `Number` The band
136+
137+
Get the maximum value for the given band
138+
122139
.. function:: Raster.crop(bounds)
123140

124141
:arg bounds: :class:`geom.Bound` The Bounds of the new Raster
@@ -135,7 +152,15 @@ Methods
135152

136153
:arg projection: :class:`proj.Projection` The target Projection
137154

138-
Reproject a Raster from one Projection to anothet Projection.
155+
Reproject a Raster from one Projection to another Projection.
156+
157+
.. function:: Raster.reclassify(ranges, options)
158+
159+
:arg ranges: `Array` An array of object literals with required min, max, and value properties. minIncluded and maxIncluded are optional.
160+
161+
:arg options: `Object` An object literal with optional band and noData values.
162+
163+
Reclassify the values of the Raster.
139164

140165
:class:`raster.Band`
141166
====================

pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@
8989
<artifactId>gt-process-feature</artifactId>
9090
<version>${gt.version}</version>
9191
</dependency>
92+
<dependency>
93+
<groupId>org.geotools</groupId>
94+
<artifactId>gt-process-raster</artifactId>
95+
<version>${gt.version}</version>
96+
</dependency>
9297
<dependency>
9398
<groupId>org.geotools</groupId>
9499
<artifactId>gt-epsg-hsql</artifactId>

src/main/java/org/geoscript/js/raster/Raster.java

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@
1212
import org.geotools.coverage.processing.CoverageProcessor;
1313
import org.geotools.geometry.DirectPosition2D;
1414
import org.geotools.geometry.jts.ReferencedEnvelope;
15+
import org.geotools.process.raster.RangeLookupProcess;
16+
import org.jaitools.numeric.Range;
1517
import org.mozilla.javascript.*;
1618
import org.mozilla.javascript.annotations.JSConstructor;
1719
import org.mozilla.javascript.annotations.JSFunction;
1820
import org.mozilla.javascript.annotations.JSGetter;
19-
import org.opengis.coverage.Coverage;
2021
import org.opengis.coverage.SampleDimension;
2122
import org.opengis.geometry.DirectPosition;
2223
import org.opengis.geometry.Envelope;
@@ -166,6 +167,65 @@ public Raster reproject(Projection projection) {
166167
return new Raster(this.getParentScope(), newCoverage);
167168
}
168169

170+
@JSFunction
171+
public Raster reclassify(NativeArray ranges, NativeObject options) {
172+
int band = (int) options.getOrDefault("band", 0);
173+
double noData = (double) options.getOrDefault("noData",0);
174+
List<Range> rangeList = new ArrayList<>();
175+
int[] pixelValues = new int[ranges.size()];
176+
for(int i = 0; i<ranges.size(); i++) {
177+
NativeObject rangeObj = (NativeObject) ranges.get(i);
178+
pixelValues[i] = getInt(rangeObj.get("value"));
179+
rangeList.add(Range.create(
180+
Double.parseDouble(rangeObj.get("min").toString()),
181+
(boolean) rangeObj.getOrDefault("minIncluded", true),
182+
Double.parseDouble(rangeObj.get("max").toString()),
183+
(boolean) rangeObj.getOrDefault("maxIncluded", true)
184+
));
185+
}
186+
RangeLookupProcess process = new RangeLookupProcess();
187+
GridCoverage2D newCoverage = process.execute(this.coverage, band, rangeList, pixelValues, noData, null);
188+
return new Raster(this.getParentScope(), newCoverage);
189+
}
190+
191+
@JSGetter
192+
public NativeObject getExtrema() {
193+
CoverageProcessor processor = new CoverageProcessor();
194+
ParameterValueGroup params = processor.getOperation("Extrema").getParameters();
195+
params.parameter("Source").setValue(coverage);
196+
GridCoverage2D coverage = (GridCoverage2D) processor.doOperation(params);
197+
Map<String, Object> values = new HashMap<>();
198+
values.put("min", coverage.getProperty("minimum"));
199+
values.put("max",coverage.getProperty("maximum"));
200+
return (NativeObject) javaToJS(values, this.getParentScope());
201+
}
202+
203+
@JSFunction
204+
public Object getMinValue(int band) {
205+
double minValue = this.coverage.getSampleDimension(band).getMinimumValue();
206+
if (Double.isInfinite(minValue)) {
207+
minValue = ((double[])this.getExtrema().get("min"))[band];
208+
}
209+
return minValue;
210+
}
211+
212+
@JSFunction
213+
public Object getMaxValue(int band) {
214+
double maxValue = this.coverage.getSampleDimension(band).getMaximumValue();
215+
if (Double.isInfinite(maxValue)) {
216+
maxValue = ((double[])this.getExtrema().get("max"))[band];
217+
}
218+
return maxValue;
219+
}
220+
221+
private int getInt(Object obj) {
222+
if (obj instanceof Number) {
223+
return ((Number)obj).intValue();
224+
} else {
225+
return getInt(Double.parseDouble(obj.toString()));
226+
}
227+
}
228+
169229
@Override
170230
public String toString() {
171231
return this.getName();

src/test/resources/org/geoscript/js/tests/geoscript/raster/test_raster.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,4 +114,32 @@ exports["test: reproject a raster"] = function() {
114114
var reprojectedTif = tif.reproject(new proj.Projection("EPSG:3857"));
115115
assert.strictEqual("EPSG:4326", tif.proj.id, "Original raster should be EPSG:4326");
116116
assert.strictEqual("EPSG:3857", reprojectedTif.proj.id, "Original raster should be EPSG:3857");
117+
};
118+
119+
exports["test: reclassify a raster"] = function() {
120+
var format = new raster.Format({source: admin.raster.source});
121+
var tif = format.read({});
122+
var reclassifiedTif = tif.reclassify([
123+
{min: -1000, max: 0, value: -1},
124+
{min: 0, max: 50, value: 1},
125+
{min: 50, max: 100, value: 2},
126+
{min: 100, max: 2000, value: 3}
127+
], {noData: 0});
128+
assert.strictEqual(-1, reclassifiedTif.getValue(new geom.Point([-175.8, 81.8]), "double")[0], "Value should be -1");
129+
assert.strictEqual(-1, reclassifiedTif.getValue({x: 10, y: 20}, "double")[0], "Value should be -1");
130+
};
131+
132+
exports["test: get min and max values for a raster band"] = function() {
133+
var format = new raster.Format({source: admin.raster.source});
134+
var tif = format.read({});
135+
assert.strictEqual(49, tif.getMinValue(0));
136+
assert.strictEqual(255, tif.getMaxValue(0));
137+
};
138+
139+
exports["test: get extrema for all raster bands"] = function() {
140+
var format = new raster.Format({source: admin.raster.source});
141+
var tif = format.read({});
142+
var extrema = tif.extrema
143+
assert.strictEqual(49, extrema.min[0]);
144+
assert.strictEqual(255, extrema.max[0]);
117145
};

0 commit comments

Comments
 (0)