Issue #2672 Handle envelopes in data access requests of gridded types.
Change-Id: I4a58e6489e2173457d50e6f3c06e2e8fffdb678c Former-commit-id:9c439866d5
[formerly9c439866d5
[formerly f634fe40e6fa7a8a3af575e79cb3d996761db983]] Former-commit-id:dc5b5526a3
Former-commit-id:02a0874646
This commit is contained in:
parent
b9af02c0b3
commit
70cbd6c61d
10 changed files with 649 additions and 222 deletions
|
@ -29,7 +29,6 @@ import org.geotools.coverage.grid.GridEnvelope2D;
|
|||
import org.geotools.coverage.grid.GridGeometry2D;
|
||||
import org.geotools.coverage.grid.InvalidGridGeometryException;
|
||||
import org.geotools.geometry.DirectPosition2D;
|
||||
import org.geotools.geometry.Envelope2D;
|
||||
import org.opengis.referencing.FactoryException;
|
||||
import org.opengis.referencing.crs.CoordinateReferenceSystem;
|
||||
import org.opengis.referencing.operation.MathTransform;
|
||||
|
@ -46,8 +45,8 @@ import com.raytheon.uf.common.geospatial.ReferencedCoordinate;
|
|||
import com.raytheon.uf.common.geospatial.interpolation.BilinearInterpolation;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.Interpolation;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.NearestNeighborInterpolation;
|
||||
import com.raytheon.uf.common.geospatial.util.EnvelopeIntersection;
|
||||
import com.raytheon.uf.common.geospatial.util.GridGeometryWrapChecker;
|
||||
import com.raytheon.uf.common.geospatial.util.SubGridGeometryCalculator;
|
||||
import com.raytheon.uf.common.gridcoverage.GridCoverage;
|
||||
import com.raytheon.uf.common.gridcoverage.LatLonGridCoverage;
|
||||
import com.raytheon.uf.common.status.IUFStatusHandler;
|
||||
|
@ -70,8 +69,6 @@ import com.raytheon.viz.grid.rsc.GridResourceData;
|
|||
import com.raytheon.viz.grid.util.ReprojectionUtil;
|
||||
import com.raytheon.viz.grid.xml.FieldDisplayTypesFactory;
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
import com.vividsolutions.jts.geom.Envelope;
|
||||
import com.vividsolutions.jts.geom.Geometry;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -82,7 +79,7 @@ import com.vividsolutions.jts.geom.Geometry;
|
|||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------- -------- ----------- --------------------------
|
||||
* ------------- -------- ----------- -----------------------------------------
|
||||
* Mar 09, 2011 bsteffen Initial creation
|
||||
* Feb 25, 2013 1659 bsteffen Add PDOs to D2DGridResource in
|
||||
* constructor to avoid duplicate data
|
||||
|
@ -94,6 +91,8 @@ import com.vividsolutions.jts.geom.Geometry;
|
|||
* Sep 24, 2013 15972 D. Friedman Make reprojection of grids configurable.
|
||||
* Nov 19, 2013 2532 bsteffen Special handling of grids larger than the
|
||||
* world.
|
||||
* Feb 04, 2014 2672 bsteffen Extract subgridding logic to geospatial
|
||||
* plugin.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -174,35 +173,33 @@ public class D2DGridResource extends GridResource<GridResourceData> implements
|
|||
IDataRecord[] dataRecs = GridResourceData.getDataRecordsForTilt(
|
||||
gridRecord, descriptor);
|
||||
if (dataRecs == null) {
|
||||
GridGeometry2D subGridGeometry = gridGeometry;
|
||||
if (!gridLargerThanWorld) {
|
||||
subGridGeometry = calculateSubgrid(gridGeometry);
|
||||
}
|
||||
if (subGridGeometry == null) {
|
||||
return null;
|
||||
} else if (subGridGeometry.equals(gridGeometry)) {
|
||||
try {
|
||||
SubGridGeometryCalculator subGrid = new SubGridGeometryCalculator(
|
||||
descriptor.getGridGeometry().getEnvelope(),
|
||||
gridGeometry);
|
||||
if (subGrid.isEmpty()) {
|
||||
return null;
|
||||
} else if (subGrid.isFull()) {
|
||||
dataRecs = DataCubeContainer.getDataRecord(gridRecord);
|
||||
} else {
|
||||
Request request = Request.buildSlab(
|
||||
subGrid.getGridRangeLow(true),
|
||||
subGrid.getGridRangeHigh(false));
|
||||
dataRecs = DataCubeContainer.getDataRecord(gridRecord,
|
||||
request, null);
|
||||
/*
|
||||
* gridGeometries used in renderables are expected to have
|
||||
* min x,y be 0.
|
||||
*/
|
||||
gridGeometry = subGrid.getZeroedSubGridGeometry();
|
||||
dataModified = true;
|
||||
}
|
||||
} catch (TransformException e) {
|
||||
/* Not a big deal, just request all data. */
|
||||
statusHandler.handle(Priority.DEBUG,
|
||||
"Unable to request subgrid, full grid will be used.",
|
||||
e);
|
||||
dataRecs = DataCubeContainer.getDataRecord(gridRecord);
|
||||
} else if (subGridGeometry != null) {
|
||||
/* transform subgrid envelope into a slab request. */
|
||||
GridEnvelope2D subGridRange = subGridGeometry.getGridRange2D();
|
||||
int[] min = { subGridRange.getLow(0), subGridRange.getLow(1) };
|
||||
int[] max = { subGridRange.getHigh(0) + 1,
|
||||
subGridRange.getHigh(1) + 1 };
|
||||
Request request = Request.buildSlab(min, max);
|
||||
dataRecs = DataCubeContainer.getDataRecord(gridRecord, request,
|
||||
null);
|
||||
/*
|
||||
* gridGeometries used in renderables are expected to have min
|
||||
* x,y be 0.
|
||||
*/
|
||||
subGridRange.x = 0;
|
||||
subGridRange.y = 0;
|
||||
gridGeometry = new GridGeometry2D(subGridRange,
|
||||
subGridGeometry.getEnvelope());
|
||||
dataModified = true;
|
||||
}
|
||||
if (dataRecs == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -257,53 +254,6 @@ public class D2DGridResource extends GridResource<GridResourceData> implements
|
|||
return data;
|
||||
}
|
||||
|
||||
protected GridGeometry2D calculateSubgrid(GridGeometry2D dataGeometry) {
|
||||
try {
|
||||
CoordinateReferenceSystem dataCRS = dataGeometry
|
||||
.getCoordinateReferenceSystem();
|
||||
org.opengis.geometry.Envelope descEnv = descriptor
|
||||
.getGridGeometry().getEnvelope();
|
||||
Envelope2D dataEnv = dataGeometry.getEnvelope2D();
|
||||
int dataWidth = dataGeometry.getGridRange2D().width;
|
||||
int dataHeight = dataGeometry.getGridRange2D().height;
|
||||
/*
|
||||
* Use grid spacing to determine a threshold for
|
||||
* EnvelopeIntersection. This guarantees the result is within one
|
||||
* grid cell.
|
||||
*/
|
||||
double dx = dataEnv.width / dataWidth;
|
||||
double dy = dataEnv.height / dataHeight;
|
||||
double threshold = Math.max(dx, dy);
|
||||
Geometry geom = EnvelopeIntersection.createEnvelopeIntersection(
|
||||
descEnv, dataEnv, threshold, dataWidth, dataHeight);
|
||||
/* Convert from jts envelope to geotools envelope. */
|
||||
Envelope env = geom.getEnvelopeInternal();
|
||||
Envelope2D subEnv = new Envelope2D(dataCRS, env.getMinX(),
|
||||
env.getMinY(), env.getWidth(), env.getHeight());
|
||||
GridEnvelope2D subRange = dataGeometry.worldToGrid(subEnv);
|
||||
/* Add a 1 pixel border so interpolation near the edges is nice */
|
||||
subRange.grow(1, 1);
|
||||
/* Make sure not to grow bigger than original grid. */
|
||||
subRange = new GridEnvelope2D(subRange.intersection(dataGeometry
|
||||
.getGridRange2D()));
|
||||
if (subRange.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return new GridGeometry2D(subRange, dataGeometry.getGridToCRS(),
|
||||
dataCRS);
|
||||
} catch (FactoryException e) {
|
||||
/* Not a big deal, just request all data. */
|
||||
statusHandler.handle(Priority.DEBUG, "Unable to request subgrid.",
|
||||
e);
|
||||
} catch (TransformException e) {
|
||||
/* Not a big deal, just request all data. */
|
||||
/* Java 7 multiple exception catches are going to be amazing! */
|
||||
statusHandler.handle(Priority.DEBUG, "Unable to request subgrid.",
|
||||
e);
|
||||
}
|
||||
return dataGeometry;
|
||||
}
|
||||
|
||||
public GeneralGridData reprojectData(GeneralGridData data) {
|
||||
if (descriptor == null) {
|
||||
return data;
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* 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.dataaccess.exception;
|
||||
|
||||
/**
|
||||
* An exception for when an IDataFactory cannot handle a request because the
|
||||
* requested envelope cannot be mapped onto available data. For example it is
|
||||
* valid for a factory to throw this exception if data in a mercator projection
|
||||
* is requested over the pole, which cannot be represented in mercator
|
||||
* projections.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------- -------- ----------- --------------------------
|
||||
* Feb 04, 2014 2672 bsteffen Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bsteffen
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class EnvelopeProjectionException extends DataAccessException {
|
||||
|
||||
private static final long serialVersionUID = 1;
|
||||
|
||||
public EnvelopeProjectionException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public EnvelopeProjectionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
|
@ -24,15 +24,23 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
import org.geotools.coverage.grid.GridGeometry2D;
|
||||
import org.geotools.geometry.jts.ReferencedEnvelope;
|
||||
import org.geotools.referencing.crs.DefaultGeographicCRS;
|
||||
import org.opengis.referencing.operation.TransformException;
|
||||
|
||||
import com.raytheon.uf.common.dataaccess.IDataRequest;
|
||||
import com.raytheon.uf.common.dataaccess.exception.DataRetrievalException;
|
||||
import com.raytheon.uf.common.dataaccess.exception.EnvelopeProjectionException;
|
||||
import com.raytheon.uf.common.dataaccess.grid.IGridData;
|
||||
import com.raytheon.uf.common.dataaccess.util.DataWrapperUtil;
|
||||
import com.raytheon.uf.common.dataaccess.util.PDOUtil;
|
||||
import com.raytheon.uf.common.dataplugin.PluginDataObject;
|
||||
import com.raytheon.uf.common.dataquery.responses.DbQueryResponse;
|
||||
import com.raytheon.uf.common.datastorage.Request;
|
||||
import com.raytheon.uf.common.datastorage.records.IDataRecord;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.data.DataSource;
|
||||
import com.raytheon.uf.common.geospatial.util.SubGridGeometryCalculator;
|
||||
import com.vividsolutions.jts.geom.Envelope;
|
||||
|
||||
/**
|
||||
* An abstract factory for getting grid data from plugins that use
|
||||
|
@ -42,12 +50,15 @@ import com.raytheon.uf.common.datastorage.records.IDataRecord;
|
|||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jan 17, 2013 bsteffen Initial creation
|
||||
* Feb 14, 2013 1614 bsteffen Refactor data access framework to use
|
||||
* single request.
|
||||
* Jan 14, 2014 2667 mnash Remove getGeometryData methods
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------- -------- ----------- -----------------------------------------
|
||||
* Jan 17, 2013 bsteffen Initial creation
|
||||
* Feb 14, 2013 1614 bsteffen Refactor data access framework to use
|
||||
* single request.
|
||||
* Jan 14, 2014 2667 mnash Remove getGeometryData methods
|
||||
* Feb 04, 2014 2672 bsteffen Enable subgridding when envelopes are
|
||||
* requested
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bsteffen
|
||||
|
@ -82,28 +93,86 @@ public abstract class AbstractGridDataPluginFactory extends
|
|||
|
||||
PluginDataObject pdo = (PluginDataObject) resultMap.get(null);
|
||||
|
||||
IDataRecord dataRecord = getDataRecord(pdo);
|
||||
|
||||
/*
|
||||
* Extract the grid geometry.
|
||||
*/
|
||||
GridGeometry2D gridGeometry = getGridGeometry(pdo);
|
||||
|
||||
IGridData defaultGridData = null;
|
||||
defaultGridData = this.constructGridDataResponse(request, pdo,
|
||||
gridGeometry, dataRecord);
|
||||
DataSource dataSource = null;
|
||||
|
||||
gridData.add(defaultGridData);
|
||||
Envelope envelope = request.getEnvelope();
|
||||
if (envelope != null) {
|
||||
ReferencedEnvelope requestEnv = new ReferencedEnvelope(
|
||||
envelope, DefaultGeographicCRS.WGS84);
|
||||
SubGridGeometryCalculator subGrid = calculateSubGrid(
|
||||
requestEnv, gridGeometry);
|
||||
if (subGrid == null || !subGrid.isEmpty()) {
|
||||
dataSource = getDataSource(pdo, subGrid);
|
||||
if (subGrid != null) {
|
||||
gridGeometry = subGrid.getZeroedSubGridGeometry();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dataSource = getDataSource(pdo, null);
|
||||
}
|
||||
|
||||
if (dataSource != null) {
|
||||
gridData.add(this.constructGridDataResponse(request, pdo,
|
||||
gridGeometry, dataSource));
|
||||
}
|
||||
}
|
||||
|
||||
return gridData.toArray(new IGridData[gridData.size()]);
|
||||
}
|
||||
|
||||
protected IDataRecord getDataRecord(PluginDataObject pdo) {
|
||||
/**
|
||||
* Generate a SubGridGeometryCalculator appropriate for determining what
|
||||
* area of data to request for this dataType. A return type of null can be
|
||||
* used to indicate the entire gridGeometry should be used.
|
||||
*
|
||||
* @param envelope
|
||||
* The requested envelope in WGS84
|
||||
* @param gridGeometry
|
||||
* The gridGeometry.
|
||||
* @return a SubGridGeometryCalculator.
|
||||
* @throws EnvelopeProjectionException
|
||||
*/
|
||||
protected SubGridGeometryCalculator calculateSubGrid(
|
||||
ReferencedEnvelope envelope, GridGeometry2D gridGeometry)
|
||||
throws EnvelopeProjectionException {
|
||||
try {
|
||||
return PDOUtil.getDataRecord(pdo, "Data", Request.ALL);
|
||||
return new SubGridGeometryCalculator(envelope, gridGeometry);
|
||||
} catch (TransformException e) {
|
||||
throw new EnvelopeProjectionException(
|
||||
"Error determining subgrid from envelope: " + envelope, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Request the raw data for a pdo.
|
||||
*
|
||||
* @param pdo
|
||||
* the pdo with metadata popualted
|
||||
* @param subGrid
|
||||
* object describing area requested.
|
||||
* @return a DataSource holding the raw data.
|
||||
*/
|
||||
protected DataSource getDataSource(PluginDataObject pdo,
|
||||
SubGridGeometryCalculator subGrid) {
|
||||
try {
|
||||
IDataRecord dataRecord = null;
|
||||
if (subGrid == null || subGrid.isFull()) {
|
||||
dataRecord = PDOUtil.getDataRecord(pdo, "Data", Request.ALL);
|
||||
} else if (!subGrid.isEmpty()) {
|
||||
Request dataStoreReq = Request.buildSlab(
|
||||
subGrid.getGridRangeLow(true),
|
||||
subGrid.getGridRangeHigh(false));
|
||||
dataRecord = PDOUtil.getDataRecord(pdo, "Data", dataStoreReq);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return DataWrapperUtil.constructArrayWrapper(dataRecord, false);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new DataRetrievalException(
|
||||
"Failed to retrieve the IDataRecord for PluginDataObject: "
|
||||
+ pdo.toString(), e);
|
||||
|
@ -129,6 +198,6 @@ public abstract class AbstractGridDataPluginFactory extends
|
|||
*/
|
||||
protected abstract IGridData constructGridDataResponse(
|
||||
IDataRequest request, PluginDataObject pdo,
|
||||
GridGeometry2D gridGeometry, IDataRecord dataRecord);
|
||||
GridGeometry2D gridGeometry, DataSource dataSource);
|
||||
|
||||
}
|
||||
|
|
|
@ -31,29 +31,28 @@ import com.raytheon.uf.common.dataaccess.exception.DataRetrievalException;
|
|||
import com.raytheon.uf.common.dataaccess.grid.IGridData;
|
||||
import com.raytheon.uf.common.dataaccess.impl.AbstractGridDataPluginFactory;
|
||||
import com.raytheon.uf.common.dataaccess.impl.DefaultGridData;
|
||||
import com.raytheon.uf.common.dataaccess.util.DataWrapperUtil;
|
||||
import com.raytheon.uf.common.dataplugin.PluginDataObject;
|
||||
import com.raytheon.uf.common.dataplugin.gfe.db.objects.GFERecord;
|
||||
import com.raytheon.uf.common.dataplugin.gfe.db.objects.GridLocation;
|
||||
import com.raytheon.uf.common.dataplugin.gfe.db.objects.GridParmInfo;
|
||||
import com.raytheon.uf.common.dataplugin.gfe.grid.Grid2DByte;
|
||||
import com.raytheon.uf.common.dataplugin.gfe.grid.Grid2DFloat;
|
||||
import com.raytheon.uf.common.dataplugin.gfe.grid.IGrid2D;
|
||||
import com.raytheon.uf.common.dataplugin.gfe.slice.DiscreteGridSlice;
|
||||
import com.raytheon.uf.common.dataplugin.gfe.slice.IGridSlice;
|
||||
import com.raytheon.uf.common.dataplugin.gfe.slice.ScalarGridSlice;
|
||||
import com.raytheon.uf.common.dataplugin.gfe.slice.WeatherGridSlice;
|
||||
import com.raytheon.uf.common.dataplugin.gfe.weather.WeatherKey;
|
||||
import com.raytheon.uf.common.dataplugin.level.Level;
|
||||
import com.raytheon.uf.common.dataplugin.level.MasterLevel;
|
||||
import com.raytheon.uf.common.dataquery.requests.DbQueryRequest;
|
||||
import com.raytheon.uf.common.dataquery.requests.RequestConstraint;
|
||||
import com.raytheon.uf.common.dataquery.requests.RequestConstraint.ConstraintType;
|
||||
import com.raytheon.uf.common.dataquery.responses.DbQueryResponse;
|
||||
import com.raytheon.uf.common.datastorage.records.ByteDataRecord;
|
||||
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.interpolation.data.ByteArrayWrapper;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.data.DataSource;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.data.FloatArrayWrapper;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.data.OffsetDataSource;
|
||||
import com.raytheon.uf.common.geospatial.util.SubGridGeometryCalculator;
|
||||
import com.raytheon.uf.common.util.StringUtil;
|
||||
|
||||
/**
|
||||
|
@ -64,15 +63,16 @@ import com.raytheon.uf.common.util.StringUtil;
|
|||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Feb 4, 2013 bsteffen Initial creation
|
||||
* Feb 14, 2013 1614 bsteffen Refactor data access framework to use
|
||||
* single request.
|
||||
* May 02, 2013 1949 bsteffen Update GFE data access in Product
|
||||
* Browser, Volume Browser, and Data Access
|
||||
* Framework.
|
||||
* 10/31/2013 2508 randerso Change to use DiscreteGridSlice.getKeys()
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------- -------- ----------- --------------------------
|
||||
* Feb 04, 2013 bsteffen Initial creation
|
||||
* Feb 14, 2013 1614 bsteffen Refactor data access framework to use
|
||||
* single request.
|
||||
* May 02, 2013 1949 bsteffen Update GFE data access in Product
|
||||
* Browser, Volume Browser, and Data Access
|
||||
* Framework.
|
||||
* Oct 31, 2013 2508 randerso Change to use DiscreteGridSlice.getKeys()
|
||||
* Feb 04, 2014 2672 bsteffen Enable requesting subgrids.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -104,11 +104,10 @@ public class GFEGridFactory extends AbstractGridDataPluginFactory implements
|
|||
@Override
|
||||
protected IGridData constructGridDataResponse(IDataRequest request,
|
||||
PluginDataObject pdo, GridGeometry2D gridGeometry,
|
||||
IDataRecord dataRecord) {
|
||||
DataSource dataSource) {
|
||||
GFERecord gfeRecord = asGFERecord(pdo);
|
||||
|
||||
DefaultGridData defaultGridData = new DefaultGridData(
|
||||
DataWrapperUtil.constructArrayWrapper(dataRecord, false),
|
||||
DefaultGridData defaultGridData = new DefaultGridData(dataSource,
|
||||
gridGeometry);
|
||||
defaultGridData.setDataTime(pdo.getDataTime());
|
||||
defaultGridData.setParameter(gfeRecord.getParmName());
|
||||
|
@ -121,9 +120,10 @@ public class GFEGridFactory extends AbstractGridDataPluginFactory implements
|
|||
attrs.put(MODEL_NAME, gfeRecord.getDbId().getModelName());
|
||||
attrs.put(MODEL_TIME, gfeRecord.getDbId().getModelTime());
|
||||
attrs.put(SITE_ID, gfeRecord.getDbId().getSiteId());
|
||||
if (dataRecord.getDataAttributes().containsKey(KEYS)) {
|
||||
attrs.put(KEYS, StringUtil.join((String[]) dataRecord
|
||||
.getDataAttributes().get(KEYS), ','));
|
||||
|
||||
Object messageData = gfeRecord.getMessageData();
|
||||
if (messageData instanceof Object[]) {
|
||||
attrs.put(KEYS, StringUtil.join((Object[]) messageData, ','));
|
||||
}
|
||||
defaultGridData.setAttributes(attrs);
|
||||
|
||||
|
@ -203,58 +203,49 @@ public class GFEGridFactory extends AbstractGridDataPluginFactory implements
|
|||
}
|
||||
|
||||
@Override
|
||||
protected IDataRecord getDataRecord(PluginDataObject pdo) {
|
||||
protected DataSource getDataSource(PluginDataObject pdo,
|
||||
SubGridGeometryCalculator subGrid) {
|
||||
GFERecord gfeRecord = asGFERecord(pdo);
|
||||
|
||||
IGridSlice slice = null;
|
||||
try {
|
||||
IGridSlice slice = GFEDataAccessUtil.getSlice(gfeRecord);
|
||||
GridLocation loc = slice.getGridInfo().getGridLoc();
|
||||
gfeRecord.setGridInfo(slice.getGridInfo());
|
||||
IGrid2D data = null;
|
||||
Map<String, Object> attrs = new HashMap<String, Object>();
|
||||
if (slice instanceof ScalarGridSlice) {
|
||||
// This also grabs vector data.
|
||||
data = ((ScalarGridSlice) slice).getScalarGrid();
|
||||
return new FloatDataRecord("Data", gfeRecord.getDataURI(),
|
||||
((Grid2DFloat) data).getFloats(), 2, new long[] {
|
||||
loc.getNx(), loc.getNy() });
|
||||
} else if (slice instanceof DiscreteGridSlice) {
|
||||
DiscreteGridSlice castedSlice = (DiscreteGridSlice) slice;
|
||||
data = castedSlice.getDiscreteGrid();
|
||||
Object[] dKeys = castedSlice.getKeys();
|
||||
String[] keys = new String[dKeys.length];
|
||||
for (int i = 0; i < dKeys.length; i++) {
|
||||
keys[i] = dKeys[i].toString();
|
||||
}
|
||||
byte[] bytes = ((Grid2DByte) data).getBytes();
|
||||
ByteDataRecord record = new ByteDataRecord("Data",
|
||||
gfeRecord.getDataURI(), bytes, 2, new long[] {
|
||||
loc.getNx(), loc.getNy() });
|
||||
attrs.put(KEYS, keys);
|
||||
record.setDataAttributes(attrs);
|
||||
return record;
|
||||
} else if (slice instanceof WeatherGridSlice) {
|
||||
WeatherGridSlice castedSlice = (WeatherGridSlice) slice;
|
||||
data = castedSlice.getWeatherGrid();
|
||||
WeatherKey[] wKeys = castedSlice.getKeys();
|
||||
String[] keys = new String[wKeys.length];
|
||||
for (int i = 0; i < wKeys.length; i++) {
|
||||
keys[i] = wKeys[i].toString();
|
||||
}
|
||||
byte[] bytes = ((Grid2DByte) data).getBytes();
|
||||
ByteDataRecord record = new ByteDataRecord("Data",
|
||||
gfeRecord.getDataURI(), bytes, 2, new long[] {
|
||||
loc.getNx(), loc.getNy() });
|
||||
attrs.put(KEYS, keys);
|
||||
record.setDataAttributes(attrs);
|
||||
return record;
|
||||
} else {
|
||||
throw new DataRetrievalException("Unknown slice of type "
|
||||
+ slice.getClass().getSimpleName());
|
||||
}
|
||||
slice = GFEDataAccessUtil.getSlice(gfeRecord);
|
||||
} catch (Exception e) {
|
||||
throw new DataRetrievalException(e);
|
||||
}
|
||||
GridParmInfo info = slice.getGridInfo();
|
||||
GridLocation loc = info.getGridLoc();
|
||||
gfeRecord.setGridInfo(slice.getGridInfo());
|
||||
DataSource dataSource = null;
|
||||
Object[] keys = null;
|
||||
if (slice instanceof ScalarGridSlice) {
|
||||
// This also grabs vector data.
|
||||
Grid2DFloat data = ((ScalarGridSlice) slice).getScalarGrid();
|
||||
dataSource = new FloatArrayWrapper(data.getFloats(), loc.getNx(),
|
||||
loc.getNy());
|
||||
} else if (slice instanceof DiscreteGridSlice) {
|
||||
DiscreteGridSlice discreteSlice = (DiscreteGridSlice) slice;
|
||||
Grid2DByte data = discreteSlice.getDiscreteGrid();
|
||||
keys = discreteSlice.getKeys();
|
||||
dataSource = new ByteArrayWrapper(data.getBytes(), loc.getNx(),
|
||||
loc.getNy());
|
||||
} else if (slice instanceof WeatherGridSlice) {
|
||||
WeatherGridSlice weatherSlice = (WeatherGridSlice) slice;
|
||||
Grid2DByte data = weatherSlice.getWeatherGrid();
|
||||
keys = weatherSlice.getKeys();
|
||||
dataSource = new ByteArrayWrapper(data.getBytes(), loc.getNx(),
|
||||
loc.getNy());
|
||||
} else {
|
||||
throw new DataRetrievalException("Unknown slice of type "
|
||||
+ slice.getClass().getSimpleName());
|
||||
}
|
||||
if (subGrid != null && !subGrid.isFull()) {
|
||||
int[] offsets = subGrid.getGridRangeLow(true);
|
||||
dataSource = new OffsetDataSource(dataSource, offsets[0],
|
||||
offsets[1]);
|
||||
}
|
||||
gfeRecord.setMessageData(keys);
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -38,7 +38,6 @@ import com.raytheon.uf.common.dataaccess.exception.DataRetrievalException;
|
|||
import com.raytheon.uf.common.dataaccess.grid.IGridData;
|
||||
import com.raytheon.uf.common.dataaccess.impl.AbstractGridDataPluginFactory;
|
||||
import com.raytheon.uf.common.dataaccess.impl.DefaultGridData;
|
||||
import com.raytheon.uf.common.dataaccess.util.DataWrapperUtil;
|
||||
import com.raytheon.uf.common.dataplugin.PluginDataObject;
|
||||
import com.raytheon.uf.common.dataplugin.grid.GridConstants;
|
||||
import com.raytheon.uf.common.dataplugin.grid.GridRecord;
|
||||
|
@ -48,7 +47,7 @@ import com.raytheon.uf.common.dataplugin.level.Level;
|
|||
import com.raytheon.uf.common.dataplugin.level.mapping.LevelMapper;
|
||||
import com.raytheon.uf.common.dataquery.requests.RequestConstraint;
|
||||
import com.raytheon.uf.common.dataquery.requests.RequestConstraint.ConstraintType;
|
||||
import com.raytheon.uf.common.datastorage.records.IDataRecord;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.data.DataSource;
|
||||
import com.raytheon.uf.common.parameter.mapping.ParameterMapper;
|
||||
import com.raytheon.uf.common.util.mapping.Mapper;
|
||||
|
||||
|
@ -59,11 +58,13 @@ import com.raytheon.uf.common.util.mapping.Mapper;
|
|||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jan 17, 2013 bsteffen Initial creation
|
||||
* Feb 14, 2013 1614 bsteffen Refactor data access framework to use
|
||||
* single request.
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------- -------- ----------- --------------------------
|
||||
* Jan 17, 2013 bsteffen Initial creation
|
||||
* Feb 14, 2013 1614 bsteffen Refactor data access framework to use
|
||||
* single request.
|
||||
* Feb 04, 2014 2672 bsteffen Enable requesting subgrids.
|
||||
*
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -187,7 +188,7 @@ public class GridDataAccessFactory extends AbstractGridDataPluginFactory
|
|||
@Override
|
||||
protected IGridData constructGridDataResponse(IDataRequest request,
|
||||
PluginDataObject pdo, GridGeometry2D gridGeometry,
|
||||
IDataRecord dataRecord) {
|
||||
DataSource dataSource) {
|
||||
if (pdo instanceof GridRecord == false) {
|
||||
throw new DataRetrievalException(this.getClass().getSimpleName()
|
||||
+ " cannot handle " + pdo.getClass().getSimpleName());
|
||||
|
@ -210,8 +211,8 @@ public class GridDataAccessFactory extends AbstractGridDataPluginFactory
|
|||
parameter, namespace, requestParameters);
|
||||
|
||||
if (identifiers.containsKey(GridConstants.DATASET_ID)) {
|
||||
List<String> requestedDatasets = Arrays.asList(identifiers.get(GridConstants.DATASET_ID)
|
||||
.toString());
|
||||
List<String> requestedDatasets = Arrays.asList(identifiers.get(
|
||||
GridConstants.DATASET_ID).toString());
|
||||
datasetId = reverseResolveMapping(
|
||||
DatasetIdMapper.getInstance(), datasetId, namespace,
|
||||
requestedDatasets);
|
||||
|
@ -243,8 +244,8 @@ public class GridDataAccessFactory extends AbstractGridDataPluginFactory
|
|||
}
|
||||
}
|
||||
|
||||
DefaultGridData defaultGridData = new DefaultGridData(
|
||||
DataWrapperUtil.constructArrayWrapper(dataRecord), gridGeometry);
|
||||
DefaultGridData defaultGridData = new DefaultGridData(dataSource,
|
||||
gridGeometry);
|
||||
defaultGridData.setDataTime(pdo.getDataTime());
|
||||
defaultGridData.setParameter(parameter);
|
||||
defaultGridData.setLevel(level);
|
||||
|
|
|
@ -28,21 +28,21 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
|
||||
import org.geotools.coverage.grid.GridGeometry2D;
|
||||
import org.geotools.geometry.jts.ReferencedEnvelope;
|
||||
import org.opengis.referencing.FactoryException;
|
||||
|
||||
import com.raytheon.uf.common.dataaccess.IDataFactory;
|
||||
import com.raytheon.uf.common.dataaccess.IDataRequest;
|
||||
import com.raytheon.uf.common.dataaccess.exception.DataRetrievalException;
|
||||
import com.raytheon.uf.common.dataaccess.exception.EnvelopeProjectionException;
|
||||
import com.raytheon.uf.common.dataaccess.grid.IGridData;
|
||||
import com.raytheon.uf.common.dataaccess.impl.AbstractGridDataPluginFactory;
|
||||
import com.raytheon.uf.common.dataaccess.impl.DefaultGridData;
|
||||
import com.raytheon.uf.common.dataaccess.util.DataWrapperUtil;
|
||||
import com.raytheon.uf.common.dataaccess.util.PDOUtil;
|
||||
import com.raytheon.uf.common.dataplugin.PluginDataObject;
|
||||
import com.raytheon.uf.common.dataplugin.level.Level;
|
||||
import com.raytheon.uf.common.dataplugin.level.MasterLevel;
|
||||
import com.raytheon.uf.common.dataplugin.radar.RadarRecord;
|
||||
import com.raytheon.uf.common.dataplugin.radar.RadarStoredData;
|
||||
import com.raytheon.uf.common.dataplugin.radar.projection.RadarProjectionFactory;
|
||||
import com.raytheon.uf.common.dataplugin.radar.util.RadarDataRetriever;
|
||||
import com.raytheon.uf.common.dataplugin.radar.util.RadarInfo;
|
||||
|
@ -50,27 +50,35 @@ import com.raytheon.uf.common.dataplugin.radar.util.RadarInfoDict;
|
|||
import com.raytheon.uf.common.dataplugin.radar.util.RadarUtil;
|
||||
import com.raytheon.uf.common.dataquery.requests.RequestConstraint;
|
||||
import com.raytheon.uf.common.dataquery.requests.RequestConstraint.ConstraintType;
|
||||
import com.raytheon.uf.common.datastorage.records.ByteDataRecord;
|
||||
import com.raytheon.uf.common.datastorage.records.IDataRecord;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.data.ByteArrayWrapper;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.data.DataSource;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.data.DataWrapper1D;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.data.ShortArrayWrapper;
|
||||
import com.raytheon.uf.common.geospatial.util.SubGridGeometryCalculator;
|
||||
import com.raytheon.uf.common.localization.PathManagerFactory;
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
import com.vividsolutions.jts.geom.Envelope;
|
||||
|
||||
/**
|
||||
*
|
||||
* A data factory for getting radar data from the metadata database. There are
|
||||
* currently not any required identifiers.
|
||||
*
|
||||
* Radar does not return subgrids for request envelopes like other gridded
|
||||
* types. Instead data for only icaos within the request envelope are returned
|
||||
* and all data for the product is used. This is done because subgridding radial
|
||||
* products is complex and this is not often what a caller actually wants.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jan 23, 2013 bsteffen Initial creation
|
||||
* Feb 14, 2013 1614 bsteffen Refactor data access framework to use
|
||||
* single request.
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------- -------- ----------- --------------------------
|
||||
* Jan 23, 2013 bsteffen Initial creation
|
||||
* Feb 14, 2013 1614 bsteffen Refactor data access framework to use
|
||||
* single request.
|
||||
* Feb 04, 2014 2672 bsteffen Enable requesting icaos within envelope.
|
||||
*
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -86,6 +94,10 @@ public class RadarGridFactory extends AbstractGridDataPluginFactory implements
|
|||
|
||||
private static final String ICAO = "icao";
|
||||
|
||||
private static final String LONGITUDE = "longitude";
|
||||
|
||||
private static final String LATITUDE = "latitude";
|
||||
|
||||
private static final String FORMAT = "format";
|
||||
|
||||
private static final String RADIAL_FORMAT = "Radial";
|
||||
|
@ -106,19 +118,9 @@ public class RadarGridFactory extends AbstractGridDataPluginFactory implements
|
|||
@Override
|
||||
protected IGridData constructGridDataResponse(IDataRequest request,
|
||||
PluginDataObject pdo, GridGeometry2D gridGeometry,
|
||||
IDataRecord dataRecord) {
|
||||
DataSource dataSource) {
|
||||
RadarRecord radarRecord = asRadarRecord(pdo);
|
||||
DataWrapper1D wrapper = DataWrapperUtil.constructArrayWrapper(
|
||||
dataRecord, false);
|
||||
wrapper.setFillValue(0);
|
||||
DataSource source = wrapper;
|
||||
if (radarRecord.getFormat().equals(RADIAL_FORMAT)) {
|
||||
// The raw data is in bin,radial format but the grid geometries we
|
||||
// use are radial,bin so need to do some swapping.
|
||||
source = new AxisSwapDataSource(source, radarRecord.getNumBins());
|
||||
|
||||
}
|
||||
DefaultGridData defaultGridData = new DefaultGridData(source,
|
||||
DefaultGridData defaultGridData = new DefaultGridData(dataSource,
|
||||
gridGeometry);
|
||||
defaultGridData.setDataTime(pdo.getDataTime());
|
||||
// reverse map parameter to match request.
|
||||
|
@ -161,14 +163,20 @@ public class RadarGridFactory extends AbstractGridDataPluginFactory implements
|
|||
RadarRecord radarRecord = asRadarRecord(pdo);
|
||||
if (radarRecord.getFormat().equals(RADIAL_FORMAT)) {
|
||||
try {
|
||||
float[] angleData = radarRecord.getAngleData();
|
||||
if (angleData == null) {
|
||||
populateRecord(radarRecord);
|
||||
angleData = radarRecord.getAngleData();
|
||||
}
|
||||
|
||||
// NOTE: do not set swapXY=true even though it matches the raw
|
||||
// data better because there is lots of code, especially on the
|
||||
// Viz side that does not correctly handle the resulting
|
||||
// GridGeometry.
|
||||
return RadarProjectionFactory.constructGridGeometry(
|
||||
new Coordinate(radarRecord.getLongitude(), radarRecord
|
||||
.getLatitude()), radarRecord.getAngleData(),
|
||||
radarRecord.getGateResolution(), radarRecord
|
||||
.getLatitude()), angleData, radarRecord
|
||||
.getGateResolution(), radarRecord
|
||||
.getTrueElevationAngle(), radarRecord
|
||||
.getNumBins(), false);
|
||||
} catch (FactoryException e) {
|
||||
|
@ -188,19 +196,82 @@ public class RadarGridFactory extends AbstractGridDataPluginFactory implements
|
|||
}
|
||||
|
||||
@Override
|
||||
protected IDataRecord getDataRecord(PluginDataObject pdo) {
|
||||
protected SubGridGeometryCalculator calculateSubGrid(
|
||||
ReferencedEnvelope envelope, GridGeometry2D gridGeometry)
|
||||
throws EnvelopeProjectionException {
|
||||
/*
|
||||
* The SubGridGeometryCalculator cannot accurately calculate subgrids
|
||||
* into RadialBin projections. For this factory the request envelope is
|
||||
* only used to limit the sites, not to subgrid. Returning null causes
|
||||
* the super class to request a full grid.
|
||||
*/
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DataSource getDataSource(PluginDataObject pdo,
|
||||
SubGridGeometryCalculator subGrid) {
|
||||
RadarRecord radarRecord = asRadarRecord(pdo);
|
||||
DataSource dataSource = getDataSource(radarRecord);
|
||||
if (dataSource == null) {
|
||||
/*
|
||||
* Radial data prepopulates the record to get the gridGeometry but
|
||||
* raster data waits until now.
|
||||
*/
|
||||
populateRecord(radarRecord);
|
||||
dataSource = getDataSource(radarRecord);
|
||||
if (dataSource == null) {
|
||||
throw new DataRetrievalException("No grid data found for "
|
||||
+ radarRecord);
|
||||
}
|
||||
}
|
||||
if (radarRecord.getFormat().equals(RADIAL_FORMAT)) {
|
||||
/*
|
||||
* The raw data is in bin,radial format but the grid geometries we
|
||||
* use are radial,bin so need to do some swapping.
|
||||
*/
|
||||
dataSource = new AxisSwapDataSource(dataSource,
|
||||
radarRecord.getNumBins());
|
||||
}
|
||||
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate a DataSource from the raw data(byte or short) in the provided
|
||||
* record.
|
||||
*
|
||||
* @param radarRecord
|
||||
* @return a DataSource or null if the record is not populated or has no
|
||||
* grid data.
|
||||
*/
|
||||
private DataSource getDataSource(RadarRecord radarRecord) {
|
||||
int nx = radarRecord.getNumBins();
|
||||
int ny = radarRecord.getNumRadials();
|
||||
byte[] bytes = radarRecord.getRawData();
|
||||
if (bytes != null) {
|
||||
ByteArrayWrapper wrapper = new ByteArrayWrapper(bytes, nx, ny);
|
||||
wrapper.setFillValue(0);
|
||||
return wrapper;
|
||||
}
|
||||
short[] shorts = radarRecord.getRawShortData();
|
||||
if (shorts != null) {
|
||||
ShortArrayWrapper wrapper = new ShortArrayWrapper(shorts, nx, ny);
|
||||
wrapper.setFillValue(0);
|
||||
return wrapper;
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
protected void populateRecord(RadarRecord radarRecord)
|
||||
throws DataRetrievalException {
|
||||
try {
|
||||
RadarDataRetriever.populateRadarRecord(PDOUtil.getDataStore(pdo),
|
||||
radarRecord);
|
||||
RadarDataRetriever.populateRadarRecord(
|
||||
PDOUtil.getDataStore(radarRecord), radarRecord);
|
||||
} catch (Exception e) {
|
||||
throw new DataRetrievalException(e);
|
||||
}
|
||||
IDataRecord rec = new ByteDataRecord(RadarStoredData.RAW_DATA_ID,
|
||||
radarRecord.getDataURI(), radarRecord.getRawData(), 2,
|
||||
new long[] { radarRecord.getNumBins(),
|
||||
radarRecord.getNumRadials() });
|
||||
return rec;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -236,6 +307,17 @@ public class RadarGridFactory extends AbstractGridDataPluginFactory implements
|
|||
constraints.put(ICAO, icaoConstraint);
|
||||
}
|
||||
|
||||
if (request.getEnvelope() != null) {
|
||||
Envelope envelope = request.getEnvelope();
|
||||
|
||||
String minLon = Double.toString(envelope.getMinX());
|
||||
String maxLon = Double.toString(envelope.getMaxX());
|
||||
constraints.put(LONGITUDE, new RequestConstraint(minLon, maxLon));
|
||||
String minLat = Double.toString(envelope.getMinY());
|
||||
String maxLat = Double.toString(envelope.getMaxY());
|
||||
constraints.put(LATITUDE, new RequestConstraint(minLat, maxLat));
|
||||
}
|
||||
|
||||
Map<String, Object> identifiers = request.getIdentifiers();
|
||||
if (identifiers != null && identifiers.containsKey(ICAO)) {
|
||||
constraints.put(ICAO, new RequestConstraint(identifiers.get(ICAO)
|
||||
|
@ -315,7 +397,7 @@ public class RadarGridFactory extends AbstractGridDataPluginFactory implements
|
|||
* ------------ ---------- ----------- --------------------------
|
||||
* Jan 25, 2013 bsteffen Initial creation
|
||||
* Feb 14, 2013 1614 bsteffen refactor data access framework to use
|
||||
* single request.
|
||||
* single request.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
|
|
@ -47,9 +47,11 @@ import org.opengis.referencing.operation.MathTransform;
|
|||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jun 6, 2012 bsteffen Initial creation
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------- -------- ----------- -----------------------------------------
|
||||
* Jun 06, 2012 bsteffen Initial creation
|
||||
* Feb 08, 2012 2672 bsteffen Fix projection of points between the last
|
||||
* and first radial.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -99,6 +101,11 @@ public class RadialBinMapProjection extends AzimuthRangeMapProjection {
|
|||
int nextRadial = (int) Math.ceil(radial) % normalAngleData.length;
|
||||
float prevAngle = normalAngleData[prevRadial];
|
||||
float nextAngle = normalAngleData[nextRadial];
|
||||
if (nextAngle + 180 < prevAngle) {
|
||||
nextAngle += 360;
|
||||
} else if (nextAngle - 180 > prevAngle) {
|
||||
nextAngle -= 360;
|
||||
}
|
||||
double az = prevAngle + (radial - prevRadial) * (nextAngle - prevAngle);
|
||||
return super.inverseTransformNormalized(az, ran, dest);
|
||||
}
|
||||
|
|
|
@ -35,13 +35,12 @@ import com.raytheon.uf.common.dataaccess.IDataRequest;
|
|||
import com.raytheon.uf.common.dataaccess.exception.DataRetrievalException;
|
||||
import com.raytheon.uf.common.dataaccess.impl.AbstractGridDataPluginFactory;
|
||||
import com.raytheon.uf.common.dataaccess.impl.DefaultGridData;
|
||||
import com.raytheon.uf.common.dataaccess.util.DataWrapperUtil;
|
||||
import com.raytheon.uf.common.dataplugin.PluginDataObject;
|
||||
import com.raytheon.uf.common.dataplugin.satellite.SatelliteRecord;
|
||||
import com.raytheon.uf.common.dataplugin.satellite.units.SatelliteUnits;
|
||||
import com.raytheon.uf.common.dataquery.requests.RequestConstraint;
|
||||
import com.raytheon.uf.common.dataquery.requests.RequestConstraint.ConstraintType;
|
||||
import com.raytheon.uf.common.datastorage.records.IDataRecord;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.data.DataSource;
|
||||
|
||||
/**
|
||||
* A data factory for getting satellite data from the metadata database. There
|
||||
|
@ -51,12 +50,13 @@ import com.raytheon.uf.common.datastorage.records.IDataRecord;
|
|||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jan 02, 2012 bkowal Initial creation
|
||||
* Jan 22, 2012 bsteffen Extract common functionality to AbstractGridDataPluginFactory
|
||||
* Feb 14, 2013 1614 bsteffen Refactor data access framework to use
|
||||
* single request.
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------- -------- ----------- --------------------------
|
||||
* Jan 02, 2012 bkowal Initial creation
|
||||
* Jan 22, 2012 bsteffen Extract common functionality to AbstractGridDataPluginFactory
|
||||
* Feb 14, 2013 1614 bsteffen Refactor data access framework to use
|
||||
* single request.
|
||||
* Feb 04, 2014 2672 bsteffen Enable requesting subgrids.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -84,15 +84,14 @@ public class SatelliteGridFactory extends AbstractGridDataPluginFactory
|
|||
|
||||
protected DefaultGridData constructGridDataResponse(IDataRequest request,
|
||||
PluginDataObject pdo, GridGeometry2D gridGeometry,
|
||||
IDataRecord dataRecord) {
|
||||
DataSource dataSource) {
|
||||
if(pdo instanceof SatelliteRecord == false){
|
||||
throw new DataRetrievalException(this.getClass().getSimpleName()
|
||||
+ " cannot handle " + pdo.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
SatelliteRecord satelliteRecord = (SatelliteRecord) pdo;
|
||||
DefaultGridData defaultGridData = new DefaultGridData(
|
||||
DataWrapperUtil.constructArrayWrapper(dataRecord, false),
|
||||
DefaultGridData defaultGridData = new DefaultGridData(dataSource,
|
||||
gridGeometry);
|
||||
defaultGridData.setDataTime(pdo.getDataTime());
|
||||
defaultGridData.setParameter(satelliteRecord.getPhysicalElement());
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
* 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.geospatial.interpolation.data;
|
||||
|
||||
/**
|
||||
* DataSource which wraps another DataSource but offsets the coordinates by
|
||||
* constant values. This can be useful for generating a DataSource that
|
||||
* represents a subgrid of a full grid where the subgrid should be zero indexed.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------- -------- ----------- --------------------------
|
||||
* Feb 04, 2014 2672 bsteffen Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bsteffen
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class OffsetDataSource implements DataSource {
|
||||
|
||||
protected final DataSource wrappedSource;
|
||||
|
||||
protected final int xOffset;
|
||||
|
||||
protected final int yOffset;
|
||||
|
||||
public OffsetDataSource(DataSource wrappedSource, int xOffset, int yOffset) {
|
||||
this.wrappedSource = wrappedSource;
|
||||
this.xOffset = xOffset;
|
||||
this.yOffset = yOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDataValue(int x, int y) {
|
||||
return wrappedSource.getDataValue(xOffset + x, yOffset + y);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,213 @@
|
|||
/**
|
||||
* 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.geospatial.util;
|
||||
|
||||
import org.geotools.coverage.grid.GridEnvelope2D;
|
||||
import org.geotools.coverage.grid.GridGeometry2D;
|
||||
import org.geotools.geometry.Envelope2D;
|
||||
import org.opengis.coverage.grid.GridEnvelope;
|
||||
import org.opengis.coverage.grid.GridGeometry;
|
||||
import org.opengis.geometry.Envelope;
|
||||
import org.opengis.referencing.FactoryException;
|
||||
import org.opengis.referencing.crs.CoordinateReferenceSystem;
|
||||
import org.opengis.referencing.operation.TransformException;
|
||||
|
||||
import com.vividsolutions.jts.geom.Geometry;
|
||||
|
||||
/**
|
||||
* Calculates a portion of a grid geometry that overlaps an envelope in a
|
||||
* different projection. Provides convienence methods for accessing versions of
|
||||
* the GridGeometry and range that are easier to use.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------- -------- ----------- --------------------------
|
||||
* Feb 04, 2014 2672 bsteffen Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bsteffen
|
||||
* @version 1.0
|
||||
*/
|
||||
public class SubGridGeometryCalculator {
|
||||
|
||||
private final Envelope envelope;
|
||||
|
||||
private final GridGeometry gridGeometry;
|
||||
|
||||
private final GridGeometry subGridGeometry;
|
||||
|
||||
/**
|
||||
* Create a new SubGridGeometryCalculator.
|
||||
*
|
||||
* @param envelope
|
||||
* The area which should be included in the subgrid, all grid
|
||||
* points within this area will be included. Grid points outside
|
||||
* the envelope will be included only if they are needed to keep
|
||||
* the grid evenly spaced(for example when the difference in CRS
|
||||
* has significant warping.)
|
||||
* @param gridGeometry
|
||||
* The full grid geometry for which a subgrid is needed. The
|
||||
* subgrid will be defined in the same grid space as this
|
||||
* geometry.
|
||||
* @throws TransformException
|
||||
* If something goes wrong mapping the envelope crs onto the
|
||||
* grid geometry crs.
|
||||
*/
|
||||
public SubGridGeometryCalculator(Envelope envelope, GridGeometry gridGeometry)
|
||||
throws TransformException {
|
||||
this.envelope = envelope;
|
||||
this.gridGeometry = gridGeometry;
|
||||
this.subGridGeometry = calculate(envelope, gridGeometry);
|
||||
}
|
||||
|
||||
protected static GridGeometry calculate(Envelope envelope,
|
||||
GridGeometry gridGeometry) throws TransformException {
|
||||
GridGeometry2D gg2D = GridGeometry2D.wrap(gridGeometry);
|
||||
CoordinateReferenceSystem gridCRS = gg2D.getCoordinateReferenceSystem();
|
||||
GridEnvelope2D gridRange = gg2D.getGridRange2D();
|
||||
Envelope2D gridEnv = gg2D.getEnvelope2D();
|
||||
int gridWidth = gridRange.width;
|
||||
int gridHeight = gridRange.height;
|
||||
/*
|
||||
* Use grid spacing to determine a threshold for EnvelopeIntersection.
|
||||
* This guarantees the result is within one grid cell.
|
||||
*/
|
||||
double dx = gridEnv.width / gridWidth;
|
||||
double dy = gridEnv.height / gridHeight;
|
||||
double threshold = Math.max(dx, dy);
|
||||
Geometry geom = null;
|
||||
try {
|
||||
geom = EnvelopeIntersection.createEnvelopeIntersection(envelope,
|
||||
gridEnv, threshold, gridWidth, gridHeight);
|
||||
} catch (FactoryException e) {
|
||||
throw new TransformException("Error initializing transforms.", e);
|
||||
}
|
||||
/* Convert from jts envelope to geotools envelope. */
|
||||
com.vividsolutions.jts.geom.Envelope env = geom.getEnvelopeInternal();
|
||||
Envelope2D subEnv = new Envelope2D(gridCRS, env.getMinX(),
|
||||
env.getMinY(), env.getWidth(), env.getHeight());
|
||||
GridEnvelope2D subRange = gg2D.worldToGrid(subEnv);
|
||||
/* Add a 1 pixel border so interpolation near the edges is nice */
|
||||
subRange.grow(1, 1);
|
||||
/* Make sure not to grow bigger than original grid. */
|
||||
subRange = new GridEnvelope2D(subRange.intersection(gridRange));
|
||||
if (subRange.equals(gridRange)) {
|
||||
return gridGeometry;
|
||||
}
|
||||
return new GridGeometry2D(subRange, gridGeometry.getGridToCRS(),
|
||||
gridCRS);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The original envelope used to create this calculator.
|
||||
*/
|
||||
public Envelope getEnvelope() {
|
||||
return envelope;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The original grid geometry used to create this calculator.
|
||||
*/
|
||||
public GridGeometry getGridGeometry() {
|
||||
return gridGeometry;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The grid geometry describing the overlapping portion. The range
|
||||
* of the geometry will have values that line up with the source
|
||||
* geometry.
|
||||
*/
|
||||
public GridGeometry getSubGridGeometry() {
|
||||
return subGridGeometry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts/Casts the sub grid geometry to a {@link GridGeometry2D}
|
||||
*
|
||||
* @see #getSubGridGeometry()
|
||||
*/
|
||||
public GridGeometry2D getSubGridGeometry2D() {
|
||||
return GridGeometry2D.wrap(subGridGeometry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new grid geometry describing the subgrid area with the minimum
|
||||
* values of the range set to 0. This type of geometry does not have
|
||||
* information about the range but is often more compatible with certain
|
||||
* code that assumes 0 minimum ranges.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public GridGeometry2D getZeroedSubGridGeometry() {
|
||||
GridGeometry2D subGridGeometry = getSubGridGeometry2D();
|
||||
GridEnvelope2D subGridRange = subGridGeometry.getGridRange2D();
|
||||
subGridRange.x = 0;
|
||||
subGridRange.y = 0;
|
||||
return new GridGeometry2D(subGridRange, subGridGeometry.getEnvelope());
|
||||
}
|
||||
|
||||
public int[] getGridRangeLow(boolean inclusive) {
|
||||
int[] low = subGridGeometry.getGridRange().getLow()
|
||||
.getCoordinateValues();
|
||||
if (!inclusive) {
|
||||
for (int i = 0; i < low.length; i += 1) {
|
||||
low[i] -= 1;
|
||||
}
|
||||
}
|
||||
return low;
|
||||
}
|
||||
|
||||
public int[] getGridRangeHigh(boolean inclusive) {
|
||||
int[] high = subGridGeometry.getGridRange().getHigh()
|
||||
.getCoordinateValues();
|
||||
if (!inclusive) {
|
||||
for (int i = 0; i < high.length; i += 1) {
|
||||
high[i] += 1;
|
||||
}
|
||||
}
|
||||
return high;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the envelope does not intersect the grid geometry.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
GridEnvelope range = subGridGeometry.getGridRange();
|
||||
for (int i = 0; i < range.getDimension(); i += 1) {
|
||||
if (range.getSpan(i) <= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the envelope intersects the entire grid geometry.
|
||||
*/
|
||||
public boolean isFull() {
|
||||
return subGridGeometry == gridGeometry;
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Reference in a new issue