Omaha #3959 - Make subgridding grid based.

Change-Id: If1970961641536655fd1a951c0e433dbaca0687c

Former-commit-id: e0ff8b49c1 [formerly c3b5f78811d231009dad7533fd650a68634e3e29]
Former-commit-id: 9df7d7e987
This commit is contained in:
Richard Peter 2015-03-04 11:29:41 -06:00
parent db4044191e
commit fc68d9b30d
13 changed files with 481 additions and 826 deletions

View file

@ -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,9 +345,19 @@ 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]
subGridDataArray[0:subny, midx:subnx] = GridUtil.GRID_FILL_VALUE
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:
numpyDataArray = numpyDataArray[starty:endY, startx:endX]

View file

@ -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,17 +609,27 @@ 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) {
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,8 +644,15 @@ public class Grib1Decoder extends AbstractDecoder {
}
// handle grid wrap for world wide grids
for (int column = 0; column < columnCount; column++, newGridColumn++) {
newGrid[newGridRow][newGridColumn] = data[row][column];
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;
}
}
}

View file

@ -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,16 +126,10 @@ 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;
boolean shiftSubGridWest = false;
/**
@ -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,143 +274,166 @@ public class GribSpatialCache {
*/
private boolean loadSubGrid(String modelName, GridCoverage coverage) {
SubGridDef subGridDef = subGridDefMap.get(modelName);
if (subGridDef != null) {
String referenceGrid = subGridDef.getReferenceGrid();
if (referenceGrid == null) {
referenceGrid = GribModelLookup.getInstance()
.getModelByName(subGridDef.getReferenceModel())
.getGrid();
try {
if (subGridDef != null) {
String referenceGrid = subGridDef.getReferenceGrid();
if (referenceGrid == null) {
referenceGrid = GribModelLookup.getInstance()
.getModelByName(subGridDef.getReferenceModel())
.getGrid();
if (referenceGrid == null) {
statusHandler
.error("Failed to generate sub grid, Unable to determine coverage for referenceModel ["
+ subGridDef.getReferenceModel() + "]");
return false;
}
}
GridCoverage referenceCoverage = getGridByName(referenceGrid
.toString());
if (referenceCoverage == null) {
statusHandler
.error("Failed to generate sub grid, Unable to determine coverage for referenceModel ["
+ subGridDef.getReferenceModel() + "]");
.error("Failed to generate sub grid, Unable to determine coverage for referenceGrid ["
+ referenceGrid + "]");
return false;
}
Coordinate subGridCenterLatLon = new Coordinate(
subGridDef.getCenterLongitude(),
subGridDef.getCenterLatitude());
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
*/
boolean shiftThisSubGridWest = this.shiftSubGridWest;
if (subGridDef.getShiftWest() != null) {
shiftThisSubGridWest = subGridDef.getShiftWest();
}
if (shiftThisSubGridWest == true) {
shiftX = nx / 5;
}
double xCenterPoint = subGridCenterGridCoord.x - shiftX;
double yCenterPoint = subGridCenterGridCoord.y;
double xDistance = nx / 2;
double yDistance = ny / 2;
int leftX = (int) (xCenterPoint - xDistance);
int upperY = (int) (yCenterPoint - yDistance);
/*
* 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);
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");
}
Coordinate[] corners = new Coordinate[4];
System.arraycopy(origCoords, 0, corners, 0, 4);
MapUtil.latLonToGridCoordinate(corners,
PixelOrientation.CENTER, coverage);
/*
* 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;
}
}
GridCoverage referenceCoverage = getGridByName(referenceGrid
.toString());
if (referenceCoverage == null) {
statusHandler
.error("Failed to generate sub grid, Unable to determine coverage for referenceGrid ["
+ referenceGrid + "]");
return false;
}
Coordinate subGridCenterLatLon = new Coordinate(
subGridDef.getCenterLongitude(),
subGridDef.getCenterLatitude());
Coordinate subGridCenterGridCoord = MapUtil.latLonToGridCoordinate(
subGridCenterLatLon, PixelOrientation.CENTER,
referenceCoverage);
double shiftX = 0;
// 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;
}
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);
// 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;
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(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,
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: "
+ modelName, e);
return false;
}
}else{
return false;
}
} catch (Exception e) {
statusHandler.error("Failed to generate sub grid for model "
+ modelName, e);
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;
}
subGridCoverage = insert(subGridCoverage);
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,9 +545,8 @@ public class GribSpatialCache {
names.add(name);
} catch (Exception e) {
// Log error but do not throw exception
statusHandler.error(
"Unable to read default grids file: "
+ fd.getFilePath(), e);
statusHandler.error("Unable to read default grids file: "
+ fd.getFilePath(), e);
}
}
Coordinate defaultCenterPoint = null;
@ -540,9 +555,8 @@ public class GribSpatialCache {
defaultCenterPoint = getDefaultSubGridCenterPoint();
} catch (Exception e) {
statusHandler
.error(
"Failed to generate sub grid definitions. Unable to lookup WFO Center Point",
e);
.error("Failed to generate sub grid definitions. Unable to lookup WFO Center Point",
e);
}
for (FileData fd : fdl.getSubGridFileList()) {
try {
@ -556,9 +570,8 @@ public class GribSpatialCache {
}
} catch (Exception e) {
// Log error but do not throw exception
statusHandler.error(
"Unable to read default grids file: "
+ fd.getFilePath(), e);
statusHandler.error("Unable to read default grids file: "
+ fd.getFilePath(), e);
}
}
this.gridNameMap = gridNameMap;
@ -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;
}

View file

@ -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,14 +60,14 @@ 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;
// annotation on setter to enforce data constraints
private Double centerLatitude;
@ -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;
}
@ -104,7 +104,8 @@ public class SubGridDef {
public void setShiftWest(Boolean shiftWest) {
this.shiftWest = shiftWest;
}
}
/**
* a model may have more than one grid so use reference grid instead.
*
@ -132,7 +133,7 @@ public class SubGridDef {
public void setReferenceGrid(String referenceGrid) {
this.referenceGrid = referenceGrid;
}
public Double getCenterLatitude() {
return centerLatitude;
}

View file

@ -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();
}
/**

View file

@ -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() {

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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;

View file

@ -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();
}
}

View file

@ -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;
}
}

View file

@ -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];
}
}
}
}
}
}