Merge "Issue #2177 Improve county portion descriptions." into omaha_13.5.2
Former-commit-id:07f087013f
[formerly07f087013f
[formerly 1b7f1d8dce2cc1161ce06ca0c4a8df68803a12e1]] Former-commit-id:321ddebdde
Former-commit-id:0af2308491
This commit is contained in:
commit
2e26b28a40
9 changed files with 1528 additions and 126 deletions
|
@ -32,6 +32,7 @@ import java.util.List;
|
|||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Dec 11, 2007 #601 chammack Initial Creation.
|
||||
* Aug 19, 2013 2177 jsanchez Removed suppress attribute.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -49,11 +50,6 @@ public class AffectedAreas {
|
|||
*/
|
||||
protected List<String> partOfArea;
|
||||
|
||||
/**
|
||||
* The partOfArea to suppress (e.g. "ns")
|
||||
*/
|
||||
protected String suppress;
|
||||
|
||||
/** The notation of the area affected (e.g. "COUNTY") */
|
||||
protected String areaNotation;
|
||||
|
||||
|
@ -89,17 +85,15 @@ public class AffectedAreas {
|
|||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* the name to set
|
||||
* @param name
|
||||
* the name to set
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the areaNotation
|
||||
*/
|
||||
|
|
|
@ -46,7 +46,6 @@ import com.raytheon.uf.common.status.UFStatus;
|
|||
import com.raytheon.uf.common.status.UFStatus.Priority;
|
||||
import com.raytheon.uf.viz.core.exception.VizException;
|
||||
import com.raytheon.viz.warngen.gui.WarngenLayer;
|
||||
import com.raytheon.viz.warngen.suppress.SuppressMap;
|
||||
import com.raytheon.viz.warngen.util.Abbreviation;
|
||||
import com.vividsolutions.jts.geom.Geometry;
|
||||
import com.vividsolutions.jts.geom.prep.PreparedGeometry;
|
||||
|
@ -74,6 +73,7 @@ import com.vividsolutions.jts.geom.prep.PreparedGeometry;
|
|||
* Nov 9, 2012 DR 15430 D. Friedman Extracted method converFeAreaToPartList.
|
||||
* Apr 29, 2013 1955 jsanchez Ignored comparing the geometry's user data when finding intersected areas.
|
||||
* May 2, 2013 1963 jsanchez Updated method to determine partOfArea.
|
||||
* Aug 19, 2013 2177 jsanchez Used portionsUtil to calculate area portion descriptions.
|
||||
* </pre>
|
||||
*
|
||||
* @author chammack
|
||||
|
@ -89,13 +89,15 @@ public class Area {
|
|||
*/
|
||||
public static final double DEFAULT_PORTION_TOLERANCE = 0.60;
|
||||
|
||||
private Area() {
|
||||
private PortionsUtil portionsUtil;
|
||||
|
||||
public Area(PortionsUtil portionsUtil) {
|
||||
this.portionsUtil = portionsUtil;
|
||||
}
|
||||
|
||||
public static AffectedAreas[] findAffectedAreas(
|
||||
WarngenConfiguration config, Geometry polygon,
|
||||
Geometry warningArea, String localizedSite) throws VizException {
|
||||
public AffectedAreas[] findAffectedAreas(WarngenConfiguration config,
|
||||
Geometry polygon, Geometry warningArea, String localizedSite)
|
||||
throws VizException {
|
||||
|
||||
// --- Begin argument checking ---
|
||||
Validate.notNull(config.getGeospatialConfig().getAreaSource(),
|
||||
|
@ -113,7 +115,7 @@ public class Area {
|
|||
localizedSite, geoms);
|
||||
}
|
||||
|
||||
private static AffectedAreas[] findAffectedAreas(
|
||||
private AffectedAreas[] findAffectedAreas(
|
||||
AreaSourceConfiguration areaConfig,
|
||||
GeospatialConfiguration geospatialConfig, Geometry polygon,
|
||||
String localizedSite, List<Geometry> geoms) throws VizException {
|
||||
|
@ -183,7 +185,6 @@ public class Area {
|
|||
area.stateabbr = regionFeature.attributes.get(areaNotationField)
|
||||
.toString();
|
||||
area.size = regionGeom.getArea();
|
||||
area.suppress = suppressType(areaSource, area.stateabbr, area.fips);
|
||||
|
||||
Object tzData = regionFeature.attributes.get(timezonePathcastField);
|
||||
|
||||
|
@ -219,9 +220,16 @@ public class Area {
|
|||
double tolerCheck = regionGeom.getArea()
|
||||
* DEFAULT_PORTION_TOLERANCE;
|
||||
if (areaIntersection < tolerCheck) {
|
||||
area.partOfArea = GisUtil
|
||||
.asStringList(GisUtil.calculatePortion(regionGeom,
|
||||
intersection, true, true));
|
||||
try {
|
||||
String entityID = area.stateabbr + areaSource.charAt(0)
|
||||
+ area.fips.substring(2);
|
||||
area.partOfArea = GisUtil.asStringList(portionsUtil
|
||||
.getPortions(entityID, regionGeom, intersection,
|
||||
true));
|
||||
} catch (Exception e) {
|
||||
statusHandler.error("Unable to calculate part of area for "
|
||||
+ area.name, e);
|
||||
}
|
||||
}
|
||||
|
||||
// Search the parent region
|
||||
|
@ -277,10 +285,9 @@ public class Area {
|
|||
* @return
|
||||
* @throws VizException
|
||||
*/
|
||||
public static Map<String, Object> findInsectingAreas(
|
||||
WarngenConfiguration config, Geometry warnPolygon,
|
||||
Geometry warnArea, String localizedSite, WarngenLayer warngenLayer)
|
||||
throws VizException {
|
||||
public Map<String, Object> findInsectingAreas(WarngenConfiguration config,
|
||||
Geometry warnPolygon, Geometry warnArea, String localizedSite,
|
||||
WarngenLayer warngenLayer) throws VizException {
|
||||
Map<String, Object> areasMap = new HashMap<String, Object>();
|
||||
|
||||
String hatchedAreaSource = config.getHatchedAreaSource()
|
||||
|
@ -311,18 +318,6 @@ public class Area {
|
|||
|
||||
}
|
||||
|
||||
private static String suppressType(String areaSource, String state,
|
||||
String fips) {
|
||||
String retVal = SuppressMap.NONE;
|
||||
String type = areaSource.equalsIgnoreCase("zone") ? "Z" : "C";
|
||||
|
||||
if (state != null && fips != null) {
|
||||
String key = state + type + fips.substring(2);
|
||||
retVal = SuppressMap.getInstance().getType(key);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public static List<String> converFeAreaToPartList(String feArea) {
|
||||
final List<String> partList = new ArrayList<String>();
|
||||
if (feArea == null) {
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
/**
|
||||
* 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.warngen.gis;
|
||||
|
||||
/**
|
||||
* Port of A1 constants applied to a grid to determine county or zone portions.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Aug 5, 2013 2177 jsanchez Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author jsanchez
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class CoverageConstants {
|
||||
|
||||
public static final int XSOUTH = 0x0001;
|
||||
|
||||
public static final int SOUTH = 0x0002;
|
||||
|
||||
public static final int NORTH = 0x0040;
|
||||
|
||||
public static final int XNORTH = 0x0080;
|
||||
|
||||
public static final int CENTER_NS = 0x0018;
|
||||
|
||||
public static final int CENTRAL_NS = 0x0024;
|
||||
|
||||
public static final int XWEST = 0x0100;
|
||||
|
||||
public static final int WEST = 0x0200;
|
||||
|
||||
public static final int EAST = 0x4000;
|
||||
|
||||
public static final int XEAST = 0x8000;
|
||||
|
||||
public static final int CENTER_EW = 0x1800;
|
||||
|
||||
public static final int CENTRAL_EW = 0x2400;
|
||||
|
||||
public static final int SOUTHERN = 0x0003;
|
||||
|
||||
public static final int NORTHERN = 0x00C0;
|
||||
|
||||
public static final int WESTERN = 0x0300;
|
||||
|
||||
public static final int EASTERN = 0xC000;
|
||||
|
||||
public static final int SOUTHSIDE = 0x000F;
|
||||
|
||||
public static final int NORTHSIDE = 0x00F0;
|
||||
|
||||
public static final int WESTSIDE = 0x0F00;
|
||||
|
||||
public static final int EASTSIDE = 0xF000;
|
||||
|
||||
public static final int EXTREME = 0x8181;
|
||||
|
||||
public static final int NOT_EXTREME = 0x7E7E;
|
||||
|
||||
public static final int EXTREME_NS = 0x0081;
|
||||
|
||||
public static final int EXTREME_EW = 0x8100;
|
||||
|
||||
public static final int CENTRAL = 0x2424;
|
||||
|
||||
public static final int CENTER = 0x1818;
|
||||
|
||||
public static final int NOT_CENTRAL = 0xC3C3;
|
||||
|
||||
public static final int NORTH_SOUTH = 0x00FF;
|
||||
|
||||
public static final int EAST_WEST = 0xFF00;
|
||||
|
||||
public static final int NNE = 0x0001;
|
||||
|
||||
public static final int ENE = 0x0002;
|
||||
|
||||
public static final int ESE = 0x0004;
|
||||
|
||||
public static final int SSE = 0x0008;
|
||||
|
||||
public static final int SSW = 0x0010;
|
||||
|
||||
public static final int WSW = 0x0020;
|
||||
|
||||
public static final int WNW = 0x0040;
|
||||
|
||||
public static final int NNW = 0x0080;
|
||||
|
||||
public static final int EXTREME_YES = 0xFFFF00;
|
||||
|
||||
public static final int EXTREME_NO = 0x00FF;
|
||||
|
||||
public static final int EXTREME_CORNER = 0xFF0000;
|
||||
|
||||
public static int[] NS_MASK = new int[256];
|
||||
|
||||
public static int[] EW_MASK = new int[256];
|
||||
|
||||
static {
|
||||
int i;
|
||||
|
||||
NS_MASK[0] = 0;
|
||||
for (i = 1; i < 256; i++) {
|
||||
if (i < 87) {
|
||||
NS_MASK[i] = XSOUTH | SOUTH;
|
||||
} else if (i > 167) {
|
||||
NS_MASK[i] = XNORTH | NORTH;
|
||||
} else if (i < 106) {
|
||||
NS_MASK[i] = SOUTH;
|
||||
} else if (i > 148) {
|
||||
NS_MASK[i] = NORTH;
|
||||
} else if (i < 118) {
|
||||
NS_MASK[i] = CENTRAL_NS | SOUTH;
|
||||
} else if (i > 138) {
|
||||
NS_MASK[i] = CENTRAL_NS | NORTH;
|
||||
} else if (i < 127) {
|
||||
NS_MASK[i] = CENTER_NS | CENTRAL_NS | SOUTH;
|
||||
} else if (i > 127) {
|
||||
NS_MASK[i] = CENTER_NS | CENTRAL_NS | NORTH;
|
||||
} else {
|
||||
NS_MASK[i] = CENTER_NS | CENTRAL_NS;
|
||||
}
|
||||
}
|
||||
|
||||
EW_MASK[0] = 0;
|
||||
for (i = 1; i < 256; i++) {
|
||||
if (i < 87) {
|
||||
EW_MASK[i] = XWEST | WEST;
|
||||
} else if (i > 167) {
|
||||
EW_MASK[i] = XEAST | EAST;
|
||||
} else if (i < 106) {
|
||||
EW_MASK[i] = WEST;
|
||||
} else if (i > 145) {
|
||||
EW_MASK[i] = EAST;
|
||||
} else if (i < 118) {
|
||||
EW_MASK[i] = CENTRAL_EW | WEST;
|
||||
} else if (i > 138) {
|
||||
EW_MASK[i] = CENTRAL_EW | EAST;
|
||||
} else if (i < 127) {
|
||||
EW_MASK[i] = CENTER_EW | CENTRAL_EW | WEST;
|
||||
} else if (i > 127) {
|
||||
EW_MASK[i] = CENTER_EW | CENTRAL_EW | EAST;
|
||||
} else {
|
||||
EW_MASK[i] = CENTER_EW | CENTRAL_EW;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private CoverageConstants() {
|
||||
|
||||
}
|
||||
}
|
|
@ -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.viz.warngen.gis;
|
||||
|
||||
/**
|
||||
* Simple port of an A1 struct created by GridUtil and used by PortionsUtil.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Aug 5, 2013 2177 jsanchez Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author jsanchez
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class EntityData {
|
||||
|
||||
private int meanMask = 0;
|
||||
|
||||
private int coverageMask = 0;
|
||||
|
||||
private int octants = 0;
|
||||
|
||||
public EntityData(int meanMask, int coverageMask, int octants) {
|
||||
this.meanMask = meanMask;
|
||||
this.coverageMask = coverageMask;
|
||||
this.octants = octants;
|
||||
}
|
||||
|
||||
public int getMeanMask() {
|
||||
return meanMask;
|
||||
}
|
||||
|
||||
public int getCoverageMask() {
|
||||
return coverageMask;
|
||||
}
|
||||
|
||||
public int getOctants() {
|
||||
return octants;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,616 @@
|
|||
/**
|
||||
* 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.warngen.gis;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.geotools.coverage.grid.GeneralGridGeometry;
|
||||
import org.geotools.coverage.grid.GridGeometry2D;
|
||||
import org.geotools.referencing.operation.DefaultMathTransformFactory;
|
||||
import org.opengis.coverage.grid.GridEnvelope;
|
||||
import org.opengis.metadata.spatial.PixelOrientation;
|
||||
import org.opengis.referencing.operation.MathTransform;
|
||||
|
||||
import com.raytheon.uf.common.dataplugin.warning.util.GeometryUtil;
|
||||
import com.raytheon.uf.viz.core.exception.VizException;
|
||||
import com.raytheon.viz.warngen.gui.WarngenLayer;
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
import com.vividsolutions.jts.geom.CoordinateSequence;
|
||||
import com.vividsolutions.jts.geom.Envelope;
|
||||
import com.vividsolutions.jts.geom.Geometry;
|
||||
import com.vividsolutions.jts.geom.GeometryFactory;
|
||||
import com.vividsolutions.jts.geom.Point;
|
||||
import com.vividsolutions.jts.geom.prep.PreparedGeometry;
|
||||
import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory;
|
||||
|
||||
/**
|
||||
* Converts the county or zone and the intersecting warning area to grids. The
|
||||
* county or zone is also weighted to determine the northern, southern, eastern,
|
||||
* and western parts of the county or zone. Most of the code is ported from A1
|
||||
* to create an EntityData object that will be used by PortionsUtil to determine
|
||||
* the applicable impacted portions of a county or zone.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Aug 5, 2013 jsanchez Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author jsanchez
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class GridUtil {
|
||||
|
||||
private int ny = 0;
|
||||
|
||||
private int nx = 0;
|
||||
|
||||
private int[] ewGrid;
|
||||
|
||||
private int[] nsGrid;
|
||||
|
||||
private byte[] warnedAreaGrid;
|
||||
|
||||
private byte[] countyOrZoneGrid;
|
||||
|
||||
private WarngenLayer layer;
|
||||
|
||||
private MathTransform latLonToContour, contourToLatLon;
|
||||
|
||||
public GridUtil(WarngenLayer layer, GeneralGridGeometry localGridGeometry,
|
||||
MathTransform localToLatLon) throws Exception {
|
||||
this.layer = layer;
|
||||
|
||||
GridEnvelope range = localGridGeometry.getGridRange();
|
||||
this.nx = range.getHigh(0);
|
||||
this.ny = range.getHigh(1);
|
||||
|
||||
org.opengis.geometry.Envelope ge = localGridGeometry.getEnvelope();
|
||||
contourToLatLon = new DefaultMathTransformFactory()
|
||||
.createConcatenatedTransform(new GridGeometry2D(range, ge)
|
||||
.getGridToCRS(PixelOrientation.CENTER), localToLatLon);
|
||||
latLonToContour = contourToLatLon.inverse();
|
||||
|
||||
ewGrid = new int[nx * ny];
|
||||
nsGrid = new int[nx * ny];
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the countyOrZone geometry and the warnedArea into grids and sets
|
||||
* the appropriate data in an EntityData object.
|
||||
*
|
||||
* @param countyOrZone
|
||||
* @param warnedArea
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public EntityData calculateGrids(Geometry countyOrZone, Geometry warnedArea)
|
||||
throws Exception {
|
||||
countyOrZoneGrid = toByteArray(countyOrZone);
|
||||
warnedAreaGrid = toByteArray(warnedArea);
|
||||
int[] bounds = awips1FinishAreaEntity();
|
||||
EntityData entityData = finishDefineArea(bounds);
|
||||
return entityData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the geometry into a byte array that is expected by ported A1
|
||||
* code.
|
||||
*
|
||||
* @param geometry
|
||||
* @return
|
||||
* @throws VizException
|
||||
*/
|
||||
private byte[] toByteArray(Geometry geometry) throws VizException {
|
||||
byte[] bytes = new byte[nx * ny];
|
||||
float[][] floatData = toFloatData(geometry);
|
||||
|
||||
// Rotates grid
|
||||
int k = 0;
|
||||
for (int j = ny - 1; j >= 0; j--) {
|
||||
for (int i = 0; i < nx; i++) {
|
||||
if (floatData[i][j] == 1) {
|
||||
bytes[k] = 1;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the geometry into a 2-D float array.
|
||||
*
|
||||
* @param geometry
|
||||
* @return
|
||||
* @throws VizException
|
||||
*/
|
||||
private float[][] toFloatData(Geometry geometry) throws VizException {
|
||||
Geometry contoured = layer.convertGeom(geometry, latLonToContour);
|
||||
List<Geometry> geomList = new ArrayList<Geometry>(
|
||||
contoured.getNumGeometries());
|
||||
GeometryUtil.buildGeometryList(geomList, contoured);
|
||||
List<PreparedGeometry> prepped = new ArrayList<PreparedGeometry>(
|
||||
geomList.size());
|
||||
for (Geometry g : geomList) {
|
||||
prepped.add(PreparedGeometryFactory.prepare(g));
|
||||
}
|
||||
|
||||
GeometryFactory gf = geometry.getFactory();
|
||||
Point point = gf.createPoint(new Coordinate(0, 0));
|
||||
CoordinateSequence pointCS = point.getCoordinateSequence();
|
||||
float[][] contourAreaData = new float[nx][ny];
|
||||
for (PreparedGeometry geom : prepped) {
|
||||
Envelope env = geom.getGeometry().getEnvelopeInternal();
|
||||
int startX = (int) env.getMinX();
|
||||
int startY = (int) env.getMinY();
|
||||
int width = (int) env.getMaxX();
|
||||
int height = (int) env.getMaxY();
|
||||
if (startX < 0 || width > nx || startY < 0 || height > ny) {
|
||||
continue;
|
||||
}
|
||||
startX = Math.max(0, startX - 1);
|
||||
startY = Math.max(0, startY - 1);
|
||||
width = Math.min(nx, width + 1);
|
||||
height = Math.min(ny, height + 1);
|
||||
for (int x = startX; x < width; ++x) {
|
||||
for (int y = startY; y < height; ++y) {
|
||||
|
||||
pointCS.setOrdinate(0, 0, x);
|
||||
pointCS.setOrdinate(0, 1, y);
|
||||
point.geometryChanged();
|
||||
if (contourAreaData[x][y] == 0.0f && geom.intersects(point)) {
|
||||
contourAreaData[x][y] = 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return contourAreaData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ported only the logic from A1 code
|
||||
* GeoEntityLookupTable::finishDefineArea() that calculates the meanMask,
|
||||
* coverageMask,and octants for an entity (i.e. county or zone).
|
||||
*
|
||||
* @param countyOrZone
|
||||
* @param warnedArea
|
||||
* @return
|
||||
*/
|
||||
private EntityData finishDefineArea(int[] bounds) {
|
||||
int meanMask = 0;
|
||||
int coverageMask = 0;
|
||||
int octants = 0;
|
||||
|
||||
int ewCount = 0;
|
||||
int nsCount = 0;
|
||||
int ewTotal = 0;
|
||||
int nsTotal = 0;
|
||||
|
||||
int k = 0;
|
||||
int min_i = bounds[0];
|
||||
int max_i = bounds[1];
|
||||
int min_j = bounds[2];
|
||||
int max_j = bounds[3];
|
||||
for (int j = min_j; j < max_j; j++) {
|
||||
k = nx * j + min_i;
|
||||
for (int i = min_i; i < max_i; i++, k++) {
|
||||
if (warnedAreaGrid[k] == 1) {
|
||||
int e = countyOrZoneGrid[k];
|
||||
|
||||
int ii = ewGrid[k];
|
||||
int jj = nsGrid[k];
|
||||
|
||||
if (ii == 0 && jj == 0) {
|
||||
continue;
|
||||
}
|
||||
ewTotal += ii;
|
||||
if (ii > 0) {
|
||||
ewCount++;
|
||||
}
|
||||
nsTotal += jj;
|
||||
if (jj > 0) {
|
||||
nsCount++;
|
||||
}
|
||||
int m = CoverageConstants.EW_MASK[ii]
|
||||
| CoverageConstants.NS_MASK[jj];
|
||||
coverageMask |= m;
|
||||
if ((m & CoverageConstants.CENTRAL) == CoverageConstants.CENTRAL) {
|
||||
continue;
|
||||
}
|
||||
if (ii == 0) {
|
||||
ii = 127;
|
||||
}
|
||||
if (jj == 0) {
|
||||
jj = 127;
|
||||
}
|
||||
if (ii < 127) {
|
||||
if (jj < 127) {
|
||||
e = (ii > jj ? CoverageConstants.SSW
|
||||
: CoverageConstants.WSW);
|
||||
} else {
|
||||
e = (ii > 254 - jj ? CoverageConstants.NNW
|
||||
: CoverageConstants.WNW);
|
||||
}
|
||||
} else {
|
||||
if (jj < 127) {
|
||||
e = (ii < 254 - jj ? CoverageConstants.SSE
|
||||
: CoverageConstants.ESE);
|
||||
} else {
|
||||
e = (ii < jj ? CoverageConstants.NNE
|
||||
: CoverageConstants.ENE);
|
||||
}
|
||||
}
|
||||
if ((m & CoverageConstants.EXTREME_NS) > 0) {
|
||||
e <<= 8;
|
||||
}
|
||||
if ((m & CoverageConstants.EXTREME_EW) > 0) {
|
||||
e <<= 8;
|
||||
}
|
||||
octants |= e;
|
||||
} else {
|
||||
warnedAreaGrid[k] = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (ewCount > 0) {
|
||||
ewTotal = (ewTotal + ewCount / 2) / ewCount;
|
||||
}
|
||||
if (nsCount > 0) {
|
||||
nsTotal = (nsTotal + nsCount / 2) / nsCount;
|
||||
}
|
||||
|
||||
meanMask = CoverageConstants.NS_MASK[nsTotal]
|
||||
| CoverageConstants.EW_MASK[ewTotal];
|
||||
return new EntityData(meanMask, coverageMask, octants);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the _ewGrid and _nsGrid via A1 ~~ mAgIc ~~
|
||||
*/
|
||||
private int[] awips1FinishAreaEntity() {
|
||||
|
||||
final double EXTREME_FRAC = 0.1;
|
||||
final double MIN_EXTREME = 87;
|
||||
final double MAX_EXTREME = 167;
|
||||
|
||||
int k = 0;
|
||||
int ii, jj;
|
||||
|
||||
/*
|
||||
* identify those points on the boundary of the entity so we can shrink
|
||||
* from there
|
||||
*/
|
||||
int i_mean = 0;
|
||||
int j_mean = 0;
|
||||
int new_tot = 0;
|
||||
int ii_mean = 0;
|
||||
int jj_mean = 0;
|
||||
int min_i = Integer.MAX_VALUE;
|
||||
int min_j = Integer.MAX_VALUE;
|
||||
int max_i = Integer.MIN_VALUE;
|
||||
int max_j = Integer.MIN_VALUE;
|
||||
|
||||
for (jj = 0; jj < ny; jj++) {
|
||||
k = nx * jj;
|
||||
for (ii = 0; ii < nx; ii++, k++) {
|
||||
// If the entity is not 1 then it's not part of the county or
|
||||
// zone area.
|
||||
if (countyOrZoneGrid[k] != 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ii > max_i) {
|
||||
max_i = ii;
|
||||
}
|
||||
|
||||
if (ii < min_i) {
|
||||
min_i = ii;
|
||||
}
|
||||
|
||||
if (jj > max_j) {
|
||||
max_j = jj;
|
||||
}
|
||||
if (jj < min_j) {
|
||||
min_j = jj;
|
||||
}
|
||||
++new_tot;
|
||||
ii_mean += ii;
|
||||
jj_mean += jj;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* restablish some things that might have changed since the first time
|
||||
* they were calculated.
|
||||
*/
|
||||
// if (!outside) {
|
||||
ii_mean /= new_tot;
|
||||
jj_mean /= new_tot;
|
||||
i_mean = ii_mean;
|
||||
j_mean = jj_mean;
|
||||
// }/*endif*/
|
||||
|
||||
/* assign correct base for directional computation */
|
||||
// I changed this from ii_mean to this
|
||||
double i_base = (min_i + max_i) / 2;
|
||||
// I changed this from jj_mean to this
|
||||
double j_base = (min_j + max_j) / 2;
|
||||
|
||||
/*
|
||||
* calculate needed rotation factors for computation of amount each
|
||||
* point is north and east of centroid
|
||||
*/
|
||||
double x_intcpg = 0.5;
|
||||
double y_intcpg = 0.5;
|
||||
|
||||
double dx = 1, dy = 1;
|
||||
double x = (i_base - x_intcpg);
|
||||
double y = (j_base - y_intcpg);
|
||||
|
||||
// Below is some code from the original A1 code. I assumed that x_intcpg
|
||||
// to be 0.5 to avoid porting all the methods in gelt_maker.c.
|
||||
// xy_to_ll(&x,&y,&lat,&lon,&my_proj);
|
||||
// lat01=lat+0.1;
|
||||
// ll_to_xy(&lat01,&lon,&dx,&dy,&my_proj);
|
||||
// dx -= x;
|
||||
|
||||
dy -= y;
|
||||
|
||||
double mag = Math.sqrt(dx * dx + dy * dy);
|
||||
dx /= mag;
|
||||
dy /= mag;
|
||||
double erot_i = -dy;
|
||||
double erot_j = -dx;
|
||||
|
||||
double nrot_i = dx;
|
||||
double nrot_j = dy;
|
||||
|
||||
int[] ew_hist = new int[nx * ny];
|
||||
int[] ns_hist = new int[nx * ny];
|
||||
|
||||
/* Calculate north/south & east/west offsets, create histogram of these. */
|
||||
// TODO I did not fully implement the histograms as used in a1. Using
|
||||
// the histograms created index out of bounds errors. If the field is
|
||||
// unhappy with the portions, then porting the histograms needs to be
|
||||
// re-investigated.
|
||||
int ns1 = 0, ns2 = 0, ew1 = 0, ew2 = 0;
|
||||
int np_n = 0, np_s = 0, np_e = 0, np_w = 0;
|
||||
ns_hist[0] = 0;
|
||||
ew_hist[0] = 0;
|
||||
for (jj = min_j; jj < max_j; jj++) {
|
||||
k = nx * jj + min_i;
|
||||
for (ii = min_i; ii < max_i; ii++, k++) {
|
||||
// If the entity is not 1 then it's not part of the county or
|
||||
// zone area.
|
||||
if (countyOrZoneGrid[k] != 1) {
|
||||
continue;
|
||||
}
|
||||
double di = ii - i_base;
|
||||
double dj = jj - j_base;
|
||||
|
||||
double dns = (int) (nrot_i * di + nrot_j * dj);
|
||||
while (ns1 > dns) {
|
||||
// ns_hist[--ns1] = 0;
|
||||
--ns1;
|
||||
}
|
||||
|
||||
while (ns2 < dns) {
|
||||
// ns_hist[++ns2] = 0;
|
||||
++ns2;
|
||||
}
|
||||
// ns_hist[(int) dns]++;
|
||||
|
||||
double dew = (int) (erot_i * di + erot_j * dj);
|
||||
while (ew1 > dew) {
|
||||
// ew_hist[--ew1] = 0;
|
||||
--ew1;
|
||||
}
|
||||
while (ew2 < dew) {
|
||||
// ew_hist[++ew2] = 0;
|
||||
++ew2;
|
||||
}
|
||||
// ew_hist[(int) dew]++;
|
||||
|
||||
if (dew < 0) {
|
||||
np_w++;
|
||||
}
|
||||
if (dew > 0) {
|
||||
np_e++;
|
||||
}
|
||||
if (dns < 0) {
|
||||
np_s++;
|
||||
}
|
||||
if (dns > 0) {
|
||||
np_n++;
|
||||
}
|
||||
}/* end for */
|
||||
}/* end for */
|
||||
|
||||
/*
|
||||
* Transform n-s & e-w offsets into normalized distances north and
|
||||
* south. This is done based on a preferred fraction of each area that
|
||||
* is "extreme".
|
||||
*/
|
||||
|
||||
// a lot of assumptions were made here. therefore, not everything in
|
||||
// this part was fully ported.
|
||||
double target = np_w * EXTREME_FRAC;
|
||||
// for (ii = 0, k = ew1; k < -1 && ii < target; k++) {
|
||||
// ii += ew_hist[k];
|
||||
// }
|
||||
// if (ii / target > 1.5) {
|
||||
// k--;
|
||||
// }
|
||||
// if (k < ew1) {
|
||||
// k = ew1;
|
||||
// }
|
||||
|
||||
k = ew1;
|
||||
double mu_w = (MIN_EXTREME - 127) / (k + 0.5);
|
||||
|
||||
target = np_e * EXTREME_FRAC;
|
||||
// for (ii = 0, k = ew2; k > 1 && ii < target; k--) {
|
||||
// ii += ew_hist[k];
|
||||
// }
|
||||
// if (ii / target > 1.5) {
|
||||
// k++;
|
||||
// }
|
||||
// if (k > ew2) {
|
||||
// k = ew2;
|
||||
// }
|
||||
|
||||
k = ew2;
|
||||
double mu_e = (MAX_EXTREME - 127) / (k - 0.5);
|
||||
|
||||
target = np_s * EXTREME_FRAC;
|
||||
// for (ii = 0, k = ns1; k < -1 && ii < target; k++) {
|
||||
// ii += ns_hist[k];
|
||||
// }
|
||||
// if (ii / target > 1.5) {
|
||||
// k--;
|
||||
// }
|
||||
// if (k < ns1) {
|
||||
// k = ns1;
|
||||
// }
|
||||
|
||||
k = ns1;// TODO - REPLACE WITH ABOVE
|
||||
double mu_s = (MIN_EXTREME - 127) / (k + 0.5);
|
||||
|
||||
target = np_n * EXTREME_FRAC;
|
||||
// for (ii = 0, k = ns2; k > 1 && ii < target; k--) {
|
||||
// ii += ns_hist[k];
|
||||
// }
|
||||
// if (ii / target > 1.5) {
|
||||
// k++;
|
||||
// }
|
||||
// if (k > ns2) {
|
||||
// k = ns2;
|
||||
// }
|
||||
|
||||
k = ns2;
|
||||
double mu_n = (MAX_EXTREME - 127) / (k - 0.5);
|
||||
|
||||
for (jj = min_j; jj < max_j; jj++) {
|
||||
k = nx * jj + min_i;
|
||||
for (ii = min_i; ii < max_i; ii++, k++) {
|
||||
// If the entity is not 1 then it's not part of the county or
|
||||
// zone area.
|
||||
if (countyOrZoneGrid[k] != 1) {
|
||||
ewGrid[k] = 0;
|
||||
nsGrid[k] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
double di = ii - i_base;
|
||||
double dj = jj - j_base;
|
||||
double dns = (int) (nrot_i * di + nrot_j * dj);
|
||||
double dew = (int) (erot_i * di + erot_j * dj);
|
||||
int c_ns2 = (int) (dns);
|
||||
int c_ew2 = (int) (dew);
|
||||
|
||||
if (c_ew2 < 0) {
|
||||
dx = c_ew2 * mu_w;
|
||||
} else {
|
||||
dx = c_ew2 * mu_e;
|
||||
}
|
||||
|
||||
if (dx > 127) {
|
||||
dx = 127;
|
||||
}
|
||||
|
||||
if (dx < -127) {
|
||||
dx = -127;
|
||||
}
|
||||
|
||||
ewGrid[k] = (int) (127 + (int) (dx));
|
||||
|
||||
if (c_ns2 < 0) {
|
||||
dy = c_ns2 * mu_s;
|
||||
} else {
|
||||
dy = c_ns2 * mu_n;
|
||||
}
|
||||
|
||||
if (dy > 127) {
|
||||
dy = 127;
|
||||
}
|
||||
|
||||
if (dy < -127) {
|
||||
dy = -127;
|
||||
}
|
||||
|
||||
nsGrid[k] = (int) (127 + (int) (dy));
|
||||
}
|
||||
}
|
||||
// System.out.println("-----------------------------------");
|
||||
// printGrids(countyOrZoneGrid, min_i, max_i, min_j, max_j);
|
||||
// System.out.println("-----------------------------------");
|
||||
// printGrids(_currentArea, min_i, max_i, min_j, max_j);
|
||||
// System.out.println("-------------- EAST WEST ---------------------");
|
||||
// printGrids(ewGrid, min_i, max_i, min_j, max_j);
|
||||
// System.out.println("-------------- NORTH SOUTH ---------------------");
|
||||
// printGrids(nsGrid, min_i, max_i, min_j, max_j);
|
||||
// System.out.println("north/south - east/west done");
|
||||
return new int[] { min_i, max_i, min_j, max_j };
|
||||
|
||||
}
|
||||
|
||||
// For debugging and view the grid in ascii format.
|
||||
private void printGrids(int[] grid, int min_i, int max_i, int min_j,
|
||||
int max_j) {
|
||||
int k = 0;
|
||||
for (int jj = min_j; jj < max_j; jj++) {
|
||||
k = nx * jj + min_i;
|
||||
for (int ii = min_i; ii < max_i; ii++) {
|
||||
System.out.print((int) grid[k]);
|
||||
k++;
|
||||
}
|
||||
System.out.println("-");
|
||||
}
|
||||
}
|
||||
|
||||
// For debugging and view the grid in ascii format.
|
||||
private void printGrids(byte[] grid, int min_i, int max_i, int min_j,
|
||||
int max_j) {
|
||||
int k = 0;
|
||||
for (int jj = min_j; jj < max_j; jj++) {
|
||||
k = nx * jj + min_i;
|
||||
for (int ii = min_i; ii < max_i; ii++) {
|
||||
System.out.print((int) grid[k]);
|
||||
k++;
|
||||
}
|
||||
System.out.println("-");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,471 @@
|
|||
/**
|
||||
* 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.warngen.gis;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.raytheon.viz.warngen.gis.GisUtil.Direction;
|
||||
import com.raytheon.viz.warngen.gui.WarngenLayer;
|
||||
import com.vividsolutions.jts.geom.Geometry;
|
||||
|
||||
/**
|
||||
* Port of A1 code that determines the portions of the county or zone
|
||||
* descriptions, such as NORTHWEST.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Aug 5, 2013 2177 jsanchez Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author jsanchez
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class PortionsUtil {
|
||||
|
||||
private GridUtil gridUtil;
|
||||
|
||||
public PortionsUtil(WarngenLayer layer) throws Exception {
|
||||
gridUtil = new GridUtil(layer, layer.getLocalGridGeometry(),
|
||||
layer.getlocalToLatLon());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the the appropriate portion description for the warnedArea
|
||||
* intersecting the countyOrZone.
|
||||
*
|
||||
* @param entityID
|
||||
* @param countyOrZone
|
||||
* @param warnedArea
|
||||
* @param useExtreme
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public EnumSet<Direction> getPortions(String entityID,
|
||||
Geometry countyOrZone, Geometry warnedArea, boolean useExtreme)
|
||||
throws Exception {
|
||||
countyOrZone.getUserData();
|
||||
EntityData entityData = gridUtil.calculateGrids(countyOrZone,
|
||||
warnedArea);
|
||||
EnumSet<Direction> portions = getAreaDesc(entityData.getMeanMask(),
|
||||
entityData.getCoverageMask(), entityData.getOctants(),
|
||||
useExtreme);
|
||||
return suppressPortions(entityID, portions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up if the designated entity ID has an suppressed directions. For
|
||||
* example, a county or zone may not need to include the north and sound
|
||||
* direction description if it was included in the area.suppress file.
|
||||
*
|
||||
* @param entityID
|
||||
* @param portions
|
||||
* @return
|
||||
*/
|
||||
private EnumSet<Direction> suppressPortions(String entityID,
|
||||
EnumSet<Direction> portions) {
|
||||
Map<String, List<Direction>> suppressedCounties = SuppressMap
|
||||
.getInstance().getAreas();
|
||||
if (entityID != null && suppressedCounties != null
|
||||
&& !suppressedCounties.isEmpty()) {
|
||||
List<Direction> suppressedDirections = suppressedCounties
|
||||
.get(entityID.toUpperCase());
|
||||
if (suppressedDirections != null && !suppressedDirections.isEmpty()) {
|
||||
portions.removeAll(suppressedDirections);
|
||||
}
|
||||
}
|
||||
|
||||
return portions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Port from A1 code of GeoEntityLookupTable::getAreaDesc.
|
||||
*
|
||||
* @param meanMask
|
||||
* @param areaMask
|
||||
* @param octants
|
||||
* @param exYes
|
||||
*/
|
||||
private static EnumSet<Direction> getAreaDesc(int meanMask, int areaMask,
|
||||
int octants, boolean exYes) {
|
||||
EnumSet<Direction> portions = EnumSet.noneOf(Direction.class);
|
||||
|
||||
// Test for case where we cannot do portions
|
||||
if (meanMask == 0 || areaMask == 0) {
|
||||
return portions;
|
||||
}
|
||||
|
||||
// The next block of code is the original port of A1 code but prevented
|
||||
// producing the correct result:
|
||||
// Test for case where area is completely within one subsection.
|
||||
// if (meanMask == areaMask) {
|
||||
// return getPointDesc(meanMask, exYes);
|
||||
// }
|
||||
|
||||
// Test for central by not being near adjacent borders.
|
||||
if (octants == 0
|
||||
|| ((octants & CoverageConstants.EXTREME_YES) == 0)
|
||||
&& (meanMask & CoverageConstants.CENTER) == CoverageConstants.CENTER) {
|
||||
portions.add(Direction.CENTRAL);
|
||||
return portions;
|
||||
}
|
||||
|
||||
if ((octants & 0xFFFF) == 0xFFFF) {
|
||||
return portions;
|
||||
}
|
||||
|
||||
// Identify quadrants in use, q is typical, qq is diagonal.
|
||||
int xoctant = octants >> 8;
|
||||
int xxoctant = octants >> 16;
|
||||
int nn, ss, ee, ww, ne, nw, se, sw;
|
||||
nn = ss = ee = ww = ne = nw = se = sw = 0;
|
||||
int omerge = xxoctant | xoctant | octants;
|
||||
if ((omerge & (CoverageConstants.NNE | CoverageConstants.ENE)) > 0) {
|
||||
ne = 1;
|
||||
}
|
||||
if ((omerge & (CoverageConstants.SSE | CoverageConstants.ESE)) > 0) {
|
||||
se = 1;
|
||||
}
|
||||
if ((omerge & (CoverageConstants.NNW | CoverageConstants.WNW)) > 0) {
|
||||
nw = 1;
|
||||
}
|
||||
if ((omerge & (CoverageConstants.SSW | CoverageConstants.WSW)) > 0) {
|
||||
sw = 1;
|
||||
}
|
||||
if ((omerge & (CoverageConstants.NNE | CoverageConstants.NNW)) > 0) {
|
||||
nn = 1;
|
||||
}
|
||||
if ((omerge & (CoverageConstants.SSE | CoverageConstants.SSW)) > 0) {
|
||||
ss = 1;
|
||||
}
|
||||
if ((omerge & (CoverageConstants.WNW | CoverageConstants.WSW)) > 0) {
|
||||
ww = 1;
|
||||
}
|
||||
if ((omerge & (CoverageConstants.ENE | CoverageConstants.ESE)) > 0) {
|
||||
ee = 1;
|
||||
}
|
||||
if ((areaMask & CoverageConstants.NORTH_SOUTH) == 0) {
|
||||
nn = ss = ne = nw = se = sw = 0;
|
||||
}
|
||||
if ((areaMask & CoverageConstants.EAST_WEST) == 0) {
|
||||
ee = ww = ne = nw = se = sw = 0;
|
||||
}
|
||||
int q = ne + nw + se + sw;
|
||||
int qq = nn + ss + ee + ww;
|
||||
|
||||
// Identify extremes in use.
|
||||
int nnx, ssx, eex, wwx;
|
||||
nnx = ssx = eex = wwx = 0;
|
||||
if ((areaMask & CoverageConstants.XNORTH) > 0) {
|
||||
nnx = 1;
|
||||
}
|
||||
if ((areaMask & CoverageConstants.XSOUTH) > 0) {
|
||||
ssx = 1;
|
||||
}
|
||||
if ((areaMask & CoverageConstants.XWEST) > 0) {
|
||||
wwx = 1;
|
||||
}
|
||||
if ((areaMask & CoverageConstants.XEAST) > 0) {
|
||||
eex = 1;
|
||||
}
|
||||
int xxx = nnx + ssx + eex + wwx;
|
||||
|
||||
// Modify masks based on whether we can use extreme.
|
||||
if ((octants & CoverageConstants.EXTREME_NO) > 0
|
||||
&& (areaMask & CoverageConstants.EXTREME) > 0) {
|
||||
areaMask &= CoverageConstants.NOT_EXTREME;
|
||||
meanMask &= CoverageConstants.NOT_EXTREME;
|
||||
}
|
||||
|
||||
// Possible case of a stripe across the middle
|
||||
if (q == 0) {
|
||||
;// Only one direction encoded
|
||||
} else if (q == 2 && nw == se || q == 2 && ne == sw || qq == 2
|
||||
&& nn == ss || qq == 2 && ee == ww) {
|
||||
if ((meanMask & CoverageConstants.CENTRAL) == CoverageConstants.CENTRAL
|
||||
|| nnx == ssx && wwx == eex) {
|
||||
portions.add(Direction.CENTRAL);
|
||||
return portions;
|
||||
}
|
||||
return getPointDesc2(meanMask, exYes, nn, ss, ee, ww);
|
||||
}
|
||||
|
||||
// Modify masks based on whether we can use central.
|
||||
if (xxx > 2 || nnx != ssx && wwx != eex) {
|
||||
areaMask &= CoverageConstants.NOT_CENTRAL;
|
||||
meanMask &= CoverageConstants.NOT_CENTRAL;
|
||||
}
|
||||
|
||||
// Another possible case of a stripe across the middle.
|
||||
if (q == 4 && (meanMask & CoverageConstants.CENTER) > 0) {
|
||||
portions.add(Direction.CENTRAL);
|
||||
return portions;
|
||||
}
|
||||
|
||||
// All quadrants in use.
|
||||
if (q == 4 && qq == 4) {
|
||||
return EnumSet.noneOf(Direction.class);
|
||||
}
|
||||
|
||||
// Only one typical quadrant in use.
|
||||
if (q == 1) {
|
||||
// if (ne == 1) {
|
||||
// portions.add(Direction.NORTH);
|
||||
// portions.add(Direction.EAST);
|
||||
// } else if (nw == 1) {
|
||||
// portions.add(Direction.NORTH);
|
||||
// portions.add(Direction.WEST);
|
||||
// } else if (se == 1) {
|
||||
// portions.add(Direction.SOUTH);
|
||||
// portions.add(Direction.EAST);
|
||||
// } else if (sw == 1) {
|
||||
// portions.add(Direction.SOUTH);
|
||||
// portions.add(Direction.WEST);
|
||||
// }
|
||||
// return portions;
|
||||
return getPointDesc2(meanMask, exYes, nn, ss, ee, ww);
|
||||
}
|
||||
|
||||
// Further modify masks based on whether we can use central.
|
||||
if (xxx >= 2) {
|
||||
areaMask &= CoverageConstants.NOT_CENTRAL;
|
||||
meanMask &= CoverageConstants.NOT_CENTRAL;
|
||||
}
|
||||
|
||||
// No more than two quadrants of any kind in use, or all quadrants.
|
||||
if (q < 3 && qq < 3) {
|
||||
if (nnx != ssx && wwx != eex
|
||||
|| (meanMask & CoverageConstants.CENTRAL) > 0) {
|
||||
return getPointDesc2(meanMask, exYes, nn, ss, ee, ww);
|
||||
|
||||
} else {
|
||||
return getPointDesc2(areaMask, exYes, nn, ss, ee, ww);
|
||||
}
|
||||
}
|
||||
|
||||
// Three typical quadrants in use.
|
||||
if (q == 3 && qq != 3) {
|
||||
|
||||
if (ne == 0) {
|
||||
// The next line is the original port of A1 code but prevented
|
||||
// producing the correct result:
|
||||
// if (ne == 0 && (xxoctant & (SSW | WSW)) > 0) {
|
||||
portions.add(Direction.SOUTH);
|
||||
portions.add(Direction.WEST);
|
||||
|
||||
} else if (se == 0) {
|
||||
// The next line is the original port of A1 code but prevented
|
||||
// producing the correct result:
|
||||
// } else if (se == 0 && (xxoctant & (NNW | WNW)) > 0) {
|
||||
portions.add(Direction.NORTH);
|
||||
portions.add(Direction.WEST);
|
||||
|
||||
} else if (nw == 0) {
|
||||
// The next line is the original port of A1 code but prevented
|
||||
// producing the correct result:
|
||||
// } else if (nw == 0 && (xxoctant & (SSE | ESE)) > 0) {
|
||||
portions.add(Direction.SOUTH);
|
||||
portions.add(Direction.EAST);
|
||||
|
||||
} else if (sw == 0) {
|
||||
// The next line is the original port of A1 code but prevented
|
||||
// producing the correct result:
|
||||
// } else if (sw == 0 && (xxoctant & (NNE | ENE)) > 0) {
|
||||
portions.add(Direction.NORTH);
|
||||
portions.add(Direction.EAST);
|
||||
}
|
||||
// The next line is the original port of A1 code but prevented
|
||||
// producing the correct result:
|
||||
// return getPointDesc(meanMask, exYes);
|
||||
}
|
||||
|
||||
// Three diagonal quadrants in use.
|
||||
if (qq == 3 && portions.isEmpty()) {
|
||||
if (nn == 0) {
|
||||
portions.add(Direction.SOUTH);
|
||||
} else if (ss == 0) {
|
||||
portions.add(Direction.NORTH);
|
||||
} else if (ww == 0) {
|
||||
portions.add(Direction.EAST);
|
||||
} else if (ee == 0) {
|
||||
portions.add(Direction.WEST);
|
||||
}
|
||||
}
|
||||
|
||||
// add extreme for three quadrant case.
|
||||
if (!portions.isEmpty()) {
|
||||
if (exYes && ((areaMask & CoverageConstants.EXTREME)) > 0) {
|
||||
portions.add(Direction.EXTREME);
|
||||
}
|
||||
return portions;
|
||||
}
|
||||
|
||||
// All of either type of quadrant in use.
|
||||
if (q == 4 || qq == 4) {
|
||||
return EnumSet.noneOf(Direction.class);
|
||||
}
|
||||
|
||||
// Case of a pure simple direction.
|
||||
nn = areaMask & CoverageConstants.NORTHERN;
|
||||
ss = areaMask & CoverageConstants.SOUTHERN;
|
||||
ee = areaMask & CoverageConstants.EASTERN;
|
||||
ww = areaMask & CoverageConstants.WESTERN;
|
||||
if (ss > 0 && nn > 0 || q == 0) {
|
||||
if (ee == 0 && ww > 0) {
|
||||
portions.add(Direction.WEST);
|
||||
}
|
||||
if (ww == 0 && ee > 0) {
|
||||
portions.add(Direction.EAST);
|
||||
}
|
||||
} else if (ee > 0 && ww > 0 || q == 0) {
|
||||
if (nn == 0 && ss > 0) {
|
||||
portions.add(Direction.SOUTH);
|
||||
}
|
||||
if (ss == 0 && nn > 0) {
|
||||
portions.add(Direction.NORTH);
|
||||
}
|
||||
}
|
||||
|
||||
// add extreme for simple direction case.
|
||||
if (!portions.isEmpty()) {
|
||||
if (exYes && ((areaMask & CoverageConstants.EXTREME)) > 0) {
|
||||
portions.add(Direction.EXTREME);
|
||||
}
|
||||
return portions;
|
||||
}
|
||||
|
||||
// Catch with the point descriptor one last time
|
||||
return getPointDesc2(meanMask, exYes, nn, ss, ee, ww);
|
||||
}
|
||||
|
||||
/**
|
||||
* Port from A1 code of GeoEntityLookupTable::getPointDesc.
|
||||
*
|
||||
* @param mask
|
||||
* @param exYes
|
||||
* @return
|
||||
*/
|
||||
private static EnumSet<Direction> getPointDesc(int mask, boolean exYes) {
|
||||
EnumSet<Direction> portions = EnumSet.noneOf(Direction.class);
|
||||
|
||||
if (mask == 0) {
|
||||
return portions;
|
||||
}
|
||||
|
||||
int cc = mask & CoverageConstants.CENTRAL;
|
||||
if (cc == CoverageConstants.CENTRAL) {
|
||||
portions.add(Direction.CENTRAL);
|
||||
return portions;
|
||||
}
|
||||
|
||||
if ((mask & CoverageConstants.NORTH_SOUTH) == 0) {
|
||||
;
|
||||
} else if ((mask & CoverageConstants.SOUTHERN) == (mask & CoverageConstants.NORTH_SOUTH)) {
|
||||
portions.add(Direction.SOUTH);
|
||||
} else if ((mask & CoverageConstants.NORTHERN) == (mask & CoverageConstants.NORTH_SOUTH)) {
|
||||
portions.add(Direction.NORTH);
|
||||
}
|
||||
|
||||
if ((mask & CoverageConstants.EAST_WEST) == 0) {
|
||||
;
|
||||
} else if ((mask & CoverageConstants.WESTERN) == (mask & CoverageConstants.EAST_WEST)) {
|
||||
portions.add(Direction.WEST);
|
||||
} else if ((mask & CoverageConstants.EASTERN) == (mask & CoverageConstants.EAST_WEST)) {
|
||||
portions.add(Direction.EAST);
|
||||
}
|
||||
|
||||
if (portions.isEmpty()) {
|
||||
return portions;
|
||||
}
|
||||
|
||||
if (cc != 0) {
|
||||
portions.add(Direction.CENTRAL);
|
||||
}
|
||||
|
||||
if (exYes && ((int) (mask & CoverageConstants.EXTREME) > 0)) {
|
||||
portions.add(Direction.EXTREME);
|
||||
}
|
||||
|
||||
return portions;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is not a direct port from A1. The original getPointDesc did
|
||||
* not produce the expected results. This method is a modified version of
|
||||
* getPointDesct that uses the calculated qq values instead of just the
|
||||
* meanMask.
|
||||
*
|
||||
* @param mask
|
||||
* @param exYes
|
||||
* @return
|
||||
*/
|
||||
private static EnumSet<Direction> getPointDesc2(int mask, boolean exYes,
|
||||
int nn, int ss, int ee, int ww) {
|
||||
EnumSet<Direction> portions = EnumSet.noneOf(Direction.class);
|
||||
|
||||
if (mask == 0) {
|
||||
return portions;
|
||||
}
|
||||
|
||||
int counter = 0;
|
||||
if (nn > 0 && ss > 0) {
|
||||
;
|
||||
} else if (ss > 0) {
|
||||
portions.add(Direction.SOUTH);
|
||||
counter++;
|
||||
} else if (nn > 0) {
|
||||
portions.add(Direction.NORTH);
|
||||
counter++;
|
||||
}
|
||||
|
||||
if (ee > 0 && ww > 0) {
|
||||
;
|
||||
} else if (ww > 0) {
|
||||
portions.add(Direction.WEST);
|
||||
counter++;
|
||||
} else if (ee > 0) {
|
||||
portions.add(Direction.EAST);
|
||||
counter++;
|
||||
}
|
||||
|
||||
if (portions.isEmpty()) {
|
||||
return portions;
|
||||
}
|
||||
|
||||
int cc = mask & CoverageConstants.CENTRAL;
|
||||
boolean useCentral = counter < 2;
|
||||
if (useCentral && cc != 0) {
|
||||
portions.add(Direction.CENTRAL);
|
||||
}
|
||||
|
||||
if (exYes && ((int) (mask & CoverageConstants.EXTREME) > 0)) {
|
||||
portions.add(Direction.EXTREME);
|
||||
}
|
||||
|
||||
return portions;
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@
|
|||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.viz.warngen.suppress;
|
||||
package com.raytheon.viz.warngen.gis;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
|
@ -25,7 +25,10 @@ import java.io.FileInputStream;
|
|||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
@ -38,9 +41,11 @@ import com.raytheon.uf.common.localization.PathManagerFactory;
|
|||
import com.raytheon.uf.common.status.IUFStatusHandler;
|
||||
import com.raytheon.uf.common.status.UFStatus;
|
||||
import com.raytheon.uf.common.status.UFStatus.Priority;
|
||||
import com.raytheon.uf.viz.core.localization.LocalizationManager;
|
||||
import com.raytheon.viz.warngen.gis.GisUtil.Direction;
|
||||
|
||||
/**
|
||||
* TODO Add Description
|
||||
* Creates a map of all the site's area suppress files.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
|
@ -48,6 +53,7 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
|
|||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Aug 2, 2010 jsanchez Initial creation
|
||||
* Aug 15,2013 2177 jsanchez Refactored.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -66,16 +72,26 @@ public class SuppressMap {
|
|||
private static final Pattern ugcPattern = Pattern
|
||||
.compile("[A-Z]{2}[CZ][0-9]{3}");
|
||||
|
||||
public static final String NORTH_SOUTH = "NS";
|
||||
private static final List<Direction> NORTH_SOUTH = Arrays.asList(
|
||||
Direction.NORTH, Direction.SOUTH);
|
||||
|
||||
public static final String EAST_WEST = "EW";
|
||||
private static final List<Direction> EAST_WEST = Arrays.asList(
|
||||
Direction.EAST, Direction.WEST);
|
||||
|
||||
public static final String NONE = "NONE";
|
||||
private static final List<Direction> ALL = Arrays.asList(Direction.NORTH,
|
||||
Direction.SOUTH, Direction.EAST, Direction.WEST, Direction.CENTRAL,
|
||||
Direction.EXTREME);
|
||||
|
||||
public static final String ALL = "ALL";
|
||||
private static Map<String, Map<String, List<Direction>>> suppressMap = new HashMap<String, Map<String, List<Direction>>>();
|
||||
|
||||
private Map<String, String> suppressMap = new HashMap<String, String>();
|
||||
private SuppressMap() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return an instance of the SuppressMap object.
|
||||
*/
|
||||
public static SuppressMap getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new SuppressMap();
|
||||
|
@ -83,64 +99,82 @@ public class SuppressMap {
|
|||
return instance;
|
||||
}
|
||||
|
||||
private SuppressMap() {
|
||||
readFile();
|
||||
/**
|
||||
* Returns the suppressed area map for the current localized site.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Map<String, List<Direction>> getAreas() {
|
||||
String threeLetterSiteID = LocalizationManager.getInstance()
|
||||
.getCurrentSite();
|
||||
Map<String, List<Direction>> areas = suppressMap.get(threeLetterSiteID);
|
||||
|
||||
if (areas == null) {
|
||||
areas = new HashMap<String, List<Direction>>();
|
||||
IPathManager pm = PathManagerFactory.getPathManager();
|
||||
LocalizationContext lc = pm.getContext(
|
||||
LocalizationType.COMMON_STATIC, LocalizationLevel.SITE);
|
||||
File file = pm.getFile(lc, AREA_SUPPRESS_FILENAME);
|
||||
loadFile(file, areas);
|
||||
}
|
||||
|
||||
return areas;
|
||||
}
|
||||
|
||||
private void readFile() {
|
||||
// load site
|
||||
IPathManager pathMgr = PathManagerFactory.getPathManager();
|
||||
LocalizationContext lc = pathMgr.getContext(
|
||||
LocalizationType.COMMON_STATIC, LocalizationLevel.SITE);
|
||||
File file = pathMgr.getFile(lc, AREA_SUPPRESS_FILENAME);
|
||||
loadFile(file, suppressMap);
|
||||
}
|
||||
|
||||
private void loadFile(File file, Map<String, String> aliasMap) {
|
||||
/**
|
||||
* Loads the areas map with the suppress information in the file
|
||||
*
|
||||
* @param file
|
||||
* @param areas
|
||||
*/
|
||||
private void loadFile(File file, Map<String, List<Direction>> areas) {
|
||||
if ((file != null) && file.exists()) {
|
||||
Matcher m = null;
|
||||
BufferedReader fis = null;
|
||||
try {
|
||||
BufferedReader fis = new BufferedReader(new InputStreamReader(
|
||||
fis = new BufferedReader(new InputStreamReader(
|
||||
new FileInputStream(file)));
|
||||
|
||||
String line = null;
|
||||
try {
|
||||
while ((line = fis.readLine()) != null) {
|
||||
m = ugcPattern.matcher(line);
|
||||
if (m.find()) {
|
||||
String dataKey = m.group();
|
||||
String data = ALL;
|
||||
List<Direction> suppressedDirections = new ArrayList<Direction>();
|
||||
String ugc = m.group();
|
||||
if (line.indexOf("ns") > 5) {
|
||||
data = NORTH_SOUTH;
|
||||
suppressedDirections = NORTH_SOUTH;
|
||||
} else if (line.indexOf("ew") > 5) {
|
||||
data = EAST_WEST;
|
||||
suppressedDirections = EAST_WEST;
|
||||
} else {
|
||||
suppressedDirections = ALL;
|
||||
}
|
||||
aliasMap.put(dataKey, data);
|
||||
areas.put(ugc, suppressedDirections);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block. Please revise as
|
||||
// appropriate.
|
||||
statusHandler.handle(Priority.PROBLEM,
|
||||
"Could not read counties file: "
|
||||
+ AREA_SUPPRESS_FILENAME, e);
|
||||
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
// TODO Auto-generated catch block. Please revise as
|
||||
// appropriate.
|
||||
statusHandler.handle(Priority.PROBLEM,
|
||||
"Failed to find counties file: "
|
||||
+ AREA_SUPPRESS_FILENAME, e);
|
||||
|
||||
} finally {
|
||||
|
||||
if (fis != null) {
|
||||
try {
|
||||
fis.close();
|
||||
} catch (IOException e) {
|
||||
statusHandler.handle(Priority.PROBLEM,
|
||||
"Error trying to close buffered reader ", e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getType(String key) {
|
||||
if (suppressMap.containsKey(key)) {
|
||||
return suppressMap.get(key);
|
||||
} else {
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -49,6 +49,9 @@ import org.eclipse.swt.graphics.RGB;
|
|||
import org.eclipse.swt.widgets.Event;
|
||||
import org.eclipse.swt.widgets.Listener;
|
||||
import org.eclipse.ui.PlatformUI;
|
||||
import org.geotools.coverage.grid.GeneralGridEnvelope;
|
||||
import org.geotools.coverage.grid.GeneralGridGeometry;
|
||||
import org.geotools.geometry.GeneralEnvelope;
|
||||
import org.geotools.geometry.jts.JTS;
|
||||
import org.geotools.referencing.GeodeticCalculator;
|
||||
import org.opengis.referencing.crs.CoordinateReferenceSystem;
|
||||
|
@ -57,7 +60,6 @@ import org.opengis.referencing.operation.MathTransform;
|
|||
import com.raytheon.uf.common.dataplugin.warning.AbstractWarningRecord;
|
||||
import com.raytheon.uf.common.dataplugin.warning.WarningRecord.WarningAction;
|
||||
import com.raytheon.uf.common.dataplugin.warning.config.AreaSourceConfiguration;
|
||||
import com.raytheon.uf.common.dataplugin.warning.config.AreaSourceConfiguration.AreaType;
|
||||
import com.raytheon.uf.common.dataplugin.warning.config.BulletActionGroup;
|
||||
import com.raytheon.uf.common.dataplugin.warning.config.DialogConfiguration;
|
||||
import com.raytheon.uf.common.dataplugin.warning.config.GridSpacing;
|
||||
|
@ -185,6 +187,7 @@ import com.vividsolutions.jts.io.WKTReader;
|
|||
* 07/26/2013 DR 16376 Qinglu Lin Moved adjustVertex() and computeSlope() to PolygonUtil; removed calculateDistance();
|
||||
* updated AreaHatcher's run().
|
||||
* 07/26/2013 DR 16450 D. Friedman Fix logic errors when frame count is one.
|
||||
* 08/19/2013 2177 jsanchez Set a GeneralGridGeometry object in the GeospatialDataList.
|
||||
* </pre>
|
||||
*
|
||||
* @author mschenke
|
||||
|
@ -212,24 +215,28 @@ public class WarngenLayer extends AbstractStormTrackResource {
|
|||
IExtent localExtent;
|
||||
|
||||
int nx, ny;
|
||||
|
||||
GeneralGridGeometry localGridGeometry;
|
||||
}
|
||||
|
||||
private static class GeospatialDataAccessor {
|
||||
GeospatialDataList geoData;
|
||||
|
||||
AreaSourceConfiguration areaConfig;
|
||||
|
||||
public GeospatialDataAccessor(GeospatialDataList geoData,
|
||||
AreaSourceConfiguration areaConfig) {
|
||||
if (geoData == null || areaConfig == null) {
|
||||
throw new IllegalArgumentException("GeospatialDataAccessor must not be null");
|
||||
throw new IllegalArgumentException(
|
||||
"GeospatialDataAccessor must not be null");
|
||||
}
|
||||
this.geoData = geoData;
|
||||
this.areaConfig = areaConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the geometry area that intersects the cwa filter for the polygon in
|
||||
* local projection space
|
||||
* Build the geometry area that intersects the cwa filter for the
|
||||
* polygon in local projection space
|
||||
*
|
||||
* @param polygon
|
||||
* polygon to intersect with in lat/lon space
|
||||
|
@ -243,8 +250,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
|
|||
PreparedGeometry prepGeom = (PreparedGeometry) r.attributes
|
||||
.get(GeospatialDataList.LOCAL_PREP_GEOM);
|
||||
try {
|
||||
Geometry intersection = GeometryUtil.intersection(polygon,
|
||||
prepGeom);
|
||||
Geometry intersection = GeometryUtil.intersection(
|
||||
polygon, prepGeom);
|
||||
if (intersection.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -407,7 +414,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
|
|||
}
|
||||
|
||||
try {
|
||||
warningPolygon = PolygonUtil.removeDuplicateCoordinate(warningPolygon);
|
||||
warningPolygon = PolygonUtil
|
||||
.removeDuplicateCoordinate(warningPolygon);
|
||||
Polygon hatched = polygonUtil.hatchWarningArea(
|
||||
warningPolygon,
|
||||
removeCounties(warningArea,
|
||||
|
@ -425,27 +433,37 @@ public class WarngenLayer extends AbstractStormTrackResource {
|
|||
LinearRing lr = gf.createLinearRing(coords);
|
||||
hatchedArea = gf.createPolygon(lr, null);
|
||||
int adjustPolygon_counter = 0;
|
||||
while (!hatchedArea.isValid() && adjustPolygon_counter < 1) {
|
||||
System.out.println("Calling adjustPolygon #" + adjustPolygon_counter);
|
||||
while (!hatchedArea.isValid()
|
||||
&& adjustPolygon_counter < 1) {
|
||||
System.out.println("Calling adjustPolygon #"
|
||||
+ adjustPolygon_counter);
|
||||
PolygonUtil.adjustPolygon(coords);
|
||||
PolygonUtil.round(coords, 2);
|
||||
coords = PolygonUtil.removeDuplicateCoordinate(coords);
|
||||
coords = PolygonUtil.removeOverlaidLinesegments(coords);
|
||||
coords = PolygonUtil
|
||||
.removeDuplicateCoordinate(coords);
|
||||
coords = PolygonUtil
|
||||
.removeOverlaidLinesegments(coords);
|
||||
lr = gf.createLinearRing(coords);
|
||||
hatchedArea = gf.createPolygon(lr, null);
|
||||
adjustPolygon_counter += 1;
|
||||
}
|
||||
int counter = 0;
|
||||
if (!hatchedArea.isValid() && counter < 2) {
|
||||
System.out.println("calling adjustVertex & alterVertexes: loop #" + counter);
|
||||
System.out
|
||||
.println("calling adjustVertex & alterVertexes: loop #"
|
||||
+ counter);
|
||||
int adjustVertex_counter = 0;
|
||||
lr = gf.createLinearRing(coords);
|
||||
hatchedArea = gf.createPolygon(lr, null);
|
||||
while (!hatchedArea.isValid() && adjustVertex_counter < 5) {
|
||||
System.out.println(" Calling adjustVertex #" + adjustVertex_counter);
|
||||
while (!hatchedArea.isValid()
|
||||
&& adjustVertex_counter < 5) {
|
||||
System.out.println(" Calling adjustVertex #"
|
||||
+ adjustVertex_counter);
|
||||
coords = PolygonUtil.adjustVertex(coords);
|
||||
coords = PolygonUtil.removeDuplicateCoordinate(coords);
|
||||
coords = PolygonUtil.removeOverlaidLinesegments(coords);
|
||||
coords = PolygonUtil
|
||||
.removeDuplicateCoordinate(coords);
|
||||
coords = PolygonUtil
|
||||
.removeOverlaidLinesegments(coords);
|
||||
lr = gf.createLinearRing(coords);
|
||||
hatchedArea = gf.createPolygon(lr, null);
|
||||
adjustVertex_counter += 1;
|
||||
|
@ -453,10 +471,14 @@ public class WarngenLayer extends AbstractStormTrackResource {
|
|||
int inner_counter = 0;
|
||||
System.out.println("");
|
||||
while (!hatchedArea.isValid() && inner_counter < 5) {
|
||||
System.out.println(" Calling alterVertexes #" + inner_counter);
|
||||
System.out
|
||||
.println(" Calling alterVertexes #"
|
||||
+ inner_counter);
|
||||
coords = PolygonUtil.alterVertexes(coords);
|
||||
coords = PolygonUtil.removeDuplicateCoordinate(coords);
|
||||
coords = PolygonUtil.removeOverlaidLinesegments(coords);
|
||||
coords = PolygonUtil
|
||||
.removeDuplicateCoordinate(coords);
|
||||
coords = PolygonUtil
|
||||
.removeOverlaidLinesegments(coords);
|
||||
lr = gf.createLinearRing(coords);
|
||||
hatchedArea = gf.createPolygon(lr, null);
|
||||
inner_counter += 1;
|
||||
|
@ -674,8 +696,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
|
|||
displayState.angle = 0;
|
||||
displayState.speed = 0;
|
||||
} else if (checkStormTrackData(data = ToolsDataManager
|
||||
.getInstance()
|
||||
.getStormTrackData())) {
|
||||
.getInstance().getStormTrackData())) {
|
||||
displayState.angle = adjustAngle(data.getMotionDirection());
|
||||
displayState.speed = knotToMeterPerSec.convert(data
|
||||
.getMotionSpeed());
|
||||
|
@ -995,8 +1016,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
|
|||
}
|
||||
if (config != null) {
|
||||
init(config);
|
||||
displayState.setInitiallyMotionless(
|
||||
this.configuration.isTrackEnabled() == false
|
||||
displayState.setInitiallyMotionless(this.configuration
|
||||
.isTrackEnabled() == false
|
||||
|| this.configuration.getPathcastConfig() == null);
|
||||
}
|
||||
}
|
||||
|
@ -1044,9 +1065,11 @@ public class WarngenLayer extends AbstractStormTrackResource {
|
|||
+ (System.currentTimeMillis() - t0) + "ms");
|
||||
}
|
||||
|
||||
/** Adds geospatial data to siteMap and timezoneMap for the given
|
||||
* template configuration. This must not have any site effects on the
|
||||
* currently loaded template or the current product being edited.
|
||||
/**
|
||||
* Adds geospatial data to siteMap and timezoneMap for the given template
|
||||
* configuration. This must not have any site effects on the currently
|
||||
* loaded template or the current product being edited.
|
||||
*
|
||||
* @param config
|
||||
*/
|
||||
private void loadGeodataForConfiguration(WarngenConfiguration config) {
|
||||
|
@ -1083,7 +1106,6 @@ public class WarngenLayer extends AbstractStormTrackResource {
|
|||
Coordinate c = new GeometryFactory()
|
||||
.buildGeometry(geoms).getCentroid()
|
||||
.getCoordinate();
|
||||
|
||||
gData.latLonToLocal = MapUtil
|
||||
.getTransformFromLatLon(MapUtil
|
||||
.constructStereographic(
|
||||
|
@ -1146,6 +1168,18 @@ public class WarngenLayer extends AbstractStormTrackResource {
|
|||
gData.nx = nx;
|
||||
gData.ny = ny;
|
||||
|
||||
GeneralGridEnvelope range = new GeneralGridEnvelope(
|
||||
new int[] { 0, 0 }, new int[] { gData.nx,
|
||||
gData.ny }, false);
|
||||
GeneralEnvelope ge = new GeneralEnvelope(new double[] {
|
||||
gData.localExtent.getMinX(),
|
||||
gData.localExtent.getMaxY() }, new double[] {
|
||||
gData.localExtent.getMaxX(),
|
||||
gData.localExtent.getMinY() });
|
||||
|
||||
gData.localGridGeometry = new GeneralGridGeometry(
|
||||
range, ge);
|
||||
|
||||
System.out.println("Time to lookup geospatial data "
|
||||
+ (System.currentTimeMillis() - tq0));
|
||||
siteMap.put(currKey, gData);
|
||||
|
@ -1188,6 +1222,14 @@ public class WarngenLayer extends AbstractStormTrackResource {
|
|||
return new GeospatialData[0];
|
||||
}
|
||||
|
||||
public GeneralGridGeometry getLocalGridGeometry() {
|
||||
return geoData.localGridGeometry;
|
||||
}
|
||||
|
||||
public MathTransform getlocalToLatLon() {
|
||||
return geoData.localToLatLon;
|
||||
}
|
||||
|
||||
private GeospatialDataList getGeodataList(String areaSource,
|
||||
String localizedSite) {
|
||||
String key = areaSource + "." + localizedSite;
|
||||
|
@ -1303,7 +1345,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
|
|||
* Returns a set of UGCs for each area in the CWA that intersects the given
|
||||
* polygon.
|
||||
*/
|
||||
public Set<String> getUgcsForCountyWatches(Polygon polygon) throws Exception {
|
||||
public Set<String> getUgcsForCountyWatches(Polygon polygon)
|
||||
throws Exception {
|
||||
GeospatialDataAccessor gda = getCountyGeospatialDataAcessor();
|
||||
Set<String> ugcs = new HashSet<String>();
|
||||
for (String fips : gda.getAllFipsInArea(gda.buildArea(polygon))) {
|
||||
|
@ -1321,17 +1364,20 @@ public class WarngenLayer extends AbstractStormTrackResource {
|
|||
return ugcs;
|
||||
}
|
||||
|
||||
private GeospatialDataAccessor getCountyGeospatialDataAcessor() throws Exception {
|
||||
private GeospatialDataAccessor getCountyGeospatialDataAcessor()
|
||||
throws Exception {
|
||||
GeospatialDataList gdl = searchCountyGeospatialDataAccessor();
|
||||
if (gdl == null) {
|
||||
// Cause county geospatial data to be loaded
|
||||
// TODO: Should not be referencing tornadoWarning.
|
||||
WarngenConfiguration torConfig = WarngenConfiguration.loadConfig("tornadoWarning", getLocalizedSite());
|
||||
WarngenConfiguration torConfig = WarngenConfiguration.loadConfig(
|
||||
"tornadoWarning", getLocalizedSite());
|
||||
loadGeodataForConfiguration(torConfig);
|
||||
gdl = searchCountyGeospatialDataAccessor();
|
||||
}
|
||||
|
||||
// TODO: There should be some way to get the "county" configuration by name
|
||||
// TODO: There should be some way to get the "county" configuration by
|
||||
// name
|
||||
// independent of a template
|
||||
AreaSourceConfiguration areaConfig = new AreaSourceConfiguration();
|
||||
areaConfig.setFipsField("FIPS");
|
||||
|
@ -1341,7 +1387,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
|
|||
|
||||
private GeospatialDataList searchCountyGeospatialDataAccessor() {
|
||||
synchronized (siteMap) {
|
||||
for (Map.Entry<String, GeospatialDataList> entry : siteMap.entrySet()) {
|
||||
for (Map.Entry<String, GeospatialDataList> entry : siteMap
|
||||
.entrySet()) {
|
||||
String[] keyParts = entry.getKey().split("\\.");
|
||||
if (keyParts.length == 2
|
||||
&& "county".equalsIgnoreCase(keyParts[0])
|
||||
|
@ -1938,8 +1985,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
|
|||
return;
|
||||
}
|
||||
if (warningAction == null || warningAction == WarningAction.NEW) {
|
||||
if ((configuration.isTrackEnabled() == false ||
|
||||
configuration.getPathcastConfig() == null)
|
||||
if ((configuration.isTrackEnabled() == false || configuration
|
||||
.getPathcastConfig() == null)
|
||||
&& !this.displayState.isNonstationary()
|
||||
&& this.displayState.displayType != DisplayType.POLY) {
|
||||
createSquare();
|
||||
|
@ -2271,8 +2318,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
|
|||
}
|
||||
|
||||
Point point = displayState.dragMePoint;
|
||||
if (motdir != null && motspd != null &&
|
||||
(motspd != 0 || configuration.isTrackEnabled())) {
|
||||
if (motdir != null && motspd != null
|
||||
&& (motspd != 0 || configuration.isTrackEnabled())) {
|
||||
displayState.setInitiallyMotionless(false);
|
||||
displayState.angle = adjustAngle(motdir);
|
||||
displayState.speed = knotToMeterPerSec.convert(motspd);
|
||||
|
@ -2325,10 +2372,9 @@ public class WarngenLayer extends AbstractStormTrackResource {
|
|||
if (m.find()) {
|
||||
int hour = Integer.parseInt(m.group(1));
|
||||
int minute = Integer.parseInt(m.group(2));
|
||||
frameTime = TimeUtil.timeOfDayToAbsoluteTime(
|
||||
hour * TimeUtil.SECONDS_PER_HOUR +
|
||||
minute * TimeUtil.SECONDS_PER_MINUTE,
|
||||
warnRecord.getIssueTime());
|
||||
frameTime = TimeUtil.timeOfDayToAbsoluteTime(hour
|
||||
* TimeUtil.SECONDS_PER_HOUR + minute
|
||||
* TimeUtil.SECONDS_PER_MINUTE, warnRecord.getIssueTime());
|
||||
} else {
|
||||
frameTime = warnRecord.getIssueTime();
|
||||
}
|
||||
|
@ -2376,8 +2422,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
|
|||
FramesInfo info = descriptor.getFramesInfo();
|
||||
int currentFrame = trackUtil.getCurrentFrame(info);
|
||||
int frameCount = trackUtil.getFrameCount(info);
|
||||
if (currentFrame == frameCount - 1
|
||||
|| ! displayState.isNonstationary()) {
|
||||
if (currentFrame == frameCount - 1 || !displayState.isNonstationary()) {
|
||||
return coordinate;
|
||||
}
|
||||
DataTime[] datatimes = trackUtil.getDataTimes(info);
|
||||
|
@ -2686,7 +2731,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
|
|||
getFips(f));
|
||||
if (tmp.isEmpty()) {
|
||||
String fip = getFips(f);
|
||||
if (fip != null && uniqueFip != null && fip.equals(uniqueFip)) {
|
||||
if (fip != null && uniqueFip != null
|
||||
&& fip.equals(uniqueFip)) {
|
||||
updateWarnedAreas(true);
|
||||
}
|
||||
break;
|
||||
|
@ -2769,8 +2815,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
|
|||
if (areaHatcher != null) {
|
||||
Polygon polygon = state.getWarningPolygon();
|
||||
polygon = tryToIntersectWithOriginalPolygon(polygon);
|
||||
areaHatcher.hatchArea(polygon,
|
||||
state.getWarningArea(),
|
||||
areaHatcher.hatchArea(polygon, state.getWarningArea(),
|
||||
state.getOldWarningPolygon());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,6 +98,7 @@ import com.raytheon.viz.warngen.gis.Area;
|
|||
import com.raytheon.viz.warngen.gis.ClosestPointComparator;
|
||||
import com.raytheon.viz.warngen.gis.GisUtil;
|
||||
import com.raytheon.viz.warngen.gis.PathCast;
|
||||
import com.raytheon.viz.warngen.gis.PortionsUtil;
|
||||
import com.raytheon.viz.warngen.gis.Wx;
|
||||
import com.raytheon.viz.warngen.gui.BackupData;
|
||||
import com.raytheon.viz.warngen.gui.FollowupData;
|
||||
|
@ -154,6 +155,7 @@ import com.vividsolutions.jts.io.WKTReader;
|
|||
* May 10, 2013 1951 rjpeter Updated ugcZones references
|
||||
* May 30, 2013 DR 16237 D. Friedman Fix watch query.
|
||||
* Jun 18, 2013 2118 njensen Only calculate pathcast if it's actually used
|
||||
* Aug 19, 2013 2177 jsanchez Passed PortionsUtil to Area class.
|
||||
* </pre>
|
||||
*
|
||||
* @author njensen
|
||||
|
@ -301,17 +303,18 @@ public class TemplateRunner {
|
|||
AffectedAreas[] cancelareas = null;
|
||||
Map<String, Object> intersectAreas = null;
|
||||
Wx wx = null;
|
||||
Area area = new Area(new PortionsUtil(warngenLayer));
|
||||
long wwaMNDTime = 0l;
|
||||
try {
|
||||
t0 = System.currentTimeMillis();
|
||||
areas = Area.findAffectedAreas(config, warnPolygon, warningArea,
|
||||
areas = area.findAffectedAreas(config, warnPolygon, warningArea,
|
||||
threeLetterSiteId);
|
||||
System.out.println("Time to get areas = "
|
||||
+ (System.currentTimeMillis() - t0));
|
||||
context.put(config.getHatchedAreaSource().getVariable(), areas);
|
||||
|
||||
t0 = System.currentTimeMillis();
|
||||
intersectAreas = Area.findInsectingAreas(config, warnPolygon,
|
||||
intersectAreas = area.findInsectingAreas(config, warnPolygon,
|
||||
warningArea, threeLetterSiteId, warngenLayer);
|
||||
System.out.println("Time to get intersecting areas = "
|
||||
+ (System.currentTimeMillis() - t0));
|
||||
|
@ -324,10 +327,11 @@ public class TemplateRunner {
|
|||
double minSize = 1.0E-3d;
|
||||
if ((areas != null) && (areas.length > 0)) {
|
||||
Set<String> timeZones = new HashSet<String>();
|
||||
for (AffectedAreas area : areas) {
|
||||
if (area.getTimezone() != null) {
|
||||
for (AffectedAreas affectedAreas : areas) {
|
||||
if (affectedAreas.getTimezone() != null) {
|
||||
// Handles counties that span two time zones
|
||||
String oneLetterTimeZones = area.getTimezone().trim();
|
||||
String oneLetterTimeZones = affectedAreas.getTimezone()
|
||||
.trim();
|
||||
oneLetterTZ = new String[oneLetterTimeZones.length()];
|
||||
if (oneLetterTimeZones.length() == 1) {
|
||||
timeZones.add(String.valueOf(oneLetterTimeZones
|
||||
|
@ -799,14 +803,14 @@ public class TemplateRunner {
|
|||
Geometry removedAreas = warngenLayer.getWarningAreaForGids(
|
||||
oldGids, oldWarningArea);
|
||||
if (removedAreas.isEmpty() == false) {
|
||||
cancelareas = Area.findAffectedAreas(config,
|
||||
cancelareas = area.findAffectedAreas(config,
|
||||
oldWarn.getGeometry(), removedAreas,
|
||||
threeLetterSiteId);
|
||||
for (int i = 0; i < cancelareas.length; i++) {
|
||||
for (AffectedAreas area : areas) {
|
||||
for (AffectedAreas affectedAreas : areas) {
|
||||
if ((cancelareas[i] != null)
|
||||
&& cancelareas[i].getFips().equals(
|
||||
area.getFips())) {
|
||||
affectedAreas.getFips())) {
|
||||
cancelareas[i] = null;
|
||||
}
|
||||
}
|
||||
|
@ -824,7 +828,7 @@ public class TemplateRunner {
|
|||
// This may not be efficient enough. Is it possible that
|
||||
// a removed intersected county be in the affected
|
||||
// intersected county. Need an example to fully test.
|
||||
Map<String, Object> intersectRemovedAreas = Area
|
||||
Map<String, Object> intersectRemovedAreas = area
|
||||
.findInsectingAreas(config, warnPolygon,
|
||||
removedAreas, threeLetterSiteId,
|
||||
warngenLayer);
|
||||
|
|
Loading…
Add table
Reference in a new issue