Issue #704 create a radial bin and azimuth range map projection so radar data can use standard api.
Change-Id: If5bba07e679881188b190363cc234ba145ce9f23 Former-commit-id:dd353747d0
[formerly f99f9b49b0682fccf17f6d03d5cbde7f80cf7b39] Former-commit-id:f63d2bc7c2
This commit is contained in:
parent
6b9d13211d
commit
e629fcb15b
5 changed files with 451 additions and 1 deletions
|
@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2
|
|||
Bundle-Name: Radar
|
||||
Bundle-SymbolicName: com.raytheon.uf.common.dataplugin.radar
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Eclipse-RegisterBuddy: com.raytheon.edex.common, com.raytheon.uf.common.serialization, com.raytheon.viz.core
|
||||
Eclipse-RegisterBuddy: com.raytheon.edex.common, com.raytheon.uf.common.serialization, com.raytheon.viz.core, org.geotools
|
||||
Bundle-Activator: com.raytheon.uf.common.dataplugin.radar.Activator
|
||||
Bundle-Vendor: RAYTHEON
|
||||
Require-Bundle: org.eclipse.core.runtime,
|
||||
|
@ -31,6 +31,7 @@ Export-Package: com.raytheon.uf.common.dataplugin.radar;
|
|||
com.raytheon.uf.common.time",
|
||||
com.raytheon.uf.common.dataplugin.radar.level3;uses:="com.raytheon.uf.common.dataplugin.radar.level3.generic,com.raytheon.uf.common.serialization",
|
||||
com.raytheon.uf.common.dataplugin.radar.level3.generic;uses:="com.raytheon.uf.common.serialization",
|
||||
com.raytheon.uf.common.dataplugin.radar.projection,
|
||||
com.raytheon.uf.common.dataplugin.radar.request;uses:="com.raytheon.uf.common.serialization.comm",
|
||||
com.raytheon.uf.common.dataplugin.radar.util;
|
||||
uses:="com.raytheon.uf.common.dataplugin.radar,
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
com.raytheon.uf.common.dataplugin.radar.projection.AzimuthRangeMapProjection$Provider
|
||||
com.raytheon.uf.common.dataplugin.radar.projection.RadialBinMapProjection$Provider
|
|
@ -0,0 +1,130 @@
|
|||
/**
|
||||
* 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.radar.projection;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
|
||||
import org.geotools.parameter.DefaultParameterDescriptorGroup;
|
||||
import org.geotools.referencing.operation.projection.ObliqueStereographic;
|
||||
import org.geotools.referencing.operation.projection.ProjectionException;
|
||||
import org.opengis.parameter.InvalidParameterNameException;
|
||||
import org.opengis.parameter.InvalidParameterValueException;
|
||||
import org.opengis.parameter.ParameterDescriptor;
|
||||
import org.opengis.parameter.ParameterDescriptorGroup;
|
||||
import org.opengis.parameter.ParameterNotFoundException;
|
||||
import org.opengis.parameter.ParameterValueGroup;
|
||||
import org.opengis.referencing.FactoryException;
|
||||
import org.opengis.referencing.operation.MathTransform;
|
||||
|
||||
/**
|
||||
* Coordinates in the AzimuthRangeProjection represent the azimuth and range
|
||||
* relative to the point defined by the intersection of the central meridian and
|
||||
* the latitude of origin. The x coordinate is the azimuth angle in degrees and
|
||||
* the the y coordinate is the distance from the point in meters.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jun 6, 2012 bsteffen Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bsteffen
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class AzimuthRangeMapProjection extends ObliqueStereographic {
|
||||
|
||||
private static final long serialVersionUID = 4469133725910219322L;
|
||||
|
||||
protected AzimuthRangeMapProjection(ParameterValueGroup values)
|
||||
throws ParameterNotFoundException {
|
||||
super(values);
|
||||
this.globalScale = 1.0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParameterDescriptorGroup getParameterDescriptors() {
|
||||
return Provider.PARAMETERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Point2D inverseTransformNormalized(double azimuth, double range,
|
||||
Point2D dest) throws ProjectionException {
|
||||
range = range / (scaleFactor * semiMajor);
|
||||
azimuth = Math.toRadians(azimuth);
|
||||
double x = range * Math.sin(azimuth);
|
||||
double y = range * Math.cos(azimuth);
|
||||
return super.inverseTransformNormalized(x, y, dest);
|
||||
}
|
||||
|
||||
protected double normalizeAngle(double rangeLow, double rangeHigh,
|
||||
double angle) {
|
||||
while (angle < rangeLow) {
|
||||
angle += 360;
|
||||
}
|
||||
while (angle > rangeHigh) {
|
||||
angle -= 360;
|
||||
}
|
||||
return angle;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Point2D transformNormalized(double lon, double lat, Point2D dest)
|
||||
throws ProjectionException {
|
||||
Point2D tmp = new Point2D.Double();
|
||||
super.transformNormalized(lon, lat, tmp);
|
||||
double azimuth = Math.toDegrees(Math.atan2(tmp.getX(), tmp.getY()));
|
||||
double range = scaleFactor * semiMajor
|
||||
* Math.hypot(tmp.getX(), tmp.getY());
|
||||
if (dest != null) {
|
||||
dest.setLocation(azimuth, range);
|
||||
return dest;
|
||||
}
|
||||
return new Point2D.Double(azimuth, range);
|
||||
}
|
||||
|
||||
public static class Provider extends AbstractProvider {
|
||||
|
||||
private static final long serialVersionUID = 6736153862347982008L;
|
||||
|
||||
static final ParameterDescriptorGroup PARAMETERS = new DefaultParameterDescriptorGroup(
|
||||
"Azimuth_Range", new ParameterDescriptor[] { SEMI_MAJOR,
|
||||
SEMI_MINOR, CENTRAL_MERIDIAN, LATITUDE_OF_ORIGIN,
|
||||
SCALE_FACTOR, FALSE_EASTING, FALSE_NORTHING });
|
||||
|
||||
public Provider() {
|
||||
super(PARAMETERS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MathTransform createMathTransform(ParameterValueGroup values)
|
||||
throws InvalidParameterNameException,
|
||||
ParameterNotFoundException, InvalidParameterValueException,
|
||||
FactoryException {
|
||||
return new AzimuthRangeMapProjection(values);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/**
|
||||
* 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.radar.projection;
|
||||
|
||||
import org.geotools.coverage.grid.GridEnvelope2D;
|
||||
import org.geotools.coverage.grid.GridGeometry2D;
|
||||
import org.geotools.geometry.Envelope2D;
|
||||
import org.geotools.referencing.operation.DefaultMathTransformFactory;
|
||||
import org.geotools.referencing.operation.builder.GridToEnvelopeMapper;
|
||||
import org.geotools.referencing.operation.projection.MapProjection.AbstractProvider;
|
||||
import org.opengis.parameter.ParameterValueGroup;
|
||||
import org.opengis.referencing.FactoryException;
|
||||
import org.opengis.referencing.crs.CoordinateReferenceSystem;
|
||||
import org.opengis.referencing.crs.ProjectedCRS;
|
||||
|
||||
import com.raytheon.uf.common.geospatial.MapUtil;
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
|
||||
/**
|
||||
* TODO Add Description
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jun 7, 2012 bsteffen Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bsteffen
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class RadarProjectionFactory {
|
||||
|
||||
private static DefaultMathTransformFactory dmtFactory = new DefaultMathTransformFactory();
|
||||
|
||||
public static ProjectedCRS constructAzRan(Coordinate centerLatLon)
|
||||
throws FactoryException {
|
||||
ParameterValueGroup group = dmtFactory
|
||||
.getDefaultParameters("Azimuth_Range");
|
||||
group.parameter(AbstractProvider.SEMI_MAJOR.getName().getCode())
|
||||
.setValue(MapUtil.AWIPS_EARTH_RADIUS);
|
||||
group.parameter(AbstractProvider.SEMI_MINOR.getName().getCode())
|
||||
.setValue(MapUtil.AWIPS_EARTH_RADIUS);
|
||||
group.parameter(AbstractProvider.CENTRAL_MERIDIAN.getName().getCode())
|
||||
.setValue(centerLatLon.x);
|
||||
group.parameter(AbstractProvider.LATITUDE_OF_ORIGIN.getName().getCode())
|
||||
.setValue(centerLatLon.y);
|
||||
return MapUtil.constructProjection("Azimuth Range", group);
|
||||
}
|
||||
|
||||
public static ProjectedCRS constructRadialBin(Coordinate centerLatLon,
|
||||
float[] angleData, double binWidth, double tiltAngle)
|
||||
throws FactoryException {
|
||||
ParameterValueGroup group = dmtFactory
|
||||
.getDefaultParameters("Radial_Bin");
|
||||
group.parameter(AbstractProvider.SEMI_MAJOR.getName().getCode())
|
||||
.setValue(MapUtil.AWIPS_EARTH_RADIUS);
|
||||
group.parameter(AbstractProvider.SEMI_MINOR.getName().getCode())
|
||||
.setValue(MapUtil.AWIPS_EARTH_RADIUS);
|
||||
group.parameter(AbstractProvider.CENTRAL_MERIDIAN.getName().getCode())
|
||||
.setValue(centerLatLon.x);
|
||||
group.parameter(AbstractProvider.LATITUDE_OF_ORIGIN.getName().getCode())
|
||||
.setValue(centerLatLon.y);
|
||||
group.parameter(
|
||||
RadialBinMapProjection.Provider.ANGLE_DATA.getName().getCode())
|
||||
.setValue(angleData);
|
||||
group.parameter(
|
||||
RadialBinMapProjection.Provider.BIN_LENGTH.getName().getCode())
|
||||
.setValue(binWidth);
|
||||
group.parameter(
|
||||
RadialBinMapProjection.Provider.TILT_ANGLE.getName().getCode())
|
||||
.setValue(tiltAngle);
|
||||
return MapUtil.constructProjection("Radial Bin", group);
|
||||
}
|
||||
|
||||
public static GridGeometry2D constructGridGeometry(Coordinate centerLatLon,
|
||||
float[] angleData, double binWidth, double tiltAngle, int numBins,
|
||||
boolean swapXY) throws FactoryException {
|
||||
CoordinateReferenceSystem crs = constructRadialBin(centerLatLon,
|
||||
angleData, binWidth, tiltAngle);
|
||||
GridEnvelope2D gridRange = null;
|
||||
if (swapXY) {
|
||||
gridRange = new GridEnvelope2D(0, 0, numBins, angleData.length);
|
||||
} else {
|
||||
gridRange = new GridEnvelope2D(0, 0, angleData.length, numBins);
|
||||
}
|
||||
Envelope2D envelope = new Envelope2D(crs, 0, 0, angleData.length,
|
||||
numBins);
|
||||
GridToEnvelopeMapper mapper = new GridToEnvelopeMapper(gridRange,
|
||||
envelope);
|
||||
mapper.setSwapXY(swapXY);
|
||||
mapper.setReverseAxis(new boolean[] { false, false });
|
||||
return new GridGeometry2D(gridRange, mapper.createTransform(), crs);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,200 @@
|
|||
/**
|
||||
* 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.radar.projection;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.geotools.parameter.DefaultParameterDescriptor;
|
||||
import org.geotools.parameter.DefaultParameterDescriptorGroup;
|
||||
import org.geotools.referencing.operation.MathTransformProvider;
|
||||
import org.geotools.referencing.operation.projection.ProjectionException;
|
||||
import org.opengis.parameter.InvalidParameterNameException;
|
||||
import org.opengis.parameter.InvalidParameterValueException;
|
||||
import org.opengis.parameter.ParameterDescriptor;
|
||||
import org.opengis.parameter.ParameterDescriptorGroup;
|
||||
import org.opengis.parameter.ParameterNotFoundException;
|
||||
import org.opengis.parameter.ParameterValueGroup;
|
||||
import org.opengis.referencing.FactoryException;
|
||||
import org.opengis.referencing.operation.MathTransform;
|
||||
|
||||
/**
|
||||
* Coordinates in the RadialBinMapProjection represent the radial and bin
|
||||
* relative to the point defined by the intersection of the central meridian and
|
||||
* the latitude of origin. The x coordinate is the radial index into the
|
||||
* angleData, the y coordinate is the bin number, which is computed using the
|
||||
* binWidth and the tilt angle.
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jun 6, 2012 bsteffen Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bsteffen
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class RadialBinMapProjection extends AzimuthRangeMapProjection {
|
||||
|
||||
private static final long serialVersionUID = 6392115431894559801L;
|
||||
|
||||
private float[] normalAngleData;
|
||||
|
||||
private double flatBinLength;
|
||||
|
||||
protected RadialBinMapProjection(ParameterValueGroup values)
|
||||
throws ParameterNotFoundException {
|
||||
super(values);
|
||||
float[] angleData = Provider.getValue(Provider.ANGLE_DATA, values);
|
||||
normalAngleData = new float[angleData.length];
|
||||
normalAngleData[0] = angleData[0];
|
||||
for (int i = 1; i < angleData.length; i += 1) {
|
||||
if (angleData[i] <= angleData[0]) {
|
||||
normalAngleData[i] = angleData[i] + 360;
|
||||
} else {
|
||||
normalAngleData[i] = angleData[i];
|
||||
}
|
||||
}
|
||||
double tiltAngle = Provider.getValue(Provider.TILT_ANGLE, values);
|
||||
double binLength = Provider.getValue(Provider.BIN_LENGTH, values);
|
||||
this.flatBinLength = binLength * Math.cos(Math.toRadians(tiltAngle));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParameterDescriptorGroup getParameterDescriptors() {
|
||||
return Provider.PARAMETERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Point2D inverseTransformNormalized(double radial, double bin,
|
||||
Point2D dest) throws ProjectionException {
|
||||
double ran = bin * flatBinLength;
|
||||
while (radial < 0) {
|
||||
radial += normalAngleData.length;
|
||||
}
|
||||
int prevRadial = (int) Math.floor(radial) % normalAngleData.length;
|
||||
int nextRadial = (int) Math.ceil(radial) % normalAngleData.length;
|
||||
float prevAngle = normalAngleData[prevRadial];
|
||||
float nextAngle = normalAngleData[nextRadial];
|
||||
double az = prevAngle + (radial - prevRadial) * (nextAngle - prevAngle);
|
||||
return super.inverseTransformNormalized(az, ran, dest);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Point2D transformNormalized(double lon, double lat, Point2D dest)
|
||||
throws ProjectionException {
|
||||
Point2D tmp = new Point2D.Double();
|
||||
tmp = super.transformNormalized(lon, lat, tmp);
|
||||
double az = tmp.getX();
|
||||
double ran = tmp.getY();
|
||||
// System.out.println(ran);
|
||||
double radial = Double.NaN;
|
||||
double bin = ran / flatBinLength;
|
||||
float nextAngle = normalAngleData[0] + 360;
|
||||
az = normalizeAngle(normalAngleData[0], nextAngle, az);
|
||||
for (int i = normalAngleData.length - 1; i >= 0; i -= 1) {
|
||||
float prevAngle = normalAngleData[i];
|
||||
if (prevAngle <= az && nextAngle > az) {
|
||||
radial = (i) + (az - prevAngle) / (nextAngle - prevAngle);
|
||||
break;
|
||||
}
|
||||
prevAngle = nextAngle;
|
||||
}
|
||||
dest.setLocation(radial, bin);
|
||||
return dest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
long temp;
|
||||
temp = Double.doubleToLongBits(flatBinLength);
|
||||
result = prime * result + (int) (temp ^ (temp >>> 32));
|
||||
result = prime * result + Arrays.hashCode(normalAngleData);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (!super.equals(obj))
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
RadialBinMapProjection other = (RadialBinMapProjection) obj;
|
||||
if (Double.doubleToLongBits(flatBinLength) != Double
|
||||
.doubleToLongBits(other.flatBinLength))
|
||||
return false;
|
||||
if (!Arrays.equals(normalAngleData, other.normalAngleData))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static class Provider extends AbstractProvider {
|
||||
|
||||
private static final long serialVersionUID = 4990986103949071193L;
|
||||
|
||||
static final ParameterDescriptor<float[]> ANGLE_DATA = DefaultParameterDescriptor
|
||||
.create("angle_data", "The angle in degrees of each radial",
|
||||
float[].class, null, true);
|
||||
|
||||
static final ParameterDescriptor<Double> TILT_ANGLE = DefaultParameterDescriptor
|
||||
.create("tilt_angle",
|
||||
"The angle in degrees above ground level",
|
||||
Double.class, null, true);
|
||||
|
||||
static final ParameterDescriptor<Double> BIN_LENGTH = DefaultParameterDescriptor
|
||||
.create("bin_length", "The length of bins in meters",
|
||||
Double.class, null, true);
|
||||
|
||||
static final ParameterDescriptorGroup PARAMETERS = new DefaultParameterDescriptorGroup(
|
||||
"Radial_Bin", new ParameterDescriptor[] { SEMI_MAJOR,
|
||||
SEMI_MINOR, CENTRAL_MERIDIAN, LATITUDE_OF_ORIGIN,
|
||||
ANGLE_DATA, TILT_ANGLE, BIN_LENGTH, SCALE_FACTOR,
|
||||
FALSE_EASTING, FALSE_NORTHING });
|
||||
|
||||
public Provider() {
|
||||
super(PARAMETERS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MathTransform createMathTransform(ParameterValueGroup values)
|
||||
throws InvalidParameterNameException,
|
||||
ParameterNotFoundException, InvalidParameterValueException,
|
||||
FactoryException {
|
||||
return new RadialBinMapProjection(values);
|
||||
}
|
||||
|
||||
static <T> T getValue(ParameterDescriptor<T> descriptor,
|
||||
ParameterValueGroup group) {
|
||||
return MathTransformProvider.value(descriptor, group);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Reference in a new issue