Merge "Omaha #4709 Triangulate on ingest." into omaha_16.2.1
Former-commit-id: 4aaa9f486271ad8922e0c54554725bb431b48cb8
This commit is contained in:
commit
b7de73ec1c
14 changed files with 851 additions and 9 deletions
|
@ -58,7 +58,7 @@ public class TriangleMath {
|
||||||
}
|
}
|
||||||
int orientation2 = CGAlgorithms.orientationIndex(v2, v0, p);
|
int orientation2 = CGAlgorithms.orientationIndex(v2, v0, p);
|
||||||
if (orientation0 != orientation2) {
|
if (orientation0 != orientation2) {
|
||||||
if (orientation1 == 0) {
|
if (orientation2 == 0) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -9,5 +9,8 @@ Require-Bundle: com.raytheon.uf.common.dataplugin;bundle-version="1.14.0",
|
||||||
com.raytheon.uf.common.serialization;bundle-version="1.15.1",
|
com.raytheon.uf.common.serialization;bundle-version="1.15.1",
|
||||||
com.raytheon.uf.common.dataplugin.level;bundle-version="1.14.1";visibility:=reexport,
|
com.raytheon.uf.common.dataplugin.level;bundle-version="1.14.1";visibility:=reexport,
|
||||||
com.raytheon.uf.common.parameter;bundle-version="1.14.0";visibility:=reexport,
|
com.raytheon.uf.common.parameter;bundle-version="1.14.0";visibility:=reexport,
|
||||||
com.raytheon.uf.common.datastorage;bundle-version="1.15.0"
|
com.raytheon.uf.common.datastorage;bundle-version="1.15.0",
|
||||||
Export-Package: com.raytheon.uf.common.dataplugin.pointset
|
org.geotools;bundle-version="10.5.0",
|
||||||
|
javax.measure;bundle-version="1.0.0"
|
||||||
|
Export-Package: com.raytheon.uf.common.dataplugin.pointset,
|
||||||
|
com.raytheon.uf.common.dataplugin.pointset.traingulate
|
||||||
|
|
|
@ -23,6 +23,7 @@ import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.FloatBuffer;
|
import java.nio.FloatBuffer;
|
||||||
|
import java.nio.IntBuffer;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
@ -32,6 +33,7 @@ import com.raytheon.uf.common.datastorage.IDataStore.StoreOp;
|
||||||
import com.raytheon.uf.common.datastorage.StorageException;
|
import com.raytheon.uf.common.datastorage.StorageException;
|
||||||
import com.raytheon.uf.common.datastorage.records.FloatDataRecord;
|
import com.raytheon.uf.common.datastorage.records.FloatDataRecord;
|
||||||
import com.raytheon.uf.common.datastorage.records.IDataRecord;
|
import com.raytheon.uf.common.datastorage.records.IDataRecord;
|
||||||
|
import com.raytheon.uf.common.datastorage.records.IntegerDataRecord;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -67,10 +69,14 @@ public class PointSetLocation {
|
||||||
|
|
||||||
private static final String LONGITUDE = "longitude";
|
private static final String LONGITUDE = "longitude";
|
||||||
|
|
||||||
|
private static final String TRIANGLES = "triangle_indices";
|
||||||
|
|
||||||
private final FloatBuffer longitudes;
|
private final FloatBuffer longitudes;
|
||||||
|
|
||||||
private final FloatBuffer latitudes;
|
private final FloatBuffer latitudes;
|
||||||
|
|
||||||
|
private IntBuffer triangles;
|
||||||
|
|
||||||
private final String id;
|
private final String id;
|
||||||
|
|
||||||
public PointSetLocation(float[] longitudes, float[] latitudes) {
|
public PointSetLocation(float[] longitudes, float[] latitudes) {
|
||||||
|
@ -109,9 +115,13 @@ public class PointSetLocation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected PointSetLocation(float[] longitudes, float[] latitudes, String id) {
|
protected PointSetLocation(float[] longitudes, float[] latitudes,
|
||||||
|
int[] triangles, String id) {
|
||||||
this.longitudes = FloatBuffer.wrap(longitudes);
|
this.longitudes = FloatBuffer.wrap(longitudes);
|
||||||
this.latitudes = FloatBuffer.wrap(latitudes);
|
this.latitudes = FloatBuffer.wrap(latitudes);
|
||||||
|
if (triangles != null) {
|
||||||
|
this.triangles = IntBuffer.wrap(triangles);
|
||||||
|
}
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,6 +144,14 @@ public class PointSetLocation {
|
||||||
return latitudes;
|
return latitudes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IntBuffer getTriangles() {
|
||||||
|
return triangles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTriangles(IntBuffer triangles) {
|
||||||
|
this.triangles = triangles;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save to an {@link IDataStore}. The provided file will be used to get the
|
* Save to an {@link IDataStore}. The provided file will be used to get the
|
||||||
* IDataStore and is not an actual file on the local system.
|
* IDataStore and is not an actual file on the local system.
|
||||||
|
@ -150,6 +168,10 @@ public class PointSetLocation {
|
||||||
longitudes.array()));
|
longitudes.array()));
|
||||||
store.addDataRecord(new FloatDataRecord(LATITUDE, getGroup(id),
|
store.addDataRecord(new FloatDataRecord(LATITUDE, getGroup(id),
|
||||||
latitudes.array()));
|
latitudes.array()));
|
||||||
|
if (triangles != null) {
|
||||||
|
store.addDataRecord(new IntegerDataRecord(TRIANGLES, getGroup(id),
|
||||||
|
triangles.array()));
|
||||||
|
}
|
||||||
store.store(StoreOp.REPLACE);
|
store.store(StoreOp.REPLACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,12 +185,15 @@ public class PointSetLocation {
|
||||||
IDataRecord[] datasets = store.retrieve(getGroup(id));
|
IDataRecord[] datasets = store.retrieve(getGroup(id));
|
||||||
float[] latitudes = null;
|
float[] latitudes = null;
|
||||||
float[] longitudes = null;
|
float[] longitudes = null;
|
||||||
|
int[] triangles = null;
|
||||||
|
|
||||||
for(IDataRecord record : datasets){
|
for(IDataRecord record : datasets){
|
||||||
if (record.getName().equals(LATITUDE)) {
|
if (record.getName().equals(LATITUDE)) {
|
||||||
latitudes = (float[]) record.getDataObject();
|
latitudes = (float[]) record.getDataObject();
|
||||||
} else if (record.getName().equals(LONGITUDE)) {
|
} else if (record.getName().equals(LONGITUDE)) {
|
||||||
longitudes = (float[]) record.getDataObject();
|
longitudes = (float[]) record.getDataObject();
|
||||||
|
} else if (record.getName().equals(TRIANGLES)) {
|
||||||
|
triangles = (int[]) record.getDataObject();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (longitudes == null || latitudes == null) {
|
if (longitudes == null || latitudes == null) {
|
||||||
|
@ -176,7 +201,7 @@ public class PointSetLocation {
|
||||||
"Unable to determine location information for " + id
|
"Unable to determine location information for " + id
|
||||||
+ " from " + file.getName());
|
+ " from " + file.getName());
|
||||||
}
|
}
|
||||||
return new PointSetLocation(longitudes, latitudes, id);
|
return new PointSetLocation(longitudes, latitudes, triangles, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static String getGroup(String id) {
|
protected static String getGroup(String id) {
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
/**
|
||||||
|
* 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.dataplugin.pointset.traingulate;
|
||||||
|
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
|
||||||
|
import com.vividsolutions.jts.triangulate.quadedge.TriangleVisitor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link TriangleVisitor} used by the {@link DelauneyTriangulator} to build
|
||||||
|
* an index buffer of triangle vertices. This is an abstract class to allow
|
||||||
|
* subclasses to implement custom filtering for invalid triangles.
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
*
|
||||||
|
* SOFTWARE HISTORY
|
||||||
|
*
|
||||||
|
* Date Ticket# Engineer Description
|
||||||
|
* ------------- -------- --------- --------------------------
|
||||||
|
* Aug 24, 2015 4709 bsteffen Initial creation
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author bsteffen
|
||||||
|
*/
|
||||||
|
public abstract class AbstractIndexBufferBuilder implements TriangleVisitor {
|
||||||
|
|
||||||
|
protected final IntBuffer buffer;
|
||||||
|
|
||||||
|
public AbstractIndexBufferBuilder(int size) {
|
||||||
|
this.buffer = IntBuffer.allocate(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This will copy the index buffer into a new buffer that is the size of the
|
||||||
|
* consumed portion of the buffer.
|
||||||
|
*/
|
||||||
|
public IntBuffer getBuffer() {
|
||||||
|
int bufferSize = buffer.position();
|
||||||
|
buffer.position(0);
|
||||||
|
buffer.limit(bufferSize);
|
||||||
|
IntBuffer result = IntBuffer.allocate(bufferSize);
|
||||||
|
result.put(buffer);
|
||||||
|
result.rewind();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void addTriangle(int i0, int i1, int i2) {
|
||||||
|
buffer.put(i0);
|
||||||
|
buffer.put(i1);
|
||||||
|
buffer.put(i2);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,159 @@
|
||||||
|
/**
|
||||||
|
* 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.dataplugin.pointset.traingulate;
|
||||||
|
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.geotools.referencing.CRS;
|
||||||
|
import org.geotools.referencing.crs.DefaultGeographicCRS;
|
||||||
|
import org.opengis.referencing.FactoryException;
|
||||||
|
import org.opengis.referencing.crs.CoordinateReferenceSystem;
|
||||||
|
import org.opengis.referencing.operation.MathTransform;
|
||||||
|
import org.opengis.referencing.operation.TransformException;
|
||||||
|
|
||||||
|
import com.raytheon.uf.common.dataplugin.pointset.PointSetLocation;
|
||||||
|
import com.vividsolutions.jts.geom.Coordinate;
|
||||||
|
import com.vividsolutions.jts.triangulate.DelaunayTriangulationBuilder;
|
||||||
|
import com.vividsolutions.jts.triangulate.quadedge.QuadEdgeSubdivision;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for building triangles out of the scattered Lon/Lat coordinates in a
|
||||||
|
* {@link PointSetLocation}.
|
||||||
|
*
|
||||||
|
* This class will project the coordinates to a different CRS when performing
|
||||||
|
* triangulation to avoid problems near the poles or antimeridian. The CRS can
|
||||||
|
* be provided in the constructor or one will be chosen using the
|
||||||
|
* {@link TriangulationCrsFinder}.
|
||||||
|
*
|
||||||
|
* This class has the ability to perform alpha shaping to avoid creating large
|
||||||
|
* triangles for concave areas of the data. This class can use either dynamic
|
||||||
|
* alpha value as described in the {@link DynamicAlphaIndexBufferBuilder} or a
|
||||||
|
* constant alphaValue. Because the triangulation is performed on a projection
|
||||||
|
* of the data, the alpha value may need to be inflated to take into account
|
||||||
|
* distortions in projections, the larger the area the data covers, the more
|
||||||
|
* inflation that may be necessary.
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
*
|
||||||
|
* SOFTWARE HISTORY
|
||||||
|
*
|
||||||
|
* Date Ticket# Engineer Description
|
||||||
|
* ------------- -------- --------- --------------------------
|
||||||
|
* Aug 24, 2015 4709 bsteffen Initial creation
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author bsteffen
|
||||||
|
*/
|
||||||
|
public class DelauneyTriangulator {
|
||||||
|
|
||||||
|
protected final CoordinateReferenceSystem crs;
|
||||||
|
|
||||||
|
protected final double alphaValue;
|
||||||
|
|
||||||
|
protected final boolean dynamicAlpha;
|
||||||
|
|
||||||
|
public DelauneyTriangulator(CoordinateReferenceSystem crs, double alphaValue) {
|
||||||
|
this.crs = crs;
|
||||||
|
this.alphaValue = alphaValue;
|
||||||
|
this.dynamicAlpha = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DelauneyTriangulator(CoordinateReferenceSystem crs,
|
||||||
|
boolean dynamicAlpha) {
|
||||||
|
this.crs = crs;
|
||||||
|
this.alphaValue = Double.POSITIVE_INFINITY;
|
||||||
|
this.dynamicAlpha = dynamicAlpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DelauneyTriangulator(CoordinateReferenceSystem crs) {
|
||||||
|
this.crs = crs;
|
||||||
|
this.alphaValue = Double.POSITIVE_INFINITY;
|
||||||
|
this.dynamicAlpha = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DelauneyTriangulator(double alphaValue) {
|
||||||
|
this.crs = null;
|
||||||
|
this.alphaValue = alphaValue;
|
||||||
|
this.dynamicAlpha = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DelauneyTriangulator(boolean dynamicAlpha) {
|
||||||
|
this.crs = null;
|
||||||
|
this.alphaValue = Double.POSITIVE_INFINITY;
|
||||||
|
this.dynamicAlpha = dynamicAlpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DelauneyTriangulator() {
|
||||||
|
this.crs = null;
|
||||||
|
this.alphaValue = Double.POSITIVE_INFINITY;
|
||||||
|
this.dynamicAlpha = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected float[] interleaveOrdinates(PointSetLocation location) {
|
||||||
|
FloatBuffer longitude = location.getLongitudes();
|
||||||
|
FloatBuffer latitude = location.getLatitudes();
|
||||||
|
int numPoints = longitude.capacity();
|
||||||
|
|
||||||
|
float[] lonLats = new float[numPoints * 2];
|
||||||
|
for (int i = 0; i < numPoints; i += 1) {
|
||||||
|
lonLats[i * 2] = longitude.get(i);
|
||||||
|
lonLats[i * 2 + 1] = latitude.get(i);
|
||||||
|
}
|
||||||
|
return lonLats;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntBuffer triangulate(PointSetLocation location)
|
||||||
|
throws FactoryException, TransformException {
|
||||||
|
float[] lonLats = interleaveOrdinates(location);
|
||||||
|
int numPoints = lonLats.length / 2;
|
||||||
|
MathTransform lonLatToCrs = null;
|
||||||
|
if (crs == null) {
|
||||||
|
lonLatToCrs = new TriangulationCrsFinder()
|
||||||
|
.getTransfromFromLonLat(lonLats);
|
||||||
|
} else {
|
||||||
|
lonLatToCrs = CRS
|
||||||
|
.findMathTransform(DefaultGeographicCRS.WGS84, crs);
|
||||||
|
}
|
||||||
|
float[] xy = new float[lonLats.length];
|
||||||
|
lonLatToCrs.transform(lonLats, 0, xy, 0, numPoints);
|
||||||
|
List<Coordinate> sites = new ArrayList<>(numPoints);
|
||||||
|
for (int i = 0; i < numPoints; i += 1) {
|
||||||
|
sites.add(new Coordinate(xy[i * 2], xy[i * 2 + 1], i));
|
||||||
|
}
|
||||||
|
DelaunayTriangulationBuilder builder = new DelaunayTriangulationBuilder();
|
||||||
|
builder.setSites(sites);
|
||||||
|
QuadEdgeSubdivision subdiv = builder.getSubdivision();
|
||||||
|
int numEdges = subdiv.getEdges().size();
|
||||||
|
|
||||||
|
AbstractIndexBufferBuilder indexer = null;
|
||||||
|
if (dynamicAlpha) {
|
||||||
|
indexer = new DynamicAlphaIndexBufferBuilder(numEdges * 2);
|
||||||
|
} else {
|
||||||
|
indexer = new IndexBufferBuilder(numEdges * 2, alphaValue);
|
||||||
|
}
|
||||||
|
subdiv.visitTriangles(indexer, false);
|
||||||
|
return indexer.getBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,138 @@
|
||||||
|
/**
|
||||||
|
* 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.dataplugin.pointset.traingulate;
|
||||||
|
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.PriorityQueue;
|
||||||
|
|
||||||
|
import com.vividsolutions.jts.triangulate.quadedge.QuadEdge;
|
||||||
|
import com.vividsolutions.jts.triangulate.quadedge.Vertex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An index buffer builder which attempts to dynamically determine a correct
|
||||||
|
* maximum radius to use for filtering triangles to achieve an alpha shape. This
|
||||||
|
* can be useful if the spacing of the data is not known or could be
|
||||||
|
* particularly distorted.
|
||||||
|
*
|
||||||
|
* Similar to the {@link IndexBufferBuilder}, triangles are filtered off of the
|
||||||
|
* circumradius. The dynamic filtering is achieved by automatically accepting
|
||||||
|
* 90% of the triangles, those with the smallest circumradius. The remaining 10%
|
||||||
|
* are only included if their circumradius is less than 4 times the largest
|
||||||
|
* radius from the 90%. For example if your radii are 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||||
|
* 10, then 1-9 will be automatically included and the 10 will also be included
|
||||||
|
* because it is less than the maximum acceptable value of 9*4 = 36.
|
||||||
|
*
|
||||||
|
* This methodology should not be considered mathematically robust and could be
|
||||||
|
* changed in the future. It was derived by fiddling with the numbers with some
|
||||||
|
* sample data. The primary advantages of this simplistic approach is that it
|
||||||
|
* can be achieved without iterating over the triangles multiple times to
|
||||||
|
* calculate statistical values and it easily allows datasets with low deviation
|
||||||
|
* to be 100% included in the result. Removing good triangles is considered more
|
||||||
|
* dangerous than leaving in large triangles so having a very broad range of
|
||||||
|
* acceptance is considered an advantage.
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
*
|
||||||
|
* SOFTWARE HISTORY
|
||||||
|
*
|
||||||
|
* Date Ticket# Engineer Description
|
||||||
|
* ------------- -------- --------- --------------------------
|
||||||
|
* Aug 24, 2015 4709 bsteffen Initial creation
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author bsteffen
|
||||||
|
*/
|
||||||
|
public class DynamicAlphaIndexBufferBuilder extends AbstractIndexBufferBuilder {
|
||||||
|
|
||||||
|
|
||||||
|
private final int maxRadiusHeapSize;
|
||||||
|
|
||||||
|
private final PriorityQueue<RadiusIndexPair> maxRadiusHeap;
|
||||||
|
|
||||||
|
public DynamicAlphaIndexBufferBuilder(int size) {
|
||||||
|
super(size);
|
||||||
|
maxRadiusHeapSize = Math.max(1, size / 10);
|
||||||
|
maxRadiusHeap = new PriorityQueue<>(maxRadiusHeapSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntBuffer getBuffer() {
|
||||||
|
double radiusThreshold = maxRadiusHeap.poll().radius * 4;
|
||||||
|
while (!maxRadiusHeap.isEmpty()
|
||||||
|
&& maxRadiusHeap.peek().radius < radiusThreshold) {
|
||||||
|
maxRadiusHeap.poll();
|
||||||
|
}
|
||||||
|
int[] indicesToRemove = new int[maxRadiusHeap.size()];
|
||||||
|
for (int i = 0; i < indicesToRemove.length; i += 1) {
|
||||||
|
indicesToRemove[i] = maxRadiusHeap.poll().index;
|
||||||
|
}
|
||||||
|
Arrays.sort(indicesToRemove);
|
||||||
|
int bufferSize = buffer.position();
|
||||||
|
IntBuffer result = IntBuffer.allocate(bufferSize
|
||||||
|
- indicesToRemove.length * 3);
|
||||||
|
buffer.position(0);
|
||||||
|
for (int index : indicesToRemove) {
|
||||||
|
buffer.limit(index);
|
||||||
|
result.put(buffer);
|
||||||
|
buffer.limit(buffer.capacity());
|
||||||
|
buffer.position(index + 3);
|
||||||
|
}
|
||||||
|
buffer.limit(bufferSize);
|
||||||
|
result.put(buffer);
|
||||||
|
result.rewind();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(QuadEdge[] triEdges) {
|
||||||
|
Vertex a = triEdges[0].orig();
|
||||||
|
Vertex b = triEdges[1].orig();
|
||||||
|
Vertex c = triEdges[2].orig();
|
||||||
|
Vertex center = a.circleCenter(b, c);
|
||||||
|
double circumRadius = a.getCoordinate()
|
||||||
|
.distance(center.getCoordinate());
|
||||||
|
if (maxRadiusHeap.size() >= maxRadiusHeapSize) {
|
||||||
|
maxRadiusHeap.poll();
|
||||||
|
}
|
||||||
|
maxRadiusHeap.add(new RadiusIndexPair(buffer.position(), circumRadius));
|
||||||
|
addTriangle((int) a.getZ(), (int) b.getZ(), (int) c.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class RadiusIndexPair implements Comparable<RadiusIndexPair> {
|
||||||
|
|
||||||
|
public final int index;
|
||||||
|
|
||||||
|
public final double radius;
|
||||||
|
|
||||||
|
public RadiusIndexPair(int index, double radius) {
|
||||||
|
this.index = index;
|
||||||
|
this.radius = radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(RadiusIndexPair o) {
|
||||||
|
return Double.compare(radius, o.radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
/**
|
||||||
|
* 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.dataplugin.pointset.traingulate;
|
||||||
|
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given the dimensions of a grid this will create a triangle indices for the
|
||||||
|
* vertices of the grid. For data that is a well formed grid this is a much
|
||||||
|
* faster alternative to the {@link DelauneyTriangulator}.
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
*
|
||||||
|
* SOFTWARE HISTORY
|
||||||
|
*
|
||||||
|
* Date Ticket# Engineer Description
|
||||||
|
* ------------- -------- --------- --------------------------
|
||||||
|
* Aug 24, 2015 4709 bsteffen Initial creation
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author bsteffen
|
||||||
|
*/
|
||||||
|
public class GridTriangulator {
|
||||||
|
|
||||||
|
public IntBuffer triangulate(int nx, int ny) {
|
||||||
|
IntBuffer buffer = IntBuffer.allocate(6 * (nx - 1) * (ny - 1));
|
||||||
|
|
||||||
|
for (int j = 1; j < ny; j += 1) {
|
||||||
|
for (int i = 1; i < nx; i += 1) {
|
||||||
|
/*-
|
||||||
|
* c0---c1 c0---c1
|
||||||
|
* | | | /|
|
||||||
|
* | | ====> | / |
|
||||||
|
* | | |/ |
|
||||||
|
* c2---c3 c2---c3
|
||||||
|
*/
|
||||||
|
int c0 = (j - 1) * nx + (i - 1);
|
||||||
|
int c1 = j * nx + (i - 1);
|
||||||
|
int c2 = (j - 1) * nx + i;
|
||||||
|
int c3 = j * nx + i;
|
||||||
|
|
||||||
|
buffer.put(c0);
|
||||||
|
buffer.put(c1);
|
||||||
|
buffer.put(c2);
|
||||||
|
|
||||||
|
buffer.put(c3);
|
||||||
|
buffer.put(c1);
|
||||||
|
buffer.put(c2);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer.rewind();
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
/**
|
||||||
|
* 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.dataplugin.pointset.traingulate;
|
||||||
|
|
||||||
|
import com.vividsolutions.jts.triangulate.quadedge.QuadEdge;
|
||||||
|
import com.vividsolutions.jts.triangulate.quadedge.Vertex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple index buffer builder which filters out invalid triangles based off a
|
||||||
|
* maximum value of the radius of a circle circumscribed on the triangle. The
|
||||||
|
* resulting shape is considered an "alpha shape" of the triangulation. To
|
||||||
|
* include all triangles, and perform no alpha shaping, a max radius of
|
||||||
|
* {@link Double#POSITIVE_INFINITY} can be used, this is done automatically when
|
||||||
|
* using the {@link IndexBufferBuilder#IndexBufferBuilder(int)} constructor.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
*
|
||||||
|
* SOFTWARE HISTORY
|
||||||
|
*
|
||||||
|
* Date Ticket# Engineer Description
|
||||||
|
* ------------- -------- --------- --------------------------
|
||||||
|
* Aug 24, 2015 4709 bsteffen Initial creation
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author bsteffen
|
||||||
|
*/
|
||||||
|
public class IndexBufferBuilder extends AbstractIndexBufferBuilder {
|
||||||
|
|
||||||
|
private final double maxRadius;
|
||||||
|
|
||||||
|
public IndexBufferBuilder(int size) {
|
||||||
|
super(size);
|
||||||
|
this.maxRadius = Double.POSITIVE_INFINITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IndexBufferBuilder(int size, double maxRadius) {
|
||||||
|
super(size);
|
||||||
|
this.maxRadius = maxRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(QuadEdge[] triEdges) {
|
||||||
|
Vertex a = triEdges[0].orig();
|
||||||
|
Vertex b = triEdges[1].orig();
|
||||||
|
Vertex c = triEdges[2].orig();
|
||||||
|
double circumRadius = 0.0;
|
||||||
|
if (maxRadius > 0) {
|
||||||
|
Vertex center = a.circleCenter(b, c);
|
||||||
|
circumRadius = a.getCoordinate().distance(center.getCoordinate());
|
||||||
|
}
|
||||||
|
if (maxRadius >= circumRadius) {
|
||||||
|
addTriangle((int) a.getZ(), (int) b.getZ(), (int) c.getZ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,190 @@
|
||||||
|
/**
|
||||||
|
* 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.dataplugin.pointset.traingulate;
|
||||||
|
|
||||||
|
import org.geotools.geometry.DirectPosition2D;
|
||||||
|
import org.geotools.geometry.DirectPosition3D;
|
||||||
|
import org.geotools.referencing.CRS;
|
||||||
|
import org.geotools.referencing.crs.DefaultGeocentricCRS;
|
||||||
|
import org.geotools.referencing.crs.DefaultGeographicCRS;
|
||||||
|
import org.geotools.referencing.datum.DefaultEllipsoid;
|
||||||
|
import org.geotools.referencing.operation.DefaultMathTransformFactory;
|
||||||
|
import org.opengis.parameter.ParameterValueGroup;
|
||||||
|
import org.opengis.referencing.FactoryException;
|
||||||
|
import org.opengis.referencing.crs.CoordinateReferenceSystem;
|
||||||
|
import org.opengis.referencing.datum.Ellipsoid;
|
||||||
|
import org.opengis.referencing.operation.MathTransform;
|
||||||
|
import org.opengis.referencing.operation.TransformException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to find the most appropriate CRS to perform a delauney triangulation
|
||||||
|
* on a scattered set of points. Uses stereographic projection centered over the
|
||||||
|
* data as long as the data is all contained within a hemisphere. For data
|
||||||
|
* larger than a hemisphere it just uses an Equidistant Cylindrical Projection
|
||||||
|
* centered over the data. Using stereographic avoids problem that are common
|
||||||
|
* near the poles and the antimeridian.
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
*
|
||||||
|
* SOFTWARE HISTORY
|
||||||
|
*
|
||||||
|
* Date Ticket# Engineer Description
|
||||||
|
* ------------- -------- --------- --------------------------
|
||||||
|
* Aug 24, 2015 4709 bsteffen Initial creation
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author bsteffen
|
||||||
|
*/
|
||||||
|
public class TriangulationCrsFinder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Based off a spherical earth with a radius of 6371229 meters this is the
|
||||||
|
* squared length of a chord that covers 1/4 of the diameter of the sphere
|
||||||
|
* of the earth. In a 3D geocentric space it is useful for quickly
|
||||||
|
* determining if points are within the same hemisphere.
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* ** P ** ** P ** ** P **
|
||||||
|
* ** ** ** ,' ** ** ,' ', **
|
||||||
|
* ,' ,' ',
|
||||||
|
* ** ** ** ,' ** ** ,' ', **
|
||||||
|
* ,' ,' ',
|
||||||
|
* ** ** ** ,' ** ** ,' ', **
|
||||||
|
* C ' C '-----------------------' C
|
||||||
|
* ** ** ** **
|
||||||
|
*
|
||||||
|
* ** ** ** **
|
||||||
|
*
|
||||||
|
* ** ** ** **
|
||||||
|
* ** ** ** **
|
||||||
|
*
|
||||||
|
* The earth as a circle Point C is ¼ circle from P Extending the chord in all
|
||||||
|
* P is the center of the The line from P to C is the directions creates a semicircle
|
||||||
|
* area of interest chord this value measures in 3D it creates a hemisphere
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* The reason this is the squared chord length instead of the actual chord
|
||||||
|
* length is so that we can skip the square root operation when calculating
|
||||||
|
* distances to compare to this value.
|
||||||
|
*
|
||||||
|
* The math to calculate the value is (6371229 * √2)²
|
||||||
|
*/
|
||||||
|
private static final long MAX_STEREOGRAPHIC_CHORD_LENGTH_SQUARED = 81185117940882l;
|
||||||
|
|
||||||
|
protected final MathTransform lonLatTo3D;
|
||||||
|
|
||||||
|
public TriangulationCrsFinder() throws FactoryException {
|
||||||
|
CoordinateReferenceSystem threeD = DefaultGeocentricCRS.CARTESIAN;
|
||||||
|
CoordinateReferenceSystem lonLat = DefaultGeographicCRS.WGS84;
|
||||||
|
lonLatTo3D = CRS.findMathTransform(lonLat, threeD);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected float[] transform3D(float[] interleavedLonLats)
|
||||||
|
throws TransformException {
|
||||||
|
int numPoints = interleavedLonLats.length / 2;
|
||||||
|
float[] xyz = new float[numPoints * 3];
|
||||||
|
lonLatTo3D.transform(interleavedLonLats, 0, xyz, 0, numPoints);
|
||||||
|
return xyz;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected DirectPosition2D findLonLatCenter(float[] xyz)
|
||||||
|
throws TransformException {
|
||||||
|
int numPoints = xyz.length / 3;
|
||||||
|
|
||||||
|
double x = 0;
|
||||||
|
double y = 0;
|
||||||
|
double z = 0;
|
||||||
|
for (int i = 0; i < xyz.length; i += 3) {
|
||||||
|
x += xyz[i];
|
||||||
|
y += xyz[i + 1];
|
||||||
|
z += xyz[i + 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Its important to realize that this center3D may very well be within
|
||||||
|
* the surface of the planet and when it is transformed to LonLat, the
|
||||||
|
* depth component is lost, essentially moving the coordinate to the
|
||||||
|
* surface. So even though the center3D used in createTransform() looks
|
||||||
|
* like it is the same as this point, it is not.
|
||||||
|
*/
|
||||||
|
DirectPosition3D center3D = new DirectPosition3D(x / numPoints, y
|
||||||
|
/ numPoints, z / numPoints);
|
||||||
|
DirectPosition2D centerLonLat = new DirectPosition2D();
|
||||||
|
lonLatTo3D.inverse().transform(center3D, centerLonLat);
|
||||||
|
|
||||||
|
return centerLonLat;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected MathTransform createTransform(float[] xyz)
|
||||||
|
throws FactoryException, TransformException {
|
||||||
|
DirectPosition2D centerLonLat = findLonLatCenter(xyz);
|
||||||
|
DirectPosition3D center3D = new DirectPosition3D();
|
||||||
|
lonLatTo3D.transform(centerLonLat, center3D);
|
||||||
|
|
||||||
|
boolean isStereographicOK = true;
|
||||||
|
for (int i = 0; i < xyz.length; i += 3) {
|
||||||
|
double xd = center3D.x - xyz[i];
|
||||||
|
double yd = center3D.y - xyz[i + 1];
|
||||||
|
double zd = center3D.z - xyz[i + 2];
|
||||||
|
double chord_squared = xd * xd + yd * yd + zd * zd;
|
||||||
|
if (chord_squared > MAX_STEREOGRAPHIC_CHORD_LENGTH_SQUARED) {
|
||||||
|
isStereographicOK = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xyz = null;
|
||||||
|
if (isStereographicOK) {
|
||||||
|
DefaultMathTransformFactory dmtFactory = new DefaultMathTransformFactory();
|
||||||
|
Ellipsoid ellipsoid = DefaultEllipsoid.WGS84;
|
||||||
|
ParameterValueGroup parameters = dmtFactory
|
||||||
|
.getDefaultParameters("Stereographic");
|
||||||
|
parameters.parameter("semi_major").setValue(
|
||||||
|
ellipsoid.getSemiMajorAxis());
|
||||||
|
parameters.parameter("semi_minor").setValue(
|
||||||
|
ellipsoid.getSemiMinorAxis());
|
||||||
|
parameters.parameter("central_meridian").setValue(centerLonLat.x);
|
||||||
|
parameters.parameter("latitude_of_origin").setValue(centerLonLat.y);
|
||||||
|
|
||||||
|
return dmtFactory.createParameterizedTransform(parameters);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
DefaultMathTransformFactory dmtFactory = new DefaultMathTransformFactory();
|
||||||
|
Ellipsoid ellipsoid = DefaultEllipsoid.WGS84;
|
||||||
|
ParameterValueGroup parameters = dmtFactory
|
||||||
|
.getDefaultParameters("Equidistant_Cylindrical");
|
||||||
|
parameters.parameter("semi_major").setValue(
|
||||||
|
ellipsoid.getSemiMajorAxis());
|
||||||
|
parameters.parameter("semi_minor").setValue(
|
||||||
|
ellipsoid.getSemiMinorAxis());
|
||||||
|
parameters.parameter("central_meridian").setValue(centerLonLat.x);
|
||||||
|
|
||||||
|
return dmtFactory.createParameterizedTransform(parameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MathTransform getTransfromFromLonLat(float[] interleavedLonLats)
|
||||||
|
throws TransformException, FactoryException {
|
||||||
|
float[] xyz = transform3D(interleavedLonLats);
|
||||||
|
return createTransform(xyz);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -10,4 +10,5 @@ Require-Bundle: com.raytheon.uf.common.dataplugin.pointset;bundle-version="1.15.
|
||||||
com.raytheon.uf.common.datastorage;bundle-version="1.15.0",
|
com.raytheon.uf.common.datastorage;bundle-version="1.15.0",
|
||||||
com.raytheon.uf.common.localization;bundle-version="1.14.1",
|
com.raytheon.uf.common.localization;bundle-version="1.14.1",
|
||||||
ucar.nc2;bundle-version="4.2.0",
|
ucar.nc2;bundle-version="4.2.0",
|
||||||
org.slf4j;bundle-version="1.7.5"
|
org.slf4j;bundle-version="1.7.5",
|
||||||
|
org.geotools;bundle-version="10.5.0"
|
||||||
|
|
|
@ -38,6 +38,8 @@ import java.util.regex.Pattern;
|
||||||
|
|
||||||
import javax.xml.bind.JAXB;
|
import javax.xml.bind.JAXB;
|
||||||
|
|
||||||
|
import org.opengis.referencing.FactoryException;
|
||||||
|
import org.opengis.referencing.operation.TransformException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -49,6 +51,8 @@ import ucar.nc2.Variable;
|
||||||
import com.raytheon.uf.common.dataplugin.level.LevelFactory;
|
import com.raytheon.uf.common.dataplugin.level.LevelFactory;
|
||||||
import com.raytheon.uf.common.dataplugin.pointset.PointSetLocation;
|
import com.raytheon.uf.common.dataplugin.pointset.PointSetLocation;
|
||||||
import com.raytheon.uf.common.dataplugin.pointset.PointSetRecord;
|
import com.raytheon.uf.common.dataplugin.pointset.PointSetRecord;
|
||||||
|
import com.raytheon.uf.common.dataplugin.pointset.traingulate.DelauneyTriangulator;
|
||||||
|
import com.raytheon.uf.common.dataplugin.pointset.traingulate.GridTriangulator;
|
||||||
import com.raytheon.uf.common.datastorage.StorageException;
|
import com.raytheon.uf.common.datastorage.StorageException;
|
||||||
import com.raytheon.uf.common.localization.IPathManager;
|
import com.raytheon.uf.common.localization.IPathManager;
|
||||||
import com.raytheon.uf.common.localization.LocalizationFile;
|
import com.raytheon.uf.common.localization.LocalizationFile;
|
||||||
|
@ -56,6 +60,8 @@ import com.raytheon.uf.common.localization.exception.LocalizationException;
|
||||||
import com.raytheon.uf.common.parameter.lookup.ParameterLookup;
|
import com.raytheon.uf.common.parameter.lookup.ParameterLookup;
|
||||||
import com.raytheon.uf.edex.plugin.pointset.netcdf.description.PointSetProductDescriptions;
|
import com.raytheon.uf.edex.plugin.pointset.netcdf.description.PointSetProductDescriptions;
|
||||||
import com.raytheon.uf.edex.plugin.pointset.netcdf.description.ProductDescription;
|
import com.raytheon.uf.edex.plugin.pointset.netcdf.description.ProductDescription;
|
||||||
|
import com.raytheon.uf.edex.plugin.pointset.netcdf.description.TriangulationDescription;
|
||||||
|
import com.raytheon.uf.edex.plugin.pointset.netcdf.description.TriangulationDescription.TriangulationType;
|
||||||
import com.raytheon.uf.edex.plugin.pointset.netcdf.description.VariableDescription;
|
import com.raytheon.uf.edex.plugin.pointset.netcdf.description.VariableDescription;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -86,8 +92,7 @@ public class PointSetNetcdfDecoder {
|
||||||
.compile("LON", Pattern.CASE_INSENSITIVE);
|
.compile("LON", Pattern.CASE_INSENSITIVE);
|
||||||
|
|
||||||
private static final Pattern LATITUDE_COORDINATE_PATTERN = Pattern.compile(
|
private static final Pattern LATITUDE_COORDINATE_PATTERN = Pattern.compile(
|
||||||
"LAT",
|
"LAT", Pattern.CASE_INSENSITIVE);
|
||||||
Pattern.CASE_INSENSITIVE);
|
|
||||||
|
|
||||||
private static final PointSetRecord[] EMPTY_POINTSET_ARRAY = new PointSetRecord[0];
|
private static final PointSetRecord[] EMPTY_POINTSET_ARRAY = new PointSetRecord[0];
|
||||||
|
|
||||||
|
@ -295,6 +300,30 @@ public class PointSetNetcdfDecoder {
|
||||||
float[] latVals = (float[]) latVariable.read().get1DJavaArray(
|
float[] latVals = (float[]) latVariable.read().get1DJavaArray(
|
||||||
float.class);
|
float.class);
|
||||||
PointSetLocation location = new PointSetLocation(lonVals, latVals);
|
PointSetLocation location = new PointSetLocation(lonVals, latVals);
|
||||||
|
TriangulationDescription triangulation = description
|
||||||
|
.getTriangulation();
|
||||||
|
if (triangulation != null) {
|
||||||
|
TriangulationType type = triangulation.getType();
|
||||||
|
if (type == TriangulationType.GRID) {
|
||||||
|
int[] shape = lonVariable.getShape();
|
||||||
|
if (shape.length != 2) {
|
||||||
|
logger.warn(
|
||||||
|
"Grid triangulation for {} failed because data is not 2 dimensional",
|
||||||
|
dataVarName);
|
||||||
|
}
|
||||||
|
location.setTriangles(new GridTriangulator().triangulate(
|
||||||
|
shape[1], shape[0]));
|
||||||
|
} else if (type == TriangulationType.DELAUNEY) {
|
||||||
|
try {
|
||||||
|
location.setTriangles(new DelauneyTriangulator()
|
||||||
|
.triangulate(location));
|
||||||
|
} catch (FactoryException | TransformException e) {
|
||||||
|
logger.error(
|
||||||
|
"Delauney triangulation for {} failed because data is not 2 dimensional",
|
||||||
|
dataVarName, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
record.setLocationId(location.getId());
|
record.setLocationId(location.getId());
|
||||||
location.save(record.getStoragePath().toFile());
|
location.save(record.getStoragePath().toFile());
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,6 +94,9 @@ public class ProductDescription {
|
||||||
@XmlElement
|
@XmlElement
|
||||||
private DataTimeDescription dataTime;
|
private DataTimeDescription dataTime;
|
||||||
|
|
||||||
|
@XmlElement
|
||||||
|
private TriangulationDescription triangulation;
|
||||||
|
|
||||||
public boolean isDebug() {
|
public boolean isDebug() {
|
||||||
return debug;
|
return debug;
|
||||||
}
|
}
|
||||||
|
@ -158,8 +161,17 @@ public class ProductDescription {
|
||||||
this.dataTime = dataTime;
|
this.dataTime = dataTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TriangulationDescription getTriangulation() {
|
||||||
|
return triangulation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTriangulation(TriangulationDescription triangulation) {
|
||||||
|
this.triangulation = triangulation;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract the the datasetId, parameter, level and datatime from
|
* Extract the the datasetId, parameter, level and datatime from the file
|
||||||
|
* using the attributes contained in this description.
|
||||||
*/
|
*/
|
||||||
public PointSetRecord getRecord(NetcdfFile file,
|
public PointSetRecord getRecord(NetcdfFile file,
|
||||||
ParameterLookup parameterLookup, LevelFactory levelFactory)
|
ParameterLookup parameterLookup, LevelFactory levelFactory)
|
||||||
|
|
|
@ -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.edex.plugin.pointset.netcdf.description;
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
import javax.xml.bind.annotation.XmlAttribute;
|
||||||
|
import javax.xml.bind.annotation.XmlEnumValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the type of triangulation that should be performed. If we need any
|
||||||
|
* additional parameters to get an accurate triangulation then new attributes
|
||||||
|
* will be added here.
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
*
|
||||||
|
* SOFTWARE HISTORY
|
||||||
|
*
|
||||||
|
* Date Ticket# Engineer Description
|
||||||
|
* ------------- -------- --------- --------------------------
|
||||||
|
* Aug 24, 2015 4709 bsteffen Initial creation
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author bsteffen
|
||||||
|
*/
|
||||||
|
@XmlAccessorType(XmlAccessType.NONE)
|
||||||
|
public class TriangulationDescription {
|
||||||
|
|
||||||
|
@XmlAttribute
|
||||||
|
private TriangulationType type;
|
||||||
|
|
||||||
|
public TriangulationType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(TriangulationType type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static enum TriangulationType {
|
||||||
|
@XmlEnumValue(value = "grid")
|
||||||
|
GRID,
|
||||||
|
|
||||||
|
@XmlEnumValue(value = "delauney")
|
||||||
|
DELAUNEY;
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,5 +30,6 @@
|
||||||
<masterLevel value="EA" />
|
<masterLevel value="EA" />
|
||||||
<levelOneValue value="0.0" />
|
<levelOneValue value="0.0" />
|
||||||
</level>
|
</level>
|
||||||
|
<triangulation type="grid" />
|
||||||
</description>
|
</description>
|
||||||
</pointSetProductDescriptions>
|
</pointSetProductDescriptions>
|
Loading…
Add table
Reference in a new issue