Skip to content

Commit aedd372

Browse files
Merge pull request #14 from bcdev/se_SMAP_reader
Se smap reader append reader for SMAP L2C product improvement of WindsatReader
2 parents 35c131e + 9435fa8 commit aedd372

36 files changed

+1964
-71
lines changed

cems/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
<parent>
2626
<artifactId>fiduceo-master</artifactId>
2727
<groupId>com.bc.fiduceo</groupId>
28-
<version>1.5.8</version>
28+
<version>1.5.9-SNAPSHOT</version>
2929
</parent>
3030

3131
<modelVersion>4.0.0</modelVersion>

core/pom.xml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<parent>
66
<artifactId>fiduceo-master</artifactId>
77
<groupId>com.bc.fiduceo</groupId>
8-
<version>1.5.8</version>
8+
<version>1.5.9-SNAPSHOT</version>
99
</parent>
1010

1111
<modelVersion>4.0.0</modelVersion>
@@ -118,6 +118,12 @@
118118
<artifactId>jimfs</artifactId>
119119
<scope>test</scope>
120120
</dependency>
121+
<dependency>
122+
<groupId>org.apache.commons</groupId>
123+
<artifactId>commons-text</artifactId>
124+
<version>1.10.0</version>
125+
<scope>test</scope>
126+
</dependency>
121127

122128
</dependencies>
123129

core/src/main/java/com/bc/fiduceo/geometry/Point.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@ public interface Point extends Geometry {
3232

3333
void setLat(double lat);
3434

35-
boolean equals(Point other);
35+
boolean equals(Object other);
3636
}

core/src/main/java/com/bc/fiduceo/geometry/jts/JTSPoint.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,11 @@ public void setLat(double lat) {
8080
}
8181

8282
@Override
83-
public boolean equals(Point other) {
83+
public boolean equals(Object o) {
84+
if (o == null || !(o instanceof JTSPoint)) {
85+
return false;
86+
}
87+
final JTSPoint other = (JTSPoint) o;
8488
return other == this || other.getLon() == getLon() && other.getLat() == getLat();
8589
}
8690
}

core/src/main/java/com/bc/fiduceo/geometry/s2/BcS2Point.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,11 @@ public String toString() {
103103
}
104104

105105
@Override
106-
public boolean equals(Point other) {
106+
public boolean equals(Object o) {
107+
if (o == null || !(o instanceof BcS2Point)) {
108+
return false;
109+
}
110+
final BcS2Point other = (BcS2Point) o;
107111
return other == this || other.getLon() == getLon() && other.getLat() == getLat();
108112
}
109113

core/src/main/java/com/bc/fiduceo/reader/RawDataReader.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import ucar.ma2.*;
2626

2727
import java.awt.*;
28+
import java.awt.geom.Rectangle2D;
2829
import java.io.IOException;
2930

3031
/**
@@ -131,12 +132,18 @@ private static Array readFrom1DArray(int offsetX, int offsetY, int windowWidth,
131132
}
132133
}
133134

134-
private static boolean isWindowInside(int winOffSetX, int winOffSetY, int windowWidth, int windowHeight, int rawWidth, int rawHeight) {
135+
public static boolean isWindowInside(int winOffSetX, int winOffSetY, int windowWidth, int windowHeight, int rawWidth, int rawHeight) {
135136
final Rectangle windowRec = new Rectangle(winOffSetX, winOffSetY, windowWidth, windowHeight);
136137
final Rectangle arrayRectangle = new Rectangle(0, 0, rawWidth, rawHeight);
137138
return arrayRectangle.contains(windowRec);
138139
}
139140

141+
public static Rectangle2D getInsideWindow(int winOffSetX, int winOffSetY, int windowWidth, int windowHeight, int rawWidth, int rawHeight) {
142+
final Rectangle windowRec = new Rectangle(winOffSetX, winOffSetY, windowWidth, windowHeight);
143+
final Rectangle arrayRectangle = new Rectangle(0, 0, rawWidth, rawHeight);
144+
return arrayRectangle.createIntersection(windowRec);
145+
}
146+
140147
// package access for testing only tb 2016-04-18
141148
static InputDimension getInputDimension(int rank, int[] shape) {
142149
if (rank == 1 && shape[0] == 1) {
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
package com.bc.fiduceo.reader.smap;
2+
3+
import com.bc.fiduceo.core.Dimension;
4+
import com.bc.fiduceo.core.Interval;
5+
import com.bc.fiduceo.location.PixelLocator;
6+
import com.bc.fiduceo.math.SphericalDistance;
7+
import com.bc.fiduceo.reader.RawDataReader;
8+
import com.bc.fiduceo.util.NetCDFUtils;
9+
import ucar.ma2.Array;
10+
import ucar.ma2.Index;
11+
import ucar.ma2.InvalidRangeException;
12+
import ucar.nc2.Variable;
13+
14+
import java.awt.geom.Point2D;
15+
import java.io.IOException;
16+
import java.util.ArrayList;
17+
18+
class SmapPixelLocator implements PixelLocator {
19+
20+
private static final String YDIM_GRID = "ydim_grid";
21+
private static final String XDIM_GRID = "xdim_grid";
22+
private static final String LOOK = "look";
23+
private static final int CELL_COUNT_360_DEGREE = 360 * 4;
24+
private static final String CF_FillValue = NetCDFUtils.CF_FILL_VALUE_NAME;
25+
26+
private final Array lons;
27+
private final Array lats;
28+
private final int fullHeight;
29+
private final int fullWidth;
30+
private final float fillValue;
31+
private final int xIdx;
32+
private final int yIdx;
33+
private final double degree360ColIdx;
34+
35+
SmapPixelLocator(Variable cellonVar, Variable cellatVar, int lookVal) throws IOException {
36+
37+
yIdx = cellonVar.findDimensionIndex(YDIM_GRID);
38+
fullHeight = cellonVar.getDimension(yIdx).getLength();
39+
xIdx = cellonVar.findDimensionIndex(XDIM_GRID);
40+
fullWidth = cellonVar.getDimension(xIdx).getLength();
41+
42+
fillValue = cellonVar.findAttribute(CF_FillValue).getNumericValue().floatValue();
43+
44+
final int lookIdx = cellonVar.findDimensionIndex(LOOK);
45+
final int[] shape = cellonVar.getShape();
46+
shape[lookIdx] = 1;
47+
final int[] origin = new int[shape.length];
48+
origin[lookIdx] = lookVal;
49+
50+
try {
51+
lons = cellonVar.read(origin, shape).reduce();
52+
lats = cellatVar.read(origin, shape).reduce();
53+
degree360ColIdx = find360degreeIndex() + 0.5;
54+
} catch (InvalidRangeException e) {
55+
throw new IOException(e);
56+
}
57+
58+
}
59+
60+
@Override
61+
public Point2D getGeoLocation(double x, double y, Point2D g) {
62+
if (x<0 || x>=fullWidth|| y<0||y>=fullHeight) {
63+
return null;
64+
}
65+
final Index index = lons.getIndex();
66+
index.set((int) Math.floor(y), (int) Math.floor(x));
67+
final float lon = lons.getFloat(index);
68+
final float lat = lats.getFloat(index);
69+
if (lon != fillValue && lat != fillValue) {
70+
if (g != null) {
71+
g.setLocation(lon, lat);
72+
return g;
73+
}
74+
return new Point2D.Float(lon, lat);
75+
}
76+
return null;
77+
}
78+
79+
@Override
80+
public Point2D[] getPixelLocation(double lon, double lat) {
81+
if (lat > 90 || lat < -90) {
82+
return new Point2D[0];
83+
}
84+
lon = ensureLonRange360(lon);
85+
double lonIDX = degree360ColIdx - 1 - Math.floor(lon * 4);
86+
while (lonIDX < 0) {
87+
lonIDX += CELL_COUNT_360_DEGREE;
88+
}
89+
final double latIDX = Math.floor((lat + 90) * 4) + 0.5;
90+
91+
final ArrayList<Point2D.Double> validPixels = new ArrayList<>();
92+
addClosestValidPixel(lonIDX, latIDX, lon, lat, validPixels);
93+
94+
final double secondLonIDX = lonIDX + CELL_COUNT_360_DEGREE;
95+
if (secondLonIDX < fullWidth) {
96+
addClosestValidPixel(secondLonIDX, latIDX, lon, lat, validPixels);
97+
}
98+
return validPixels.toArray(new Point2D[0]);
99+
}
100+
101+
private void addClosestValidPixel(double lonIDX, double latIDX, double lon, double lat, ArrayList<Point2D.Double> validPixels) {
102+
try {
103+
final Dimension productSize = new Dimension("size", fullWidth, fullHeight);
104+
final Interval readSize = new Interval(3, 3);
105+
final int centerX = (int) lonIDX;
106+
final int centerY = (int) latIDX;
107+
final float[] lon3x3 = (float[]) RawDataReader.read(centerX, centerY, readSize, fillValue, lons, productSize).copyTo1DJavaArray();
108+
final float[] lat3x3 = (float[]) RawDataReader.read(centerX, centerY, readSize, fillValue, lats, productSize).copyTo1DJavaArray();
109+
double min = Double.MAX_VALUE;
110+
int minIdx = -1;
111+
final SphericalDistance sd = new SphericalDistance(lon, lat);
112+
for (int i = 0; i < lon3x3.length; i++) {
113+
float lon2 = lon3x3[i];
114+
float lat2 = lat3x3[i];
115+
if (lon2 == fillValue || lat2 == fillValue) {
116+
continue;
117+
}
118+
final double dist = sd.distance(lon2, lat2);
119+
if (dist < min) {
120+
min = dist;
121+
minIdx = i;
122+
}
123+
}
124+
if (minIdx > -1) {
125+
final int corrLonIDX = minIdx % 3 - 1;
126+
final int corrLatIDX = minIdx / 3 - 1;
127+
validPixels.add(new Point2D.Double(lonIDX + corrLonIDX, latIDX + corrLatIDX));
128+
}
129+
} catch (IOException e) {
130+
// This should never happen, because the data is already loaded.
131+
throw new RuntimeException(e);
132+
}
133+
}
134+
135+
private static double ensureLonRange360(double lon) {
136+
while (lon < 0) {
137+
lon += 360;
138+
}
139+
while (lon > 360) {
140+
lon -= 360;
141+
}
142+
if (lon == 360.0) {
143+
lon = 0.0;
144+
}
145+
return lon;
146+
}
147+
148+
private int find360degreeIndex() throws InvalidRangeException {
149+
final int[] verticalShape = new int[]{fullHeight, 1};
150+
final int[] origin = new int[2];
151+
SectionInfo mostValuesSection = new SectionInfo(0, 0, -1);
152+
int mostValuesIdx = 0;
153+
for (int x = 0; x < fullWidth; x++) {
154+
origin[xIdx] = x;
155+
final Array sectArr = lons.section(origin, verticalShape);
156+
final SectionInfo si = getSectionInfo((float[]) sectArr.copyTo1DJavaArray());
157+
// if (Double.MAX_VALUE==si.min) {
158+
// System.out.printf("%4d ---,--- ---,--- ---,--- \n", x, si.min, si.max + ((si.max - si.min) / 2), si.max);
159+
// } else {
160+
// System.out.printf("%4d %7.3f %7.3f %7.3f \n", x, si.min, si.min + ((si.max - si.min) / 2), si.max);
161+
// }
162+
if (si.validCount > mostValuesSection.validCount) {
163+
mostValuesSection = si;
164+
mostValuesIdx = x;
165+
}
166+
}
167+
final double min = mostValuesSection.min;
168+
final int quarterDegree0To360CellIndex = (int) Math.floor(min * 4);
169+
final int offsetTo360DegreeCell = CELL_COUNT_360_DEGREE - 1 - quarterDegree0To360CellIndex;
170+
return mostValuesIdx - offsetTo360DegreeCell;
171+
}
172+
173+
private SectionInfo getSectionInfo(float[] slice) {
174+
double max = -Double.MAX_VALUE;
175+
double min = Double.MAX_VALUE;
176+
int count = 0;
177+
for (float val : slice) {
178+
if (val == fillValue) {
179+
continue;
180+
}
181+
count++;
182+
if (val > max) {
183+
max = val;
184+
}
185+
if (val < min) {
186+
min = val;
187+
}
188+
}
189+
return new SectionInfo(min, max, count);
190+
}
191+
192+
static class SectionInfo {
193+
final double min;
194+
final double max;
195+
final int validCount;
196+
197+
private int x;
198+
199+
SectionInfo(double min, double max, int validCount) {
200+
this.min = min;
201+
this.max = max;
202+
this.validCount = validCount;
203+
}
204+
}
205+
}

0 commit comments

Comments
 (0)