Omaha #5150 Fix Polyline time of arrial.

Former-commit-id: c6ed62707eb88eae8d20da1c2c996e774f784d37
This commit is contained in:
Ben Steffensmeier 2015-12-02 17:27:20 -06:00
parent f595bb5b41
commit 77fa171cea
3 changed files with 354 additions and 185 deletions

View file

@ -71,53 +71,57 @@ import com.vividsolutions.jts.geom.LineString;
* <pre> * <pre>
* *
* SOFTWARE HISTORY * SOFTWARE HISTORY
* Date Ticket# Engineer Description *
* ------------ ---------- ----------- -------------------------- * Date Ticket# Engineer Description
* 05-28-2010 #6042 bkowal When an Impossible Track Exception * ------------- -------- ---------- -------------------------------------------
* Is Encountered, The Track Will Now * May 28, 2010 6042 bkowal When an Impossible Track Exception Is
* Be Reverted Back To Its Previous * Encountered, The Track Will Now Be Reverted
* State. Replaced Impossible Storm * Back To Its Previous State. Replaced
* Exception With Impossible Track * Impossible Storm Exception With Impossible
* Exception. * Track Exception.
* 06-23-2010 #6468 bkowal The Tool Will No Longer Generate * Jun 23, 2010 6468 bkowal The Tool Will No Longer Generate An
* An Exception When It Is Initially * Exception When It Is Initially Added To The
* Added To The Map While Looping * Map While Looping Is Running.
* Is Running. * Jun 23, 2010 5925 bkowal The Tool Will No Longer Generate An
* 06-23-2010 #5925 bkowal The Tool Will No Longer Generate An * Exception When The Polyline Mode Is Enabled
* Exception When The Polyline Mode * Even When A Track Has Not Been Generated.
* Is Enabled Even When A Track * Jul 14, 2010 6558 bkowal The tool will no longer generate an
* Has Not Been Generated. * exception when it is moved from a pane with
* 07-14-2010 #6558 bkowal The tool will no longer generate an * a larger frame count to a pane with a
* exception when it is moved from a * smaller frame count. The track will now
* pane with a larger frame count to a * always be centered around the initial
* pane with a smaller frame count. * location of the drag-me point when the
* The track will now always be centered around * track was created.
* the initial location of the drag-me point * Oct 27, 2010 6964 bkowal The LineStyle is now passed as a parameter
* when the track was created. * to the IGraphicsTarget drawWireframeShape
* 10-27-2010 #6964 bkowal The LineStyle is now passed as a parameter to * method.
* the IGraphicsTarget drawWireframeShape method. * Mar 15, 2013 15693 mgamazay Made sure that magnification capability
* 15Mar2013 15693 mgamazaychikov Made sure that magnification capability works. * works.
* 06-11-2013 DR 16234 D. Friedman Fix pivot index when frames count is reduced. * Jun 11, 2013 16234 dfriedman Fix pivot index when frames count is
* 06-24-2013 DR 16317 D. Friedman Handle "motionless" track. * reduced.
* 01-28-2014 DR16465 mgamazaychikov Fixed the problem with anchor point when frame * Jun 24, 2013 16317 dfriedman Handle "motionless" track.
* count changes; made line width configurable. * Jan 28, 2014 16465 mgamazay Fixed the problem with anchor point when
* 04-07-2014 DR 17232 D. Friedman Make sure pivot indexes are valid. * frame count changes; made line width
* 04-24-2014 DR 16356 Qinglu Lin Updated generateTrackInfo(), generateNewTrackInfo(), * configurable.
* and createTrack(). * Apr 07, 2014 17232 dfriedman Make sure pivot indexes are valid.
* 06-03-14 3191 njensen Fix postData to not retrieve * Apr 24, 2014 16356 qlin Updated generateTrackInfo(),
* 06-17-2014 DR17409 mgamazaychikov Fix futurePoints calculation in generateNewTrackInfo() * generateNewTrackInfo(), and createTrack().
* and generateExistingTrackInfo() * Jun 03, 2014 3191 njensen Fix postData to not retrieve
* 07-24-2014 3429 mapeters Updated deprecated drawLine() calls. * Jun 17, 2014 17409 mgamazay Fix futurePoints calculation in
* 08-21-2014 DR 15700 Qinglu Lin handle the situation where frameTime is null in paintTrack(). * generateNewTrackInfo() and
* 09-09-2014 RM #657 Qinglu Lin handle StormTrackState.trackType is null. * generateExistingTrackInfo()
* 09-25-2014 ASM #16773 D. Friedman Fix NPE. * Jul 24, 2014 3429 mapeters Updated deprecated drawLine() calls.
* 10-10-2014 ASM #16844 D. Friedman Prevent some errors when moving track. * Aug 21, 2014 15700 qlin handle the situation where frameTime is
* null in paintTrack().
* Sep 09, 2014 657 qlin handle StormTrackState.trackType is null.
* Sep 25, 2014 16773 dfriedman Fix NPE.
* Oct 10, 2014 16844 dfriedman Prevent some errors when moving track.
* Dec 02, 2015 5150 bsteffen Add option to use constant end time.
*
* </pre> * </pre>
* *
* @author mschenke * @author mschenke
* @version 1.0
*/ */
public class StormTrackDisplay implements IRenderable { public class StormTrackDisplay implements IRenderable {
private static final transient IUFStatusHandler statusHandler = UFStatus private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(StormTrackDisplay.class); .getHandler(StormTrackDisplay.class);
@ -408,7 +412,7 @@ public class StormTrackDisplay implements IRenderable {
coords = new Coordinate[] { c1, coords = new Coordinate[] { c1,
new Coordinate(worldPixel[0], worldPixel[1]), c3 }; new Coordinate(worldPixel[0], worldPixel[1]), c3 };
} }
line = new GeometryFactory().createLineString(coords); line = gf.createLineString(coords);
if (state.dragMePoint != null) { if (state.dragMePoint != null) {
state.dragMeLine = manager.figureLineFromPoint(line, state.dragMeLine = manager.figureLineFromPoint(line,
@ -518,7 +522,7 @@ public class StormTrackDisplay implements IRenderable {
double[] p = descriptor.pixelToWorld(paintProps.getView() double[] p = descriptor.pixelToWorld(paintProps.getView()
.getExtent().getCenter()); .getExtent().getCenter());
point = new Coordinate(p[0], p[1]); point = new Coordinate(p[0], p[1]);
state.dragMePoint = new GeometryFactory().createPoint(point); state.dragMePoint = gf.createPoint(point);
} }
} }
@ -777,7 +781,7 @@ public class StormTrackDisplay implements IRenderable {
if (currentState.dragMePoint == null) { if (currentState.dragMePoint == null) {
double[] p = descriptor.pixelToWorld(paintProps double[] p = descriptor.pixelToWorld(paintProps
.getView().getExtent().getCenter()); .getView().getExtent().getCenter());
currentState.dragMePoint = new GeometryFactory() currentState.dragMePoint = gf
.createPoint(new Coordinate(p[0], p[1])); .createPoint(new Coordinate(p[0], p[1]));
} }
theAnchorPoint = currentState.dragMePoint.getCoordinate(); theAnchorPoint = currentState.dragMePoint.getCoordinate();
@ -837,7 +841,7 @@ public class StormTrackDisplay implements IRenderable {
} }
private void generateExistingTrackInfo(StormTrackState state, private void generateExistingTrackInfo(StormTrackState state,
PaintProperties paintProps) throws ImpossibleTrackException { PaintProperties paintProps) {
int moveIndex = this.trackUtil.getCurrentFrame(paintProps int moveIndex = this.trackUtil.getCurrentFrame(paintProps
.getFramesInfo()); .getFramesInfo());
moveIndex = Math.min(moveIndex, state.timePoints.length - 1); moveIndex = Math.min(moveIndex, state.timePoints.length - 1);
@ -995,7 +999,7 @@ public class StormTrackDisplay implements IRenderable {
} }
private void generateNewTrackInfo(StormTrackState state, int anchorIndex, private void generateNewTrackInfo(StormTrackState state, int anchorIndex,
PaintProperties paintProps) throws ImpossibleTrackException { PaintProperties paintProps) {
double speed, angle, oppositeAngle; double speed, angle, oppositeAngle;
int frameCount = trackUtil.getFrameCount(paintProps.getFramesInfo()); int frameCount = trackUtil.getFrameCount(paintProps.getFramesInfo());
if (state.timePoints != null) { if (state.timePoints != null) {
@ -1194,7 +1198,7 @@ public class StormTrackDisplay implements IRenderable {
int shortestDistance = (int) Math.round(minIntervalInSeconds int shortestDistance = (int) Math.round(minIntervalInSeconds
* state.speed); * state.speed);
int tickLengthInMeters = (int) Math.round(shortestDistance) / 2; int tickLengthInMeters = Math.round(shortestDistance) / 2;
// Create track // Create track
Coordinate[] coords = new Coordinate[state.timePoints.length Coordinate[] coords = new Coordinate[state.timePoints.length
@ -1412,13 +1416,16 @@ public class StormTrackDisplay implements IRenderable {
state.color, radius, 180 + screenAngle, hMid, vMid, magnification); state.color, radius, 180 + screenAngle, hMid, vMid, magnification);
// End time: // End time:
Calendar currentTime = Calendar.getInstance(); long endTime = state.futurePoints[state.futurePoints.length - 1].time
currentTime.setTime(SimulatedTime.getSystemTime().getTime()); .getMatchValid();
long delta = state.futurePoints[state.futurePoints.length - 1].time if (state.liveOffsetEndTime) {
.getMatchValid() Calendar currentTime = Calendar.getInstance();
- state.futurePoints[0].time.getMatchValid(); currentTime.setTime(SimulatedTime.getSystemTime().getTime());
time = this.timeFormat.format(new Date(currentTime long delta = endTime
.getTimeInMillis() + delta)); - state.futurePoints[0].time.getMatchValid();
endTime = currentTime.getTimeInMillis() + delta;
}
time = this.timeFormat.format(new Date(endTime));
paintTextAtPoint(target, time, paintTextAtPoint(target, time,
state.futurePoints[state.futurePoints.length - 1].coord, state.futurePoints[state.futurePoints.length - 1].coord,
state.color, radius, -90 + screenAngle, hEnd, vEnd, magnification); state.color, radius, -90 + screenAngle, hEnd, vEnd, magnification);

View file

@ -31,37 +31,38 @@ import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.geom.Point;
/** /**
* TODO Add Description * All of the state information needed to display and manipulate a storm track.
* *
* <pre> * <pre>
* *
* SOFTWARE HISTORY * SOFTWARE HISTORY
* Date Ticket# Engineer Description *
* ------------ ---------- ----------- -------------------------- * Date Ticket# Engineer Description
* 07-14-2010 #6558 bkowal Added a variable that will be used * ------------- -------- ---------- -------------------------------------------
* to indicate when the user manually * Jul 14, 2010 6558 bkowal Added a variable that will be used to
* moves the drag-me point. A new method * indicate when the user manually moves the
* has been created to calculate the pivot * drag-me point. A new method has been
* indexes. * created to calculate the pivot indexes.
* 10-27-2010 #6964 bkowal Added a public class member for the LineStyle. * Oct 27, 2010 6964 bkowal Added a public class member for the
* 11/29/2012 15571 Qinglu Lin Added compuateCurrentStormCenter(); * LineStyle.
* 15Mar2013 15693 mgamazaychikov Added magnification. * Nov 29, 2012 15571 qlin Added compuateCurrentStormCenter();
* 06-24-2013 DR 16317 D. Friedman Handle "motionless" track. * Mar 15, 2013 15693 mgamazay Added magnification.
* 04-24-2014 DR 16356 Qinglu Lin Added newWarnGen, oneStormAngle, justSwitchedToLOS, * Jun 24, 2013 16317 dfriedman Handle "motionless" track.
* justSwitchedToOS, and trackType. * Apr 24, 2014 16356 qlin Added newWarnGen, oneStormAngle,
* 06-24-2014 DR 17436 Qinglu Lin Assigned "unknown" to trackType. * justSwitchedToLOS, justSwitchedToOS, and
* trackType.
* Jun 24, 2014 17436 qlin Assigned "unknown" to trackType.
* Dec 02, 2015 5150 bsteffen Add option to use constant end time.
* *
* </pre> * </pre>
* *
* @author mschenke * @author mschenke
* @version 1.0
*/ */
public class StormTrackState { public class StormTrackState {
public enum Mode { public enum Mode {
DRAG_ME, TRACK, NONE DRAG_ME, TRACK, NONE
}; }
public enum DisplayType { public enum DisplayType {
POINT("me"), POLY("line"), CIRCULAR("me"); POINT("me"), POLY("line"), CIRCULAR("me");
@ -209,6 +210,12 @@ public class StormTrackState {
public boolean justSwitchedToOS = false; public boolean justSwitchedToOS = false;
/*
* When true the end time will be adjusted on the display to be offset from
* the current time instead of the last frame.
*/
public boolean liveOffsetEndTime = true;
public static String trackType = "unknown"; public static String trackType = "unknown";
/** Compute the coordinate of the storm center at the time defined by dataTime via interpolation. */ /** Compute the coordinate of the storm center at the time defined by dataTime via interpolation. */

View file

@ -39,7 +39,6 @@ import org.opengis.coverage.grid.GridEnvelope;
import com.raytheon.uf.common.geospatial.LocalTimeZone; import com.raytheon.uf.common.geospatial.LocalTimeZone;
import com.raytheon.uf.common.geospatial.SpatialException; import com.raytheon.uf.common.geospatial.SpatialException;
import com.raytheon.uf.common.time.DataTime;
import com.raytheon.uf.viz.core.DrawableCircle; import com.raytheon.uf.viz.core.DrawableCircle;
import com.raytheon.uf.viz.core.DrawableString; import com.raytheon.uf.viz.core.DrawableString;
import com.raytheon.uf.viz.core.IDisplayPane; import com.raytheon.uf.viz.core.IDisplayPane;
@ -75,39 +74,45 @@ import com.raytheon.viz.ui.input.EditableManager;
import com.raytheon.viz.ui.input.InputAdapter; import com.raytheon.viz.ui.input.InputAdapter;
import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineSegment;
import com.vividsolutions.jts.geom.LineString;
/** /**
* TODO Add Description * Layer which contains a configurable storm track as well as a Time Of
* Arrival/Lead Time point. The primary purpose is to display the distance and
* time it would take to reach the lead point following the storm track.
* *
* <pre> * <pre>
* *
* SOFTWARE HISTORY * SOFTWARE HISTORY
* Date Ticket# Engineer Description *
* ------------ ---------- ----------- -------------------------- * Date Ticket# Engineer Description
* June 28 2010 #6513 bkowal Switching the mode of the Time of Arrival / * ------------- -------- ---------- -------------------------------------------
* Lead time tool to Polyline before creating a * Jun 28, 2010 6513 bkowal Switching the mode of the Time of Arrival /
* a track will no longer cause the tool to * Lead time tool to Polyline before creating
* crash. * a a track will no longer cause the tool to
* July 28 2010 #4518 bkowal CDT time will now be displayed in the Time of * crash.
* Arrival point label when the scale is * Jul 28, 2010 4518 bkowal CDT time will now be displayed in the Time
* WFO or State(s). * of Arrival point label when the scale is
* Aug 19 2010 #4518 bkowal Instead of CDT time, the users local time * WFO or State(s).
* will be displayed. Progressive Disclosure * Aug 19, 2010 4518 bkowal Instead of CDT time, the users local time
* Properties are now used to determine whether * will be displayed. Progressive Disclosure
* local time should be displayed or not. * Properties are now used to determine
* Oct 19 2010 #6753 bkowal Added logic to change the text alignment from * whether local time should be displayed or
* left-to-right if there is not enough room * not.
* for the text to the left of the point. * Oct 19, 2010 6753 bkowal Added logic to change the text alignment
* 15Mar2013 15693 mgamazaychikov Added magnification capability. * from left-to-right if there is not enough
* Apr 12 2013 DR 16032 D. Friedman Make it work in multiple panes. * room for the text to the left of the point.
* Aug 14 2014 3523 mapeters Updated deprecated {@link DrawableString#textStyle} * Mar 15, 2013 15693 mgamazay Added magnification capability.
* assignments. * Apr 12, 2013 16032 dfriedman Make it work in multiple panes.
* Aug 14, 2014 3523 mapeters Updated deprecated DrawableString.textStyle
* assignments.
* Dec 02, 2015 5150 bsteffen Calculate correct lead time for Polylines.
*
* </pre> * </pre>
* *
* @author mschenke * @author mschenke
* @version 1.0
*/ */
public class TimeOfArrivalLayer extends AbstractStormTrackResource { public class TimeOfArrivalLayer extends AbstractStormTrackResource {
public static class LeadTimeState { public static class LeadTimeState {
@ -122,9 +127,15 @@ public class TimeOfArrivalLayer extends AbstractStormTrackResource {
public boolean changed; public boolean changed;
} }
/* Thread Dangerous: Must only be used on the "paint" thread. */
private final DateFormat timeFormat = new SimpleDateFormat("HH:mm"); private final DateFormat timeFormat = new SimpleDateFormat("HH:mm");
// private DateFormat localTimeFormat = new SimpleDateFormat("HH:mmz"); /*
* Thread Dangerous: Must only be used on the "paint" thread.
*
* The time zone should be set based off the end time before each use.
*/
private final DateFormat localTimeFormat = new SimpleDateFormat("HH:mmz");
private static final String formatString = "%sZ (%s) %s miles"; private static final String formatString = "%sZ (%s) %s miles";
@ -306,6 +317,8 @@ public class TimeOfArrivalLayer extends AbstractStormTrackResource {
if (displayState.mode == Mode.TRACK) { if (displayState.mode == Mode.TRACK) {
if (displayState.displayType == DisplayType.CIRCULAR) { if (displayState.displayType == DisplayType.CIRCULAR) {
constructCircularStuff(target); constructCircularStuff(target);
} else if (displayState.displayType == DisplayType.POLY) {
constructPolyStuff(target);
} }
} }
} }
@ -451,6 +464,44 @@ public class TimeOfArrivalLayer extends AbstractStormTrackResource {
} }
} }
/**
* Create lines in jazzyExtras that mirror the dragMeLine projected out to
* intersect the lead point. Should only be used when the display type is
* {@link DisplayType#POLY}.
*/
private void constructPolyStuff(IGraphicsTarget target) {
if (jazzyExtras != null) {
jazzyExtras.dispose();
}
jazzyExtras = target.createWireframeShape(false, descriptor);
Coordinate startLonLat = getLeadDragMePoint();
if(startLonLat == null){
return;
}
Coordinate endLonLat = leadState.loc;
double[] startPixel = descriptor.worldToPixel(new double[] {
startLonLat.x, startLonLat.y });
double[] endPixel = descriptor.worldToPixel(new double[] {
endLonLat.x, endLonLat.y });
double dx = endPixel[0] - startPixel[0];
double dy = endPixel[1] - startPixel[1];
LineString fullLine = displayState.dragMeLine;
double[][] pixels = new double[fullLine.getNumPoints()][];
for (int i = 0; i < fullLine.getNumPoints(); i += 1) {
Coordinate c = fullLine.getCoordinateN(i);
pixels[i] = descriptor.worldToPixel(new double[] {
c.x, c.y });
pixels[i][0] += dx;
pixels[i][1] += dy;
}
jazzyExtras.addLineSegment(pixels);
}
private void constructCircularStuff(IGraphicsTarget target) private void constructCircularStuff(IGraphicsTarget target)
throws VizException { throws VizException {
@ -550,6 +601,7 @@ public class TimeOfArrivalLayer extends AbstractStormTrackResource {
// Default angle for POINT // Default angle for POINT
displayState.displayType = StormTrackState.DisplayType.POINT; displayState.displayType = StormTrackState.DisplayType.POINT;
displayState.labelMode = LabelMode.TIME; displayState.labelMode = LabelMode.TIME;
displayState.liveOffsetEndTime = false;
state.angle = 48; state.angle = 48;
state.dragMePoint = null; state.dragMePoint = null;
state.dragMeLine = null; state.dragMeLine = null;
@ -584,7 +636,135 @@ public class TimeOfArrivalLayer extends AbstractStormTrackResource {
}); });
} }
/**
* Determine a point along the dragMeLine that can be combined with the lead
* point to create a line that is perpendicular to the storm track. This is
* the point that is used when determining the distance of the lead point.
* This method will return null if the lead point is too far from the storm
* track so no point exists. Should only be used when the display type is
* {@link DisplayType#POLY}.
*/
private Coordinate getLeadDragMePoint() {
/*
* The input and output points are all in Lon/Lat but all math is
* performed in the descriptor pixel space to minimize the potential for
* projection related problems.
*/
Coordinate startLonLat = displayState.timePoints[0].coord;
Coordinate endLonLat = displayState.timePoints[displayState.timePoints.length - 1].coord;
double[] startPixel = descriptor.worldToPixel(new double[] {
startLonLat.x, startLonLat.y });
double[] endPixel = descriptor.worldToPixel(new double[] { endLonLat.x,
endLonLat.y });
double[] leadPixel = descriptor.worldToPixel(new double[] {
leadState.loc.x, leadState.loc.y });
double dx = leadPixel[0] - endPixel[0];
double dy = leadPixel[1] - endPixel[1];
double[] leadStartPixel = { startPixel[0] + dx, startPixel[1] + dy };
/*
* This is a line that is parallel to the storm track and the same
* distance as the timePoints in the storm track.
*/
LineSegment leadLine = new LineSegment(leadStartPixel[0],
leadStartPixel[1], leadPixel[0], leadPixel[1]);
LineString fullLine = displayState.dragMeLine;
Coordinate c = fullLine.getCoordinateN(0);
double[] prevPixel = descriptor.worldToPixel(new double[] { c.x, c.y });
Coordinate bestIntersection = null;
for (int i = 1; i < fullLine.getNumPoints(); i += 1) {
c = fullLine.getCoordinateN(i);
double[] currPixel = descriptor.worldToPixel(new double[] { c.x,
c.y });
LineSegment segment = new LineSegment(prevPixel[0], prevPixel[1],
currPixel[0], currPixel[1]);
/*
* The leadLine may not be long enough to reach from the lead point
* to the dragMeLine so must use lineIntersection to extend both
* segments infinitely
*/
Coordinate intersection = segment.lineIntersection(leadLine);
/*
* lineIntersection may extends both lines but only an intersection
* that is actually on the segment is valid so ensure that the
* intersection point is reasonably close to the segment.
*/
if (segment.distance(intersection) < 0.0000001) {
/*
* If the dragMeLine is complex thre can be multiple
* intersections, only keep the closest one.
*/
if (bestIntersection == null) {
bestIntersection = intersection;
} else if (bestIntersection.distance(new Coordinate(
leadPixel[0], leadPixel[1])) > intersection
.distance(new Coordinate(leadPixel[0], leadPixel[1]))) {
bestIntersection = intersection;
}
}
prevPixel = currPixel;
}
if (bestIntersection != null) {
double[] intersectionLonLat = descriptor.pixelToWorld(new double[] {
bestIntersection.x, bestIntersection.y });
return new Coordinate(intersectionLonLat[0], intersectionLonLat[1]);
}
return bestIntersection;
}
/**
* Determine the distance(in meters) from the lead point to the current
* point, line, or front. This is the distance displayed in the lead time
* text. This method will return Double.NaN if the lead point is
* unrealistic.
*/
private double getLeadDistance() {
GeodeticCalculator gc = new GeodeticCalculator();
if (displayState.displayType == DisplayType.POLY) {
Coordinate dragMe = getLeadDragMePoint();
if (dragMe == null) {
return Double.NaN;
}
gc.setStartingGeographicPoint(dragMe.x, dragMe.y);
gc.setDestinationGeographicPoint(leadState.loc.x, leadState.loc.y);
double distance = gc.getOrthodromicDistance();
double angle = unadjustAngle(gc.getAzimuth());
double stateAngle = unadjustAngle(displayState.angle);
if(Math.abs(angle - stateAngle) > 180){
distance = -1*distance;
}
return distance;
}else{
StormCoord start = displayState.timePoints[0];
Coordinate end = displayState.timePoints[displayState.timePoints.length - 1].coord;
gc.setStartingGeographicPoint(start.coord.x, start.coord.y);
gc.setDestinationGeographicPoint(end.x, end.y);
double distFromStartEnd = gc.getOrthodromicDistance();
end = leadState.loc;
gc.setDestinationGeographicPoint(end.x, end.y);
double angle = unadjustAngle(gc.getAzimuth());
double stateAngle = unadjustAngle(displayState.angle);
double distance = gc.getOrthodromicDistance();
if (Math.abs(angle - stateAngle) >= 22.5) {
return Double.NaN;
}else{
return distance
- distFromStartEnd;
}
}
}
private void updateLeadTimeState() { private void updateLeadTimeState() {
leadState.changed = false;
// based on display state and lead time location, figure out distance, // based on display state and lead time location, figure out distance,
// duration, and time // duration, and time
@ -592,94 +772,69 @@ public class TimeOfArrivalLayer extends AbstractStormTrackResource {
return; return;
} }
// First get Time from start point double distance = getLeadDistance();
StormCoord start = displayState.timePoints[0]; if (Double.isNaN(distance)) {
Coordinate end = displayState.timePoints[displayState.timePoints.length - 1].coord;
GeodeticCalculator gc = new GeodeticCalculator();
gc.setStartingGeographicPoint(start.coord.x, start.coord.y);
gc.setDestinationGeographicPoint(end.x, end.y);
double distFromStartEnd = gc.getOrthodromicDistance();
end = leadState.loc;
gc.setDestinationGeographicPoint(end.x, end.y);
double angle = unadjustAngle(gc.getAzimuth());
double stateAngle = unadjustAngle(displayState.angle);
double distance = gc.getOrthodromicDistance();
leadState.distance = distance;
// TODO: Figure out point on line and distance to line if in POLY mode
// and set distance accordingly, then uncomment TODO in constructLines
if (Math.abs(angle - stateAngle) >= 22.5) {
leadState.text = "Unrealistic Point of Arrival"; leadState.text = "Unrealistic Point of Arrival";
} else { return;
}
long timeInSec = (long) (distance / displayState.speed); StormCoord endStormCoord = displayState.timePoints[displayState.timePoints.length - 1];
DataTime toa = new DataTime(new Date(start.time.getMatchValid()
+ (timeInSec * 1000))); Date refDate = endStormCoord.time.getValidTimeAsDate();
long timeInSec = (long) (distance / displayState.speed);
Date date = new Date(toa.getMatchValid());
Date refDate = new Date( Date date = new Date(refDate.getTime() + (timeInSec * 1000));
displayState.timePoints[displayState.timePoints.length - 1].time
.getMatchValid()); boolean negative = date.getTime() < refDate.getTime();
boolean negative = date.getTime() < refDate.getTime(); String miles = "";
String hoursMinutesFormat = "";
String miles = ""; if (negative) {
String hoursMinutesFormat = ""; hoursMinutesFormat += "-";
if (negative) { miles += "-";
hoursMinutesFormat += "-"; }
miles += "-";
} long timeDiffInMinutes = Math.abs(date.getTime() - refDate.getTime())
/ (60 * 1000);
long timeDiffInMinutes = Math.abs(date.getTime()
- refDate.getTime()) long hours = timeDiffInMinutes / 60;
/ (60 * 1000); long minutes = timeDiffInMinutes % 60;
Object[] args = new Object[2];
long hours = timeDiffInMinutes / 60; if (hours > 0) {
long minutes = timeDiffInMinutes % 60; hoursMinutesFormat += "%02d hours ";
Object[] args = new Object[2]; args[0] = hours;
if (hours > 0) { args[1] = minutes;
hoursMinutesFormat += "%02d hours "; } else {
args[0] = hours; args[0] = minutes;
args[1] = minutes; }
} else {
args[0] = minutes; hoursMinutesFormat += "%02d minutes";
}
miles += (int) metersToMiles.convert(Math.abs(distance));
hoursMinutesFormat += "%02d minutes";
String time = this.timeFormat.format(date);
miles += (int) metersToMiles.convert(Math.abs(distance int currentDisplayWidth = ((IMapDescriptor) this.descriptor)
- distFromStartEnd)); .getMapWidth();
String time = this.timeFormat.format(date); if (!this.pdProps.isDisclosed(currentDisplayWidth)) {
int currentDisplayWidth = ((IMapDescriptor) this.descriptor) // Do not include Local time
.getMapWidth(); leadState.text = String.format(formatString, time,
String.format(hoursMinutesFormat, args), miles);
if (!this.pdProps.isDisclosed(currentDisplayWidth)) { } else {
// Do not include Local time // Include Local time
leadState.text = String.format(formatString, time, String localTime = "";
String.format(hoursMinutesFormat, args), miles); try {
} else { Coordinate end = endStormCoord.coord;
// Include Local time localTimeFormat
String localTime = ""; // this.localTimeFormat.format(date); .setTimeZone(LocalTimeZone.getLocalTimeZone(end));
try { localTime = localTimeFormat.format(date);
DateFormat df = new SimpleDateFormat("HH:mmz"); } catch (SpatialException e) {
// System.err.println(end.x + " " + end.y); e.printStackTrace();
df.setTimeZone(LocalTimeZone.getLocalTimeZone(end)); }
localTime = df.format(date);
} catch (SpatialException e) { leadState.text = String.format(
e.printStackTrace(); TimeOfArrivalLayer.formatStringIncludeLocal, time,
} localTime, String.format(hoursMinutesFormat, args), miles);
leadState.text = String.format(
TimeOfArrivalLayer.formatStringIncludeLocal, time,
localTime, String.format(hoursMinutesFormat, args),
miles);
}
} }
leadState.changed = false;
} }
public void makeEditableAndReopenDialog() { public void makeEditableAndReopenDialog() {