Issue #2185 Cache computed grid reprojections.
Former-commit-id: 891f2241dd238b2901f8c1daee8f2236558f42e0
This commit is contained in:
parent
08a90aa293
commit
ae8110acf6
5 changed files with 173 additions and 94 deletions
|
@ -20,13 +20,8 @@
|
|||
package com.raytheon.uf.viz.kml.export.graphics.ext;
|
||||
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.collections.keyvalue.MultiKey;
|
||||
import org.eclipse.swt.graphics.RGB;
|
||||
import org.geotools.coverage.grid.GridEnvelope2D;
|
||||
import org.geotools.coverage.grid.GridGeometry2D;
|
||||
|
@ -41,6 +36,7 @@ import com.raytheon.uf.common.geospatial.interpolation.BilinearInterpolation;
|
|||
import com.raytheon.uf.common.geospatial.interpolation.GridReprojection;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.Interpolation;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.NearestNeighborInterpolation;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.PrecomputedGridReprojection;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.data.DataSource;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.data.FloatArrayWrapper;
|
||||
import com.raytheon.uf.viz.core.DrawableImage;
|
||||
|
@ -63,6 +59,7 @@ import de.micromata.opengis.kml.v_2_2_0.LatLonBox;
|
|||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jun 14, 2012 bsteffen Initial creation
|
||||
* Jul 17, 2013 2185 bsteffen Cache computed grid reprojections.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -72,8 +69,6 @@ import de.micromata.opengis.kml.v_2_2_0.LatLonBox;
|
|||
|
||||
public abstract class KmlGroundOverlayGenerator extends KmlFeatureGenerator {
|
||||
|
||||
private static Map<MultiKey, Reference<GridReprojection>> reprojCache = new HashMap<MultiKey, Reference<GridReprojection>>();
|
||||
|
||||
protected final double alpha;
|
||||
|
||||
protected final DrawableImage[] images;
|
||||
|
@ -133,27 +128,7 @@ public abstract class KmlGroundOverlayGenerator extends KmlFeatureGenerator {
|
|||
}
|
||||
|
||||
protected GridReprojection getReprojection(GridGeometry2D src,
|
||||
GridGeometry2D dest) throws FactoryException, TransformException {
|
||||
MultiKey key = new MultiKey(src, dest);
|
||||
GridReprojection reproj = null;
|
||||
boolean needsCompute = false;
|
||||
synchronized (reprojCache) {
|
||||
Reference<GridReprojection> reprojRef = reprojCache.get(key);
|
||||
if (reprojRef != null) {
|
||||
reproj = reprojRef.get();
|
||||
}
|
||||
if (reproj == null) {
|
||||
reproj = new GridReprojection(src, dest);
|
||||
needsCompute = true;
|
||||
reprojCache.put(key,
|
||||
new SoftReference<GridReprojection>(reproj));
|
||||
}
|
||||
}
|
||||
synchronized (reproj) {
|
||||
if (needsCompute) {
|
||||
reproj.computeTransformTable();
|
||||
}
|
||||
}
|
||||
return reproj;
|
||||
GridGeometry2D dest) throws TransformException {
|
||||
return PrecomputedGridReprojection.getReprojection(src, dest);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ import com.raytheon.uf.common.geospatial.MapUtil;
|
|||
import com.raytheon.uf.common.geospatial.interpolation.GridReprojection;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.GridSampler;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.Interpolation;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.PrecomputedGridReprojection;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.data.FloatArrayWrapper;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.data.FloatBufferWrapper;
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
|
@ -56,7 +57,8 @@ import com.vividsolutions.jts.geom.Coordinate;
|
|||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Mar 9, 2011 bsteffen Initial creation
|
||||
* Mar 09, 2011 bsteffen Initial creation
|
||||
* Jul 17, 2013 2185 bsteffen Cache computed grid reprojections.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -217,7 +219,8 @@ public class GeneralGridData {
|
|||
Interpolation interpolation) throws FactoryException,
|
||||
TransformException {
|
||||
GridGeometry2D newGeom = GridGeometry2D.wrap(newGridGeometry);
|
||||
GridReprojection reproj = new GridReprojection(gridGeometry, newGeom);
|
||||
GridReprojection reproj = PrecomputedGridReprojection.getReprojection(
|
||||
gridGeometry, newGeom);
|
||||
GridSampler sampler = new GridSampler(interpolation);
|
||||
if (isVector()) {
|
||||
sampler.setSource(new FloatBufferWrapper(getUComponent(),
|
||||
|
|
|
@ -46,6 +46,7 @@ import com.raytheon.uf.common.geospatial.MapUtil;
|
|||
import com.raytheon.uf.common.geospatial.interpolation.BilinearInterpolation;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.GridReprojection;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.NearestNeighborInterpolation;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.PrecomputedGridReprojection;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.data.ByteBufferWrapper;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.data.DataSource;
|
||||
import com.raytheon.uf.common.geospatial.interpolation.data.FloatArrayWrapper;
|
||||
|
@ -60,9 +61,11 @@ import com.vividsolutions.jts.geom.Coordinate;
|
|||
* SOFTWARE HISTORY
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* 5/16/08 875 bphillip Initial Creation.
|
||||
* 10/10/12 #1260 randerso Added getters for source and destination glocs
|
||||
* 02/19/13 #1637 randerso Fixed remapping of byte grids
|
||||
* May 16, 2008 875 bphillip Initial Creation.
|
||||
* Oct 10, 2012 1260 randerso Added getters for source and destination
|
||||
* glocs
|
||||
* Feb 19, 2013 1637 randerso Fixed remapping of byte grids
|
||||
* Jul 17, 2013 2185 bsteffen Cache computed grid reprojections.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -462,8 +465,8 @@ public class RemapGrid {
|
|||
GridGeometry2D destGeometry = MapUtil.getGridGeometry(destinationGloc);
|
||||
synchronized (this) {
|
||||
if (interp == null) {
|
||||
interp = new GridReprojection(sourceGeometry, destGeometry);
|
||||
interp.computeTransformTable();
|
||||
interp = PrecomputedGridReprojection.getReprojection(
|
||||
sourceGeometry, destGeometry);
|
||||
}
|
||||
}
|
||||
DataSource source = new ByteBufferWrapper(data, sourceGeometry);
|
||||
|
@ -540,8 +543,8 @@ public class RemapGrid {
|
|||
.getGridGeometry(destinationGloc);
|
||||
synchronized (this) {
|
||||
if (interp == null) {
|
||||
interp = new GridReprojection(sourceGeometry, destGeometry);
|
||||
interp.computeTransformTable();
|
||||
interp = PrecomputedGridReprojection.getReprojection(
|
||||
sourceGeometry, destGeometry);
|
||||
}
|
||||
}
|
||||
DataSource source = new FloatArrayWrapper(data, sourceGeometry);
|
||||
|
|
|
@ -47,6 +47,7 @@ import com.raytheon.uf.common.geospatial.interpolation.data.DataSource;
|
|||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jun 18, 2012 bsteffen Initial creation
|
||||
* Jul 17, 2013 2185 bsteffen Cache computed grid reprojections.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -66,8 +67,6 @@ public class GridReprojection {
|
|||
|
||||
protected MathTransform transform;
|
||||
|
||||
protected float[] transformTable = null;
|
||||
|
||||
public GridReprojection(GeneralGridGeometry sourceGeometry,
|
||||
GeneralGridGeometry targetGeometry) {
|
||||
this.sourceGeometry = sourceGeometry;
|
||||
|
@ -128,63 +127,11 @@ public class GridReprojection {
|
|||
protected Point2D.Double getReprojectDataPoint(int x, int y)
|
||||
throws TransformException, FactoryException {
|
||||
initTransforms();
|
||||
if (transformTable != null && x >= 0 && x < targetNx && y >= 0
|
||||
&& y < targetNy) {
|
||||
int index = (y * targetNx + x) * 2;
|
||||
float xVal = transformTable[index];
|
||||
float yVal = transformTable[index + 1];
|
||||
if (!Float.isNaN(xVal) && !Float.isNaN(yVal)) {
|
||||
return new Point2D.Double(xVal, yVal);
|
||||
}
|
||||
}
|
||||
DirectPosition2D dp = new DirectPosition2D(x, y);
|
||||
transform.transform(dp, dp);
|
||||
return dp;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function precomputes the math transform for all grid cells in the
|
||||
* target grid range. This method is recommended when you are reprojecting
|
||||
* multiple datasets using the same interpolation. Precalculating this table
|
||||
* takes time and uses more memory but cuts the time to perform
|
||||
* interpolation significantly.
|
||||
*
|
||||
*
|
||||
* @return the size in bytes of the extra memory used by the transform
|
||||
* table.
|
||||
* @throws FactoryException
|
||||
* @throws TransformException
|
||||
*/
|
||||
public int computeTransformTable() throws FactoryException,
|
||||
TransformException {
|
||||
initTransforms();
|
||||
float[] transformTable = new float[targetNy * targetNx * 2];
|
||||
int index = 0;
|
||||
for (int j = 0; j < targetNy; j++) {
|
||||
for (int i = 0; i < targetNx; i++) {
|
||||
transformTable[index++] = i;
|
||||
transformTable[index++] = j;
|
||||
}
|
||||
}
|
||||
try {
|
||||
transform.transform(transformTable, 0, transformTable, 0, targetNy
|
||||
* targetNx);
|
||||
} catch (ProjectionException e) {
|
||||
;// Ignore, the points in the transformTable that are invalid are
|
||||
// set to NaN, no other action is necessary.
|
||||
}
|
||||
this.transformTable = transformTable;
|
||||
return transformTable.length * 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* delete the transform table, freeing up memory but slowing down any future
|
||||
* reprojections
|
||||
*/
|
||||
public void clearTransformTable() {
|
||||
transformTable = null;
|
||||
}
|
||||
|
||||
public GeneralGridGeometry getSourceGeometry() {
|
||||
return sourceGeometry;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
/**
|
||||
* 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;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.collections.keyvalue.MultiKey;
|
||||
import org.geotools.coverage.grid.GeneralGridGeometry;
|
||||
import org.geotools.referencing.operation.projection.ProjectionException;
|
||||
import org.opengis.referencing.FactoryException;
|
||||
import org.opengis.referencing.operation.TransformException;
|
||||
|
||||
/**
|
||||
* A GridReprojection which precomputes the coordinates of all the grid cells so
|
||||
* that multiple reprojects will be much faster. This implements a memory/time
|
||||
* tradeoff, using much more memory than an ordinary GridReprojection so that it
|
||||
* is able to reproject much faster. Because of the high memory usage all
|
||||
* instances are cached so they can be shared for identical reprojections.
|
||||
*
|
||||
* The current caching implementation uses soft references. When the
|
||||
* reprojection is no longer referenced then the memory will be reclaimed by the
|
||||
* JVM as needed.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jul 17, 2013 2185 bsteffen Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bsteffen
|
||||
* @version 1.0
|
||||
*/
|
||||
public class PrecomputedGridReprojection extends GridReprojection {
|
||||
|
||||
protected float[] transformTable;
|
||||
|
||||
protected PrecomputedGridReprojection(GeneralGridGeometry sourceGeometry,
|
||||
GeneralGridGeometry targetGeometry) {
|
||||
super(sourceGeometry, targetGeometry);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function precomputes the math transform for all grid cells in the
|
||||
* target grid range. Precalculating this table takes time and uses more
|
||||
* memory but cuts the time to perform interpolation significantly.
|
||||
*
|
||||
* @throws TransformException
|
||||
*/
|
||||
protected void computeTransformTable() throws TransformException {
|
||||
try {
|
||||
initTransforms();
|
||||
} catch (FactoryException e) {
|
||||
throw new TransformException("Error preparing transform.", e);
|
||||
}
|
||||
float[] transformTable = new float[targetNy * targetNx * 2];
|
||||
int index = 0;
|
||||
for (int j = 0; j < targetNy; j++) {
|
||||
for (int i = 0; i < targetNx; i++) {
|
||||
transformTable[index++] = i;
|
||||
transformTable[index++] = j;
|
||||
}
|
||||
}
|
||||
try {
|
||||
transform.transform(transformTable, 0, transformTable, 0, targetNy
|
||||
* targetNx);
|
||||
} catch (ProjectionException e) {
|
||||
;// Ignore the points in the transformTable that are
|
||||
// invalid are set to NaN, no other action is necessary.
|
||||
}
|
||||
this.transformTable = transformTable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Point2D.Double getReprojectDataPoint(int x, int y)
|
||||
throws TransformException, FactoryException {
|
||||
if (x >= 0 && x < targetNx && y >= 0 && y < targetNy) {
|
||||
int index = (y * targetNx + x) * 2;
|
||||
float xVal = transformTable[index];
|
||||
float yVal = transformTable[index + 1];
|
||||
if (!Float.isNaN(xVal) && !Float.isNaN(yVal)) {
|
||||
return new Point2D.Double(xVal, yVal);
|
||||
}
|
||||
}
|
||||
return super.getReprojectDataPoint(x, y);
|
||||
}
|
||||
|
||||
private static final Map<MultiKey, Reference<PrecomputedGridReprojection>> cache = new HashMap<MultiKey, Reference<PrecomputedGridReprojection>>();
|
||||
|
||||
/**
|
||||
* Get a shared GridReprojection. This reprojection will have the transform
|
||||
* table computed.
|
||||
*
|
||||
* @param sourceGeometry
|
||||
* @param targetGeometry
|
||||
* @return
|
||||
* @throws FactoryException
|
||||
* @throws TransformException
|
||||
*/
|
||||
public static PrecomputedGridReprojection getReprojection(
|
||||
GeneralGridGeometry sourceGeometry,
|
||||
GeneralGridGeometry targetGeometry) throws TransformException {
|
||||
PrecomputedGridReprojection reprojection = null;
|
||||
boolean created = false;
|
||||
MultiKey key = new MultiKey(sourceGeometry, targetGeometry);
|
||||
synchronized (cache) {
|
||||
Reference<PrecomputedGridReprojection> ref = cache.get(key);
|
||||
if (ref != null) {
|
||||
reprojection = ref.get();
|
||||
}
|
||||
if (reprojection == null) {
|
||||
reprojection = new PrecomputedGridReprojection(sourceGeometry,
|
||||
targetGeometry);
|
||||
created = true;
|
||||
cache.put(key, new SoftReference<PrecomputedGridReprojection>(
|
||||
reprojection));
|
||||
}
|
||||
}
|
||||
synchronized (reprojection) {
|
||||
if (created) {
|
||||
reprojection.computeTransformTable();
|
||||
}
|
||||
}
|
||||
return reprojection;
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Reference in a new issue