Omaha #5150 Fix Polyline time of arrial.
Former-commit-id: c6ed62707eb88eae8d20da1c2c996e774f784d37
This commit is contained in:
parent
f595bb5b41
commit
77fa171cea
3 changed files with 354 additions and 185 deletions
|
@ -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);
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
Loading…
Add table
Reference in a new issue