Omaha #3959 - Make subgridding grid based.
Change-Id: If1970961641536655fd1a951c0e433dbaca0687c Former-commit-id:e0ff8b49c1
[formerly c3b5f78811d231009dad7533fd650a68634e3e29] Former-commit-id:9df7d7e987
This commit is contained in:
parent
db4044191e
commit
fc68d9b30d
13 changed files with 481 additions and 826 deletions
|
@ -24,6 +24,7 @@
|
|||
# ------------ ---------- ----------- --------------------------
|
||||
# ??? Initial creation
|
||||
# Jul 07, 2014 3344 rferrel Change GRID_FILL_VALUE to new plugin location.
|
||||
# Mar 05, 2015 3959 rjpeter Fix subgrid across seam of world wide grid.
|
||||
#
|
||||
|
||||
import grib2
|
||||
|
@ -135,6 +136,7 @@ logHandler = UFStatusHandler.UFStatusHandler("com.raytheon.edex.plugin.grib", "E
|
|||
# to GRID_FILL_VALUE
|
||||
# Dec 15, 2014 DR16509 Matt Foster Changes in _decodePdsSection to accommodate
|
||||
# EKDMOS
|
||||
# Mar 05, 2015 3959 rjpeter Update sub gridding to handle world wrap.
|
||||
#
|
||||
class GribDecoder():
|
||||
|
||||
|
@ -343,8 +345,18 @@ class GribDecoder():
|
|||
# handle world wide grid wrap
|
||||
if (endX > nx):
|
||||
subGridDataArray = numpy.zeros((subny, subnx), numpy.float32)
|
||||
midx = nx - startx
|
||||
subGridDataArray[0:subny, 0:midx] = numpyDataArray[starty:endY, startx:nx]
|
||||
endX = nx
|
||||
wrapCount = gridCoverage.getWorldWrapCount()
|
||||
|
||||
if wrapCount > 0:
|
||||
# handle grid that comes in with data already wrapped
|
||||
endX = wrapCount
|
||||
|
||||
midx = endX - startx
|
||||
subGridDataArray[0:subny, 0:midx] = numpyDataArray[starty:endY, startx:endX]
|
||||
if (wrapCount > 0):
|
||||
subGridDataArray[0:subny, midx:subnx] = numpyDataArray[starty:endY, 0:subnx - midx]
|
||||
else:
|
||||
subGridDataArray[0:subny, midx:subnx] = GridUtil.GRID_FILL_VALUE
|
||||
numpyDataArray = subGridDataArray
|
||||
else:
|
||||
|
|
|
@ -79,6 +79,7 @@ import com.raytheon.uf.common.time.DataTime;
|
|||
import com.raytheon.uf.common.time.DataTime.FLAG;
|
||||
import com.raytheon.uf.common.time.TimeRange;
|
||||
import com.raytheon.uf.common.util.ArraysUtil;
|
||||
import com.raytheon.uf.common.util.GridUtil;
|
||||
import com.raytheon.uf.common.util.mapping.MultipleMappingException;
|
||||
|
||||
/**
|
||||
|
@ -99,7 +100,7 @@ import com.raytheon.uf.common.util.mapping.MultipleMappingException;
|
|||
* Oct 15, 2013 2473 bsteffen Removed deprecated and unused code.
|
||||
* Jul 30, 2014 3469 bsteffen Improve logging of invalid files.
|
||||
* Sep 09, 2014 3356 njensen Remove CommunicationException
|
||||
*
|
||||
* Mar 05, 2015 3959 rjpeter Added world wrap check to subGrid.
|
||||
* </pre>
|
||||
*
|
||||
* @author bphillip
|
||||
|
@ -456,7 +457,8 @@ public class Grib1Decoder extends AbstractDecoder {
|
|||
float[][] dataArray = this.resizeDataTo2D(data,
|
||||
gridCoverage.getNx(), gridCoverage.getNy());
|
||||
dataArray = this.subGrid(dataArray, subGrid.getUpperLeftX(),
|
||||
subGrid.getUpperLeftY(), subGrid.getNX(), subGrid.getNY());
|
||||
subGrid.getUpperLeftY(), subGrid.getNX(), subGrid.getNY(),
|
||||
gridCoverage);
|
||||
data = this.resizeDataTo1D(dataArray, subGrid.getNY(),
|
||||
subGrid.getNX());
|
||||
retVal.setMessageData(data);
|
||||
|
@ -607,18 +609,28 @@ public class Grib1Decoder extends AbstractDecoder {
|
|||
* The number of columns in the sub-grid
|
||||
* @param rowCount
|
||||
* The number of rows in the sub-grid
|
||||
* @param coverage
|
||||
* The parent coverage
|
||||
* @return The sub-grid of data
|
||||
*/
|
||||
private float[][] subGrid(float[][] data, int startColumn, int startRow,
|
||||
int columnCount, int rowCount) {
|
||||
int columnCount, int rowCount, GridCoverage coverage) {
|
||||
float[][] newGrid = new float[rowCount][columnCount];
|
||||
|
||||
// sub grid might wrap around a world wide grid, double check bounds
|
||||
int endRow = startRow + rowCount;
|
||||
int endColumn = startColumn + columnCount;
|
||||
int wrapCount = -1;
|
||||
if (endColumn > data[0].length) {
|
||||
wrapCount = coverage.getWorldWrapCount();
|
||||
|
||||
if (wrapCount > 0) {
|
||||
/* account for grids that already wrap in the incoming data */
|
||||
endColumn = wrapCount;
|
||||
} else {
|
||||
endColumn = data[0].length;
|
||||
}
|
||||
}
|
||||
// determine remaining col count for world wide grids
|
||||
columnCount -= endColumn - startColumn;
|
||||
|
||||
|
@ -632,9 +644,16 @@ public class Grib1Decoder extends AbstractDecoder {
|
|||
}
|
||||
|
||||
// handle grid wrap for world wide grids
|
||||
if (columnCount > 0 && wrapCount > 0) {
|
||||
for (int column = 0; column < columnCount; column++, newGridColumn++) {
|
||||
newGrid[newGridRow][newGridColumn] = data[row][column];
|
||||
}
|
||||
} else {
|
||||
for (int column = 0; column < columnCount; column++, newGridColumn++) {
|
||||
newGrid[newGridRow][newGridColumn] = GridUtil.GRID_FILL_VALUE;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return newGrid;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
package com.raytheon.edex.plugin.grib.spatial;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
@ -77,7 +78,7 @@ import com.vividsolutions.jts.geom.Coordinate;
|
|||
* AWIPSI
|
||||
* Oct 15, 2013 2473 bsteffen Rewrite deprecated code.
|
||||
* Jul 21, 2014 3373 bclement JAXB managers only live during initializeGrids()
|
||||
*
|
||||
* Mar 04, 2015 3959 rjpeter Update for grid based subgridding.
|
||||
* </pre>
|
||||
*
|
||||
* @author bphillip
|
||||
|
@ -112,12 +113,12 @@ public class GribSpatialCache {
|
|||
/**
|
||||
* Map containing the subGrid coverage based on a subGridKey
|
||||
*/
|
||||
private Map<String, GridCoverage> subGridCoverageMap;
|
||||
private final Map<String, GridCoverage> subGridCoverageMap;
|
||||
|
||||
/**
|
||||
* Map containing the subGrid based on a the subGridKey
|
||||
*/
|
||||
private Map<String, SubGrid> definedSubGridMap;
|
||||
private final Map<String, SubGrid> definedSubGridMap;
|
||||
|
||||
/**
|
||||
* Map containing the subGrid definition based on a model name and the base
|
||||
|
@ -125,12 +126,6 @@ public class GribSpatialCache {
|
|||
*/
|
||||
private Map<String, SubGridDef> subGridDefMap;
|
||||
|
||||
/**
|
||||
* Map of coverage id to the number of columns in world wrap or -1 for no
|
||||
* wrapping.
|
||||
*/
|
||||
private Map<Integer, Integer> worldWrapMap;
|
||||
|
||||
private FileDataList fileDataList;
|
||||
|
||||
private long fileScanTime = 0;
|
||||
|
@ -158,7 +153,6 @@ public class GribSpatialCache {
|
|||
definedSubGridMap = new HashMap<String, SubGrid>();
|
||||
subGridCoverageMap = new HashMap<String, GridCoverage>();
|
||||
subGridDefMap = new HashMap<String, SubGridDef>();
|
||||
worldWrapMap = new HashMap<Integer, Integer>();
|
||||
scanFiles();
|
||||
}
|
||||
|
||||
|
@ -272,7 +266,7 @@ public class GribSpatialCache {
|
|||
|
||||
/**
|
||||
* If a sub grid area is defined for this model than this will process that
|
||||
* defintion and piopulate the subGridCoverageMap and definedSubGridMap.
|
||||
* definition and populate the subGridCoverageMap and definedSubGridMap.
|
||||
*
|
||||
* @param modelName
|
||||
* @param coverage
|
||||
|
@ -280,6 +274,8 @@ public class GribSpatialCache {
|
|||
*/
|
||||
private boolean loadSubGrid(String modelName, GridCoverage coverage) {
|
||||
SubGridDef subGridDef = subGridDefMap.get(modelName);
|
||||
try {
|
||||
|
||||
if (subGridDef != null) {
|
||||
String referenceGrid = subGridDef.getReferenceGrid();
|
||||
if (referenceGrid == null) {
|
||||
|
@ -307,116 +303,137 @@ public class GribSpatialCache {
|
|||
subGridDef.getCenterLongitude(),
|
||||
subGridDef.getCenterLatitude());
|
||||
|
||||
Coordinate subGridCenterGridCoord = MapUtil.latLonToGridCoordinate(
|
||||
subGridCenterLatLon, PixelOrientation.CENTER,
|
||||
referenceCoverage);
|
||||
Coordinate subGridCenterGridCoord = MapUtil
|
||||
.latLonToGridCoordinate(subGridCenterLatLon,
|
||||
PixelOrientation.CENTER, referenceCoverage);
|
||||
|
||||
double shiftX = 0;
|
||||
int nx = subGridDef.getNx();
|
||||
int ny = subGridDef.getNy();
|
||||
|
||||
// Check whether 'shiftWest' flag is set in subgrid definition xml file
|
||||
/*
|
||||
* Check whether 'shiftWest' flag is set in subgrid definition
|
||||
* xml file
|
||||
*/
|
||||
boolean shiftThisSubGridWest = this.shiftSubGridWest;
|
||||
if (subGridDef.getShiftWest() != null) {
|
||||
shiftThisSubGridWest = subGridDef.getShiftWest();
|
||||
}
|
||||
|
||||
if (shiftThisSubGridWest == true) {
|
||||
shiftX = subGridDef.getNx() / 5;
|
||||
shiftX = nx / 5;
|
||||
}
|
||||
|
||||
double xCenterPoint = subGridCenterGridCoord.x - shiftX;
|
||||
double yCenterPoint = subGridCenterGridCoord.y;
|
||||
|
||||
double xDistance = subGridDef.getNx() / 2;
|
||||
double yDistance = subGridDef.getNy() / 2;
|
||||
Coordinate lowerLeftPosition = new Coordinate(xCenterPoint
|
||||
- xDistance, yCenterPoint + yDistance);
|
||||
Coordinate upperRightPosition = new Coordinate(xCenterPoint
|
||||
+ xDistance, yCenterPoint - yDistance);
|
||||
double xDistance = nx / 2;
|
||||
double yDistance = ny / 2;
|
||||
int leftX = (int) (xCenterPoint - xDistance);
|
||||
int upperY = (int) (yCenterPoint - yDistance);
|
||||
|
||||
// If the western edge of the subgrid is placed west of the full grid boundary
|
||||
// (possibly when westward shifting above was done) it will be shifted back
|
||||
// to within the boundary, but the eastern edge should be shifted back also, by
|
||||
// a proportional amount
|
||||
if (lowerLeftPosition.x < 0) upperRightPosition.x -= lowerLeftPosition.x;
|
||||
/*
|
||||
* trim will handle all validation of the subgrid as well as any
|
||||
* shifting to get within boundary, this includes world wrap
|
||||
* checking.
|
||||
*/
|
||||
SubGrid subGrid = new SubGrid(leftX, upperY, nx, ny);
|
||||
GridCoverage subGridCoverage = referenceCoverage.trim(subGrid);
|
||||
|
||||
lowerLeftPosition = MapUtil.gridCoordinateToLatLon(
|
||||
lowerLeftPosition, PixelOrientation.CENTER,
|
||||
referenceCoverage);
|
||||
upperRightPosition = MapUtil.gridCoordinateToLatLon(
|
||||
upperRightPosition, PixelOrientation.CENTER,
|
||||
referenceCoverage);
|
||||
|
||||
return trim(modelName, coverage, lowerLeftPosition, upperRightPosition);
|
||||
} else {
|
||||
Integer wrapCount = worldWrapMap.get(coverage.getId());
|
||||
if (wrapCount == null) {
|
||||
wrapCount = GridGeometryWrapChecker.checkForWrapping(coverage
|
||||
.getGridGeometry());
|
||||
worldWrapMap.put(coverage.getId(), wrapCount);
|
||||
if (!referenceCoverage.equals(coverage)) {
|
||||
/*
|
||||
* need to take reference subGrid and convert to subGrid in
|
||||
* original coverage
|
||||
*/
|
||||
subGridCoverage.initialize();
|
||||
Coordinate[] origCoords = subGridCoverage.getGeometry()
|
||||
.getCoordinates();
|
||||
if (origCoords.length != 5) {
|
||||
throw new GridCoverageException(
|
||||
"Coverage geometry is not a quadrilateral, cannot create referenced subgrid");
|
||||
}
|
||||
if(wrapCount > 0 && wrapCount < coverage.getNx()){
|
||||
// make sure that there is data going around the world only
|
||||
// once, if the data starts another iteration around the world,
|
||||
// subgrid it to cut off the extra data. This mostly hits to
|
||||
// remove one redundant column.
|
||||
Coordinate upperRightPosition = new Coordinate(wrapCount - 1, 0);
|
||||
upperRightPosition = MapUtil.gridCoordinateToLatLon(upperRightPosition,
|
||||
Coordinate[] corners = new Coordinate[4];
|
||||
System.arraycopy(origCoords, 0, corners, 0, 4);
|
||||
MapUtil.latLonToGridCoordinate(corners,
|
||||
PixelOrientation.CENTER, coverage);
|
||||
try {
|
||||
Coordinate lowerLeftPosition = new Coordinate(
|
||||
coverage.getLowerLeftLon(),
|
||||
coverage.getLowerLeftLat());
|
||||
return trim(modelName, coverage, lowerLeftPosition,
|
||||
upperRightPosition);
|
||||
} catch (GridCoverageException e) {
|
||||
statusHandler.error(
|
||||
"Failed to generate sub grid for world wide grid: "
|
||||
|
||||
/*
|
||||
* Don't depend on given corners to be in a specific
|
||||
* position. Can safely assume the lower 2 values are on the
|
||||
* same side.
|
||||
*/
|
||||
double[] xCoords = new double[4];
|
||||
xCoords[0] = corners[0].x;
|
||||
xCoords[1] = corners[1].x;
|
||||
xCoords[2] = corners[2].x;
|
||||
xCoords[3] = corners[3].x;
|
||||
double[] yCoords = new double[4];
|
||||
yCoords[0] = corners[0].y;
|
||||
yCoords[1] = corners[1].y;
|
||||
yCoords[2] = corners[2].y;
|
||||
yCoords[3] = corners[3].y;
|
||||
Arrays.sort(xCoords);
|
||||
Arrays.sort(yCoords);
|
||||
|
||||
/* Guarantee the subGrid is within the reference impl */
|
||||
leftX = (int) Math.ceil(xCoords[1]);
|
||||
upperY = (int) Math.ceil(yCoords[1]);
|
||||
int rightX = (int) Math.floor(xCoords[2]);
|
||||
int lowerY = (int) Math.floor(yCoords[2]);
|
||||
/* Add 1 for inclusive */
|
||||
nx = rightX - leftX + 1;
|
||||
ny = lowerY - upperY + 1;
|
||||
subGrid = new SubGrid(leftX, upperY, nx, ny);
|
||||
subGridCoverage = coverage.trim(subGrid);
|
||||
}
|
||||
|
||||
insertSubGrib(modelName, coverage, subGridCoverage, subGrid);
|
||||
} else {
|
||||
int wrapCount = GridGeometryWrapChecker
|
||||
.checkForWrapping(coverage.getGridGeometry());
|
||||
|
||||
if ((wrapCount > 0) && (wrapCount < coverage.getNx())) {
|
||||
/*
|
||||
* make sure that there is data going around the world only
|
||||
* once, if the data starts another iteration around the
|
||||
* world, subgrid it to cut off the extra data. This mostly
|
||||
* hits to remove one redundant column.
|
||||
*/
|
||||
SubGrid subGrid = new SubGrid(0, 0, wrapCount,
|
||||
coverage.getNy());
|
||||
GridCoverage subGridCoverage = coverage.trim(subGrid);
|
||||
insertSubGrib(modelName, coverage, subGridCoverage, subGrid);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
statusHandler.error("Failed to generate sub grid for model "
|
||||
+ modelName, e);
|
||||
return false;
|
||||
}
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Final step of subgrid generation, based off the two Coordinates generate
|
||||
* a subgrid coverage, insert it into the db and add it to caches.
|
||||
* Inserts the subGridCoverage into the database and adds it to the caches.
|
||||
*
|
||||
* @param modelName
|
||||
* @param coverage
|
||||
* @param lowerLeft
|
||||
* @param upperRight
|
||||
* @return true on success, false if something went wrong, so no subgrid is
|
||||
* available. This method will log errors and return false
|
||||
* @param subGridCoverage
|
||||
* @param subGrid
|
||||
* @throws GridCoverageException
|
||||
*/
|
||||
private boolean trim(String modelName, GridCoverage coverage,
|
||||
Coordinate lowerLeft, Coordinate upperRight) {
|
||||
SubGrid subGrid = new SubGrid();
|
||||
subGrid.setLowerLeftLon(lowerLeft.x);
|
||||
subGrid.setLowerLeftLat(lowerLeft.y);
|
||||
subGrid.setUpperRightLon(upperRight.x);
|
||||
subGrid.setUpperRightLat(upperRight.y);
|
||||
|
||||
// verify numbers in -180 -> 180 range
|
||||
subGrid.setLowerLeftLon(MapUtil.correctLon(subGrid.getLowerLeftLon()));
|
||||
subGrid.setUpperRightLon(MapUtil.correctLon(subGrid.getUpperRightLon()));
|
||||
|
||||
GridCoverage subGridCoverage = coverage.trim(subGrid);
|
||||
|
||||
private void insertSubGrib(String modelName, GridCoverage coverage,
|
||||
GridCoverage subGridCoverage, SubGrid subGrid)
|
||||
throws GridCoverageException {
|
||||
if (subGridCoverage != null) {
|
||||
try {
|
||||
subGridCoverage = insert(subGridCoverage);
|
||||
} catch (Exception e) {
|
||||
statusHandler.error(e.getLocalizedMessage(), e);
|
||||
return false;
|
||||
}
|
||||
subGridCoverageMap.put(subGridKey(modelName, coverage),
|
||||
subGridCoverage);
|
||||
definedSubGridMap.put(subGridKey(modelName, coverage), subGrid);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -512,12 +529,11 @@ public class GribSpatialCache {
|
|||
ct = ClusterLockUtils.lock("grib", "spatialCache", 120000, true);
|
||||
} while (!LockState.SUCCESSFUL.equals(ct.getLockState()));
|
||||
|
||||
|
||||
try {
|
||||
for (FileData fd : fdl.getCoverageFileList()) {
|
||||
try {
|
||||
GridCoverage grid = gridCovJaxb
|
||||
.unmarshalFromXmlFile(fd.getFilePath());
|
||||
GridCoverage grid = gridCovJaxb.unmarshalFromXmlFile(fd
|
||||
.getFilePath());
|
||||
String name = grid.getName();
|
||||
grid = insert(grid);
|
||||
spatialNameMap.put(name, grid);
|
||||
|
@ -529,8 +545,7 @@ public class GribSpatialCache {
|
|||
names.add(name);
|
||||
} catch (Exception e) {
|
||||
// Log error but do not throw exception
|
||||
statusHandler.error(
|
||||
"Unable to read default grids file: "
|
||||
statusHandler.error("Unable to read default grids file: "
|
||||
+ fd.getFilePath(), e);
|
||||
}
|
||||
}
|
||||
|
@ -540,8 +555,7 @@ public class GribSpatialCache {
|
|||
defaultCenterPoint = getDefaultSubGridCenterPoint();
|
||||
} catch (Exception e) {
|
||||
statusHandler
|
||||
.error(
|
||||
"Failed to generate sub grid definitions. Unable to lookup WFO Center Point",
|
||||
.error("Failed to generate sub grid definitions. Unable to lookup WFO Center Point",
|
||||
e);
|
||||
}
|
||||
for (FileData fd : fdl.getSubGridFileList()) {
|
||||
|
@ -556,8 +570,7 @@ public class GribSpatialCache {
|
|||
}
|
||||
} catch (Exception e) {
|
||||
// Log error but do not throw exception
|
||||
statusHandler.error(
|
||||
"Unable to read default grids file: "
|
||||
statusHandler.error("Unable to read default grids file: "
|
||||
+ fd.getFilePath(), e);
|
||||
}
|
||||
}
|
||||
|
@ -572,8 +585,7 @@ public class GribSpatialCache {
|
|||
}
|
||||
long endTime = System.currentTimeMillis();
|
||||
statusHandler.info("Grib grid coverages initialized: "
|
||||
+ (endTime - startTime)
|
||||
+ "ms");
|
||||
+ (endTime - startTime) + "ms");
|
||||
}
|
||||
|
||||
private GridCoverage insert(GridCoverage coverage)
|
||||
|
@ -626,15 +638,14 @@ public class GribSpatialCache {
|
|||
defaultSubGridLocation.getCenterLatitude());
|
||||
statusHandler
|
||||
.info("Default sub grid location is overriden as ["
|
||||
+ defaultCenterPoint.y + "/" + defaultCenterPoint.x
|
||||
+ "]");
|
||||
+ defaultCenterPoint.y + "/"
|
||||
+ defaultCenterPoint.x + "]");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
statusHandler.error(
|
||||
"Unable to load default sub grid location from file: "
|
||||
+ defaultSubGridLocationFile.getFile()
|
||||
.getAbsolutePath(),
|
||||
e);
|
||||
.getAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -646,19 +657,21 @@ public class GribSpatialCache {
|
|||
.handleRequest(centerPointRequest);
|
||||
statusHandler
|
||||
.info("Default sub grid location is wfo center point ["
|
||||
+ defaultCenterPoint.y + "/" + defaultCenterPoint.x + "]");
|
||||
/* If we are getting the WFO center as the center point, it means that
|
||||
// the site has not defined its own center in the site file
|
||||
// defaultSubGridCenterPoint.xml (see previous If block).
|
||||
// Therefore, we will be shifting the domain westward to be similar to
|
||||
// AWIPSI default behavior, so set a flag here.
|
||||
// If the site *has* defined a center in defaultSubGridCenterPoint.xml,
|
||||
// we will use that as the true, intended center and will not shift the
|
||||
// domain further.
|
||||
+ defaultCenterPoint.y + "/" + defaultCenterPoint.x
|
||||
+ "]");
|
||||
/*
|
||||
* If we are getting the WFO center as the center point, it means
|
||||
* that the site has not defined its own center in the site file
|
||||
* defaultSubGridCenterPoint.xml (see previous If block). Therefore,
|
||||
* we will be shifting the domain westward to be similar to AWIPSI
|
||||
* default behavior, so set a flag here. If the site *has* defined a
|
||||
* center in defaultSubGridCenterPoint.xml, we will use that as the
|
||||
* true, intended center and will not shift the domain further.
|
||||
*/
|
||||
shiftSubGridWest = true;
|
||||
} else {
|
||||
shiftSubGridWest = false;
|
||||
}
|
||||
else shiftSubGridWest = false;
|
||||
|
||||
return defaultCenterPoint;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ import javax.xml.bind.annotation.XmlRootElement;
|
|||
import com.raytheon.uf.common.geospatial.MapUtil;
|
||||
|
||||
/**
|
||||
* A sub grid definition
|
||||
* A sub grid definition.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
|
@ -39,7 +39,7 @@ import com.raytheon.uf.common.geospatial.MapUtil;
|
|||
* ------------- -------- ----------- --------------------------
|
||||
* Jun 25, 2010 rjpeter Initial creation
|
||||
* Oct 15, 2013 2473 bsteffen Remove deprecated ISerializableObject.
|
||||
*
|
||||
* Mar 04, 2015 3959 rjpeter Make nx/ny int.
|
||||
* </pre>
|
||||
*
|
||||
* @author rjpeter
|
||||
|
@ -60,10 +60,10 @@ public class SubGridDef {
|
|||
private String referenceGrid;
|
||||
|
||||
@XmlElement(required = true)
|
||||
private double nx;
|
||||
private int nx;
|
||||
|
||||
@XmlElement(required = true)
|
||||
private double ny;
|
||||
private int ny;
|
||||
|
||||
@XmlElement
|
||||
private Boolean shiftWest;
|
||||
|
@ -82,19 +82,19 @@ public class SubGridDef {
|
|||
this.modelNames = modelNames;
|
||||
}
|
||||
|
||||
public double getNx() {
|
||||
public int getNx() {
|
||||
return nx;
|
||||
}
|
||||
|
||||
public void setNx(double nx) {
|
||||
public void setNx(int nx) {
|
||||
this.nx = nx;
|
||||
}
|
||||
|
||||
public double getNy() {
|
||||
public int getNy() {
|
||||
return ny;
|
||||
}
|
||||
|
||||
public void setNy(double ny) {
|
||||
public void setNy(int ny) {
|
||||
this.ny = ny;
|
||||
}
|
||||
|
||||
|
@ -105,6 +105,7 @@ public class SubGridDef {
|
|||
public void setShiftWest(Boolean shiftWest) {
|
||||
this.shiftWest = shiftWest;
|
||||
}
|
||||
|
||||
/**
|
||||
* a model may have more than one grid so use reference grid instead.
|
||||
*
|
||||
|
|
|
@ -26,9 +26,6 @@ import javax.measure.converter.ConversionException;
|
|||
import javax.measure.converter.UnitConverter;
|
||||
import javax.measure.unit.Unit;
|
||||
|
||||
import org.geotools.coverage.grid.GridGeometry2D;
|
||||
import org.opengis.metadata.spatial.PixelOrientation;
|
||||
|
||||
import com.raytheon.uf.common.dataplugin.annotations.DataURI;
|
||||
import com.raytheon.uf.common.dataplugin.grid.GridPathProvider;
|
||||
import com.raytheon.uf.common.dataplugin.grid.GridRecord;
|
||||
|
@ -39,7 +36,6 @@ import com.raytheon.uf.common.datastorage.Request;
|
|||
import com.raytheon.uf.common.datastorage.StorageException;
|
||||
import com.raytheon.uf.common.datastorage.records.FloatDataRecord;
|
||||
import com.raytheon.uf.common.datastorage.records.IDataRecord;
|
||||
import com.raytheon.uf.common.geospatial.MapUtil;
|
||||
import com.raytheon.uf.common.geospatial.util.GridGeometryWrapChecker;
|
||||
import com.raytheon.uf.common.gridcoverage.GridCoverage;
|
||||
import com.raytheon.uf.common.gridcoverage.LambertConformalGridCoverage;
|
||||
|
@ -50,7 +46,6 @@ import com.raytheon.uf.common.gridcoverage.exception.GridCoverageException;
|
|||
import com.raytheon.uf.common.gridcoverage.subgrid.SubGrid;
|
||||
import com.raytheon.uf.common.localization.IPathManager;
|
||||
import com.raytheon.uf.common.parameter.lookup.ParameterLookup;
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
|
||||
/**
|
||||
* Convenience class for requesting grid data. This class provides automatic
|
||||
|
@ -66,7 +61,7 @@ import com.vividsolutions.jts.geom.Coordinate;
|
|||
* Jan 14, 2013 1469 bkowal No longer needs to retrieve the location
|
||||
* of the hdf5 data directory.
|
||||
* Dec 16, 2013 2574 bsteffen Fixed bugs in setRequestArea.
|
||||
*
|
||||
* Mar 04, 2015 3959 rjpeter Update for grid based subgridding.
|
||||
* </pre>
|
||||
*
|
||||
* @author bsteffen
|
||||
|
@ -128,20 +123,22 @@ public class GridDataRetriever {
|
|||
public boolean setWorldWrapColumns(int worldWrapColumns)
|
||||
throws GridCoverageException {
|
||||
GridCoverage dataLoc = record.getLocation();
|
||||
GridGeometry2D dataGeom = dataLoc.getGridGeometry();
|
||||
int wrapX = GridGeometryWrapChecker.checkForWrapping(dataGeom);
|
||||
if (wrapX != -1) {
|
||||
int wrapX = GridGeometryWrapChecker.checkForWrapping(dataLoc
|
||||
.getGridGeometry());
|
||||
|
||||
if (wrapX != GridGeometryWrapChecker.NO_WRAP) {
|
||||
int newX = wrapX + worldWrapColumns;
|
||||
|
||||
if (newX == dataLoc.getNx()) {
|
||||
this.request = Request.ALL;
|
||||
} else if (newX < dataLoc.getNx()) {
|
||||
Coordinate upperRight = new Coordinate(newX - 1, 0);
|
||||
upperRight = MapUtil.gridCoordinateToLatLon(upperRight,
|
||||
PixelOrientation.CENTER, dataLoc);
|
||||
setRequestArea(dataLoc.getLowerLeftLon(),
|
||||
dataLoc.getLowerLeftLat(), upperRight.x, upperRight.y);
|
||||
} else {
|
||||
this.request = Request.ALL;
|
||||
/*
|
||||
* Let subgridding handle getting the full grid in case grid
|
||||
* stored stored with world wrap columns.
|
||||
*/
|
||||
setRequestArea(wrapX, dataLoc.getNy());
|
||||
this.worldWrapColumns = worldWrapColumns;
|
||||
|
||||
if (dataLoc instanceof LatLonGridCoverage) {
|
||||
LatLonGridCoverage newLoc = new LatLonGridCoverage(
|
||||
(LatLonGridCoverage) dataLoc);
|
||||
|
@ -170,8 +167,8 @@ public class GridDataRetriever {
|
|||
requestCoverage.setNx(newX);
|
||||
requestCoverage.setGridGeometry(null);
|
||||
requestCoverage.initialize();
|
||||
this.worldWrapColumns = newX - dataLoc.getNx();
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -180,29 +177,22 @@ public class GridDataRetriever {
|
|||
|
||||
/**
|
||||
* Set the requested area to be a subgrid of the total area. This uses the
|
||||
* trim functionality of GridCoverage to generate an area which has corners
|
||||
* at the provided latitude and longitude.
|
||||
* trim functionality of GridCoverage to generate an area based on the
|
||||
* passed nx/ny.
|
||||
*
|
||||
* @param lon1
|
||||
* @param lat1
|
||||
* @param lon2
|
||||
* @param lat2
|
||||
* @throws GridDataRetrievalException
|
||||
* @throws GridCoverageException
|
||||
* @param nx
|
||||
* @param ny
|
||||
*/
|
||||
protected void setRequestArea(double lon1, double lat1, double lon2,
|
||||
double lat2) throws GridCoverageException {
|
||||
protected void setRequestArea(int nx, int ny) {
|
||||
SubGrid subGrid = new SubGrid();
|
||||
subGrid.setLowerLeftLat(Math.min(lat1, lat2));
|
||||
subGrid.setLowerLeftLon(Math.min(lon1, lon1));
|
||||
subGrid.setUpperRightLat(Math.max(lat1, lat2));
|
||||
subGrid.setUpperRightLon(Math.max(lon2, lon2));
|
||||
requestCoverage = record.getLocation().trim(subGrid);
|
||||
// leave UL point as 0,0
|
||||
subGrid.setNX(nx);
|
||||
subGrid.setNY(ny);
|
||||
record.getLocation().trim(subGrid);
|
||||
int[] minIndex = { subGrid.getUpperLeftX(), subGrid.getUpperLeftY() };
|
||||
int[] maxIndex = { subGrid.getUpperLeftX() + subGrid.getNX(),
|
||||
subGrid.getUpperLeftY() + subGrid.getNY() };
|
||||
request = Request.buildSlab(minIndex, maxIndex);
|
||||
requestCoverage.initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -44,6 +44,7 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
|||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
import org.geotools.coverage.grid.GridGeometry2D;
|
||||
import org.hibernate.annotations.Type;
|
||||
import org.opengis.metadata.spatial.PixelOrientation;
|
||||
import org.opengis.referencing.FactoryException;
|
||||
import org.opengis.referencing.crs.CoordinateReferenceSystem;
|
||||
import org.opengis.referencing.operation.MathTransform;
|
||||
|
@ -55,10 +56,12 @@ import com.raytheon.uf.common.geospatial.IGridGeometryProvider;
|
|||
import com.raytheon.uf.common.geospatial.ISpatialObject;
|
||||
import com.raytheon.uf.common.geospatial.MapUtil;
|
||||
import com.raytheon.uf.common.geospatial.adapter.GeometryAdapter;
|
||||
import com.raytheon.uf.common.geospatial.util.GridGeometryWrapChecker;
|
||||
import com.raytheon.uf.common.gridcoverage.exception.GridCoverageException;
|
||||
import com.raytheon.uf.common.gridcoverage.subgrid.SubGrid;
|
||||
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
|
||||
import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
import com.vividsolutions.jts.geom.Geometry;
|
||||
|
||||
/**
|
||||
|
@ -79,8 +82,8 @@ import com.vividsolutions.jts.geom.Geometry;
|
|||
* Oct 15, 2013 2473 bsteffen add @XmlSeeAlso for self contained JAXB
|
||||
* context.
|
||||
* Apr 11, 2014 2947 bsteffen Implement IGridGeometryProvider.
|
||||
* 10/16/2014 3454 bphillip Upgrading to Hibernate 4
|
||||
*
|
||||
* Oct 16, 2014 3454 bphillip Upgrading to Hibernate 4
|
||||
* Mar 04, 2015 3959 rjpeter Update for grid based subgridding.
|
||||
* </pre>
|
||||
*
|
||||
* @author bphillip
|
||||
|
@ -275,13 +278,156 @@ public abstract class GridCoverage extends PersistableDataObject<Integer>
|
|||
public abstract String getProjectionType();
|
||||
|
||||
/**
|
||||
* Trim this GridCoverage to a sub grid.
|
||||
* Trim this GridCoverage to a sub grid. Nx/Ny are given priority when the
|
||||
* subGrid is outside the bounds of the originating grid, causing the
|
||||
* subGrid to shift instead of being the intersection.
|
||||
*
|
||||
* @param subGridDef
|
||||
* @param subGrid
|
||||
* @return trimmed coverage
|
||||
*/
|
||||
public abstract GridCoverage trim(SubGrid subGrid);
|
||||
public GridCoverage trim(SubGrid subGrid) {
|
||||
/*
|
||||
* validate the subgrid bounds, adjusting as necessary to fit in bounds.
|
||||
* Also validate world wrap settings.
|
||||
*/
|
||||
int sgUlx = subGrid.getUpperLeftX();
|
||||
int sgUly = subGrid.getUpperLeftY();
|
||||
int sgNx = subGrid.getNX();
|
||||
int sgNy = subGrid.getNY();
|
||||
|
||||
/* validate sgUlx and sgNx */
|
||||
int worldWrapCount = getWorldWrapCount();
|
||||
|
||||
if (worldWrapCount != GridGeometryWrapChecker.NO_WRAP) {
|
||||
/* Check eastern boundary */
|
||||
if (sgUlx < 0) {
|
||||
/*
|
||||
* All subGrid code wraps on the western boundary, offset sgUlx
|
||||
* into valid range
|
||||
*/
|
||||
sgUlx += worldWrapCount;
|
||||
}
|
||||
|
||||
/*
|
||||
* subgrid allowed to extend beyond boundary, ensure subgrid is no
|
||||
* bigger than the wrap count, this allows moving of the seam if
|
||||
* desired
|
||||
*/
|
||||
if (sgNx > worldWrapCount) {
|
||||
sgNx = worldWrapCount;
|
||||
}
|
||||
} else {
|
||||
/* Check eastern boundary */
|
||||
if (sgUlx < 0) {
|
||||
sgUlx += worldWrapCount;
|
||||
}
|
||||
|
||||
if (sgUlx + sgNx > nx) {
|
||||
/*
|
||||
* subgrid extending beyond eastern boundary of grid, back up
|
||||
* sgUlx by the difference
|
||||
*/
|
||||
sgUlx = nx - sgNx;
|
||||
|
||||
if (sgUlx < 0) {
|
||||
/*
|
||||
* moved start beyond western boundary, reduce sgNx to
|
||||
* compensate
|
||||
*/
|
||||
sgNx += sgUlx;
|
||||
sgUlx = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* validate sgUly and sgNy */
|
||||
if (sgUly + sgNy > ny) {
|
||||
/*
|
||||
* subgrid extending beyond southern boundary of grid, back up sgUly
|
||||
* by the difference
|
||||
*/
|
||||
sgUly = ny - sgNy;
|
||||
|
||||
if (sgUly < 0) {
|
||||
/*
|
||||
* moved subgrid beyond northern boundary, reduce sgNy to
|
||||
* compensate
|
||||
*/
|
||||
sgNy += sgUly;
|
||||
sgUly = 0;
|
||||
}
|
||||
} else if (sgUly < 0) {
|
||||
/* Move northern boundary */
|
||||
sgUly = 0;
|
||||
}
|
||||
|
||||
subGrid.setUpperLeftX(sgUlx);
|
||||
subGrid.setUpperLeftY(sgUly);
|
||||
subGrid.setNX(sgNx);
|
||||
subGrid.setNY(sgNy);
|
||||
|
||||
GridCoverage rval = cloneCrsParameters(subGrid);
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for returning if this grid world wraps. Note: Coverage
|
||||
* must be initialized before calling this.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getWorldWrapCount() {
|
||||
if (geometry == null) {
|
||||
try {
|
||||
this.initialize();
|
||||
} catch (GridCoverageException e) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot look up world wrap count. GridCoverage not initialized.",
|
||||
e);
|
||||
}
|
||||
|
||||
}
|
||||
return GridGeometryWrapChecker.checkForWrapping(getGridGeometry());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a clone of this coverage setting any crs parameters based on the
|
||||
* defined subgrid.
|
||||
*
|
||||
* @param subGrid
|
||||
* @return
|
||||
*/
|
||||
private GridCoverage cloneCrsParameters(SubGrid subGrid) {
|
||||
GridCoverage rval = cloneImplCrsParameters(subGrid);
|
||||
/* Set the base GridCoverage values */
|
||||
rval.setName(SUBGRID_TOKEN + this.getId());
|
||||
rval.description = "SubGrid of " + this.description;
|
||||
rval.dx = this.dx;
|
||||
rval.dy = this.dy;
|
||||
rval.spacingUnit = this.spacingUnit;
|
||||
|
||||
/* grid space is 0,0 for upper left */
|
||||
Coordinate lowerLeft = new Coordinate(subGrid.getUpperLeftX(),
|
||||
subGrid.getUpperLeftY() + subGrid.getNY() - 1);
|
||||
lowerLeft = MapUtil.gridCoordinateToLatLon(lowerLeft,
|
||||
PixelOrientation.CENTER, this);
|
||||
|
||||
rval.firstGridPointCorner = Corner.LowerLeft;
|
||||
rval.lo1 = lowerLeft.x;
|
||||
rval.la1 = lowerLeft.y;
|
||||
rval.nx = subGrid.getNX();
|
||||
rval.ny = subGrid.getNY();
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a clone of this coverage setting any implementation specific crs
|
||||
* parameters.
|
||||
*
|
||||
* @param subGrid
|
||||
* @return
|
||||
*/
|
||||
protected abstract GridCoverage cloneImplCrsParameters(SubGrid subGrid);
|
||||
|
||||
@Override
|
||||
public Geometry getGeometry() {
|
||||
|
|
|
@ -20,9 +20,6 @@
|
|||
|
||||
package com.raytheon.uf.common.gridcoverage;
|
||||
|
||||
import javax.measure.converter.UnitConverter;
|
||||
import javax.measure.unit.SI;
|
||||
import javax.measure.unit.Unit;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
|
@ -31,18 +28,13 @@ import javax.xml.bind.annotation.XmlElement;
|
|||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
import org.opengis.referencing.operation.MathTransform;
|
||||
|
||||
import com.raytheon.uf.common.dataplugin.annotations.DataURI;
|
||||
import com.raytheon.uf.common.geospatial.MapUtil;
|
||||
import com.raytheon.uf.common.gridcoverage.exception.GridCoverageException;
|
||||
import com.raytheon.uf.common.gridcoverage.subgrid.SubGrid;
|
||||
import com.raytheon.uf.common.gridcoverage.subgrid.TrimUtil;
|
||||
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
|
||||
import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
|
||||
import com.raytheon.uf.common.status.IUFStatusHandler;
|
||||
import com.raytheon.uf.common.status.UFStatus;
|
||||
import com.raytheon.uf.common.status.UFStatus.Priority;
|
||||
|
||||
/**
|
||||
* Defines a Lambert Conformal grid coverage. This class is generally used to
|
||||
|
@ -58,7 +50,7 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
|
|||
* Sep 10, 2012 15270 D. Friedman Fix subgrid model name handling.
|
||||
* Jan 17, 2014 2125 rjpeter Removed invalid @Table annotation.
|
||||
* Jun 05, 2014 3243 bsteffen Remove deprecated lambert conformal call.
|
||||
*
|
||||
* Mar 04, 2015 3959 rjpeter Update for grid based subgridding.
|
||||
* </pre>
|
||||
*
|
||||
* @author bphillip
|
||||
|
@ -69,9 +61,6 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
|
|||
@XmlAccessorType(XmlAccessType.NONE)
|
||||
@DynamicSerialize
|
||||
public class LambertConformalGridCoverage extends GridCoverage {
|
||||
private static final transient IUFStatusHandler statusHandler = UFStatus
|
||||
.getHandler(LambertConformalGridCoverage.class);
|
||||
|
||||
private static final long serialVersionUID = 5113332463602932317L;
|
||||
|
||||
/** The name of the projectio */
|
||||
|
@ -129,59 +118,13 @@ public class LambertConformalGridCoverage extends GridCoverage {
|
|||
}
|
||||
|
||||
@Override
|
||||
public GridCoverage trim(SubGrid subGrid) {
|
||||
protected GridCoverage cloneImplCrsParameters(SubGrid subGrid) {
|
||||
LambertConformalGridCoverage rval = new LambertConformalGridCoverage();
|
||||
rval.description = this.description;
|
||||
rval.dx = this.dx;
|
||||
rval.dy = this.dy;
|
||||
rval.spacingUnit = this.spacingUnit;
|
||||
rval.latin1 = this.latin1;
|
||||
rval.latin2 = this.latin2;
|
||||
rval.lov = this.lov;
|
||||
rval.majorAxis = this.majorAxis;
|
||||
rval.minorAxis = this.minorAxis;
|
||||
|
||||
try {
|
||||
Unit<?> spacingUnitObj = Unit.valueOf(spacingUnit);
|
||||
if (spacingUnitObj.isCompatible(SI.METRE)) {
|
||||
UnitConverter converter = spacingUnitObj
|
||||
.getConverterTo(SI.METRE);
|
||||
double dxMeter = converter.convert(dx);
|
||||
double dyMeter = converter.convert(dy);
|
||||
MathTransform fromLatLon = MapUtil
|
||||
.getTransformFromLatLon(getCrs());
|
||||
MathTransform toLatLon = fromLatLon.inverse();
|
||||
|
||||
try {
|
||||
TrimUtil.trimMeterSpace(getLowerLeftLat(),
|
||||
getLowerLeftLon(), subGrid, this.nx, this.ny,
|
||||
dxMeter, dyMeter, fromLatLon, toLatLon, true);
|
||||
} catch (GridCoverageException e) {
|
||||
statusHandler.handle(Priority.WARN, "Grid coverage ["
|
||||
+ this.getName() + "] not applicable to this site");
|
||||
return null;
|
||||
}
|
||||
|
||||
rval.firstGridPointCorner = Corner.LowerLeft;
|
||||
rval.lo1 = subGrid.getLowerLeftLon();
|
||||
rval.la1 = subGrid.getLowerLeftLat();
|
||||
rval.nx = subGrid.getNX();
|
||||
rval.ny = subGrid.getNY();
|
||||
|
||||
rval.setName(SUBGRID_TOKEN + this.getId());
|
||||
} else {
|
||||
statusHandler.handle(Priority.PROBLEM,
|
||||
"Error creating sub grid definition [" + this.name
|
||||
+ "], units are not compatible with meter ["
|
||||
+ spacingUnit + "]");
|
||||
rval = null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
statusHandler.handle(Priority.PROBLEM,
|
||||
"Error creating sub grid definition", e);
|
||||
rval = null;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,11 +30,7 @@ import javax.xml.bind.annotation.XmlRootElement;
|
|||
import com.raytheon.uf.common.geospatial.MapUtil;
|
||||
import com.raytheon.uf.common.gridcoverage.exception.GridCoverageException;
|
||||
import com.raytheon.uf.common.gridcoverage.subgrid.SubGrid;
|
||||
import com.raytheon.uf.common.gridcoverage.subgrid.TrimUtil;
|
||||
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
|
||||
import com.raytheon.uf.common.status.IUFStatusHandler;
|
||||
import com.raytheon.uf.common.status.UFStatus;
|
||||
import com.raytheon.uf.common.status.UFStatus.Priority;
|
||||
|
||||
/**
|
||||
* Defines a Lat/Lon grid coverage. This class is generally used to describe
|
||||
|
@ -49,6 +45,7 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
|
|||
* 4/7/09 1994 bphillip Initial Creation
|
||||
* 09/10/2012 DR 15270 D. Friedman Fix subgrid model name handling.
|
||||
* Jan 17, 2014 2125 rjpeter Removed invalid @Table annotation.
|
||||
* Mar 04, 2015 3959 rjpeter Update for grid based subgridding.
|
||||
* </pre>
|
||||
*
|
||||
* @author bphillip
|
||||
|
@ -59,9 +56,6 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
|
|||
@XmlAccessorType(XmlAccessType.NONE)
|
||||
@DynamicSerialize
|
||||
public class LatLonGridCoverage extends GridCoverage {
|
||||
private static final transient IUFStatusHandler statusHandler = UFStatus
|
||||
.getHandler(LatLonGridCoverage.class);
|
||||
|
||||
private static final long serialVersionUID = 8371251040172233074L;
|
||||
|
||||
/** The name of the projection */
|
||||
|
@ -128,37 +122,9 @@ public class LatLonGridCoverage extends GridCoverage {
|
|||
}
|
||||
|
||||
@Override
|
||||
public GridCoverage trim(SubGrid subGrid) {
|
||||
protected GridCoverage cloneImplCrsParameters(SubGrid subGrid) {
|
||||
LatLonGridCoverage rval = new LatLonGridCoverage();
|
||||
rval.description = this.description;
|
||||
rval.dx = this.dx;
|
||||
rval.dy = this.dy;
|
||||
rval.spacingUnit = this.spacingUnit;
|
||||
|
||||
try {
|
||||
if (spacingUnit.equals("degree")) {
|
||||
TrimUtil.trimLatLonSpace(getLowerLeftLat(), getLowerLeftLon(),
|
||||
subGrid, this.nx, this.ny, this.dx, this.dy);
|
||||
|
||||
rval.firstGridPointCorner = Corner.LowerLeft;
|
||||
rval.lo1 = subGrid.getLowerLeftLon();
|
||||
rval.la1 = subGrid.getLowerLeftLat();
|
||||
rval.nx = subGrid.getNX();
|
||||
rval.ny = subGrid.getNY();
|
||||
rval.setName(SUBGRID_TOKEN + this.getId());
|
||||
} else {
|
||||
throw new GridCoverageException(
|
||||
"SubGridding a lat/lon grid not in lat lon spacing is unimplemented");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
statusHandler.handle(Priority.PROBLEM,
|
||||
"Error creating sub grid definition for grid [" + this.name
|
||||
+ "]", e);
|
||||
rval = null;
|
||||
}
|
||||
|
||||
return rval;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,9 +20,6 @@
|
|||
|
||||
package com.raytheon.uf.common.gridcoverage;
|
||||
|
||||
import javax.measure.converter.UnitConverter;
|
||||
import javax.measure.unit.SI;
|
||||
import javax.measure.unit.Unit;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
|
@ -32,6 +29,7 @@ import javax.xml.bind.annotation.XmlRootElement;
|
|||
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
import org.geotools.geometry.DirectPosition2D;
|
||||
import org.opengis.metadata.spatial.PixelOrientation;
|
||||
import org.opengis.referencing.crs.CoordinateReferenceSystem;
|
||||
import org.opengis.referencing.operation.MathTransform;
|
||||
|
||||
|
@ -39,12 +37,9 @@ import com.raytheon.uf.common.dataplugin.annotations.DataURI;
|
|||
import com.raytheon.uf.common.geospatial.MapUtil;
|
||||
import com.raytheon.uf.common.gridcoverage.exception.GridCoverageException;
|
||||
import com.raytheon.uf.common.gridcoverage.subgrid.SubGrid;
|
||||
import com.raytheon.uf.common.gridcoverage.subgrid.TrimUtil;
|
||||
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
|
||||
import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
|
||||
import com.raytheon.uf.common.status.IUFStatusHandler;
|
||||
import com.raytheon.uf.common.status.UFStatus;
|
||||
import com.raytheon.uf.common.status.UFStatus.Priority;
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
|
||||
/**
|
||||
* Defines a Mercator grid coverage. This class is generally used to describe
|
||||
|
@ -59,6 +54,7 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
|
|||
* 4/7/09 1994 bphillip Initial Creation
|
||||
* 09/10/2012 DR 15270 D. Friedman Fix subgrid model name handling.
|
||||
* Jan 17, 2014 2125 rjpeter Removed invalid @Table annotation.
|
||||
* Mar 04, 2015 3959 rjpeter Update for grid based subgridding.
|
||||
* </pre>
|
||||
*
|
||||
* @author bphillip
|
||||
|
@ -69,9 +65,6 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
|
|||
@XmlAccessorType(XmlAccessType.NONE)
|
||||
@DynamicSerialize
|
||||
public class MercatorGridCoverage extends GridCoverage {
|
||||
private static final transient IUFStatusHandler statusHandler = UFStatus
|
||||
.getHandler(MercatorGridCoverage.class);
|
||||
|
||||
private static final long serialVersionUID = 3140441023975157052L;
|
||||
|
||||
/** The name of the projection */
|
||||
|
@ -215,57 +208,20 @@ public class MercatorGridCoverage extends GridCoverage {
|
|||
}
|
||||
|
||||
@Override
|
||||
public GridCoverage trim(SubGrid subGrid) {
|
||||
protected GridCoverage cloneImplCrsParameters(SubGrid subGrid) {
|
||||
MercatorGridCoverage rval = new MercatorGridCoverage();
|
||||
rval.description = this.description;
|
||||
rval.dx = this.dx;
|
||||
rval.dy = this.dy;
|
||||
rval.spacingUnit = this.spacingUnit;
|
||||
rval.latin = this.latin;
|
||||
rval.majorAxis = this.majorAxis;
|
||||
rval.minorAxis = this.minorAxis;
|
||||
|
||||
try {
|
||||
Unit<?> spacingUnitObj = Unit.valueOf(spacingUnit);
|
||||
if (spacingUnitObj.isCompatible(SI.METRE)) {
|
||||
UnitConverter converter = spacingUnitObj
|
||||
.getConverterTo(SI.METRE);
|
||||
double dxMeter = converter.convert(dx);
|
||||
double dyMeter = converter.convert(dy);
|
||||
MathTransform fromLatLon = MapUtil
|
||||
.getTransformFromLatLon(getCrs());
|
||||
MathTransform toLatLon = fromLatLon.inverse();
|
||||
/* grid space is 0,0 for upper left */
|
||||
Coordinate upperRight = new Coordinate(subGrid.getUpperLeftX()
|
||||
+ subGrid.getNX() - 1, subGrid.getUpperLeftY());
|
||||
upperRight = MapUtil.gridCoordinateToLatLon(upperRight,
|
||||
PixelOrientation.CENTER, this);
|
||||
|
||||
try {
|
||||
TrimUtil.trimMeterSpace(getLowerLeftLat(),
|
||||
getLowerLeftLon(), subGrid, this.nx, this.ny,
|
||||
dxMeter, dyMeter, fromLatLon, toLatLon, true);
|
||||
} catch (GridCoverageException e) {
|
||||
statusHandler.handle(Priority.WARN, "Grid coverage ["
|
||||
+ this.getName() + "] not applicable to this site");
|
||||
return null;
|
||||
}
|
||||
|
||||
rval.firstGridPointCorner = Corner.LowerLeft;
|
||||
rval.lo1 = subGrid.getLowerLeftLon();
|
||||
rval.la1 = subGrid.getLowerLeftLat();
|
||||
rval.lo2 = subGrid.getUpperRightLon();
|
||||
rval.la2 = subGrid.getUpperRightLat();
|
||||
rval.nx = subGrid.getNX();
|
||||
rval.ny = subGrid.getNY();
|
||||
rval.setName(SUBGRID_TOKEN + this.getId());
|
||||
} else {
|
||||
statusHandler.handle(Priority.PROBLEM,
|
||||
"Error creating sub grid definition [" + this.name
|
||||
+ "], units are not compatible with meter ["
|
||||
+ spacingUnit + "]");
|
||||
rval = null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
statusHandler.handle(Priority.PROBLEM,
|
||||
"Error creating sub grid definition", e);
|
||||
rval = null;
|
||||
}
|
||||
rval.lo2 = upperRight.x;
|
||||
rval.la2 = upperRight.y;
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
|
|
@ -20,9 +20,6 @@
|
|||
|
||||
package com.raytheon.uf.common.gridcoverage;
|
||||
|
||||
import javax.measure.converter.UnitConverter;
|
||||
import javax.measure.unit.SI;
|
||||
import javax.measure.unit.Unit;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
|
@ -31,18 +28,14 @@ import javax.xml.bind.annotation.XmlElement;
|
|||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
import org.opengis.referencing.operation.MathTransform;
|
||||
|
||||
import com.raytheon.uf.common.dataplugin.annotations.DataURI;
|
||||
import com.raytheon.uf.common.geospatial.MapUtil;
|
||||
import com.raytheon.uf.common.geospatial.util.GridGeometryWrapChecker;
|
||||
import com.raytheon.uf.common.gridcoverage.exception.GridCoverageException;
|
||||
import com.raytheon.uf.common.gridcoverage.subgrid.SubGrid;
|
||||
import com.raytheon.uf.common.gridcoverage.subgrid.TrimUtil;
|
||||
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
|
||||
import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
|
||||
import com.raytheon.uf.common.status.IUFStatusHandler;
|
||||
import com.raytheon.uf.common.status.UFStatus;
|
||||
import com.raytheon.uf.common.status.UFStatus.Priority;
|
||||
|
||||
/**
|
||||
* Defines a Polar Stereographic grid coverage. This class is generally used to
|
||||
|
@ -57,6 +50,7 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
|
|||
* 4/7/09 1994 bphillip Initial Creation
|
||||
* 09/10/2012 DR 15270 D. Friedman Fix subgrid model name handling.
|
||||
* Jan 17, 2014 2125 rjpeter Removed invalid @Table annotation.
|
||||
* Mar 04, 2015 3959 rjpeter Update for grid based subgridding.
|
||||
* </pre>
|
||||
*
|
||||
* @author bphillip
|
||||
|
@ -67,9 +61,6 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
|
|||
@XmlAccessorType(XmlAccessType.NONE)
|
||||
@DynamicSerialize
|
||||
public class PolarStereoGridCoverage extends GridCoverage {
|
||||
private static final transient IUFStatusHandler statusHandler = UFStatus
|
||||
.getHandler(PolarStereoGridCoverage.class);
|
||||
|
||||
private static final long serialVersionUID = 2640862310607194072L;
|
||||
|
||||
/** The name of the projection */
|
||||
|
@ -115,60 +106,25 @@ public class PolarStereoGridCoverage extends GridCoverage {
|
|||
}
|
||||
|
||||
@Override
|
||||
public GridCoverage trim(SubGrid subGrid) {
|
||||
protected GridCoverage cloneImplCrsParameters(SubGrid subGrid) {
|
||||
PolarStereoGridCoverage rval = new PolarStereoGridCoverage();
|
||||
rval.description = this.description;
|
||||
rval.dx = this.dx;
|
||||
rval.dy = this.dy;
|
||||
rval.spacingUnit = this.spacingUnit;
|
||||
rval.lov = this.lov;
|
||||
rval.majorAxis = this.majorAxis;
|
||||
rval.minorAxis = this.minorAxis;
|
||||
|
||||
try {
|
||||
Unit<?> spacingUnitObj = Unit.valueOf(spacingUnit);
|
||||
if (spacingUnitObj.isCompatible(SI.METRE)) {
|
||||
UnitConverter converter = spacingUnitObj
|
||||
.getConverterTo(SI.METRE);
|
||||
double dxMeter = converter.convert(dx);
|
||||
double dyMeter = converter.convert(dy);
|
||||
MathTransform fromLatLon = MapUtil
|
||||
.getTransformFromLatLon(getCrs());
|
||||
MathTransform toLatLon = fromLatLon.inverse();
|
||||
|
||||
// don't check world wrap on a polar stereo grid
|
||||
try {
|
||||
TrimUtil.trimMeterSpace(getLowerLeftLat(),
|
||||
getLowerLeftLon(), subGrid, this.nx, this.ny,
|
||||
dxMeter, dyMeter, fromLatLon, toLatLon, false);
|
||||
} catch (GridCoverageException e) {
|
||||
statusHandler.handle(Priority.WARN, "Grid coverage ["
|
||||
+ this.getName() + "] not applicable to this site");
|
||||
return null;
|
||||
}
|
||||
|
||||
rval.firstGridPointCorner = Corner.LowerLeft;
|
||||
rval.lo1 = subGrid.getLowerLeftLon();
|
||||
rval.la1 = subGrid.getLowerLeftLat();
|
||||
rval.nx = subGrid.getNX();
|
||||
rval.ny = subGrid.getNY();
|
||||
rval.setName(SUBGRID_TOKEN + this.getId());
|
||||
} else {
|
||||
statusHandler.handle(Priority.PROBLEM,
|
||||
"Error creating sub grid definition [" + this.name
|
||||
+ "], units are not compatible with meter ["
|
||||
+ spacingUnit + "]");
|
||||
rval = null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
statusHandler.handle(Priority.PROBLEM,
|
||||
"Error creating sub grid definition", e);
|
||||
rval = null;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see com.raytheon.uf.common.gridcoverage.GridCoverage#getWorldWrapCount()
|
||||
*/
|
||||
@Override
|
||||
public int getWorldWrapCount() {
|
||||
/* PolarStereographic grids cannot wrap */
|
||||
return GridGeometryWrapChecker.NO_WRAP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProjectionType() {
|
||||
return PROJECTION_TYPE;
|
||||
|
|
|
@ -30,13 +30,11 @@ import org.apache.commons.lang.builder.HashCodeBuilder;
|
|||
|
||||
import com.raytheon.uf.common.dataplugin.annotations.DataURI;
|
||||
import com.raytheon.uf.common.geospatial.MapUtil;
|
||||
import com.raytheon.uf.common.geospatial.util.GridGeometryWrapChecker;
|
||||
import com.raytheon.uf.common.gridcoverage.exception.GridCoverageException;
|
||||
import com.raytheon.uf.common.gridcoverage.subgrid.SubGrid;
|
||||
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
|
||||
import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
|
||||
import com.raytheon.uf.common.status.IUFStatusHandler;
|
||||
import com.raytheon.uf.common.status.UFStatus;
|
||||
import com.raytheon.uf.common.status.UFStatus.Priority;
|
||||
|
||||
/**
|
||||
* Stereographic Coverage used by radar data.
|
||||
|
@ -47,7 +45,7 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
|
|||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Apr 7, 2010 #4473 rjpeter Initial creation
|
||||
*
|
||||
* Mar 04, 2015 3959 rjpeter Update for grid based subgridding.
|
||||
* </pre>
|
||||
*
|
||||
* @author rjpeter
|
||||
|
@ -60,9 +58,6 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
|
|||
public class StereographicGridCoverage extends GridCoverage {
|
||||
private static final long serialVersionUID = -3420227375272208743L;
|
||||
|
||||
private static final transient IUFStatusHandler statusHandler = UFStatus
|
||||
.getHandler(StereographicGridCoverage.class);
|
||||
|
||||
/** Orientation of the grid */
|
||||
@Column
|
||||
@XmlElement
|
||||
|
@ -104,11 +99,22 @@ public class StereographicGridCoverage extends GridCoverage {
|
|||
}
|
||||
|
||||
@Override
|
||||
public GridCoverage trim(SubGrid subGrid) {
|
||||
statusHandler
|
||||
.handle(Priority.ERROR,
|
||||
"StereographicGridCoverage does not currently support subgridding");
|
||||
return null;
|
||||
protected GridCoverage cloneImplCrsParameters(SubGrid subGrid) {
|
||||
StereographicGridCoverage rval = new StereographicGridCoverage();
|
||||
rval.lov = this.lov;
|
||||
rval.lad = this.lad;
|
||||
return rval;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see com.raytheon.uf.common.gridcoverage.GridCoverage#getWorldWrapCount()
|
||||
*/
|
||||
@Override
|
||||
public int getWorldWrapCount() {
|
||||
/* Stereographic grids cannot wrap */
|
||||
return GridGeometryWrapChecker.NO_WRAP;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -122,20 +128,26 @@ public class StereographicGridCoverage extends GridCoverage {
|
|||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
if (this == obj) {
|
||||
return true;
|
||||
if (!super.equals(obj))
|
||||
}
|
||||
if (!super.equals(obj)) {
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
StereographicGridCoverage other = (StereographicGridCoverage) obj;
|
||||
if (Double.doubleToLongBits(lad) != Double.doubleToLongBits(other.lad))
|
||||
if (Double.doubleToLongBits(lad) != Double.doubleToLongBits(other.lad)) {
|
||||
return false;
|
||||
if (Double.doubleToLongBits(lov) != Double.doubleToLongBits(other.lov))
|
||||
}
|
||||
if (Double.doubleToLongBits(lov) != Double.doubleToLongBits(other.lov)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean spatialEquals(GridCoverage other) {
|
||||
if (super.spatialEquals(other)) {
|
||||
StereographicGridCoverage otherStereo = (StereographicGridCoverage) other;
|
||||
|
@ -159,5 +171,4 @@ public class StereographicGridCoverage extends GridCoverage {
|
|||
key.append(lad);
|
||||
return key.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,15 +20,15 @@
|
|||
package com.raytheon.uf.common.gridcoverage.subgrid;
|
||||
|
||||
/**
|
||||
* A sub grid definition
|
||||
* A sub grid definition.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Oct 08, 2009 3177 rjpeter Initial creation
|
||||
*
|
||||
* Oct 08, 2009 3177 rjpeter Initial creation.
|
||||
* Mar 04, 2015 3959 rjpeter Made grid based only.
|
||||
* </pre>
|
||||
*
|
||||
* @author rjpeter
|
||||
|
@ -48,17 +48,16 @@ public class SubGrid {
|
|||
/** the height of the sub grid */
|
||||
private int nY;
|
||||
|
||||
/** lower left latitude of the subgrid area */
|
||||
private double lowerLeftLat;
|
||||
public SubGrid() {
|
||||
|
||||
/** lower left longitude of the subgrid area */
|
||||
private double lowerLeftLon;
|
||||
}
|
||||
|
||||
/** upper right latitude of the subgrid area */
|
||||
private double upperRightLat;
|
||||
|
||||
/** upper right longitude of the subgrid area */
|
||||
private double upperRightLon;
|
||||
public SubGrid(int upperLeftX, int upperLeftY, int nX, int nY) {
|
||||
this.upperLeftX = upperLeftX;
|
||||
this.upperLeftY = upperLeftY;
|
||||
this.nX = nX;
|
||||
this.nY = nY;
|
||||
}
|
||||
|
||||
public int getUpperLeftX() {
|
||||
return upperLeftX;
|
||||
|
@ -92,36 +91,17 @@ public class SubGrid {
|
|||
nY = ny;
|
||||
}
|
||||
|
||||
public double getLowerLeftLat() {
|
||||
return lowerLeftLat;
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder rval = new StringBuilder(40);
|
||||
rval.append("SubGrid[upperLeftX=").append(upperLeftX)
|
||||
.append(", upperLeftY=").append(upperLeftY).append(", nX=")
|
||||
.append(nX).append(", nY=").append(nY).append("]");
|
||||
return super.toString();
|
||||
}
|
||||
|
||||
public void setLowerLeftLat(double lowerLeftLat) {
|
||||
this.lowerLeftLat = lowerLeftLat;
|
||||
}
|
||||
|
||||
public double getLowerLeftLon() {
|
||||
return lowerLeftLon;
|
||||
}
|
||||
|
||||
public void setLowerLeftLon(double lowerLeftLon) {
|
||||
this.lowerLeftLon = lowerLeftLon;
|
||||
}
|
||||
|
||||
public double getUpperRightLat() {
|
||||
return upperRightLat;
|
||||
}
|
||||
|
||||
public void setUpperRightLat(double upperRightLat) {
|
||||
this.upperRightLat = upperRightLat;
|
||||
}
|
||||
|
||||
public double getUpperRightLon() {
|
||||
return upperRightLon;
|
||||
}
|
||||
|
||||
public void setUpperRightLon(double upperRightLon) {
|
||||
this.upperRightLon = upperRightLon;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,338 +0,0 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.uf.common.gridcoverage.subgrid;
|
||||
|
||||
import org.opengis.referencing.operation.MathTransform;
|
||||
|
||||
import com.raytheon.uf.common.geospatial.MapUtil;
|
||||
import com.raytheon.uf.common.gridcoverage.exception.GridCoverageException;
|
||||
|
||||
/**
|
||||
* Provides utility methods for trimming grids into subgrids.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jun 30, 2010 rjpeter Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author rjpeter
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class TrimUtil {
|
||||
|
||||
/**
|
||||
* Uses the lat/lon values in subGrid to calculate a valid overlapping area
|
||||
* to the parent grid and then sets the nx,ny and the lower Left x and y in
|
||||
* the subgrid object.
|
||||
*
|
||||
* @param parentLLLat
|
||||
* @param parentLLLon
|
||||
* @param subGrid
|
||||
* @param nx
|
||||
* @param ny
|
||||
* @param dxMeter
|
||||
* @param dyMeter
|
||||
* @param fromLatLon
|
||||
* @param toLatLon
|
||||
* @param checkGridWrap
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void trimMeterSpace(double parentLLLat, double parentLLLon,
|
||||
SubGrid subGrid, int nx, int ny, double dxMeter, double dyMeter,
|
||||
MathTransform fromLatLon, MathTransform toLatLon,
|
||||
boolean checkGridWrap) throws Exception {
|
||||
double[] lonLats = new double[8];
|
||||
double[] lonLatsInMeters = new double[8];
|
||||
lonLats[0] = parentLLLon;
|
||||
lonLats[1] = parentLLLat;
|
||||
lonLats[4] = subGrid.getLowerLeftLon();
|
||||
lonLats[5] = subGrid.getLowerLeftLat();
|
||||
lonLats[6] = subGrid.getUpperRightLon();
|
||||
lonLats[7] = subGrid.getUpperRightLat();
|
||||
|
||||
if (checkGridWrap) {
|
||||
// determine UR of parent
|
||||
fromLatLon.transform(lonLats, 0, lonLatsInMeters, 0, 1);
|
||||
// size minus one so boundaries are inclusive
|
||||
lonLatsInMeters[2] = lonLatsInMeters[0] + (nx - 1) * dxMeter;
|
||||
lonLatsInMeters[3] = lonLatsInMeters[1] + (ny - 1) * dyMeter;
|
||||
toLatLon.transform(lonLatsInMeters, 2, lonLats, 2, 1);
|
||||
|
||||
validateLongitudes(lonLats);
|
||||
}
|
||||
|
||||
// adjust all longitudes to be offset from LL of parent grid
|
||||
if (lonLats[4] < lonLats[0]) {
|
||||
lonLats[4] += 360;
|
||||
}
|
||||
if (lonLats[6] < lonLats[0]) {
|
||||
lonLats[6] += 360;
|
||||
}
|
||||
|
||||
fromLatLon.transform(lonLats, 0, lonLatsInMeters, 0, 4);
|
||||
// recalculate anyway
|
||||
lonLatsInMeters[2] = lonLatsInMeters[0] + dxMeter * (nx - 1);
|
||||
lonLatsInMeters[3] = lonLatsInMeters[1] + dyMeter * (ny - 1);
|
||||
|
||||
// sanity check lat bounds
|
||||
if (lonLatsInMeters[5] < lonLatsInMeters[1]) {
|
||||
lonLatsInMeters[5] = lonLatsInMeters[1];
|
||||
}
|
||||
if (lonLatsInMeters[7] > lonLatsInMeters[3]) {
|
||||
lonLatsInMeters[7] = lonLatsInMeters[3];
|
||||
}
|
||||
|
||||
// if grid wrap was not checked then need to constrain lons
|
||||
if (!checkGridWrap) {
|
||||
if (lonLatsInMeters[4] < lonLatsInMeters[0]) {
|
||||
lonLatsInMeters[4] = lonLatsInMeters[0];
|
||||
}
|
||||
if (lonLatsInMeters[6] > lonLatsInMeters[2]) {
|
||||
lonLatsInMeters[6] = lonLatsInMeters[2];
|
||||
}
|
||||
if (lonLatsInMeters[6] < lonLatsInMeters[4]) {
|
||||
throw new GridCoverageException(
|
||||
"Model does not contain area defined by sub grid.");
|
||||
}
|
||||
}
|
||||
|
||||
// need to determine exact LL grid point, round up to be just inside
|
||||
// subGrid def
|
||||
// X/Y is 0/0 in Upper Left
|
||||
int leftX = (int) (Math.ceil((lonLatsInMeters[4] - lonLatsInMeters[0])
|
||||
/ dxMeter));
|
||||
int lowerY = ny
|
||||
- (int) (Math.ceil((lonLatsInMeters[5] - lonLatsInMeters[1])
|
||||
/ dyMeter));
|
||||
|
||||
if (leftX < 0) {
|
||||
/**
|
||||
* All the other checks should have caught this. This is a dirty
|
||||
* hack that is only here until this method can be rewritten.
|
||||
*/
|
||||
leftX = 0;
|
||||
}
|
||||
|
||||
// determine exact LL in meter
|
||||
lonLatsInMeters[4] = lonLatsInMeters[0] + leftX * dxMeter;
|
||||
lonLatsInMeters[5] = lonLatsInMeters[1] + (ny - lowerY) * dyMeter;
|
||||
|
||||
// determine number points, round down to be inside sub grid, inclusive
|
||||
subGrid.setNX((int) ((lonLatsInMeters[6] - lonLatsInMeters[4]) / dxMeter) + 1);
|
||||
subGrid.setNY((int) ((lonLatsInMeters[7] - lonLatsInMeters[5]) / dyMeter) + 1);
|
||||
|
||||
// just double check possible rounding error, in case of using
|
||||
// subgridding to shift a world wide grid
|
||||
if (subGrid.getNX() > nx) {
|
||||
subGrid.setNX(nx);
|
||||
}
|
||||
if (subGrid.getNY() > ny) {
|
||||
subGrid.setNY(ny);
|
||||
}
|
||||
|
||||
// sub gridding needs the upper left x/y to pull out the data
|
||||
// X/Y is 0/0 at UR and NX/NY at LL
|
||||
subGrid.setUpperLeftX(leftX);
|
||||
subGrid.setUpperLeftY(lowerY - subGrid.getNY());
|
||||
|
||||
// determine exact UR in meter
|
||||
lonLatsInMeters[6] = lonLatsInMeters[4] + (subGrid.getNX() - 1)
|
||||
* dxMeter;
|
||||
lonLatsInMeters[7] = lonLatsInMeters[5] + (subGrid.getNY() - 1)
|
||||
* dyMeter;
|
||||
|
||||
toLatLon.transform(lonLatsInMeters, 4, lonLats, 4, 1);
|
||||
subGrid.setLowerLeftLon(MapUtil.correctLon(lonLats[4]));
|
||||
subGrid.setLowerLeftLat(MapUtil.correctLat(lonLats[5]));
|
||||
subGrid.setUpperRightLon(MapUtil.correctLon(lonLats[6]));
|
||||
subGrid.setUpperRightLat(MapUtil.correctLat(lonLats[7]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the lat/lon values in subGrid to calculate a valid overlapping area
|
||||
* to the parent grid and then sets the nx,ny and the lower Left x and y in
|
||||
* the subgrid object.
|
||||
*
|
||||
* @param parentLLLat
|
||||
* @param parentLLLon
|
||||
* * @param subGrid
|
||||
* @param nx
|
||||
* @param ny
|
||||
* @param dx
|
||||
* @param dy
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void trimLatLonSpace(double parentLLLat, double parentLLLon,
|
||||
SubGrid subGrid, int nx, int ny, double dx, double dy)
|
||||
throws Exception {
|
||||
|
||||
double lonLats[] = new double[8];
|
||||
lonLats[0] = parentLLLon;
|
||||
lonLats[1] = parentLLLat;
|
||||
// size minus 1 so boundaries are inclusive
|
||||
lonLats[2] = lonLats[0] + (nx - 1) * dx;
|
||||
lonLats[3] = lonLats[1] + (ny - 1) * dy;
|
||||
lonLats[4] = subGrid.getLowerLeftLon();
|
||||
lonLats[5] = subGrid.getLowerLeftLat();
|
||||
lonLats[6] = subGrid.getUpperRightLon();
|
||||
lonLats[7] = subGrid.getUpperRightLat();
|
||||
|
||||
// check grid wrap
|
||||
validateLongitudes(lonLats);
|
||||
|
||||
// sanity check lats
|
||||
if (lonLats[5] < lonLats[1]) {
|
||||
lonLats[5] = lonLats[1];
|
||||
}
|
||||
if (lonLats[7] > lonLats[3]) {
|
||||
lonLats[7] = lonLats[3];
|
||||
}
|
||||
|
||||
// adjust all longitudes to be offset from LL of parent grid
|
||||
if (lonLats[2] < lonLats[0]) {
|
||||
lonLats[2] += 360;
|
||||
}
|
||||
if (lonLats[4] < lonLats[0]) {
|
||||
lonLats[4] += 360;
|
||||
}
|
||||
if (lonLats[6] < lonLats[0]) {
|
||||
lonLats[6] += 360;
|
||||
}
|
||||
|
||||
// if subGrid wraps, need to add 360
|
||||
if (lonLats[6] < lonLats[4]) {
|
||||
lonLats[6] += 360;
|
||||
}
|
||||
|
||||
// need to determine exact LL grid point
|
||||
// X/Y is 0/0 in Upper Left
|
||||
int leftX = (int) ((lonLats[4] - lonLats[0]) / dx);
|
||||
int lowerY = ny - (int) ((lonLats[5] - lonLats[1]) / dy);
|
||||
|
||||
// determine exact LL
|
||||
lonLats[4] = lonLats[0] + leftX * dx;
|
||||
lonLats[5] = lonLats[1] + (ny - lowerY) * dy;
|
||||
|
||||
// determine number points, round up and inclusive
|
||||
subGrid.setNX((int) ((lonLats[6] - lonLats[4]) / dx + 0.5) + 1);
|
||||
subGrid.setNY((int) ((lonLats[7] - lonLats[5]) / dy + 0.5) + 1);
|
||||
|
||||
// just double check possible rounding error, in case of using
|
||||
// subgridding to shift a world wide grid
|
||||
if (subGrid.getNX() > nx) {
|
||||
subGrid.setNX(nx);
|
||||
}
|
||||
if (subGrid.getNY() > ny) {
|
||||
subGrid.setNY(ny);
|
||||
}
|
||||
|
||||
// sub gridding needs the upper left x/y to pull out the data
|
||||
// X/Y is 0/0 at UR and NX/NY at LL
|
||||
subGrid.setUpperLeftX(leftX);
|
||||
subGrid.setUpperLeftY(lowerY - subGrid.getNY());
|
||||
|
||||
// determine exact UR
|
||||
lonLats[6] = lonLats[4] + (subGrid.getNX() - 1) * dx;
|
||||
lonLats[7] = lonLats[5] + (subGrid.getNY() - 1) * dy;
|
||||
|
||||
subGrid.setLowerLeftLon(MapUtil.correctLon(lonLats[4]));
|
||||
subGrid.setLowerLeftLat(MapUtil.correctLat(lonLats[5]));
|
||||
subGrid.setUpperRightLon(MapUtil.correctLon(lonLats[6]));
|
||||
subGrid.setUpperRightLat(MapUtil.correctLat(lonLats[7]));
|
||||
}
|
||||
|
||||
private static void validateLongitudes(double lonLats[])
|
||||
throws GridCoverageException {
|
||||
// check > 180 and wrap back around
|
||||
if (lonLats[2] > 180) {
|
||||
lonLats[2] -= 360;
|
||||
}
|
||||
|
||||
// rough guess if its world wide
|
||||
boolean parentCoverageWraps = lonLats[2] < lonLats[0];
|
||||
boolean isWorldWide = (parentCoverageWraps && ((lonLats[2] - lonLats[0]) < 2.5))
|
||||
|| ((lonLats[2] - lonLats[0]) > 357);
|
||||
|
||||
// no need to constrain sub grid if parent is world wide
|
||||
if (!isWorldWide) {
|
||||
boolean subCoverageWraps = lonLats[6] < lonLats[4];
|
||||
|
||||
if ((parentCoverageWraps && subCoverageWraps)
|
||||
|| (!parentCoverageWraps && !subCoverageWraps)) {
|
||||
// compare lons normally
|
||||
if (lonLats[4] < lonLats[0]) {
|
||||
lonLats[4] = lonLats[0];
|
||||
}
|
||||
if (lonLats[6] > lonLats[2]) {
|
||||
lonLats[6] = lonLats[2];
|
||||
}
|
||||
} else if (parentCoverageWraps) {
|
||||
// parent coverage wraps, sub coverage doesn't wrap
|
||||
if (lonLats[6] > lonLats[2]) {
|
||||
// UR is valid, compare LL normally
|
||||
if (lonLats[4] < lonLats[0]) {
|
||||
lonLats[4] = lonLats[0];
|
||||
}
|
||||
} else {
|
||||
// verify LL is before UR of parent
|
||||
if (lonLats[4] > lonLats[2]) {
|
||||
// invalid grid
|
||||
throw new GridCoverageException(
|
||||
"Model does not contain area defined by sub grid.");
|
||||
}
|
||||
|
||||
// UR needs to be checked normally
|
||||
if (lonLats[6] > lonLats[2]) {
|
||||
lonLats[6] = lonLats[2];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// parent coverage doesn't wrap, sub coverage wraps
|
||||
if (lonLats[6] < lonLats[4]) {
|
||||
// LL is valid, constrain UR as normal
|
||||
if (lonLats[6] > lonLats[2]) {
|
||||
lonLats[6] = lonLats[2];
|
||||
}
|
||||
} else {
|
||||
// verify UR is after LL of parent
|
||||
if (lonLats[6] < lonLats[0]) {
|
||||
// invalid grid
|
||||
throw new GridCoverageException(
|
||||
"Model does not contain area defined by sub grid.");
|
||||
}
|
||||
|
||||
// sub LL was beyond grib, set it to LL of parent inside
|
||||
// the wrap
|
||||
lonLats[4] = lonLats[0];
|
||||
|
||||
// UR needs to be checked normally
|
||||
if (lonLats[6] > lonLats[2]) {
|
||||
lonLats[6] = lonLats[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue