Issue #2791 Switch contouring to use DataSource for data access.

Former-commit-id: 6c90be7554bcbbf0aeb363b6e76c455d3896be83
This commit is contained in:
Ben Steffensmeier 2014-02-27 18:03:33 -06:00
parent 475557d4c8
commit 23ce77d864
20 changed files with 710 additions and 728 deletions

View file

@ -1,23 +1,21 @@
Manifest-Version: 1.0 Manifest-Version: 1.0
Bundle-ManifestVersion: 2 Bundle-ManifestVersion: 2
Bundle-Name: Contours Plug-in Bundle-Name: Contour Generation and Display
Bundle-SymbolicName: com.raytheon.viz.core.contours;singleton:=true Bundle-SymbolicName: com.raytheon.viz.core.contours
Bundle-Version: 1.12.1174.qualifier Bundle-Version: 1.14.0.qualifier
Bundle-Activator: com.raytheon.viz.core.contours.Activator
Bundle-Vendor: Raytheon Bundle-Vendor: Raytheon
Require-Bundle: org.eclipse.core.runtime, Bundle-RequiredExecutionEnvironment: JavaSE-1.6
org.eclipse.ui,
com.raytheon.uf.common.datastorage;bundle-version="1.12.1174",
com.raytheon.uf.common.geospatial;bundle-version="1.12.1174",
com.raytheon.uf.common.status;bundle-version="1.12.1174",
com.raytheon.uf.common.util;bundle-version="1.12.1174",
com.raytheon.uf.viz.core;bundle-version="1.12.1174",
com.raytheon.uf.common.wxmath;bundle-version="1.0.0"
Bundle-ActivationPolicy: lazy Bundle-ActivationPolicy: lazy
Require-Bundle: com.raytheon.uf.viz.core;bundle-version="1.14.1",
org.eclipse.core.runtime,
org.eclipse.ui,
com.raytheon.uf.common.geospatial,
com.raytheon.uf.common.util,
com.raytheon.uf.common.wxmath,
com.raytheon.uf.common.style,
com.raytheon.uf.common.status,
org.apache.commons.collections
Import-Package: com.raytheon.viz.core.interval
Export-Package: com.raytheon.viz.core.contours, Export-Package: com.raytheon.viz.core.contours,
com.raytheon.viz.core.contours.rsc.displays, com.raytheon.viz.core.contours.rsc.displays,
com.raytheon.viz.core.contours.util com.raytheon.viz.core.contours.util
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Import-Package: com.raytheon.uf.common.style,
com.raytheon.uf.common.style.contour,
com.raytheon.viz.core.interval

View file

@ -1,5 +1,4 @@
source.. = src/ source.. = src/
output.. = bin/ output.. = bin/
bin.includes = META-INF/,\ bin.includes = META-INF/,\
.,\ .
plugin.xml

View file

@ -1,69 +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.viz.core.contours;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
/**
* The activator class controls the plug-in life cycle
*/
public class Activator extends AbstractUIPlugin {
// The plug-in ID
public static final String PLUGIN_ID = "com.raytheon.viz.core.contours";
// The shared instance
private static Activator plugin;
/**
* The constructor
*/
public Activator() {
}
/*
* (non-Javadoc)
* @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
*/
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
}
/*
* (non-Javadoc)
* @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
*/
public void stop(BundleContext context) throws Exception {
plugin = null;
super.stop(context);
}
/**
* Returns the shared instance
*
* @return the shared instance
*/
public static Activator getDefault() {
return plugin;
}
}

View file

@ -21,7 +21,7 @@ package com.raytheon.viz.core.contours;
import org.geotools.coverage.grid.GeneralGridGeometry; import org.geotools.coverage.grid.GeneralGridGeometry;
import com.raytheon.uf.common.datastorage.records.IDataRecord; import com.raytheon.uf.common.geospatial.interpolation.data.DataSource;
import com.raytheon.uf.common.style.contour.ContourPreferences; import com.raytheon.uf.common.style.contour.ContourPreferences;
import com.raytheon.uf.viz.core.IExtent; import com.raytheon.uf.viz.core.IExtent;
import com.raytheon.uf.viz.core.IGraphicsTarget; import com.raytheon.uf.viz.core.IGraphicsTarget;
@ -39,9 +39,11 @@ import com.raytheon.viz.core.contours.ContourSupport.ContourGroup;
* *
* SOFTWARE HISTORY * SOFTWARE HISTORY
* *
* Date Ticket# Engineer Description * Date Ticket# Engineer Description
* ------------ ---------- ----------- -------------------------- * ------------- -------- ----------- --------------------------
* Feb 25, 2011 ekladstrup Initial creation * Feb 25, 2011 ekladstrup Initial creation
* Feb 27, 2014 2791 bsteffen Switch from IDataRecord to DataSource
*
* *
* </pre> * </pre>
* *
@ -50,14 +52,14 @@ import com.raytheon.viz.core.contours.ContourSupport.ContourGroup;
*/ */
public class ContourCreateRequest { public class ContourCreateRequest {
public ContourCreateRequest(String identifier, IDataRecord[] record, public ContourCreateRequest(String identifier, DataSource[] source,
float level, IExtent pixelExtent, double currentDensity, float level, IExtent pixelExtent, double currentDensity,
double currentMagnification, GeneralGridGeometry imageGridGeometry, double currentMagnification, GeneralGridGeometry imageGridGeometry,
IGraphicsTarget target, IMapDescriptor descriptor, IGraphicsTarget target, IMapDescriptor descriptor,
ContourPreferences prefs, float zoom) { ContourPreferences prefs, float zoom) {
super(); super();
this.identifier = identifier; this.identifier = identifier;
this.record = record; this.source = source;
this.level = level; this.level = level;
this.pixelExtent = pixelExtent; this.pixelExtent = pixelExtent;
this.imageGridGeometry = imageGridGeometry; this.imageGridGeometry = imageGridGeometry;
@ -79,12 +81,12 @@ public class ContourCreateRequest {
this.identifier = identifier; this.identifier = identifier;
} }
public IDataRecord[] getRecord() { public DataSource[] getSource() {
return record; return source;
} }
public void setRecord(IDataRecord[] record) { public void setSource(DataSource[] source) {
this.record = record; this.source = source;
} }
public float getLevel() { public float getLevel() {
@ -183,7 +185,7 @@ public class ContourCreateRequest {
private String identifier; private String identifier;
private IDataRecord[] record; private DataSource[] source;
private float level; private float level;

View file

@ -37,9 +37,10 @@ import com.raytheon.viz.core.contours.ContourSupport.ContourGroup;
* *
* SOFTWARE HISTORY * SOFTWARE HISTORY
* *
* Date Ticket# Engineer Description * Date Ticket# Engineer Description
* ------------ ---------- ----------- -------------------------- * ------------- -------- ----------- --------------------------
* Oct 24, 2007 chammack Initial Creation. * Oct 24, 2007 chammack Initial Creation.
* Feb 27, 2014 2791 bsteffen Switch from IDataRecord to DataSource
* *
* </pre> * </pre>
* *
@ -114,9 +115,10 @@ public class ContourManagerJob extends Job {
;// request has been canceled or contours exist ;// request has been canceled or contours exist
} else { } else {
long t0 = System.currentTimeMillis(); long t0 = System.currentTimeMillis();
ContourGroup cg = ContourSupport.createContours( ContourGroup cg = null;
req.getRecord(), req.getLevel(), cg = ContourSupport.createContours(req.getSource(),
req.getPixelExtent(), req.getCurrentDensity(), req.getLevel(), req.getPixelExtent(),
req.getCurrentDensity(),
req.getCurrentMagnification(), req.getCurrentMagnification(),
req.getImageGridGeometry(), req.getTarget(), req.getImageGridGeometry(), req.getTarget(),
req.getDescriptor(), req.getPrefs(), req.getZoom()); req.getDescriptor(), req.getPrefs(), req.getZoom());
@ -126,7 +128,8 @@ public class ContourManagerJob extends Job {
+ (System.currentTimeMillis() - t0)); + (System.currentTimeMillis() - t0));
} }
} catch (Throwable e) { } catch (Throwable e) {
return new Status(Status.ERROR, Activator.PLUGIN_ID, return new Status(Status.ERROR, ContourManagerJob.class
.getPackage().getName(),
"Error creating contours", e); "Error creating contours", e);
} }

View file

@ -28,16 +28,20 @@ import org.eclipse.swt.graphics.RGB;
import org.geotools.coverage.grid.GeneralGridGeometry; import org.geotools.coverage.grid.GeneralGridGeometry;
import org.geotools.geometry.DirectPosition2D; import org.geotools.geometry.DirectPosition2D;
import org.geotools.geometry.jts.JTS; import org.geotools.geometry.jts.JTS;
import org.opengis.coverage.grid.GridEnvelope;
import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.MathTransform;
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.MapUtil;
import com.raytheon.uf.common.geospatial.interpolation.data.DataCopy;
import com.raytheon.uf.common.geospatial.interpolation.data.DataSource;
import com.raytheon.uf.common.geospatial.interpolation.data.FloatArrayWrapper;
import com.raytheon.uf.common.style.contour.ContourPreferences; import com.raytheon.uf.common.style.contour.ContourPreferences;
import com.raytheon.uf.common.wxmath.Constants;
import com.raytheon.uf.common.wxmath.DistFilter; import com.raytheon.uf.common.wxmath.DistFilter;
import com.raytheon.uf.viz.core.IGraphicsTarget; import com.raytheon.uf.viz.core.IGraphicsTarget;
import com.raytheon.uf.viz.core.IGraphicsTarget.LineStyle; import com.raytheon.uf.viz.core.IGraphicsTarget.LineStyle;
import com.raytheon.uf.viz.core.PixelExtent; import com.raytheon.uf.viz.core.PixelExtent;
import com.raytheon.uf.viz.core.datastructure.LoopProperties;
import com.raytheon.uf.viz.core.drawables.IFont; import com.raytheon.uf.viz.core.drawables.IFont;
import com.raytheon.uf.viz.core.drawables.IFont.Style; import com.raytheon.uf.viz.core.drawables.IFont.Style;
import com.raytheon.uf.viz.core.drawables.IRenderable; import com.raytheon.uf.viz.core.drawables.IRenderable;
@ -56,11 +60,13 @@ import com.vividsolutions.jts.geom.Coordinate;
* *
* <pre> * <pre>
* SOFTWARE HISTORY * SOFTWARE HISTORY
* Date Ticket# Engineer Description * Date Ticket# Engineer Description
* ------------ ---------- ----------- -------------------------- * ------------- -------- ----------- --------------------------
* Jul 10, 2008 #1233 chammack Initial creation * Jul 10, 2008 1233 chammack Initial creation
* Jul 18, 2013 #2199 mschenke Made code only smooth data once * Jul 18, 2013 2199 mschenke Made code only smooth data once
* Aug 23, 2013 #2157 dgilling Remove meteolib dependency. * Aug 23, 2013 2157 dgilling Remove meteolib dependency.
* Feb 27, 2014 2791 bsteffen Switch from IDataRecord to DataSource and
* reduce loop freezing.
* *
* </pre> * </pre>
* *
@ -88,7 +94,7 @@ public abstract class ContourRenderable implements IRenderable {
private final String uuid; private final String uuid;
private IDataRecord[] data; private DataSource[] data;
// This is the width of CONUS // This is the width of CONUS
private static final double METERS_AT_BASE_ZOOMLEVEL = 5878649.0; private static final double METERS_AT_BASE_ZOOMLEVEL = 5878649.0;
@ -99,7 +105,7 @@ public abstract class ContourRenderable implements IRenderable {
private static final int NUMBER_CONTOURING_LEVELS = 10; private static final int NUMBER_CONTOURING_LEVELS = 10;
public abstract IDataRecord[] getData() throws VizException; public abstract DataSource[] getData() throws VizException;
public abstract GeneralGridGeometry getGridGeometry() throws VizException; public abstract GeneralGridGeometry getGridGeometry() throws VizException;
@ -124,7 +130,7 @@ public abstract class ContourRenderable implements IRenderable {
this.requestMap = new HashMap<String, ContourCreateRequest>(); this.requestMap = new HashMap<String, ContourCreateRequest>();
} }
private IDataRecord[] getContourData() throws VizException { private DataSource[] getContourData() throws VizException {
if (data == null) { if (data == null) {
data = getData(); data = getData();
if (data != null) { if (data != null) {
@ -280,7 +286,7 @@ public abstract class ContourRenderable implements IRenderable {
return; return;
} }
IDataRecord[] dataRecord = getContourData(); DataSource[] dataRecord = getContourData();
if (dataRecord == null) { if (dataRecord == null) {
return; return;
} }
@ -317,25 +323,38 @@ public abstract class ContourRenderable implements IRenderable {
} }
int retries = 0; int retries = 0;
LoopProperties loopProps = paintProps
.getLoopProperties();
if (loopProps != null && loopProps
.isLooping()) {
/**
* If the display is looping, wait a few ms to
* let contouring finish so that if the
* contouring is fast enough the user is not
* presented with empty frames. If too many
* resources do this, it freezes the UI so scale
* the sleep time based off the number of
* resources because empty frames are better
* than freezing. This scaling also gives
* everyone a chance to queue up work so that
* multiprocessing is done more efficiently.
*/
retries = 100 / descriptor.getResourceList()
.size();
}
do { do {
// grab request from map // grab request from map
request = requestMap.get(identifier); request = requestMap.get(identifier);
cg = request.getContourGroup(); cg = request.getContourGroup();
retries--;
try { try {
if (cg == null if (cg == null && retries > 0) {
&& paintProps.getLoopProperties() != null Thread.sleep(10);
&& paintProps.getLoopProperties()
.isLooping()) {
Thread.sleep(50);
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
// ignore retries = 0;
} }
retries++; } while (cg == null && retries > 0);
} while (cg == null
&& paintProps.getLoopProperties() != null
&& paintProps.getLoopProperties()
.isLooping() && retries < 10);
if (cg != null) { if (cg != null) {
if (cg != contourGroup[i]) { if (cg != contourGroup[i]) {
@ -396,7 +415,7 @@ public abstract class ContourRenderable implements IRenderable {
} }
} }
private IDataRecord[] smoothData(IDataRecord[] dataRecord, private DataSource[] smoothData(DataSource[] dataRecord,
GeneralGridGeometry gridGeometry, ContourPreferences contourPrefs) GeneralGridGeometry gridGeometry, ContourPreferences contourPrefs)
throws VizException { throws VizException {
if (contourPrefs != null && contourPrefs.getSmoothingDistance() != null) { if (contourPrefs != null && contourPrefs.getSmoothingDistance() != null) {
@ -424,32 +443,23 @@ public abstract class ContourRenderable implements IRenderable {
} catch (Exception e) { } catch (Exception e) {
throw new VizException(e); throw new VizException(e);
} }
// Calculate the Dagnol Distance in Points // Calculate the Diagnol Distance in Points
FloatDataRecord rec = (FloatDataRecord) dataRecord[0]; GridEnvelope range = gridGeometry.getGridRange();
float[] data = rec.getFloatData(); int nx = range.getSpan(0);
int nx = (int) rec.getSizes()[0]; int ny = range.getSpan(1);
int ny = (int) rec.getSizes()[1];
double distanceInPoints = Math.sqrt(nx * nx + ny * ny); double distanceInPoints = Math.sqrt(nx * nx + ny * ny);
// Determine the number of points to smooth, assume // Determine the number of points to smooth, assume
// smoothingDistance is in km // smoothingDistance is in km
float npts = (float) (distanceInPoints float npts = (float) (distanceInPoints
* contourPrefs.getSmoothingDistance() / (distanceInM / 1000)); * contourPrefs.getSmoothingDistance() / (distanceInM / 1000));
// Replace our NaN with their NaN FloatArrayWrapper data = new FloatArrayWrapper(gridGeometry);
for (int j = 0; j < data.length; j++) { data.setFillValue(Constants.LEGACY_NAN);
if (data[j] == -999999) { DataCopy.copy(dataRecord[0], data, nx, ny);
data[j] = 1.0E37f; float[] dataArray = data.getArray();
} dataArray = DistFilter.filter(dataArray, npts, nx, ny, 1);
} data = new FloatArrayWrapper(dataArray, gridGeometry);
data = DistFilter.filter(data, npts, nx, ny, 1); data.setFillValue(Constants.LEGACY_NAN);
// Replace their NaN with our NaN return new DataSource[] {data};
for (int j = 0; j < data.length; j++) {
if (data[j] == 1.0E37f) {
data[j] = -999999;
}
}
rec = new FloatDataRecord(rec.getName(), rec.getGroup(), data,
rec.getDimension(), rec.getSizes());
return new IDataRecord[] { rec };
} else { } else {
return dataRecord; return dataRecord;
} }

View file

@ -36,21 +36,25 @@ import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.geometry.Envelope2D; import org.geotools.geometry.Envelope2D;
import org.geotools.geometry.GeneralEnvelope; import org.geotools.geometry.GeneralEnvelope;
import org.geotools.referencing.operation.DefaultMathTransformFactory; import org.geotools.referencing.operation.DefaultMathTransformFactory;
import org.opengis.coverage.grid.GridEnvelope;
import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.datum.PixelInCell; import org.opengis.referencing.datum.PixelInCell;
import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException; import org.opengis.referencing.operation.TransformException;
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.CRSCache; import com.raytheon.uf.common.geospatial.CRSCache;
import com.raytheon.uf.common.geospatial.MapUtil; import com.raytheon.uf.common.geospatial.MapUtil;
import com.raytheon.uf.common.geospatial.interpolation.data.DataCopy;
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.GridGeometryWrapChecker;
import com.raytheon.uf.common.geospatial.util.WorldWrapChecker; import com.raytheon.uf.common.geospatial.util.WorldWrapChecker;
import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.common.style.LabelingPreferences; import com.raytheon.uf.common.style.LabelingPreferences;
import com.raytheon.uf.common.style.contour.ContourPreferences;
import com.raytheon.uf.common.util.GridUtil; import com.raytheon.uf.common.util.GridUtil;
import com.raytheon.uf.viz.core.DrawableString; import com.raytheon.uf.viz.core.DrawableString;
import com.raytheon.uf.viz.core.IExtent; import com.raytheon.uf.viz.core.IExtent;
@ -72,7 +76,6 @@ import com.raytheon.viz.core.contours.util.StreamLineContainer.StreamLinePoint;
import com.raytheon.viz.core.contours.util.StrmPak; import com.raytheon.viz.core.contours.util.StrmPak;
import com.raytheon.viz.core.contours.util.StrmPakConfig; import com.raytheon.viz.core.contours.util.StrmPakConfig;
import com.raytheon.viz.core.interval.XFormFunctions; import com.raytheon.viz.core.interval.XFormFunctions;
import com.raytheon.uf.common.style.contour.ContourPreferences;
import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.Geometry;
/** /**
@ -82,19 +85,23 @@ import com.vividsolutions.jts.geom.Geometry;
* *
* SOFTWARE HISTORY * SOFTWARE HISTORY
* *
* Date Ticket# Engineer Description * Date Ticket# Engineer Description
* ------------ ---------- ----------- -------------------------- * ------------- -------- ------------ ----------------------------------------
* Oct 22, 2007 chammack Initial Creation. * Oct 22, 2007 chammack Initial Creation.
* May 26, 2009 #2172 chammack Use zoomLevel to calculate label spacing * May 26, 2009 2172 chammack Use zoomLevel to calculate label spacing
* Apr 26, 2010 #4583 rjpeter Replaced fortran fortconbuf with java port. * Apr 26, 2010 4583 rjpeter Replaced fortran fortconbuf with java
* Mar 04, 2011 #7747 njensen Cached subgrid envelopes * port.
* Jul 09, 2012 DR14940 M.Porricelli Adjust arrow size for streamlines * Mar 04, 2011 7747 njensen Cached subgrid envelopes
* Feb 15, 2013 1638 mschenke Moved edex.common Util functions into common Util * Jul 09, 2012 14940 M.Porricelli Adjust arrow size for streamlines
* Jun 26, 2013 #1999 dgilling Replace native fortran strmpak call * Feb 15, 2013 1638 mschenke Moved edex.common Util functions into
* with java port. * common Util
* Jun 26, 2013 1999 dgilling Replace native fortran strmpak call
* with java port.
* Jul 18, 2013 2199 mschenke Ensured contouring is only occurring
* over visible area
* Jul 23, 2013 2157 dgilling Remove legacy stream line drawing code.
* Feb 27, 2014 2791 bsteffen Switch from IDataRecord to DataSource
* *
* Jul 18, 2013 2199 mschenke Ensured contouring is only occurring over visible area
* Jul 23, 2013 #2157 dgilling Remove legacy stream line drawing code.
* </pre> * </pre>
* *
* @author chammack * @author chammack
@ -105,6 +112,23 @@ public class ContourSupport {
private static final transient IUFStatusHandler statusHandler = UFStatus private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(ContourSupport.class); .getHandler(ContourSupport.class);
/*
* By default contour any data source that is passed in. This is much more
* efficient than copying the data and allows us to contour any DataSource.
*
* The downside is that FortConBuf accesses each data point multiple times
* and it is possible that DataSources with lots of transformation will have
* poor performance. Since different sources will exhibit different behavior
* and it is impossible to test all sources this field provides a runtime
* flag to copy all the data so that slow sources will only need to access
* each point once at the cost of more memory and taking the time to copy.
* Hopefully this is just paranoia and this flag can be removed in the
* future. If it turns out this is necessary we will likely want to find a
* more fine grained approach to tuning this.
*/
private static boolean copyData = Boolean.getBoolean(ContourSupport.class
.getPackage().getName() + ".copyData");
private static float smallestContourValue = GridUtil.GRID_FILL_VALUE - 1; private static float smallestContourValue = GridUtil.GRID_FILL_VALUE - 1;
private static float largestContourValue = GridUtil.GRID_FILL_VALUE + 1; private static float largestContourValue = GridUtil.GRID_FILL_VALUE + 1;
@ -206,7 +230,7 @@ public class ContourSupport {
/** /**
* Create contours from provided parameters * Create contours from provided parameters
* *
* @param records * @param sources
* @param level * @param level
* @param extent * @param extent
* @param currentDensity * @param currentDensity
@ -220,7 +244,7 @@ public class ContourSupport {
* @return the ContourGroup * @return the ContourGroup
* @throws VizException * @throws VizException
*/ */
public static ContourGroup createContours(IDataRecord[] records, public static ContourGroup createContours(DataSource[] sources,
float level, IExtent extent, double currentDensity, float level, IExtent extent, double currentDensity,
double currentMagnification, GeneralGridGeometry imageGridGeometry, double currentMagnification, GeneralGridGeometry imageGridGeometry,
IGraphicsTarget target, IMapDescriptor descriptor, IGraphicsTarget target, IMapDescriptor descriptor,
@ -297,49 +321,37 @@ public class ContourSupport {
// Step 3: Get the actual data // Step 3: Get the actual data
if (records.length == 1 && records[0] != null) { if (sources.length == 1 && sources[0] != null) {
IDataRecord record = records[0];
float[] data1D = null;
long[] sz = record.getSizes();
if (record instanceof ByteDataRecord) {
byte[] data1Db = ((ByteDataRecord) record).getByteData();
data1D = new float[data1Db.length];
for (int i = 0; i < data1D.length; i++) {
data1D[i] = data1Db[i] & 0xFF;
}
} else if (record instanceof FloatDataRecord) {
data1D = ((FloatDataRecord) record).getFloatData();
} else {
throw new UnsupportedOperationException(
"Contouring is not supported for data type: "
+ record.getClass().getName());
}
// Step 4: Determine the subgrid, if any // Step 4: Determine the subgrid, if any
GridEnvelope imageRange = imageGridGeometry.getGridRange();
int minX = (int) Math.floor(Math.max(env.getMinimum(0), 0)); int minX = (int) Math.floor(Math.max(env.getMinimum(0), 0));
int minY = (int) Math.floor(Math.max(env.getMinimum(1), 0)); int minY = (int) Math.floor(Math.max(env.getMinimum(1), 0));
int maxX = (int) Math.ceil(Math.min(env.getMaximum(0), sz[0] - 1)); int maxX = (int) Math.ceil(Math.min(env.getMaximum(0),
int maxY = (int) Math.ceil(Math.min(env.getMaximum(1), sz[1] - 1)); imageRange.getHigh(0)));
int maxY = (int) Math.ceil(Math.min(env.getMaximum(1),
imageRange.getHigh(1)));
int szX = (maxX - minX) + 1; int szX = (maxX - minX) + 1;
int szY = (maxY - minY) + 1; int szY = (maxY - minY) + 1;
if (szX * szY <= 0) { if (szX * szY <= 0) {
return contourGroup; return contourGroup;
} }
float[][] subgriddedData = new float[szX][szY]; /* Make contours continous for world wrapping grids. */
int wrapNumber = GridGeometryWrapChecker
.checkForWrapping(imageGridGeometry);
if (wrapNumber - 1 >= szX) {
szX = wrapNumber + 1;
}
for (int j = 0; j < szY; j++) { DataSource subgridSource = sources[0];
for (int i = 0; i < szX; i++) { if (minX != 0 || minY != 0) {
float val = data1D[((int) sz[0] * (j + minY)) + (i + minX)]; subgridSource = new OffsetDataSource(sources[0], minX, minY);
if (Float.isNaN(val)) { }
val = GridUtil.GRID_FILL_VALUE;
} if (copyData) {
subgriddedData[i][j] = val; subgridSource = DataCopy.copy(subgridSource,
} new FloatArrayWrapper(szX, szY), szX, szY);
} }
// Use ported legacy code to determine contour interval // Use ported legacy code to determine contour interval
@ -358,12 +370,12 @@ public class ContourSupport {
// Awips 1 // Awips 1
config.xOffset = minX; config.xOffset = minX;
config.yOffset = minY; config.yOffset = minY;
config.labelSpacingLine = subgriddedData.length / 3; config.labelSpacingLine = szX / 3;
if (config.labelSpacingLine < 1) { if (config.labelSpacingLine < 1) {
config.labelSpacingLine = 1; config.labelSpacingLine = 1;
} }
config.labelSpacingOverall = (int) (subgriddedData.length * 60 config.labelSpacingOverall = (int) (szX * 60
* currentMagnification / ((PixelExtent) extent).getWidth() + 0.5); * currentMagnification / ((PixelExtent) extent).getWidth() + 0.5);
// If nothing provided, attempt to get approximately 50 contours // If nothing provided, attempt to get approximately 50 contours
@ -371,10 +383,13 @@ public class ContourSupport {
// TODO this is fairly inefficient to do every time. // TODO this is fairly inefficient to do every time.
float min = Float.POSITIVE_INFINITY; float min = Float.POSITIVE_INFINITY;
float max = Float.NEGATIVE_INFINITY; float max = Float.NEGATIVE_INFINITY;
for (float f : data1D) { for (int j = 0; j < szY; j++) {
if (f != GridUtil.GRID_FILL_VALUE && !Float.isNaN(f)) { for (int i = 0; i < szX; i++) {
min = Math.min(min, f); float f = (float) subgridSource.getDataValue(i, j);
max = Math.max(max, f); if (!Float.isNaN(f)) {
min = Math.min(min, f);
max = Math.max(max, f);
}
} }
} }
float interval = XFormFunctions float interval = XFormFunctions
@ -383,12 +398,12 @@ public class ContourSupport {
true, "", 10); true, "", 10);
config.seed = new float[] { interval }; config.seed = new float[] { interval };
config.mode = -50; config.mode = -50;
contours = FortConBuf.contour(subgriddedData, config); contours = FortConBuf.contour(subgridSource, szX, szY, config);
} else { } else {
LabelingPreferences contourLabeling = prefs LabelingPreferences contourLabeling = prefs
.getContourLabeling(); .getContourLabeling();
if (contourLabeling.getLabelSpacing() > 0) { if (contourLabeling.getLabelSpacing() > 0) {
config.labelSpacingLine = subgriddedData.length config.labelSpacingLine = szX
/ contourLabeling.getLabelSpacing(); / contourLabeling.getLabelSpacing();
if (config.labelSpacingLine < 1) { if (config.labelSpacingLine < 1) {
config.labelSpacingLine = 1; config.labelSpacingLine = 1;
@ -425,14 +440,14 @@ public class ContourSupport {
.getIncrement(); .getIncrement();
float interval; float interval;
if (contourLabeling.getNumberOfContours() > 0) { if (contourLabeling.getNumberOfContours() > 0) {
float minData = 1e37f; float minData = Float.POSITIVE_INFINITY;
float maxData = -1e37f; float maxData = Float.NEGATIVE_INFINITY;
for (float[] dataRow : subgriddedData) { for (int j = 0; j < szY; j++) {
for (float data : dataRow) { for (int i = 0; i < szX; i++) {
if (data < minData && data != -999999) { float f = (float) subgridSource.getDataValue(i, j);
minData = data; if (!Float.isNaN(f)) {
} else if (data < 999998 && data > maxData) { minData = Math.min(minData, f);
maxData = data; maxData = Math.max(maxData, f);
} }
} }
} }
@ -463,7 +478,7 @@ public class ContourSupport {
config.mode = 0; config.mode = 0;
config.seed = controls; config.seed = controls;
contours = FortConBuf.contour(subgriddedData, config); contours = FortConBuf.contour(subgridSource, szX, szY, config);
} else if (prefs.getContourLabeling().getValues() != null) { } else if (prefs.getContourLabeling().getValues() != null) {
// explicit contouring values provided // explicit contouring values provided
@ -497,7 +512,7 @@ public class ContourSupport {
} else { } else {
config.mode = vals.length; config.mode = vals.length;
} }
contours = FortConBuf.contour(subgriddedData, config); contours = FortConBuf.contour(subgridSource, szX, szY, config);
} }
} }
@ -528,7 +543,7 @@ public class ContourSupport {
long tZ1 = System.currentTimeMillis(); long tZ1 = System.currentTimeMillis();
tMinMaxAccum += tZ1 - tZ0; tMinMaxAccum += tZ1 - tZ0;
checkWorldWrapping(contours, descriptor, rastPosToLatLon); correctWorldWrapping(contours, descriptor, rastPosToLatLon);
int size = contours.xyContourPoints.size(); int size = contours.xyContourPoints.size();
// total coordinates // total coordinates
@ -613,19 +628,9 @@ public class ContourSupport {
} catch (Throwable e) { } catch (Throwable e) {
throw new VizException("Error postprocessing contours", e); throw new VizException("Error postprocessing contours", e);
} }
} else if (records.length == 2) { } else if (sources.length == 2) {
float[] uW = null; GridEnvelope range = imageGridGeometry.getGridRange();
float[] vW = null; long[] sz = { range.getSpan(0), range.getSpan(1) };
long[] sz = records[0].getSizes();
if (records[0] instanceof FloatDataRecord) {
uW = ((FloatDataRecord) records[0]).getFloatData();
vW = ((FloatDataRecord) records[1]).getFloatData();
} else {
throw new UnsupportedOperationException(
"Streamlining is not supported for data type: "
+ records.getClass().getName());
}
// Step 4: Determine the subgrid, if any // Step 4: Determine the subgrid, if any
@ -634,7 +639,8 @@ public class ContourSupport {
int maxX = (int) Math.ceil(Math.min(env.getMaximum(0), sz[0] - 1)); int maxX = (int) Math.ceil(Math.min(env.getMaximum(0), sz[0] - 1));
int maxY = (int) Math.ceil(Math.min(env.getMaximum(1), sz[1] - 1)); int maxY = (int) Math.ceil(Math.min(env.getMaximum(1), sz[1] - 1));
makeStreamLines(uW, vW, minX, minY, maxX, maxY, sz, contourGroup, makeStreamLines(sources[0], sources[1], minX, minY, maxX, maxY, sz,
contourGroup,
currentMagnification, zoom, contourGroup.lastDensity, currentMagnification, zoom, contourGroup.lastDensity,
rastPosToWorldGrid); rastPosToWorldGrid);
} }
@ -645,7 +651,7 @@ public class ContourSupport {
public static GeneralEnvelope calculateSubGrid(IExtent workingExtent, public static GeneralEnvelope calculateSubGrid(IExtent workingExtent,
GeneralGridGeometry mapGridGeometry, GeneralGridGeometry mapGridGeometry,
GeneralGridGeometry imageGridGeometry) throws VizException { GeneralGridGeometry imageGridGeometry) {
GeneralEnvelope env = new GeneralEnvelope(2); GeneralEnvelope env = new GeneralEnvelope(2);
try { try {
GridGeometry2D imageGeometry2D = GridGeometry2D GridGeometry2D imageGeometry2D = GridGeometry2D
@ -723,7 +729,6 @@ public class ContourSupport {
final double threshold1 = (200.0 / screenToPixel); final double threshold1 = (200.0 / screenToPixel);
final double threshold2 = (50.0 / screenToPixel); final double threshold2 = (50.0 / screenToPixel);
long tAccum = 0;
double q1, q2, p1, p2; double q1, q2, p1, p2;
for (int n = 0; n < valsArr.length; n++) { for (int n = 0; n < valsArr.length; n++) {
@ -764,11 +769,9 @@ public class ContourSupport {
} }
if (!tooClose if (!tooClose
/* || (labeledAtLeastOnce == false && n == valsArr.length - 1) */) { /* || (labeledAtLeastOnce == false && n == valsArr.length - 1) */) {
long t0 = System.currentTimeMillis();
shapeToAddTo.addLabel(label, valsArr[n]); shapeToAddTo.addLabel(label, valsArr[n]);
labelPoints.add(valsArr[n]); labelPoints.add(valsArr[n]);
lastPoint = valsArr[n]; lastPoint = valsArr[n];
tAccum += (System.currentTimeMillis() - t0);
} }
} }
} }
@ -1087,7 +1090,13 @@ public class ContourSupport {
int maxX = (int) (sz[0] - 1); int maxX = (int) (sz[0] - 1);
int maxY = (int) (sz[1] - 1); int maxY = (int) (sz[1] - 1);
makeStreamLines(uW, vW, minX, minY, maxX, maxY, sz, contourGroup, DataSource uWSource = new FloatArrayWrapper(uW, (int) sz[0],
(int) sz[1]);
DataSource vWSource = new FloatArrayWrapper(vW, (int) sz[0],
(int) sz[1]);
makeStreamLines(uWSource, vWSource, minX, minY, maxX, maxY, sz,
contourGroup,
1, 1, contourGroup.lastDensity * 2, gridToPixel); 1, 1, contourGroup.lastDensity * 2, gridToPixel);
return contourGroup; return contourGroup;
@ -1099,7 +1108,7 @@ public class ContourSupport {
} }
private static void makeStreamLines(float[] uW, float[] vW, int minX, private static void makeStreamLines(DataSource uW, DataSource vW, int minX,
int minY, int maxX, int maxY, long[] sz, ContourGroup contourGroup, int minY, int maxX, int maxY, long[] sz, ContourGroup contourGroup,
double currentMagnification, float zoom, double density, double currentMagnification, float zoom, double density,
MathTransform rastPosToWorldGrid) throws VizException { MathTransform rastPosToWorldGrid) throws VizException {
@ -1113,24 +1122,6 @@ public class ContourSupport {
int x = (int) sz[0]; int x = (int) sz[0];
int y = (int) sz[1]; int y = (int) sz[1];
float[][] adjustedUw = new float[szX][szY];
float[][] adjustedVw = new float[szX][szY];
for (int j = 0; j < szY; j++) {
for (int i = 0; i < szX; i++) {
float uWVal = uW[(x * (j + minY)) + (i + minX)];
if (Float.isNaN(uWVal)) {
uWVal = GridUtil.GRID_FILL_VALUE;
}
adjustedUw[szX - 1 - i][j] = uWVal;
float vWVal = vW[(x * (j + minY)) + (i + minX)];
if (Float.isNaN(vWVal)) {
vWVal = GridUtil.GRID_FILL_VALUE;
}
adjustedVw[szX - 1 - i][j] = vWVal;
}
}
// Use ported legacy code to determine contour interval // Use ported legacy code to determine contour interval
long t0 = System.currentTimeMillis(); long t0 = System.currentTimeMillis();
@ -1180,8 +1171,8 @@ public class ContourSupport {
StrmPakConfig config = new StrmPakConfig(arrowSize, minspc, maxspc, StrmPakConfig config = new StrmPakConfig(arrowSize, minspc, maxspc,
-1000000f, -999998f); -1000000f, -999998f);
StreamLineContainer container = StrmPak.strmpak(adjustedUw, adjustedVw, StreamLineContainer container = StrmPak.strmpak(uW, vW,
szX, szX, szY, config); szX, szY, config);
long t1 = System.currentTimeMillis(); long t1 = System.currentTimeMillis();
System.out.println("Contouring took: " + (t1 - t0)); System.out.println("Contouring took: " + (t1 - t0));
@ -1351,13 +1342,30 @@ public class ContourSupport {
return rval; return rval;
} }
private static void checkWorldWrapping(ContourContainer contours, /**
* Check the contour lines in a ContourContainer and split any lines that
* need to wrap over the "seam" in the display crs. If changes are needed
* the lines within contours are modified directly.
*
* @param contours
* container holding contour lines
* @param descriptor
* the discriptor for the dispaly
* @param rastPosToLatLon
* transform for converting the coordinates within contours to
* LatLon coordinates.
* @throws TransformException
*/
private static void correctWorldWrapping(ContourContainer contours,
IMapDescriptor descriptor, MathTransform rastPosToLatLon) IMapDescriptor descriptor, MathTransform rastPosToLatLon)
throws TransformException { throws TransformException {
long tZ0 = System.currentTimeMillis(); long tZ0 = System.currentTimeMillis();
WorldWrapChecker wwc = new WorldWrapChecker( WorldWrapChecker wwc = new WorldWrapChecker(
descriptor.getGridGeometry()); descriptor.getGridGeometry());
if (!wwc.needsChecking()) {
return;
}
List<float[]> splitLines = new ArrayList<float[]>(); List<float[]> splitLines = new ArrayList<float[]>();
List<Float> dupValues = new ArrayList<Float>(); List<Float> dupValues = new ArrayList<Float>();

View file

@ -64,6 +64,7 @@ import com.vividsolutions.jts.geom.Coordinate;
* Sep 10, 2013 16257 MPorricelli Fix so that wind for global grids displays on * Sep 10, 2013 16257 MPorricelli Fix so that wind for global grids displays on
* mercator maps. * mercator maps.
* Sep 23, 2013 2363 bsteffen Add more vector configuration options. * Sep 23, 2013 2363 bsteffen Add more vector configuration options.
* Feb 27, 2014 2791 bsteffen Remove Unnecessary throws
* *
* </pre> * </pre>
* *
@ -432,7 +433,7 @@ public abstract class AbstractGriddedDisplay<T> implements IRenderable {
} }
public void reproject() throws VizException { public void reproject() {
initPlotLocations(); initPlotLocations();
issueRefresh(); issueRefresh();
} }

View file

@ -24,23 +24,24 @@ import java.nio.FloatBuffer;
import org.geotools.coverage.grid.GeneralGridGeometry; import org.geotools.coverage.grid.GeneralGridGeometry;
import org.geotools.coverage.grid.GridGeometry2D; import org.geotools.coverage.grid.GridGeometry2D;
import com.raytheon.uf.common.datastorage.records.FloatDataRecord; import com.raytheon.uf.common.geospatial.interpolation.data.DataSource;
import com.raytheon.uf.common.datastorage.records.IDataRecord; import com.raytheon.uf.common.geospatial.interpolation.data.FloatBufferWrapper;
import com.raytheon.uf.common.style.contour.ContourPreferences;
import com.raytheon.uf.viz.core.exception.VizException; import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.core.map.IMapDescriptor; import com.raytheon.uf.viz.core.map.IMapDescriptor;
import com.raytheon.viz.core.contours.ContourRenderable; import com.raytheon.viz.core.contours.ContourRenderable;
import com.raytheon.uf.common.style.contour.ContourPreferences;
/** /**
* Displays contours from GFE Grid Data * Displays contours from any data source
* *
* Currently implemented using the D2D contouring capability * Currently implemented using the D2D contouring capability
* *
* <pre> * <pre>
* SOFTWARE HISTORY * SOFTWARE HISTORY
* Date Ticket# Engineer Description * Date Ticket# Engineer Description
* ------------ ---------- ----------- -------------------------- * ------------- -------- ----------- --------------------------
* Jul 11, 2008 #1233 chammack Initial creation * Jul 11, 2008 1233 chammack Initial creation
* Feb 27, 2014 2791 bsteffen Switch from IDataRecord to DataSource
* *
* </pre> * </pre>
* *
@ -54,21 +55,23 @@ public class GriddedContourDisplay extends ContourRenderable {
protected GridGeometry2D gridGeometry; protected GridGeometry2D gridGeometry;
protected FloatBuffer fb; protected DataSource source;
public GriddedContourDisplay(IMapDescriptor descriptor, public GriddedContourDisplay(IMapDescriptor descriptor,
final GridGeometry2D gridGeometry, final FloatBuffer fb) { final GridGeometry2D gridGeometry, final FloatBuffer fb) {
this(descriptor, gridGeometry, new FloatBufferWrapper(fb, gridGeometry));
}
public GriddedContourDisplay(IMapDescriptor descriptor,
final GridGeometry2D gridGeometry, final DataSource source) {
super(descriptor); super(descriptor);
this.gridGeometry = gridGeometry; this.gridGeometry = gridGeometry;
this.fb = fb; this.source = source;
} }
@Override @Override
public IDataRecord[] getData() throws VizException { public DataSource[] getData() throws VizException {
FloatDataRecord fdr = new FloatDataRecord("Data", "", fb.array(), 2, return new DataSource[] { source };
new long[] { gridGeometry.getGridRange2D().width,
gridGeometry.getGridRange2D().height });
return new IDataRecord[] { fdr };
} }
@Override @Override

View file

@ -23,8 +23,8 @@ import java.nio.FloatBuffer;
import org.geotools.coverage.grid.GridGeometry2D; import org.geotools.coverage.grid.GridGeometry2D;
import com.raytheon.uf.common.datastorage.records.FloatDataRecord; import com.raytheon.uf.common.geospatial.interpolation.data.DataSource;
import com.raytheon.uf.common.datastorage.records.IDataRecord; import com.raytheon.uf.common.geospatial.interpolation.data.FloatBufferWrapper;
import com.raytheon.uf.viz.core.exception.VizException; import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.core.map.IMapDescriptor; import com.raytheon.uf.viz.core.map.IMapDescriptor;
@ -39,11 +39,12 @@ import com.raytheon.uf.viz.core.map.IMapDescriptor;
* <pre> * <pre>
* *
* SOFTWARE HISTORY * SOFTWARE HISTORY
* Date Ticket# Engineer Description * Date Ticket# Engineer Description
* ------------ ---------- ----------- -------------------------- * ------------- -------- ----------- --------------------------
* Jun 22, 2010 bsteffen Initial creation * Jun 22, 2010 bsteffen Initial creation
* Feb 07, 2011 7948 bkowal added a public method to get * Feb 07, 2011 7948 bkowal added a public method to get the
* the direction. * direction.
* Feb 27, 2014 2791 bsteffen Switch from IDataRecord to DataSource
* *
* </pre> * </pre>
* *
@ -52,23 +53,23 @@ import com.raytheon.uf.viz.core.map.IMapDescriptor;
*/ */
public class GriddedStreamlineDisplay extends GriddedContourDisplay { public class GriddedStreamlineDisplay extends GriddedContourDisplay {
private FloatBuffer vfb; private DataSource vSource;
public GriddedStreamlineDisplay(IMapDescriptor descriptor, public GriddedStreamlineDisplay(IMapDescriptor descriptor,
GridGeometry2D gridGeometry, FloatBuffer ufb, FloatBuffer vfb) { GridGeometry2D gridGeometry, FloatBuffer ufb, FloatBuffer vfb) {
super(descriptor, gridGeometry, ufb); super(descriptor, gridGeometry, ufb);
this.vfb = vfb; this.vSource = new FloatBufferWrapper(vfb, gridGeometry);
}
public GriddedStreamlineDisplay(IMapDescriptor descriptor,
GridGeometry2D gridGeometry, DataSource ufb, DataSource vfb) {
super(descriptor, gridGeometry, ufb);
this.vSource = vfb;
} }
@Override @Override
public IDataRecord[] getData() throws VizException { public DataSource[] getData() throws VizException {
FloatDataRecord ufdr = new FloatDataRecord("uData", "", fb.array(), 2, return new DataSource[] { source, vSource };
new long[] { gridGeometry.getGridRange2D().width,
gridGeometry.getGridRange2D().height });
FloatDataRecord vfdr = new FloatDataRecord("vData", "", vfb.array(), 2,
new long[] { gridGeometry.getGridRange2D().width,
gridGeometry.getGridRange2D().height });
return new IDataRecord[] { ufdr, vfdr };
} }
} }

View file

@ -34,20 +34,19 @@ import org.opengis.referencing.operation.NoninvertibleTransformException;
import org.opengis.referencing.operation.TransformException; import org.opengis.referencing.operation.TransformException;
/** /**
* * Caches reprojected plot location for quick display.
* TODO Add Description
* *
* <pre> * <pre>
* *
* SOFTWARE HISTORY * SOFTWARE HISTORY
* *
* Date Ticket# Engineer Description * Date Ticket# Engineer Description
* ------------ ---------- ----------- -------------------------- * ------------- -------- ----------- -----------------------------------------
* Oct 13, 2011 bsteffen Initial creation * Oct 13, 2011 bsteffen Initial creation
* Sep 10, 2013 DR 16257 MPorricelli Eliminate values that * Sep 10, 2013 16257 MPorricelli Eliminate values that fail to be
* fail to be tranformed,e.g. * tranformed,e.g. when too close to pole
* when too close to pole for * for mercator projections
* mercator projections * Feb 27, 2014 2791 bsteffen Remove Unnecessary catch
* *
* </pre> * </pre>
* *
@ -169,8 +168,6 @@ public class PlotLocationCache {
throw new RuntimeException(e); throw new RuntimeException(e);
} catch (NoninvertibleTransformException e) { } catch (NoninvertibleTransformException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} catch (TransformException e) {
throw new RuntimeException(e);
} }
cache.put(key, new SoftReference<float[]>(result)); cache.put(key, new SoftReference<float[]>(result));
} }

View file

@ -24,6 +24,11 @@ import java.text.ParseException;
import java.util.Queue; import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import com.raytheon.uf.common.geospatial.interpolation.data.AxisSwapDataSource;
import com.raytheon.uf.common.geospatial.interpolation.data.DataSource;
import com.raytheon.uf.common.geospatial.interpolation.data.FloatArray2DWrapper;
import com.raytheon.uf.common.geospatial.interpolation.data.InvalidRangeDataSource;
/** /**
* Port of the fortCon.f routine. Minimal changes made to make it perform better * Port of the fortCon.f routine. Minimal changes made to make it perform better
* in java. Not object orientated and not thread safe! * in java. Not object orientated and not thread safe!
@ -31,9 +36,10 @@ import java.util.concurrent.ConcurrentLinkedQueue;
* <pre> * <pre>
* *
* SOFTWARE HISTORY * SOFTWARE HISTORY
* Date Ticket# Engineer Description * Date Ticket# Engineer Description
* ------------ ---------- ----------- -------------------------- * ------------- -------- ----------- --------------------------
* Apr 22, 2010 #4583 rjpeter Initial creation * Apr 22, 2010 4583 rjpeter Initial creation
* Feb 27, 2014 2791 bsteffen Use DataSource for generic data access.
* *
* </pre> * </pre>
* *
@ -68,13 +74,9 @@ public class FortConBuf {
} }
} }
private PointBuffer ijPntBuffer = new PointBuffer(2000, 1000, true); private PointBuffer ijPntBuffer = new PointBuffer(2000, 1000);
private float[][] dataToContour; private DataSource dataToContour;
private int nx;
private int ny;
private int nxMaxIndex; private int nxMaxIndex;
@ -96,16 +98,6 @@ public class FortConBuf {
private float[] MxAvg = new float[maxContours]; private float[] MxAvg = new float[maxContours];
private int dlx;
private int dly;
private int dld;
private int labsep;
private int celcnt;
private int c; private int c;
private int labsep2; private int labsep2;
@ -119,6 +111,34 @@ public class FortConBuf {
private static Queue<FortConBuf> instancePool = new ConcurrentLinkedQueue<FortConBuf>(); private static Queue<FortConBuf> instancePool = new ConcurrentLinkedQueue<FortConBuf>();
public static ContourContainer contour(float[][] data, FortConConfig config) { public static ContourContainer contour(float[][] data, FortConConfig config) {
int ny = data.length;
int nx = data[0].length;
DataSource source = new FloatArray2DWrapper(data, nx, ny);
source = new AxisSwapDataSource(source);
if (config.badlo < config.badhi) {
source = new InvalidRangeDataSource(source, config.badlo,
config.badhi);
}
return contour(source, ny, nx, config);
}
/**
* Perform contouring. This method ignores config.badlo and config.badhi and
* only treats NaN as bad data.
*
* @param data
* the source for data to contouring.
* @param nx
* The number of points to contour in the x direction
* @param ny
* The number of points to contour in the y direction
* @param config
* configuration options
* @return a ContourContainer
*/
public static ContourContainer contour(DataSource data, int nx, int ny,
FortConConfig config) {
ContourContainer rval = null; ContourContainer rval = null;
FortConBuf instance = null; FortConBuf instance = null;
try { try {
@ -127,7 +147,7 @@ public class FortConBuf {
instance = new FortConBuf(); instance = new FortConBuf();
} }
rval = instance.contourInternal(data, config); rval = instance.contourInternal(data, nx, ny, config);
} finally { } finally {
if (instance != null) { if (instance != null) {
instancePool.add(instance); instancePool.add(instance);
@ -137,141 +157,76 @@ public class FortConBuf {
return rval; return rval;
} }
private ContourContainer contourInternal(float[][] data, private ContourContainer contourInternal(DataSource data, int nx, int ny,
FortConConfig config) { FortConConfig config) {
dataToContour = data; dataToContour = data;
nx = dataToContour.length;
ny = dataToContour[0].length;
nxMaxIndex = nx - 1; nxMaxIndex = nx - 1;
nyMaxIndex = ny - 1; nyMaxIndex = ny - 1;
ijPntBuffer.setSize(0); ijPntBuffer.setSize(0);
ijPntBuffer.setXOffset(config.xOffset); ijPntBuffer.setXOffset(config.xOffset);
ijPntBuffer.setYOffset(config.yOffset); ijPntBuffer.setYOffset(config.yOffset);
float rawmax = -Float.MAX_VALUE; double rawmax = -Double.MAX_VALUE;
float rawmin = Float.MAX_VALUE; double rawmin = Double.MAX_VALUE;
work1 = new byte[nx][ny]; work1 = new byte[nx][ny];
work2 = new byte[nx][ny]; work2 = new byte[nx][ny];
work3 = new byte[nx][ny]; work3 = new byte[nx][ny];
work4 = new byte[nx][ny]; work4 = new byte[nx][ny];
int ldwork = Math.min(Math.min(nx, ny),
Math.max(1, config.labelSpacingLine));
// contourCount is number of contour values // contourCount is number of contour values
int contourCount, mmm; int contourCount, mmm;
int i, j, xmode, turn1, turn2, turn3, turn4, ii, jj; int i, j, xmode, turn1, turn2, turn3, turn4, ii, jj;
float val, val1, val2, dval, minval, maxval, D2; double val, val1, val2, dval, minval, maxval, D2;
String[] LabStr = new String[maxContours];
Byte bbb; Byte bbb;
// map out missing values // map out missing values
if (config.badlo < config.badhi) { // Figure out which vertical sides can accept contours.
// Figure out which vertical sides can accept contours. for (int cIdx = 0; cIdx < nx; cIdx++) {
for (int cIdx = 0; cIdx < nx; cIdx++) { val2 = dataToContour.getDataValue(cIdx, nyMaxIndex);
val2 = dataToContour[cIdx][nyMaxIndex]; for (int rIdx = nyMaxIndex - 1; rIdx >= 0; rIdx--) {
for (int rIdx = nyMaxIndex - 1; rIdx >= 0; rIdx--) { val1 = dataToContour.getDataValue(cIdx, rIdx);
val1 = dataToContour[cIdx][rIdx]; if (val1 < val2) {
if (val1 < val2) { if (val1 < rawmin) {
if (val1 > config.badhi || val2 < config.badlo) { rawmin = val1;
if (val1 < rawmin) {
rawmin = val1;
}
work4[cIdx][rIdx] = b40;
} else {
work4[cIdx][rIdx] = 1;
}
} else {
if (val2 > config.badhi || val1 < config.badlo) {
if (val2 < rawmin) {
rawmin = val2;
}
if (val2 < val1) {
work4[cIdx][rIdx] = bC0;
}
} else {
work4[cIdx][rIdx] = 1;
}
} }
val2 = val1; work4[cIdx][rIdx] = b40;
} } else if (Double.isNaN(val1) || Double.isNaN(val2)) {
} work4[cIdx][rIdx] = 1;
} else {
// Figure out which horizontal sides can accept contours. if (val2 < rawmin) {
for (int rIdx = 0; rIdx < ny; rIdx++) { rawmin = val2;
val2 = dataToContour[nxMaxIndex][rIdx];
for (int cIdx = nxMaxIndex - 1; cIdx >= 0; cIdx--) {
val1 = dataToContour[cIdx][rIdx];
if (val1 < val2) {
if (val1 > config.badhi || val2 < config.badlo) {
if (val2 > rawmax) {
rawmax = val2;
}
work3[cIdx][rIdx] = b40;
} else {
work3[cIdx][rIdx] = 1;
}
} else {
if (val2 > config.badhi || val1 < config.badlo) {
if (val1 > rawmax) {
rawmax = val1;
}
if (val2 < val1) {
work3[cIdx][rIdx] = bC0;
}
} else {
work3[cIdx][rIdx] = 1;
}
} }
val2 = val1; if (val2 < val1) {
}
}
} else { // no missing value
// Determine "sense" of vertical sides.
for (int cIdx = 0; cIdx < nx; cIdx++) {
val2 = dataToContour[cIdx][nyMaxIndex];
for (int rIdx = nyMaxIndex - 1; rIdx >= 0; rIdx--) {
val1 = dataToContour[cIdx][rIdx];
if (val1 < val2) {
if (val1 < rawmin) {
rawmin = val1;
}
work4[cIdx][rIdx] = b40;
} else {
if (val2 < rawmin) {
rawmin = val2;
}
work4[cIdx][rIdx] = bC0; work4[cIdx][rIdx] = bC0;
} }
val2 = val1;
} }
val2 = val1;
} }
}
// determine "sense" of horizontal size // Figure out which horizontal sides can accept contours.
for (int rIdx = 0; rIdx < ny; rIdx++) { for (int rIdx = 0; rIdx < ny; rIdx++) {
val2 = dataToContour[nxMaxIndex][rIdx]; val2 = dataToContour.getDataValue(nxMaxIndex, rIdx);
for (int cIdx = nxMaxIndex - 1; cIdx >= 0; cIdx--) { for (int cIdx = nxMaxIndex - 1; cIdx >= 0; cIdx--) {
val1 = dataToContour[cIdx][rIdx]; val1 = dataToContour.getDataValue(cIdx, rIdx);
if (val1 < val2) { if (val1 < val2) {
if (val2 > rawmax) { if (val2 > rawmax) {
rawmax = val2; rawmax = val2;
} }
work3[cIdx][rIdx] = b40;
work3[cIdx][rIdx] = b40; } else if (Double.isNaN(val1) || Double.isNaN(val2)) {
} else { work3[cIdx][rIdx] = 1;
if (val1 > rawmax) { } else {
rawmax = val1; if (val1 > rawmax) {
} rawmax = val1;
}
if (val2 < val1) {
work3[cIdx][rIdx] = bC0; work3[cIdx][rIdx] = bC0;
} }
val2 = val1;
} }
val2 = val1;
} }
} }
@ -355,7 +310,7 @@ public class FortConBuf {
// e.g. dont calculate contours with an offset of 1.5 when // e.g. dont calculate contours with an offset of 1.5 when
// contours are printed as integers, will cause contours // contours are printed as integers, will cause contours
// to go missing in that case // to go missing in that case
if (config != null && config.labelFormat != null) { if (config.labelFormat != null) {
DecimalFormat df = new DecimalFormat(config.labelFormat); DecimalFormat df = new DecimalFormat(config.labelFormat);
float temp = Float.valueOf(df.format(dval)); float temp = Float.valueOf(df.format(dval));
if (temp != 0) { if (temp != 0) {
@ -379,7 +334,7 @@ public class FortConBuf {
int numSteps = (int) ((val2 - val1) / dval + 1); int numSteps = (int) ((val2 - val1) / dval + 1);
val = val1; val = val1;
for (contourCount = 0; contourCount < numSteps; contourCount++) { for (contourCount = 0; contourCount < numSteps; contourCount++) {
ConVal[contourCount] = val; ConVal[contourCount] = (float) val;
val = val + dval; val = val + dval;
} }
// remove ncon-- as now ncon is the number of contour values // remove ncon-- as now ncon is the number of contour values
@ -468,8 +423,8 @@ public class FortConBuf {
// mmtol processing always amount to 0 // mmtol processing always amount to 0
float dmm = 0; float dmm = 0;
float mmlim1 = 0; double mmlim1 = 0;
float mmlim2 = 0; double mmlim2 = 0;
// Figure out limits of values which may be marked for. // Figure out limits of values which may be marked for.
if (mmm > 1 && val2 < 0) { if (mmm > 1 && val2 < 0) {
@ -496,7 +451,7 @@ public class FortConBuf {
continue MIN_MAX_SEARCH; continue MIN_MAX_SEARCH;
} }
// check that this falls within markable limits // check that this falls within markable limits
val = dataToContour[i][j]; val = dataToContour.getDataValue(i, j);
if (val < mmlim1 || val > mmlim2) { if (val < mmlim1 || val > mmlim2) {
continue MIN_MAX_SEARCH; continue MIN_MAX_SEARCH;
} }
@ -508,19 +463,23 @@ public class FortConBuf {
continue MIN_MAX_SEARCH; continue MIN_MAX_SEARCH;
} }
// check corner points // check corner points
if ((work3[im][jm] >= 2 && work4[im][jm] >= 2 && dataToContour[i][j] >= dataToContour[im][jm]) if ((work3[im][jm] >= 2 && work4[im][jm] >= 2 && val >= dataToContour
|| (work3[im][jp] >= 2 && work4[im][j] <= -2 && dataToContour[i][j] >= dataToContour[im][jp]) .getDataValue(im, jm))
|| (work3[i][jm] <= -2 && work4[ip][jm] >= 2 && dataToContour[i][j] >= dataToContour[ip][jm]) || (work3[im][jp] >= 2 && work4[im][j] <= -2 && val >= dataToContour
|| (work3[i][jp] <= -2 && work4[ip][j] <= -2 && dataToContour[i][j] >= dataToContour[ip][jp])) { .getDataValue(jp, im))
|| (work3[i][jm] <= -2 && work4[ip][jm] >= 2 && val >= dataToContour
.getDataValue(ip, jm))
|| (work3[i][jp] <= -2 && work4[ip][j] <= -2 && val >= dataToContour
.getDataValue(ip, jp))) {
continue MIN_MAX_SEARCH; continue MIN_MAX_SEARCH;
} }
// sharp min check // sharp min check
if (dmm > 0) { if (dmm > 0) {
val = dataToContour[i][j] + dmm; val = val + dmm;
if (val > dataToContour[im][j] if (val > dataToContour.getDataValue(im, j)
|| val > dataToContour[i][jm] || val > dataToContour.getDataValue(i, jm)
|| val > dataToContour[ip][j] || val > dataToContour.getDataValue(ip, j)
|| val > dataToContour[i][jp]) { || val > dataToContour.getDataValue(i, jp)) {
continue MIN_MAX_SEARCH; continue MIN_MAX_SEARCH;
} }
} }
@ -558,19 +517,23 @@ public class FortConBuf {
continue MIN_MAX_SEARCH; continue MIN_MAX_SEARCH;
} }
// check corner points // check corner points
if ((work3[im][jm] <= -2 && work4[im][jm] <= -2 && dataToContour[i][j] <= dataToContour[im][jm]) if ((work3[im][jm] <= -2 && work4[im][jm] <= -2 && val <= dataToContour
|| (work3[im][jp] <= -2 && work4[im][j] >= 2 && dataToContour[i][j] <= dataToContour[im][jp]) .getDataValue(im, jm))
|| (work3[i][jm] >= 2 && work4[ip][jm] <= -2 && dataToContour[i][j] <= dataToContour[ip][jm]) || (work3[im][jp] <= -2 && work4[im][j] >= 2 && val <= dataToContour
|| (work3[i][jp] >= 2 && work4[ip][j] >= 2 && dataToContour[i][j] <= dataToContour[ip][jp])) { .getDataValue(ip, jp))
|| (work3[i][jm] >= 2 && work4[ip][jm] <= -2 && val <= dataToContour
.getDataValue(ip, jm))
|| (work3[i][jp] >= 2 && work4[ip][j] >= 2 && val <= dataToContour
.getDataValue(ip, jp))) {
continue MIN_MAX_SEARCH; continue MIN_MAX_SEARCH;
} }
// sharp max check // sharp max check
if (dmm > 0) { if (dmm > 0) {
val = dataToContour[i][j] - dmm; val = val - dmm;
if (val < dataToContour[im][j] if (val < dataToContour.getDataValue(im, j)
|| val < dataToContour[i][jm] || val < dataToContour.getDataValue(i, jm)
|| val < dataToContour[ip][j] || val < dataToContour.getDataValue(ip, j)
|| val < dataToContour[i][jp]) { || val < dataToContour.getDataValue(i, jp)) {
continue MIN_MAX_SEARCH; continue MIN_MAX_SEARCH;
} }
} }
@ -629,12 +592,6 @@ public class FortConBuf {
// Initialize counters for total cells, labels, and label separations on // Initialize counters for total cells, labels, and label separations on
// lines. // lines.
// TODO account for fortran 1 index?
dlx = 2;
dly = 2;
dld = 3;
labsep = dld * ldwork;
celcnt = labsep / 2;
labsep2 = config.labelSpacingOverall; labsep2 = config.labelSpacingOverall;
// Fill line pattern array, scale contour value array, and set use count // Fill line pattern array, scale contour value array, and set use count
@ -693,7 +650,7 @@ public class FortConBuf {
} }
// Cell side does not have missing values, reinitialize search. // Cell side does not have missing values, reinitialize search.
D2 = dataToContour[i][j]; D2 = dataToContour.getDataValue(i, j);
if (bbb > 0) { if (bbb > 0) {
for (c = 0; c < contourCount; c++) { for (c = 0; c < contourCount; c++) {
if (ConVal[c] > D2) { if (ConVal[c] > D2) {
@ -748,7 +705,7 @@ public class FortConBuf {
} }
case 10022: { case 10022: {
// Step through possible contours we can start // Step through possible contours we can start
D2 = dataToContour[ii][jj]; D2 = dataToContour.getDataValue(ii, jj);
boolean keepProcessing = true; boolean keepProcessing = true;
while (keepProcessing) { while (keepProcessing) {
if (ConVal[c] < D2) { if (ConVal[c] < D2) {
@ -801,7 +758,7 @@ public class FortConBuf {
} }
case 10032: { case 10032: {
// Step through possible contours we can start // Step through possible contours we can start
D2 = dataToContour[ii][jj]; D2 = dataToContour.getDataValue(ii, jj);
boolean keepProcessing = true; boolean keepProcessing = true;
while (keepProcessing) { while (keepProcessing) {
if (ConVal[c] > D2) { if (ConVal[c] > D2) {
@ -840,7 +797,7 @@ public class FortConBuf {
} }
// Cell side does not have missing values, reinitialize search. // Cell side does not have missing values, reinitialize search.
D2 = dataToContour[i][j]; D2 = dataToContour.getDataValue(i, j);
if (bbb > 0) { if (bbb > 0) {
for (c = 0; c < contourCount; c++) { for (c = 0; c < contourCount; c++) {
if (ConVal[c] > D2) { if (ConVal[c] > D2) {
@ -895,7 +852,7 @@ public class FortConBuf {
} }
case 20022: { case 20022: {
// Step through possible contours we can start // Step through possible contours we can start
D2 = dataToContour[ii][jj]; D2 = dataToContour.getDataValue(ii, jj);
boolean keepProcessing = true; boolean keepProcessing = true;
while (keepProcessing) { while (keepProcessing) {
if (ConVal[c] < D2) { if (ConVal[c] < D2) {
@ -948,7 +905,7 @@ public class FortConBuf {
} }
case 20032: { case 20032: {
// Find group of contours which are bracketed // Find group of contours which are bracketed
D2 = dataToContour[ii][jj]; D2 = dataToContour.getDataValue(ii, jj);
boolean keepProcessing = true; boolean keepProcessing = true;
while (keepProcessing) { while (keepProcessing) {
if (ConVal[c] > D2) { if (ConVal[c] > D2) {
@ -987,7 +944,7 @@ public class FortConBuf {
} }
// Cell side does not have missing values, reinitialize search. // Cell side does not have missing values, reinitialize search.
D2 = dataToContour[i][j]; D2 = dataToContour.getDataValue(i, j);
if (bbb < 0) { if (bbb < 0) {
for (c = 0; c < contourCount; c++) { for (c = 0; c < contourCount; c++) {
if (ConVal[c] > D2) { if (ConVal[c] > D2) {
@ -1042,7 +999,7 @@ public class FortConBuf {
} }
case 30022: { case 30022: {
// Step through possible contours we can start // Step through possible contours we can start
D2 = dataToContour[ii][jj]; D2 = dataToContour.getDataValue(ii, jj);
boolean keepProcessing = true; boolean keepProcessing = true;
while (keepProcessing) { while (keepProcessing) {
if (ConVal[c] < D2) { if (ConVal[c] < D2) {
@ -1095,7 +1052,7 @@ public class FortConBuf {
} }
case 30032: { case 30032: {
// Step through possible contours we can start // Step through possible contours we can start
D2 = dataToContour[ii][jj]; D2 = dataToContour.getDataValue(ii, jj);
boolean keepProcessing = true; boolean keepProcessing = true;
while (keepProcessing) { while (keepProcessing) {
if (ConVal[c] > D2) { if (ConVal[c] > D2) {
@ -1134,7 +1091,7 @@ public class FortConBuf {
} }
// Cell side does not have missing values, reinitialize search. // Cell side does not have missing values, reinitialize search.
D2 = dataToContour[i][j]; D2 = dataToContour.getDataValue(i, j);
if (bbb < 0) { if (bbb < 0) {
for (c = 0; c < contourCount; c++) { for (c = 0; c < contourCount; c++) {
if (ConVal[c] > D2) { if (ConVal[c] > D2) {
@ -1189,7 +1146,7 @@ public class FortConBuf {
} }
case 40022: { case 40022: {
// Step through possible contours we can start // Step through possible contours we can start
D2 = dataToContour[ii][jj]; D2 = dataToContour.getDataValue(ii, jj);
boolean keepProcessing = true; boolean keepProcessing = true;
while (keepProcessing) { while (keepProcessing) {
if (ConVal[c] < D2) { if (ConVal[c] < D2) {
@ -1242,7 +1199,7 @@ public class FortConBuf {
} }
case 40032: { case 40032: {
// Step through possible contours we can start // Step through possible contours we can start
D2 = dataToContour[ii][jj]; D2 = dataToContour.getDataValue(ii, jj);
boolean keepProcessing = true; boolean keepProcessing = true;
while (keepProcessing) { while (keepProcessing) {
if (ConVal[c] > D2) { if (ConVal[c] > D2) {
@ -1276,12 +1233,14 @@ public class FortConBuf {
bbb = work3[i][j]; bbb = work3[i][j];
if (bbb == b52) { if (bbb == b52) {
// minima // minima
rval.minVals.add(dataToContour[i][j]); rval.minVals.add((float) dataToContour.getDataValue(i,
j));
rval.minLabelPoints.add(new float[] { rval.minLabelPoints.add(new float[] {
i + config.xOffset, j + config.yOffset }); i + config.xOffset, j + config.yOffset });
} else if (bbb == bD2) { } else if (bbb == bD2) {
// maxima // maxima
rval.maxVals.add(dataToContour[i][j]); rval.maxVals.add((float) dataToContour.getDataValue(i,
j));
rval.maxLabelPoints.add(new float[] { rval.maxLabelPoints.add(new float[] {
i + config.xOffset, j + config.yOffset }); i + config.xOffset, j + config.yOffset });
} }
@ -1341,8 +1300,6 @@ public class FortConBuf {
// | | // | |
// point 1 (i,j)-------side 1------(i+1,j) point 2 // point 1 (i,j)-------side 1------(i+1,j) point 2
float val = ConVal[c]; float val = ConVal[c];
float minavg = MnAvg[c];
float maxavg = MxAvg[c];
byte cmw = CMask[c]; byte cmw = CMask[c];
boolean GGG1 = false; boolean GGG1 = false;
boolean GGG2 = false; boolean GGG2 = false;
@ -1363,7 +1320,6 @@ public class FortConBuf {
float D2 = 0; float D2 = 0;
float D3 = 0; float D3 = 0;
float D4 = 0; float D4 = 0;
float DDQ = 0;
// reset point buffer // reset point buffer
ijPntBuffer.setSize(0); ijPntBuffer.setSize(0);
@ -1400,8 +1356,8 @@ public class FortConBuf {
icell = istart; icell = istart;
iplus = istart + 1; iplus = istart + 1;
clos1 = true; clos1 = true;
D3 = dataToContour[iplus][jcell]; D3 = (float) dataToContour.getDataValue(iplus, jcell);
D4 = dataToContour[icell][jcell]; D4 = (float) dataToContour.getDataValue(icell, jcell);
GGG3 = val >= D3; GGG3 = val >= D3;
GGG4 = val >= D4; GGG4 = val >= D4;
if (GGG3 == GGG4) { if (GGG3 == GGG4) {
@ -1427,8 +1383,8 @@ public class FortConBuf {
jcell = jstart; jcell = jstart;
jplus = jstart + 1; jplus = jstart + 1;
clos2 = true; clos2 = true;
D1 = dataToContour[iplus][jcell]; D1 = (float) dataToContour.getDataValue(iplus, jcell);
D4 = dataToContour[iplus][jplus]; D4 = (float) dataToContour.getDataValue(iplus, jplus);
GGG1 = val >= D1; GGG1 = val >= D1;
GGG4 = val >= D4; GGG4 = val >= D4;
if (GGG1 == GGG4) { if (GGG1 == GGG4) {
@ -1454,8 +1410,8 @@ public class FortConBuf {
icell = istart; icell = istart;
iplus = istart + 1; iplus = istart + 1;
clos3 = true; clos3 = true;
D1 = dataToContour[icell][jplus]; D1 = (float) dataToContour.getDataValue(icell, jplus);
D2 = dataToContour[iplus][jplus]; D2 = (float) dataToContour.getDataValue(iplus, jplus);
GGG1 = val >= D1; GGG1 = val >= D1;
GGG2 = val >= D2; GGG2 = val >= D2;
if (GGG1 == GGG2) { if (GGG1 == GGG2) {
@ -1481,8 +1437,8 @@ public class FortConBuf {
jcell = jstart; jcell = jstart;
jplus = jstart + 1; jplus = jstart + 1;
clos4 = true; clos4 = true;
D3 = dataToContour[icell][jplus]; D3 = (float) dataToContour.getDataValue(icell, jplus);
D2 = dataToContour[icell][jcell]; D2 = (float) dataToContour.getDataValue(icell, jcell);
GGG3 = val >= D3; GGG3 = val >= D3;
GGG2 = val >= D2; GGG2 = val >= D2;
if (GGG3 == GGG2) { if (GGG3 == GGG2) {
@ -1501,8 +1457,8 @@ public class FortConBuf {
D1 = D4; D1 = D4;
GGG2 = GGG3; GGG2 = GGG3;
D2 = D3; D2 = D3;
D3 = dataToContour[iplus][jplus]; D3 = (float) dataToContour.getDataValue(iplus, jplus);
D4 = dataToContour[icell][jplus]; D4 = (float) dataToContour.getDataValue(icell, jplus);
GGG3 = val >= D3; GGG3 = val >= D3;
GGG4 = val >= D4; GGG4 = val >= D4;
@ -1513,7 +1469,6 @@ public class FortConBuf {
jumpLabel = 9000; jumpLabel = 9000;
continue JUMP_LOOP; continue JUMP_LOOP;
} }
celcnt += dld;
jumpLabel = 4422; jumpLabel = 4422;
continue JUMP_LOOP; continue JUMP_LOOP;
} else if ((work4[iplus][jcell] & 1) == 0) { } else if ((work4[iplus][jcell] & 1) == 0) {
@ -1521,7 +1476,6 @@ public class FortConBuf {
jumpLabel = 9000; jumpLabel = 9000;
continue JUMP_LOOP; continue JUMP_LOOP;
} }
celcnt += dld;
jumpLabel = 2244; jumpLabel = 2244;
continue JUMP_LOOP; continue JUMP_LOOP;
} }
@ -1531,7 +1485,6 @@ public class FortConBuf {
// Determine proper path through cell from side one // Determine proper path through cell from side one
if (GGG3 == GGG4) { if (GGG3 == GGG4) {
celcnt += dld;
if (GGG2 == GGG3) { if (GGG2 == GGG3) {
jumpLabel = 4422; jumpLabel = 4422;
continue JUMP_LOOP; continue JUMP_LOOP;
@ -1540,11 +1493,9 @@ public class FortConBuf {
continue JUMP_LOOP; continue JUMP_LOOP;
} else { } else {
if (GGG1 == GGG4) { if (GGG1 == GGG4) {
celcnt += dly;
jumpLabel = 3311; jumpLabel = 3311;
continue JUMP_LOOP; continue JUMP_LOOP;
} }
celcnt += dld;
GGGD = val4 >= (D1 + D2 + D3 + D4); GGGD = val4 >= (D1 + D2 + D3 + D4);
if (GGG1 != GGGD) { if (GGG1 != GGGD) {
jumpLabel = 4422; jumpLabel = 4422;
@ -1560,8 +1511,8 @@ public class FortConBuf {
D2 = D1; D2 = D1;
GGG3 = GGG4; GGG3 = GGG4;
D3 = D4; D3 = D4;
D1 = dataToContour[icell][jcell]; D1 = (float) dataToContour.getDataValue(icell, jcell);
D4 = dataToContour[icell][jplus]; D4 = (float) dataToContour.getDataValue(icell, jplus);
GGG1 = val >= D1; GGG1 = val >= D1;
GGG4 = val >= D4; GGG4 = val >= D4;
@ -1572,7 +1523,6 @@ public class FortConBuf {
jumpLabel = 9000; jumpLabel = 9000;
continue JUMP_LOOP; continue JUMP_LOOP;
} }
celcnt += dld;
jumpLabel = 3311; jumpLabel = 3311;
continue JUMP_LOOP; continue JUMP_LOOP;
} else if ((work3[icell][jcell] & 1) == 0) { } else if ((work3[icell][jcell] & 1) == 0) {
@ -1580,7 +1530,6 @@ public class FortConBuf {
jumpLabel = 9000; jumpLabel = 9000;
continue JUMP_LOOP; continue JUMP_LOOP;
} }
celcnt += dld;
jumpLabel = 1133; jumpLabel = 1133;
continue JUMP_LOOP; continue JUMP_LOOP;
} }
@ -1590,7 +1539,6 @@ public class FortConBuf {
// Determine proper path through cell from side two. // Determine proper path through cell from side two.
if (GGG1 == GGG4) { if (GGG1 == GGG4) {
celcnt += dld;
if (GGG3 == GGG4) { if (GGG3 == GGG4) {
jumpLabel = 1133; jumpLabel = 1133;
continue JUMP_LOOP; continue JUMP_LOOP;
@ -1599,11 +1547,9 @@ public class FortConBuf {
continue JUMP_LOOP; continue JUMP_LOOP;
} else { } else {
if (GGG1 == GGG2) { if (GGG1 == GGG2) {
celcnt += dlx;
jumpLabel = 4422; jumpLabel = 4422;
continue JUMP_LOOP; continue JUMP_LOOP;
} }
celcnt += dld;
GGGD = val4 >= (D1 + D2 + D3 + D4); GGGD = val4 >= (D1 + D2 + D3 + D4);
if (GGG2 != GGGD) { if (GGG2 != GGGD) {
jumpLabel = 1133; jumpLabel = 1133;
@ -1619,8 +1565,8 @@ public class FortConBuf {
D3 = D2; D3 = D2;
GGG4 = GGG1; GGG4 = GGG1;
D4 = D1; D4 = D1;
D1 = dataToContour[icell][jcell]; D1 = (float) dataToContour.getDataValue(icell, jcell);
D2 = dataToContour[iplus][jcell]; D2 = (float) dataToContour.getDataValue(iplus, jcell);
GGG1 = val >= D1; GGG1 = val >= D1;
GGG2 = val >= D2; GGG2 = val >= D2;
@ -1631,7 +1577,6 @@ public class FortConBuf {
jumpLabel = 9000; jumpLabel = 9000;
continue JUMP_LOOP; continue JUMP_LOOP;
} }
celcnt += dld;
jumpLabel = 2244; jumpLabel = 2244;
continue JUMP_LOOP; continue JUMP_LOOP;
} else if ((work4[icell][jcell] & 1) == 0) { } else if ((work4[icell][jcell] & 1) == 0) {
@ -1639,7 +1584,6 @@ public class FortConBuf {
jumpLabel = 9000; jumpLabel = 9000;
continue JUMP_LOOP; continue JUMP_LOOP;
} }
celcnt += dld;
jumpLabel = 4422; jumpLabel = 4422;
continue JUMP_LOOP; continue JUMP_LOOP;
} }
@ -1649,7 +1593,6 @@ public class FortConBuf {
// Determine proper path through cell from side three // Determine proper path through cell from side three
if (GGG1 == GGG2) { if (GGG1 == GGG2) {
celcnt += dld;
if (GGG1 == GGG4) { if (GGG1 == GGG4) {
jumpLabel = 2244; jumpLabel = 2244;
continue JUMP_LOOP; continue JUMP_LOOP;
@ -1658,11 +1601,9 @@ public class FortConBuf {
continue JUMP_LOOP; continue JUMP_LOOP;
} else { } else {
if (GGG2 == GGG3) { if (GGG2 == GGG3) {
celcnt += dly;
jumpLabel = 1133; jumpLabel = 1133;
continue JUMP_LOOP; continue JUMP_LOOP;
} }
celcnt += dld;
GGGD = val4 >= (D1 + D2 + D3 + D4); GGGD = val4 >= (D1 + D2 + D3 + D4);
if (GGG3 != GGGD) { if (GGG3 != GGGD) {
jumpLabel = 2244; jumpLabel = 2244;
@ -1678,8 +1619,8 @@ public class FortConBuf {
D4 = D3; D4 = D3;
GGG1 = GGG2; GGG1 = GGG2;
D1 = D2; D1 = D2;
D3 = dataToContour[iplus][jplus]; D3 = (float) dataToContour.getDataValue(iplus, jplus);
D2 = dataToContour[iplus][jcell]; D2 = (float) dataToContour.getDataValue(iplus, jcell);
GGG3 = val >= D3; GGG3 = val >= D3;
GGG2 = val >= D2; GGG2 = val >= D2;
@ -1690,7 +1631,6 @@ public class FortConBuf {
jumpLabel = 9000; jumpLabel = 9000;
continue JUMP_LOOP; continue JUMP_LOOP;
} }
celcnt += dld;
jumpLabel = 1133; jumpLabel = 1133;
continue JUMP_LOOP; continue JUMP_LOOP;
} else if ((work3[icell][jplus] & 1) == 0) { } else if ((work3[icell][jplus] & 1) == 0) {
@ -1698,7 +1638,6 @@ public class FortConBuf {
jumpLabel = 9000; jumpLabel = 9000;
continue JUMP_LOOP; continue JUMP_LOOP;
} }
celcnt += dld;
jumpLabel = 3311; jumpLabel = 3311;
continue JUMP_LOOP; continue JUMP_LOOP;
} }
@ -1708,7 +1647,6 @@ public class FortConBuf {
// Determine proper path through cell from side four. // Determine proper path through cell from side four.
if (GGG2 == GGG3) { if (GGG2 == GGG3) {
celcnt += dld;
if (GGG1 == GGG2) { if (GGG1 == GGG2) {
jumpLabel = 3311; jumpLabel = 3311;
continue JUMP_LOOP; continue JUMP_LOOP;
@ -1717,11 +1655,9 @@ public class FortConBuf {
continue JUMP_LOOP; continue JUMP_LOOP;
} else { } else {
if (GGG3 == GGG4) { if (GGG3 == GGG4) {
celcnt += dlx;
jumpLabel = 2244; jumpLabel = 2244;
continue JUMP_LOOP; continue JUMP_LOOP;
} }
celcnt += dld;
GGGD = val4 >= (D1 + D2 + D3 + D4); GGGD = val4 >= (D1 + D2 + D3 + D4);
if (GGG4 != GGGD) { if (GGG4 != GGGD) {
jumpLabel = 3311; jumpLabel = 3311;
@ -1866,150 +1802,6 @@ public class FortConBuf {
} }
} }
private void markHrz(byte[][] workH, byte[][] workV, int i, int j) {
markCheck(workH, i, j);
if (labsep2 <= 0)
return;
markCheck(workV, i, j - 1);
markCheck(workV, i + 1, j - 1);
markCheck(workV, i, j);
markCheck(workV, i + 1, j);
markCheck(workH, i - 1, j);
markCheck(workH, i + 1, j);
if (labsep2 <= 1)
return;
markCheck(workV, i, j - 2);
markCheck(workV, i + 1, j - 2);
markCheck(workV, i - 1, j - 1);
markCheck(workV, i + 2, j - 1);
markCheck(workV, i - 1, j);
markCheck(workV, i + 2, j);
markCheck(workV, i, j + 1);
markCheck(workV, i + 1, j + 1);
markCheck(workH, i - 1, j - 1);
markCheck(workH, i, j - 1);
markCheck(workH, i + 1, j - 1);
markCheck(workH, i - 2, j);
markCheck(workH, i + 2, j);
markCheck(workH, i - 1, j + 1);
markCheck(workH, i, j + 1);
markCheck(workH, i + 1, j + 1);
if (labsep2 <= 2)
return;
markCheck(workV, i, j - 3);
markCheck(workV, i + 1, j - 3);
markCheck(workV, i - 1, j - 2);
markCheck(workV, i + 2, j - 2);
markCheck(workV, i - 2, j - 1);
markCheck(workV, i + 3, j - 1);
markCheck(workV, i - 2, j);
markCheck(workV, i + 3, j);
markCheck(workV, i - 1, j + 1);
markCheck(workV, i + 2, j + 1);
markCheck(workV, i, j + 2);
markCheck(workV, i + 1, j + 2);
markCheck(workH, i - 1, j - 2);
markCheck(workH, i, j - 2);
markCheck(workH, i + 1, j - 2);
markCheck(workH, i - 2, j - 1);
markCheck(workH, i + 2, j - 1);
markCheck(workH, i - 3, j);
markCheck(workH, i + 3, j);
markCheck(workH, i - 2, j + 1);
markCheck(workH, i + 2, j + 1);
markCheck(workH, i - 1, j + 2);
markCheck(workH, i, j + 2);
markCheck(workH, i + 1, j + 2);
if (labsep2 <= 3)
return;
markCheck(workV, i, j - 4);
markCheck(workV, i + 1, j - 4);
markCheck(workV, i - 1, j - 3);
markCheck(workV, i + 2, j - 3);
markCheck(workV, i - 2, j - 2);
markCheck(workV, i + 3, j - 2);
markCheck(workV, i - 3, j - 1);
markCheck(workV, i + 4, j - 1);
markCheck(workV, i - 3, j);
markCheck(workV, i + 4, j);
markCheck(workV, i - 2, j + 1);
markCheck(workV, i + 3, j + 1);
markCheck(workV, i - 1, j + 2);
markCheck(workV, i + 2, j + 2);
markCheck(workV, i, j + 3);
markCheck(workV, i + 1, j + 3);
markCheck(workH, i - 1, j - 3);
markCheck(workH, i, j - 3);
markCheck(workH, i + 1, j - 3);
markCheck(workH, i - 2, j - 2);
markCheck(workH, i + 2, j - 2);
markCheck(workH, i - 3, j - 1);
markCheck(workH, i + 3, j - 1);
markCheck(workH, i - 4, j);
markCheck(workH, i + 4, j);
markCheck(workH, i - 3, j + 1);
markCheck(workH, i + 3, j + 1);
markCheck(workH, i - 2, j + 2);
markCheck(workH, i + 2, j + 2);
markCheck(workH, i - 1, j + 3);
markCheck(workH, i, j + 3);
markCheck(workH, i + 1, j + 3);
if (labsep2 <= 4)
return;
markCheck(workV, i, j - 5);
markCheck(workV, i + 1, j - 5);
markCheck(workV, i - 1, j - 4);
markCheck(workV, i + 2, j - 4);
markCheck(workV, i - 2, j - 3);
markCheck(workV, i + 3, j - 3);
markCheck(workV, i - 3, j - 2);
markCheck(workV, i + 4, j - 2);
markCheck(workV, i - 4, j - 1);
markCheck(workV, i + 5, j - 1);
markCheck(workV, i - 4, j);
markCheck(workV, i + 5, j);
markCheck(workV, i - 3, j + 1);
markCheck(workV, i + 4, j + 1);
markCheck(workV, i - 2, j + 2);
markCheck(workV, i + 3, j + 2);
markCheck(workV, i - 1, j + 3);
markCheck(workV, i + 2, j + 3);
markCheck(workV, i, j + 4);
markCheck(workV, i + 1, j + 4);
markCheck(workH, i - 1, j - 4);
markCheck(workH, i, j - 4);
markCheck(workH, i + 1, j - 4);
markCheck(workH, i - 2, j - 3);
markCheck(workH, i + 2, j - 3);
markCheck(workH, i - 3, j - 2);
markCheck(workH, i + 3, j - 2);
markCheck(workH, i - 4, j - 1);
markCheck(workH, i + 4, j - 1);
markCheck(workH, i - 5, j);
markCheck(workH, i + 5, j);
markCheck(workH, i - 4, j + 1);
markCheck(workH, i + 4, j + 1);
markCheck(workH, i - 3, j + 2);
markCheck(workH, i + 3, j + 2);
markCheck(workH, i - 2, j + 3);
markCheck(workH, i + 2, j + 3);
markCheck(workH, i - 1, j + 4);
markCheck(workH, i, j + 4);
markCheck(workH, i + 1, j + 4);
if (labsep2 <= 5)
return;
}
private void markVrt(byte[][] workH, byte[][] workV, int i, int j) { private void markVrt(byte[][] workH, byte[][] workV, int i, int j) {
markCheck(workV, i, j); markCheck(workV, i, j);
if (labsep2 <= 0) if (labsep2 <= 0)

View file

@ -25,9 +25,10 @@ package com.raytheon.viz.core.contours.util;
* <pre> * <pre>
* *
* SOFTWARE HISTORY * SOFTWARE HISTORY
* Date Ticket# Engineer Description * Date Ticket# Engineer Description
* ------------ ---------- ----------- -------------------------- * ------------- -------- ----------- --------------------------
* Apr 23, 2010 #4583 rjpeter Initial creation * Apr 23, 2010 4583 rjpeter Initial creation
* Feb 27, 2014 2791 bsteffen Remove unused constructor arg
* *
* </pre> * </pre>
* *
@ -59,7 +60,7 @@ public class PointBuffer {
* @param initialIndex * @param initialIndex
* @param forwardDirection * @param forwardDirection
*/ */
public PointBuffer(int capacity, int initialIndex, boolean forwardDirection) { public PointBuffer(int capacity, int initialIndex) {
buffer = new float[capacity * 2]; buffer = new float[capacity * 2];
minIndex = initialIndex; minIndex = initialIndex;
index = initialIndex; index = initialIndex;

View file

@ -24,6 +24,9 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import com.raytheon.uf.common.geospatial.interpolation.data.AxisSwapDataSource;
import com.raytheon.uf.common.geospatial.interpolation.data.DataSource;
import com.raytheon.uf.common.geospatial.interpolation.data.FloatArray2DWrapper;
import com.raytheon.viz.core.contours.util.StreamLineContainer.StreamLinePoint; import com.raytheon.viz.core.contours.util.StreamLineContainer.StreamLinePoint;
/** /**
@ -35,9 +38,10 @@ import com.raytheon.viz.core.contours.util.StreamLineContainer.StreamLinePoint;
* *
* SOFTWARE HISTORY * SOFTWARE HISTORY
* *
* Date Ticket# Engineer Description * Date Ticket# Engineer Description
* ------------ ---------- ----------- -------------------------- * ------------- -------- ----------- --------------------------
* Jun 10, 2013 #1999 dgilling Initial creation * Jun 10, 2013 1999 dgilling Initial creation
* Feb 27, 2014 2791 bsteffen Use DataSource for generic data access.
* *
* </pre> * </pre>
* *
@ -126,11 +130,52 @@ public final class StrmPak {
private final PointValueBuffer<Float> JPnt; private final PointValueBuffer<Float> JPnt;
/**
* Generate streamlines using column major float data.
*
* @param uComp
* data values for the u component of the vector
* @param vComp
* data values for the v component of the vector
* @param xSize
* unused
* @param nx
* number of x coordinates
* @param ny
* number of y coordinates
* @param config
* configuration options
* @return
*/
public static StreamLineContainer strmpak(float[][] uComp, float[][] vComp, public static StreamLineContainer strmpak(float[][] uComp, float[][] vComp,
int xSize, int nx, int ny, StrmPakConfig config) { int xSize, int nx, int ny, StrmPakConfig config) {
DataSource uSource = new FloatArray2DWrapper(uComp, ny, nx);
DataSource vSource = new FloatArray2DWrapper(vComp, ny, nx);
uSource = new AxisSwapDataSource(uSource);
vSource = new AxisSwapDataSource(vSource);
return strmpak(uSource, vSource, nx, ny, config);
}
/**
* Generate streamlines using any data source.
*
* @param uComp
* data values for the u component of the vector
* @param vComp
* data values for the v component of the vector
* @param nx
* number of x coordinates
* @param ny
* number of y coordinates
* @param config
* configuration options
* @return
*/
public static StreamLineContainer strmpak(DataSource uComp,
DataSource vComp, int nx, int ny, StrmPakConfig config) {
StrmPak instance = new StrmPak(); StrmPak instance = new StrmPak();
StreamLineContainer rval = instance.strmpakInternal(uComp, vComp, StreamLineContainer rval = instance.strmpakInternal(uComp, vComp, nx,
xSize, nx, ny, config); ny, config);
return rval; return rval;
} }
@ -150,8 +195,6 @@ public final class StrmPak {
* Array of U components * Array of U components
* @param V * @param V
* Array of V components * Array of V components
* @param mnx
* First dimension of data arrays.
* @param nx * @param nx
* Inner dimension of grid. * Inner dimension of grid.
* @param ny * @param ny
@ -163,8 +206,8 @@ public final class StrmPak {
* the stream lines. Line segments will be divided by the sentinel * the stream lines. Line segments will be divided by the sentinel
* value (-99999, -99999). * value (-99999, -99999).
*/ */
private StreamLineContainer strmpakInternal(float[][] U, float[][] V, private StreamLineContainer strmpakInternal(DataSource U, DataSource V,
int mnx, int nx, int ny, StrmPakConfig config) { int nx, int ny, StrmPakConfig config) {
StreamLineContainer rVal = new StreamLineContainer(); StreamLineContainer rVal = new StreamLineContainer();
// Initialize environment of streamline output. // Initialize environment of streamline output.
@ -189,14 +232,22 @@ public final class StrmPak {
for (int j = jll; j <= jum; j++) { for (int j = jll; j <= jum; j++) {
int jj = j + 1; int jj = j + 1;
if ((!((U[i][j] < config.badlo) || U[i][j] > config.badhi)) if ((!((U.getDataValue(i, j) < config.badlo) || U.getDataValue(
|| (!((U[i][jj] < config.badlo) || U[i][jj] > config.badhi)) i, j) > config.badhi))
|| (!((U[ii][j] < config.badlo) || U[ii][j] > config.badhi)) || (!((U.getDataValue(i, jj) < config.badlo) || U
|| (!((U[ii][jj] < config.badlo) || U[ii][jj] > config.badhi)) .getDataValue(i, jj) > config.badhi))
|| (!((V[i][j] < config.badlo) || V[i][j] > config.badhi)) || (!((U.getDataValue(ii, j) < config.badlo) || U
|| (!((V[i][jj] < config.badlo) || V[i][jj] > config.badhi)) .getDataValue(ii, j) > config.badhi))
|| (!((V[ii][j] < config.badlo) || V[ii][j] > config.badhi)) || (!((U.getDataValue(ii, jj) < config.badlo) || U
|| (!((V[ii][jj] < config.badlo) || V[ii][jj] > config.badhi))) { .getDataValue(ii, jj) > config.badhi))
|| (!((V.getDataValue(i, j) < config.badlo) || V
.getDataValue(i, j) > config.badhi))
|| (!((V.getDataValue(i, jj) < config.badlo) || V
.getDataValue(i, jj) > config.badhi))
|| (!((V.getDataValue(ii, j) < config.badlo) || V
.getDataValue(ii, j) > config.badhi))
|| (!((V.getDataValue(ii, jj) < config.badlo) || V
.getDataValue(ii, jj) > config.badhi))) {
Work[0][i][j] = -1; Work[0][i][j] = -1;
Work[1][i][j] = -1; Work[1][i][j] = -1;
continue; continue;
@ -205,19 +256,23 @@ public final class StrmPak {
if ((minmag <= 0.0f) && (maxmag >= config.badlo)) { if ((minmag <= 0.0f) && (maxmag >= config.badlo)) {
continue; continue;
} }
float mag2 = U[i][j] * U[i][j] + V[i][j] * V[i][j]; double mag2 = U.getDataValue(i, j) * U.getDataValue(i, j)
+ V.getDataValue(i, j) * V.getDataValue(i, j);
if ((mag2 >= minmag2) && (mag2 <= maxmag2)) { if ((mag2 >= minmag2) && (mag2 <= maxmag2)) {
continue; continue;
} }
mag2 = U[ii][j] * U[ii][j] + V[ii][j] * V[ii][j]; mag2 = U.getDataValue(ii, j) * U.getDataValue(ii, j)
+ V.getDataValue(ii, j) * V.getDataValue(ii, j);
if ((mag2 >= minmag2) && (mag2 <= maxmag2)) { if ((mag2 >= minmag2) && (mag2 <= maxmag2)) {
continue; continue;
} }
mag2 = U[i][jj] * U[i][jj] + V[i][jj] * V[i][jj]; mag2 = U.getDataValue(i, jj) * U.getDataValue(i, jj)
+ V.getDataValue(i, jj) * V.getDataValue(i, jj);
if ((mag2 >= minmag2) && (mag2 <= maxmag2)) { if ((mag2 >= minmag2) && (mag2 <= maxmag2)) {
continue; continue;
} }
mag2 = U[ii][jj] * U[ii][jj] + V[ii][jj] * V[ii][jj]; mag2 = U.getDataValue(ii, jj) * U.getDataValue(ii, jj)
+ V.getDataValue(ii, jj) * V.getDataValue(ii, jj);
if ((mag2 >= minmag2) && (mag2 <= maxmag2)) { if ((mag2 >= minmag2) && (mag2 <= maxmag2)) {
continue; continue;
} }
@ -250,8 +305,8 @@ public final class StrmPak {
float rj0 = j1; float rj0 = j1;
for (int i = i1; i <= i2 - 1; i += k) { for (int i = i1; i <= i2 - 1; i += k) {
float ri0 = i + 0.5f; float ri0 = i + 0.5f;
StrmLin(U, V, Work, mnx, ri0, rj0, config.minspc, StrmLin(U, V, Work, ri0, rj0, config.minspc, mymax,
mymax, rVal); rVal);
} }
j1 -= k; j1 -= k;
again = true; again = true;
@ -261,8 +316,8 @@ public final class StrmPak {
float ri0 = i1; float ri0 = i1;
for (int j = j1; j <= j2 - 1; j += k) { for (int j = j1; j <= j2 - 1; j += k) {
float rj0 = j + 0.5f; float rj0 = j + 0.5f;
StrmLin(U, V, Work, mnx, ri0, rj0, config.minspc, StrmLin(U, V, Work, ri0, rj0, config.minspc, mymax,
mymax, rVal); rVal);
} }
i1 -= k; i1 -= k;
@ -273,8 +328,8 @@ public final class StrmPak {
float rj0 = j2; float rj0 = j2;
for (int i = i1; i <= i2 - 1; i += k) { for (int i = i1; i <= i2 - 1; i += k) {
float ri0 = i + 0.5f; float ri0 = i + 0.5f;
StrmLin(U, V, Work, mnx, ri0, rj0, config.minspc, StrmLin(U, V, Work, ri0, rj0, config.minspc, mymax,
mymax, rVal); rVal);
} }
j2 += k; j2 += k;
again = true; again = true;
@ -284,8 +339,8 @@ public final class StrmPak {
float ri0 = i2; float ri0 = i2;
for (int j = j1; j <= j2 - 1; j += k) { for (int j = j1; j <= j2 - 1; j += k) {
float rj0 = j + 0.5f; float rj0 = j + 0.5f;
StrmLin(U, V, Work, mnx, ri0, rj0, config.minspc, StrmLin(U, V, Work, ri0, rj0, config.minspc, mymax,
mymax, rVal); rVal);
} }
i2 += k; i2 += k;
again = true; again = true;
@ -311,8 +366,6 @@ public final class StrmPak {
* drawn in each cell. A value of -1 designates a cell as having * drawn in each cell. A value of -1 designates a cell as having
* bad or missing data. 1 is for previously drawn streamlines, 2 * bad or missing data. 1 is for previously drawn streamlines, 2
* includes the streamline currently being drawn. * includes the streamline currently being drawn.
* @param mnx
* First dimension of array to be countoured.
* @param ri0 * @param ri0
* X-coordinate to draw the streamline through. Coordinates are * X-coordinate to draw the streamline through. Coordinates are
* in array index space. * in array index space.
@ -331,7 +384,7 @@ public final class StrmPak {
* <code>StreamLineContainer</code> object accumulating all line * <code>StreamLineContainer</code> object accumulating all line
* segments necessary to draw stream lines for U and V. * segments necessary to draw stream lines for U and V.
*/ */
private void StrmLin(float[][] U, float[][] V, byte[][][] Work, int mnx, private void StrmLin(DataSource U, DataSource V, byte[][][] Work,
float ri0, float rj0, float minspc, float maxspc, float ri0, float rj0, float minspc, float maxspc,
StreamLineContainer container) { StreamLineContainer container) {
if ((ri0 < ill) || (ri0 > iur) || (rj0 < jll) || (rj0 > jur)) { if ((ri0 < ill) || (ri0 > iur) || (rj0 < jll) || (rj0 > jur)) {
@ -463,15 +516,19 @@ public final class StrmPak {
// Determine whether we are working with or against the // Determine whether we are working with or against the
// flow. // flow.
float dirflg; float dirflg;
float influx; double influx;
if (side0 == 1) { if (side0 == 1) {
influx = V[i][j] * (1.0f - x) + V[ii][j] * x; influx = V.getDataValue(i, j) * (1.0f - x)
+ V.getDataValue(ii, j) * x;
} else if (side0 == 2) { } else if (side0 == 2) {
influx = -(U[ii][j] * (1.0f - y) + U[ii][jj] * y); influx = -(U.getDataValue(ii, j) * (1.0f - y) + U
.getDataValue(ii, jj) * y);
} else if (side0 == 3) { } else if (side0 == 3) {
influx = -(V[i][jj] * (1.0f - x) + V[ii][jj] * x); influx = -(V.getDataValue(i, jj) * (1.0f - x) + V
.getDataValue(ii, jj) * x);
} else { } else {
influx = U[i][j] * (1.0f - y) + U[i][jj] * y; influx = U.getDataValue(i, j) * (1.0f - y)
+ U.getDataValue(i, jj) * y;
} }
if (influx < 0.0f) { if (influx < 0.0f) {
dirflg = -1.0f; dirflg = -1.0f;
@ -587,11 +644,15 @@ public final class StrmPak {
// Determine flux contributions from each component. // Determine flux contributions from each component.
// FIXME? in fortran Flux was a size 8 array, indexed 1 // FIXME? in fortran Flux was a size 8 array, indexed 1
// -> 8 // -> 8
float[] Flux = { Float.NaN, (-dirflg) * V[i][j], float[] Flux = { Float.NaN,
(-dirflg) * V[ii][j], dirflg * U[ii][j], (-dirflg) * (float) V.getDataValue(i, j),
dirflg * U[ii][jj], dirflg * V[ii][jj], (-dirflg) * (float) V.getDataValue(ii, j),
dirflg * V[i][jj], (-dirflg) * U[i][jj], dirflg * (float) U.getDataValue(ii, j),
(-dirflg) * U[i][j] }; dirflg * (float) U.getDataValue(ii, jj),
dirflg * (float) V.getDataValue(ii, jj),
dirflg * (float) V.getDataValue(i, jj),
(-dirflg) * (float) U.getDataValue(i, jj),
(-dirflg) * (float) U.getDataValue(i, j) };
// Count total number of in, out, and zero contributions // Count total number of in, out, and zero contributions
// to net flux. // to net flux.
@ -711,20 +772,22 @@ public final class StrmPak {
boolean forward; boolean forward;
if (side0 == 1) { if (side0 == 1) {
curloc = x; curloc = x;
forward = ((dirflg * (U[i][j] * (1.0f - x) + U[ii][j] forward = ((dirflg * (U.getDataValue(i, j)
* (1.0f - x) + U.getDataValue(ii, j)
* x)) > 0.0f); * x)) > 0.0f);
} else if (side0 == 2) { } else if (side0 == 2) {
curloc = 1.0f + y; curloc = 1.0f + y;
forward = ((dirflg * (V[ii][j] * (1.0f - y) + V[ii][jj] forward = ((dirflg * (V.getDataValue(ii, j)
* (1.0f - y) + V.getDataValue(ii, jj)
* y)) > 0.0f); * y)) > 0.0f);
} else if (side0 == 3) { } else if (side0 == 3) {
curloc = 3.0f - x; curloc = 3.0f - x;
forward = ((dirflg * (U[i][jj] * x + U[ii][jj] forward = ((dirflg * (U.getDataValue(i, jj) * x + U
* (1.0f - x))) < 0.0f); .getDataValue(ii, jj) * (1.0f - x))) < 0.0f);
} else { } else {
curloc = 4.0f - y; curloc = 4.0f - y;
forward = ((dirflg * (V[i][j] * y + V[i][jj] forward = ((dirflg * (V.getDataValue(i, j) * y + V
* (1.0f - y))) < 0.0f); .getDataValue(i, jj) * (1.0f - y))) < 0.0f);
} }
// Determine stream function value of entry // Determine stream function value of entry

View file

@ -0,0 +1,52 @@
/**
* 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;
/**
* Wrapper source which swaps the X and Y axis when accessing data.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------- -------- ----------- --------------------------
* Feb 24, 2014 2791 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class AxisSwapDataSource implements DataSource {
protected final DataSource wrappedSource;
public AxisSwapDataSource(DataSource wrappedSource) {
this.wrappedSource = wrappedSource;
}
@Override
public double getDataValue(int x, int y) {
return wrappedSource.getDataValue(y, x);
}
}

View file

@ -0,0 +1,51 @@
/**
* 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;
/**
* Provide utility method for copying data from a {@link DataSource} to a
* {@link DataDestination}.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------- -------- ----------- --------------------------
* Feb 27, 2014 2791 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class DataCopy {
public static final <D extends DataDestination> D copy(DataSource source,
D destination, int nx, int ny) {
for (int i = 0; i < nx; i += 1) {
for (int j = 0; j < ny; j += 1) {
destination.setDataValue(source.getDataValue(i, j), i, j);
}
}
return destination;
}
}

View file

@ -0,0 +1,65 @@
/**
* 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;
/**
* Returns NaN for all data values that are within a range that can be
* considered invalid.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------- -------- ----------- --------------------------
* Feb 24, 2014 2791 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class InvalidRangeDataSource implements DataSource {
protected final DataSource wrappedSource;
protected final double badlo;
protected final double badhi;
public InvalidRangeDataSource(DataSource wrappedSource, double badlo,
double badhi) {
this.wrappedSource = wrappedSource;
this.badlo = badlo;
this.badhi = badhi;
}
@Override
public double getDataValue(int x, int y) {
double val = wrappedSource.getDataValue(y, x);
if (val > badlo && val < badhi) {
val = Double.NaN;
}
return val;
}
}

View file

@ -26,12 +26,13 @@ package com.raytheon.uf.common.wxmath;
* *
* SOFTWARE HISTORY * SOFTWARE HISTORY
* *
* Date Ticket# Engineer Description * Date Ticket# Engineer Description
* ------------ ---------- ----------- -------------------------- * ------------- -------- ----------- --------------------------
* Jun 06, 2013 2043 bsteffen Ported from meteolib C * Jun 06, 2013 2043 bsteffen Ported from meteolib C
* Aug 13, 2013 2262 njensen Moved from deriv params * Aug 13, 2013 2262 njensen Moved from deriv params
* Aug 13, 2013 2262 dgilling Adding additional constants from * Aug 13, 2013 2262 dgilling Adding additional constants from
* calcrh.f, hgt2pres.f, ztopsa.f, ptozsa.f * calcrh.f, hgt2pres.f, ztopsa.f, ptozsa.f
* Feb 27, 2014 2791 bsteffen Move commonly used legacy NaN here.
* *
* </pre> * </pre>
* *
@ -95,6 +96,8 @@ public class Constants {
// from meteoLib hgt2pres.f, ztopsa.f, ptozsa.f // from meteoLib hgt2pres.f, ztopsa.f, ptozsa.f
public static final double HGT_PRES_c2 = 14600.0; public static final double HGT_PRES_c2 = 14600.0;
public static final float LEGACY_NAN = 1e37f;
// Never allow this class to be directly instantiated // Never allow this class to be directly instantiated
private Constants() { private Constants() {
throw new AssertionError(); throw new AssertionError();

View file

@ -28,10 +28,11 @@ import java.util.Arrays;
* *
* SOFTWARE HISTORY * SOFTWARE HISTORY
* *
* Date Ticket# Engineer Description * Date Ticket# Engineer Description
* ------------ ---------- ----------- -------------------------- * ------------- -------- ----------- --------------------------
* Aug 10, 2011 rjpeter Initial creation * Aug 10, 2011 rjpeter Initial creation
* Aug 13, 2013 2262 njensen Moved from deriv params * Aug 13, 2013 2262 njensen Moved from deriv params
* Feb 27, 2014 2791 bsteffen Move legacy NaN to constants.
* *
* </pre> * </pre>
* *
@ -144,7 +145,7 @@ public class DistFilter {
for (jj = dd; jj < ny; jj++, fpiMid += dnx, fpo += dnx) { for (jj = dd; jj < ny; jj++, fpiMid += dnx, fpo += dnx) {
for (ii = dd; ii < nx; ii++, fpiMid++, fpo++) { for (ii = dd; ii < nx; ii++, fpiMid++, fpo++) {
if (input[fpiMid] > 99998.0) { if (input[fpiMid] > 99998.0) {
output[fpo] = 1e37f; output[fpo] = Constants.LEGACY_NAN;
continue; continue;
} }
@ -164,7 +165,7 @@ public class DistFilter {
} }
if (tot < 0.95) { if (tot < 0.95) {
output[fpo] = 1e37f; output[fpo] = Constants.LEGACY_NAN;
} else { } else {
output[fpo] /= tot; output[fpo] /= tot;
} }
@ -190,7 +191,7 @@ public class DistFilter {
} }
if (input[fpiMid] > 99998.0) { if (input[fpiMid] > 99998.0) {
output[fpo] = 1e37f; output[fpo] = Constants.LEGACY_NAN;
continue; continue;
} }
@ -211,7 +212,7 @@ public class DistFilter {
} }
if (tot < 0.95) { if (tot < 0.95) {
output[fpo] = 1e37f; output[fpo] = Constants.LEGACY_NAN;
} else { } else {
output[fpo] /= tot; output[fpo] /= tot;
} }

View file

@ -32,9 +32,10 @@ import java.util.Arrays;
* *
* SOFTWARE HISTORY * SOFTWARE HISTORY
* *
* Date Ticket# Engineer Description * Date Ticket# Engineer Description
* ------------ ---------- ----------- -------------------------- * ------------- -------- ----------- --------------------------
* Aug 13, 2013 2262 njensen Initial creation * Aug 13, 2013 2262 njensen Initial creation
* Feb 27, 2014 2791 bsteffen Move legacy NaN to constants.
* *
* </pre> * </pre>
* *
@ -191,9 +192,9 @@ public class ScalelessAnalysis {
binidx[kk] = (short) (bb * 2 - 2); binidx[kk] = (short) (bb * 2 - 2);
double rat; double rat;
if (ii == 0) { if (ii == 0) {
rat = (float) (jj) / 0.1; rat = (jj) / 0.1;
} else if (jj == 0) { } else if (jj == 0) {
rat = 0.1 / (float) (ii); rat = 0.1 / (ii);
} else { } else {
rat = (float) (jj) / (float) (ii); rat = (float) (jj) / (float) (ii);
} }
@ -536,7 +537,7 @@ public class ScalelessAnalysis {
for (jj = sxy - 1; jj >= 0; jj--) { for (jj = sxy - 1; jj >= 0; jj--) {
int ii = 0; int ii = 0;
for (int kk = jj * sxy; ii < sxy; ii++, kk++) { for (int kk = jj * sxy; ii < sxy; ii++, kk++) {
System.err.printf("%d ", (int) (kswath0[kk])); System.err.printf("%d ", (kswath0[kk]));
} }
System.err.printf("\n"); System.err.printf("\n");
} }
@ -676,8 +677,8 @@ public class ScalelessAnalysis {
float[] grid = new float[nx * ny]; float[] grid = new float[nx * ny];
float[] raw = new float[nnd]; float[] raw = new float[nnd];
int[] counts = new int[nnd]; int[] counts = new int[nnd];
Arrays.fill(raw, 1e37f); Arrays.fill(raw, Constants.LEGACY_NAN);
Arrays.fill(grid, 1e37f); Arrays.fill(grid, Constants.LEGACY_NAN);
int raw0 = -ddd; int raw0 = -ddd;
int counts0 = -ddd; int counts0 = -ddd;
@ -743,7 +744,7 @@ public class ScalelessAnalysis {
/* work arrays with info about each grid resolved observation */ /* work arrays with info about each grid resolved observation */
float[] dists = new float[nnd]; float[] dists = new float[nnd];
Arrays.fill(dists, 1e37f); Arrays.fill(dists, Constants.LEGACY_NAN);
int dists0 = -ddd; int dists0 = -ddd;
byte[] octant = new byte[nnd]; byte[] octant = new byte[nnd];
int[] nearest = new int[nnd]; int[] nearest = new int[nnd];