mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-02 10:23:51 +00:00
Fixed bugs, added comments, refactored the code where needed.
This commit is contained in:
1 parent
1af3c9a83e
commit
f8b9da4197
4 files changed
+716
-316
No files matched your search
+63
-78
@@ -1,5 +1,11 @@
|
||||
package com.sap.sailing.gwt.ui.shared.racemap;
|
||||
|
||||
/**
|
||||
* Represents a point in the bidimensional space
|
||||
*
|
||||
* @author I077899 Bogdan Mihai
|
||||
*
|
||||
*/
|
||||
public class TwoDPoint {
|
||||
private double x;
|
||||
private double y;
|
||||
@@ -17,11 +23,11 @@ public class TwoDPoint {
|
||||
return this.y;
|
||||
}
|
||||
|
||||
public double distanceBetween(TwoDPoint point) {
|
||||
public double getDistanceTo(TwoDPoint point) {
|
||||
return distanceBetween(this.x, this.y, point.getX(), point.getY());
|
||||
}
|
||||
|
||||
public double distanceBetween(double x, double y) {
|
||||
public double getDistanceTo(double x, double y) {
|
||||
return distanceBetween(this.x, this.y, x, y);
|
||||
}
|
||||
|
||||
@@ -33,9 +39,10 @@ public class TwoDPoint {
|
||||
return distanceBetween(point1.getX(), point1.getY(), point2.getX(), point2.getY());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Point @(" + this.x + "," + this.y + ")";
|
||||
public double getDistanceTo(TwoDSegment line) {
|
||||
|
||||
return this.getDistanceTo(this.getProjection(line));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -59,98 +66,76 @@ public class TwoDPoint {
|
||||
return 31 * (new Double(this.x).hashCode()) * (new Double(this.y).hashCode());
|
||||
}
|
||||
|
||||
public TwoDPoint getDistancedPoint(double length, TwoDPoint startPoint) {
|
||||
TwoDVector vector = new TwoDVector(startPoint, this).normalize().multiplyScalar(length);
|
||||
public TwoDPoint getProjection(TwoDSegment line) {
|
||||
|
||||
double x = this.getX() + vector.getRe();
|
||||
double y = this.getY() + vector.getIm();
|
||||
double slope = line.getLineSlope();
|
||||
double intercept = line.getLineIntercept();
|
||||
|
||||
double x = (slope * this.getY() + this.getX() - slope * intercept) / (slope * slope + 1);
|
||||
double y = slope * x + intercept;
|
||||
|
||||
return new TwoDPoint(x, y);
|
||||
}
|
||||
|
||||
public static TwoDPoint getBisectingPoint(TwoDPoint origin, TwoDPoint head1, TwoDPoint head2, double scale) {
|
||||
TwoDVector v1 = new TwoDVector(origin, head1);
|
||||
TwoDVector v2 = new TwoDVector(origin, head2);
|
||||
|
||||
TwoDVector sum = (v1.normalize()).add(v2.normalize()).normalize().multiplyScalar(scale);
|
||||
|
||||
return new TwoDPoint(sum.getRe() + origin.getX(), sum.getIm() + origin.getY());
|
||||
}
|
||||
|
||||
public static TwoDPoint get90RotatedPoint(TwoDPoint origin, TwoDPoint head) {
|
||||
return getRotatedPoint(origin, head, 90);
|
||||
}
|
||||
|
||||
public static TwoDPoint get270RotatedPoint(TwoDPoint origin, TwoDPoint head) {
|
||||
return getRotatedPoint(origin, head, 270);
|
||||
}
|
||||
|
||||
public static TwoDPoint getRotatedPoint(TwoDPoint origin, TwoDPoint head, double degrees) {
|
||||
TwoDVector v = new TwoDVector(origin, head);
|
||||
v = v.rotate(degrees);
|
||||
|
||||
return new TwoDPoint(v.getRe() + origin.getX(), v.getIm() + origin.getY());
|
||||
}
|
||||
|
||||
public static TwoDPoint projectToLineByVector(TwoDPoint newOrigin, TwoDSegment line, TwoDVector vector) {
|
||||
public TwoDPoint getProjectionByVector(TwoDSegment line, TwoDVector vector) {
|
||||
|
||||
double a = vector.getRe();
|
||||
double b = vector.getIm();
|
||||
double p = line.getLineSlope();
|
||||
double q = line.getLineIntercept();
|
||||
double x0 = newOrigin.getX();
|
||||
double y0 = newOrigin.getY();
|
||||
|
||||
double x = ((q - y0) / b + x0 / a) / (1 / a - p / b);
|
||||
double x = ((q - this.y) / b + this.x / a) / (1 / a - p / b);
|
||||
double y = p * x + q;
|
||||
|
||||
return new TwoDPoint(x, y);
|
||||
}
|
||||
|
||||
public static boolean isOnTheInside(TwoDPoint beforeOriginPoint, TwoDPoint originPoint, TwoDPoint afterOriginPoint, TwoDPoint newOriginPoint) {
|
||||
|
||||
double xA = beforeOriginPoint.getX();
|
||||
double yA = beforeOriginPoint.getY();
|
||||
double xB = originPoint.getX();
|
||||
double yB = originPoint.getY();
|
||||
double xC = afterOriginPoint.getX();
|
||||
double yC = afterOriginPoint.getY();
|
||||
double xD = newOriginPoint.getX();
|
||||
double yD = newOriginPoint.getY();
|
||||
|
||||
boolean firstCondition = (yD - yA) >= ((yB - yA) * (xD - xA) / (xB - xA));
|
||||
boolean secondCondition = (yD - yB) <= ((yC - yB) * (xD - xB) / (xC - xB));
|
||||
|
||||
return firstCondition && secondCondition;
|
||||
|
||||
}
|
||||
// private static boolean isOnTheInside(TwoDPoint beforeOriginPoint, TwoDPoint originPoint, TwoDPoint
|
||||
// afterOriginPoint, TwoDPoint newOriginPoint) {
|
||||
//
|
||||
// double xA = beforeOriginPoint.getX();
|
||||
// double yA = beforeOriginPoint.getY();
|
||||
// double xB = originPoint.getX();
|
||||
// double yB = originPoint.getY();
|
||||
// double xC = afterOriginPoint.getX();
|
||||
// double yC = afterOriginPoint.getY();
|
||||
// double xD = newOriginPoint.getX();
|
||||
// double yD = newOriginPoint.getY();
|
||||
//
|
||||
// boolean firstCondition = (yD - yA) >= ((yB - yA) * (xD - xA) / (xB - xA));
|
||||
// boolean secondCondition = (yD - yB) <= ((yC - yB) * (xD - xB) / (xC - xB));
|
||||
//
|
||||
// return firstCondition && secondCondition;
|
||||
//
|
||||
// }
|
||||
|
||||
// A //B //C //Bfirst
|
||||
public static TwoDSegment getBeforeNew(TwoDPoint beforePoint, TwoDPoint origin, TwoDPoint afterPoint, TwoDPoint newOrigin) {
|
||||
TwoDSegment AB = new TwoDSegment(beforePoint, origin);
|
||||
double slopeAB = AB.getLineSlope();
|
||||
double interceptAB = AB.getLineIntercept();
|
||||
// private static TwoDSegment getBeforeNew(TwoDPoint beforePoint, TwoDPoint origin, TwoDPoint afterPoint, TwoDPoint
|
||||
// newOrigin) {
|
||||
// TwoDSegment AB = new TwoDSegment(beforePoint, origin);
|
||||
// double slopeAB = AB.getLineSlope();
|
||||
// double interceptAB = AB.getLineIntercept();
|
||||
//
|
||||
// TwoDSegment BC = new TwoDSegment(origin, afterPoint);
|
||||
// double slopeBC = BC.getLineSlope();
|
||||
// double interceptBC = BC.getLineIntercept();
|
||||
//
|
||||
// double temp1 = origin.x + newOrigin.x;
|
||||
// double temp2 = origin.y + newOrigin.y - interceptAB - interceptBC;
|
||||
//
|
||||
// double beforeFx = (temp1 - temp2 / slopeBC) / (1 - slopeAB / slopeBC);
|
||||
// double beforeFy = slopeAB * beforeFx + interceptAB;
|
||||
//
|
||||
// double afterFx = (temp1 - temp2 / slopeAB) / (1 - slopeBC / slopeAB);
|
||||
// double afterFy = slopeBC * afterFx + interceptBC;
|
||||
//
|
||||
// TwoDPoint beforeF = new TwoDPoint(beforeFx, beforeFy);
|
||||
// TwoDPoint afterF = new TwoDPoint(afterFx, afterFy);
|
||||
//
|
||||
// return new TwoDSegment(beforeF, afterF);
|
||||
// }
|
||||
|
||||
TwoDSegment BC = new TwoDSegment(origin, afterPoint);
|
||||
double slopeBC = BC.getLineSlope();
|
||||
double interceptBC = BC.getLineIntercept();
|
||||
|
||||
double temp1 = origin.x + newOrigin.x;
|
||||
double temp2 = origin.y + newOrigin.y - interceptAB - interceptBC;
|
||||
|
||||
double beforeFx = (temp1 - temp2 / slopeBC) / (1 - slopeAB / slopeBC);
|
||||
double beforeFy = slopeAB * beforeFx + interceptAB;
|
||||
|
||||
double afterFx = (temp1 - temp2 / slopeAB) / (1 - slopeBC / slopeAB);
|
||||
double afterFy = slopeBC * afterFx + interceptBC;
|
||||
|
||||
TwoDPoint beforeF = new TwoDPoint(beforeFx, beforeFy);
|
||||
TwoDPoint afterF = new TwoDPoint(afterFx, afterFy);
|
||||
|
||||
return new TwoDSegment(beforeF, afterF);
|
||||
}
|
||||
|
||||
public static boolean areInClockwiseOrder(TwoDPoint A, TwoDPoint B, TwoDPoint C) {
|
||||
private static boolean areInClockwiseOrder(TwoDPoint A, TwoDPoint B, TwoDPoint C) {
|
||||
return (C.y - A.y) * (B.x - A.x) > (B.y - A.y) * (C.x - A.x);
|
||||
}
|
||||
|
||||
|
||||
+21
-34
@@ -1,6 +1,11 @@
|
||||
package com.sap.sailing.gwt.ui.shared.racemap;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a segment (or line) in the bidimensional space.
|
||||
*
|
||||
* @author I077899 Bogdan Mihai
|
||||
*
|
||||
*/
|
||||
public class TwoDSegment {
|
||||
private double lineSlope = 0.0;
|
||||
private double lineIntercept = 0.0;
|
||||
@@ -13,13 +18,14 @@ public class TwoDSegment {
|
||||
}
|
||||
|
||||
public TwoDSegment(double x1, double y1, double x2, double y2) {
|
||||
if (x1 == x2) {
|
||||
// FIXME:
|
||||
} else {
|
||||
|
||||
if (x1 != x2) {
|
||||
this.lineSlope = (y2 - y1) / (x2 - x1);
|
||||
this.lineIntercept = (x2 * y1 - x1 * y2) / (x2 - x1);
|
||||
}
|
||||
|
||||
// TODO: if x1 == x2 ...
|
||||
|
||||
this.firstPoint = new TwoDPoint(x1, y1);
|
||||
this.secondPoint = new TwoDPoint(x2, y2);
|
||||
}
|
||||
@@ -32,18 +38,6 @@ public class TwoDSegment {
|
||||
return this.lineIntercept;
|
||||
}
|
||||
|
||||
public TwoDPoint projectionOfPointOnLine(TwoDPoint p) {
|
||||
double x = (this.lineSlope * p.getY() + p.getX() - this.lineSlope * this.lineIntercept)
|
||||
/ (this.lineSlope * this.lineSlope + 1);
|
||||
double y = this.lineSlope * x + this.lineIntercept;
|
||||
|
||||
return new TwoDPoint(x, y);
|
||||
}
|
||||
|
||||
public double distanceToLine(TwoDPoint p) {
|
||||
return TwoDPoint.distanceBetween(p, this.projectionOfPointOnLine(p));
|
||||
}
|
||||
|
||||
public TwoDPoint getFirstPoint() {
|
||||
return this.firstPoint;
|
||||
}
|
||||
@@ -52,11 +46,6 @@ public class TwoDSegment {
|
||||
return this.secondPoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Segment[" + this.firstPoint.toString() + "|" + this.secondPoint.toString() + "]";
|
||||
}
|
||||
|
||||
public TwoDVector asVector() {
|
||||
return new TwoDVector(this.firstPoint, this.secondPoint);
|
||||
}
|
||||
@@ -65,20 +54,16 @@ public class TwoDSegment {
|
||||
return TwoDPoint.areIntersecting(s1.firstPoint, s1.secondPoint, s2.firstPoint, s2.secondPoint);
|
||||
}
|
||||
|
||||
public TwoDPoint intersectionPointWith(TwoDSegment segment2) {
|
||||
return getIntersection(this, segment2);
|
||||
}
|
||||
public TwoDPoint getIntersection(TwoDSegment segment) {
|
||||
|
||||
public static TwoDPoint getIntersection(TwoDSegment segment1, TwoDSegment segment2) {
|
||||
double xA = this.firstPoint.getX();
|
||||
double yA = this.firstPoint.getY();
|
||||
|
||||
double xA = segment1.firstPoint.getX();
|
||||
double yA = segment1.firstPoint.getY();
|
||||
double xC = segment.firstPoint.getX();
|
||||
double yC = segment.firstPoint.getY();
|
||||
|
||||
double xC = segment2.firstPoint.getX();
|
||||
double yC = segment2.firstPoint.getY();
|
||||
|
||||
double m1 = segment1.lineSlope;
|
||||
double m2 = segment2.lineSlope;
|
||||
double m1 = this.lineSlope;
|
||||
double m2 = segment.lineSlope;
|
||||
|
||||
double x = (yC - yA + m1 * xA - m2 * xC) / (m1 - m2);
|
||||
double y = (yC - yA + m2 * (xA - xC)) * m1 / (m1 - m2) + yA;
|
||||
@@ -86,9 +71,11 @@ public class TwoDSegment {
|
||||
return new TwoDPoint(x, y);
|
||||
}
|
||||
|
||||
public boolean contains(TwoDPoint point) {
|
||||
public boolean contains(TwoDPoint point, boolean firstProjectOnLine) {
|
||||
|
||||
if (Math.abs(point.getY() - (this.lineSlope * point.getX() + this.lineIntercept)) > 0.00001) {
|
||||
if (firstProjectOnLine) {
|
||||
point = point.getProjection(this);
|
||||
} else if (Math.abs(point.getY() - (this.lineSlope * point.getX() + this.lineIntercept)) > 0.00001) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+20
-9
@@ -1,8 +1,13 @@
|
||||
package com.sap.sailing.gwt.ui.shared.racemap;
|
||||
|
||||
//FIXME: vectorul nul?
|
||||
|
||||
/**
|
||||
* Represents a vector in the bidimensional space
|
||||
*
|
||||
* @author I077899 Bogdan Mihai
|
||||
*
|
||||
*/
|
||||
public class TwoDVector {
|
||||
|
||||
private final double re;
|
||||
private final double im;
|
||||
private final double norm;
|
||||
@@ -17,15 +22,18 @@ public class TwoDVector {
|
||||
this.norm = Math.sqrt(this.re * this.re + this.im * this.im);
|
||||
}
|
||||
|
||||
public TwoDVector normalize() {
|
||||
@SuppressWarnings("unused")
|
||||
private TwoDVector normalize() {
|
||||
return new TwoDVector(this.re / this.norm, this.im / this.norm);
|
||||
}
|
||||
|
||||
public TwoDVector add(TwoDVector vector) {
|
||||
@SuppressWarnings("unused")
|
||||
private TwoDVector add(TwoDVector vector) {
|
||||
return new TwoDVector(this.re + vector.getRe(), this.im + vector.getIm());
|
||||
}
|
||||
|
||||
public TwoDVector substract(TwoDVector vector) {
|
||||
@SuppressWarnings("unused")
|
||||
private TwoDVector substract(TwoDVector vector) {
|
||||
return new TwoDVector(this.re - vector.getRe(), this.im - vector.getIm());
|
||||
}
|
||||
|
||||
@@ -33,15 +41,17 @@ public class TwoDVector {
|
||||
return (this.re * vector.getRe() + this.im * vector.getIm());
|
||||
}
|
||||
|
||||
public static double getCos(TwoDVector v1, TwoDVector v2) {
|
||||
@SuppressWarnings("unused")
|
||||
private static double getCos(TwoDVector v1, TwoDVector v2) {
|
||||
return (v1.dotProduct(v2) / (v1.getNorm() * v2.getNorm()));
|
||||
}
|
||||
|
||||
public TwoDVector multiplyScalar(double scalar) {
|
||||
@SuppressWarnings("unused")
|
||||
private TwoDVector multiplyScalar(double scalar) {
|
||||
return new TwoDVector(this.re * scalar, this.im * scalar);
|
||||
}
|
||||
|
||||
public TwoDVector rotate(double degrees) {
|
||||
private TwoDVector rotate(double degrees) {
|
||||
double temp = degrees * Math.PI / 180;
|
||||
double sin = Math.sin(temp);
|
||||
double cos = Math.cos(temp);
|
||||
@@ -49,7 +59,8 @@ public class TwoDVector {
|
||||
return new TwoDVector((cos * this.re) + (-1 * sin * this.im), (sin * this.re) + (cos * this.im));
|
||||
}
|
||||
|
||||
public static TwoDPoint getRotatedPoint(TwoDPoint origin, TwoDPoint head, double degrees) {
|
||||
@SuppressWarnings("unused")
|
||||
private static TwoDPoint getRotatedPoint(TwoDPoint origin, TwoDPoint head, double degrees) {
|
||||
TwoDVector v = new TwoDVector(origin, head);
|
||||
v = v.rotate(degrees);
|
||||
|
||||
|
||||
+612
-195
@@ -23,13 +23,26 @@ import com.sap.sailing.gwt.ui.shared.racemap.TwoDPoint;
|
||||
import com.sap.sailing.gwt.ui.shared.racemap.TwoDSegment;
|
||||
import com.sap.sailing.gwt.ui.shared.racemap.TwoDVector;
|
||||
|
||||
/**
|
||||
* This class represents the path polyline overlay on the GWT map. This polyline is constructed with an array of turn
|
||||
* points, saved as the turnPoints property.
|
||||
*
|
||||
* The GWT polyline offers little to no help in setting programatically a vertices, so I apply every geometry rule onto
|
||||
* the internal array of turn points, and then reconstruct the polyline after every movement.
|
||||
*
|
||||
* The main method of this class is drawPolylineOnMap, in which a new GWT polyline is created with an update handler
|
||||
* that handles every geometry related issue.
|
||||
*
|
||||
* @author I077899 Bogdan Mihai
|
||||
*
|
||||
*/
|
||||
public class PathPolyline {
|
||||
|
||||
public final static String DEFAULT_COLOR = "#8B0000";
|
||||
private final static int DEFAULT_WEIGHT = 3;
|
||||
private final static double DEFAULT_OPACITY = 1.0;
|
||||
private final static double DEFAULT_DISTANCE_PX = 25;
|
||||
private final static double SMOOTHNESS_MAX_DEG = 20.0;
|
||||
private final static double SMOOTHNESS_MAX_DEG = 20.0;
|
||||
private final static double DELTA = 0.0001;
|
||||
private final static int STEP_DURATION_MILLISECONDS = 2000;
|
||||
private final static boolean USE_REAL_AVERAGE_WIND = true;
|
||||
|
||||
@@ -50,24 +63,34 @@ public class PathPolyline {
|
||||
private SimulatorMap simulatorMap = null;
|
||||
private SimulatorMainPanel simulatorMainPanel = null;
|
||||
|
||||
public static PathPolyline createPathPolyline(List<SimulatorWindDTO> pathPoints, ErrorReporter errorReporter, SimulatorServiceAsync simulatorService,
|
||||
public static PathPolyline createPathPolyline(List<SimulatorWindDTO> pathPoints, String color, int weight, double opacity, ErrorReporter errorReporter,
|
||||
SimulatorServiceAsync simulatorService,
|
||||
MapWidget map, SimulatorMap simulatorMap, SimulatorMainPanel simulatorMainPanel, SimulatorUISelectionDTO selection) {
|
||||
|
||||
List<LatLng> points = new ArrayList<LatLng>();
|
||||
|
||||
// int counter = 1;
|
||||
// int max = 5;
|
||||
for (SimulatorWindDTO pathPoint : pathPoints) {
|
||||
if (pathPoint.isTurn) {
|
||||
|
||||
// counter++;
|
||||
points.add(LatLng.newInstance(pathPoint.position.latDeg, pathPoint.position.lngDeg));
|
||||
// if (counter > max) {
|
||||
// break;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
return new PathPolyline(points.toArray(new LatLng[0]), DEFAULT_COLOR, DEFAULT_WEIGHT, DEFAULT_OPACITY, selection,
|
||||
errorReporter, pathPoints,
|
||||
simulatorService, map, simulatorMap, simulatorMainPanel);
|
||||
return new PathPolyline(points.toArray(new LatLng[0]), color, weight, opacity, selection, errorReporter, pathPoints, simulatorService, map,
|
||||
simulatorMap, simulatorMainPanel);
|
||||
}
|
||||
|
||||
private PathPolyline() {
|
||||
public static PathPolyline createPathPolyline(List<SimulatorWindDTO> pathPoints, ErrorReporter errorReporter, SimulatorServiceAsync simulatorService,
|
||||
MapWidget map, SimulatorMap simulatorMap, SimulatorMainPanel simulatorMainPanel, SimulatorUISelectionDTO selection) {
|
||||
|
||||
return createPathPolyline(pathPoints, DEFAULT_COLOR, DEFAULT_WEIGHT, DEFAULT_OPACITY, errorReporter, simulatorService, map, simulatorMap,
|
||||
simulatorMainPanel, selection);
|
||||
}
|
||||
|
||||
private PathPolyline(LatLng[] points, String color, int weight, double opacity, SimulatorUISelectionDTO selection, ErrorReporter errorReporter,
|
||||
@@ -112,11 +135,10 @@ public class PathPolyline {
|
||||
turnPoints = newTurnPoints.toArray(new LatLng[0]);
|
||||
|
||||
} else {
|
||||
|
||||
final int indexOfMovedPoint = getIndexOfMovedPoint();
|
||||
final int noOfPoints = turnPoints.length;
|
||||
|
||||
LatLng temp = null;
|
||||
|
||||
boolean secondPart = false;
|
||||
|
||||
if (indexOfMovedPoint == 0 || indexOfMovedPoint == noOfPoints - 1 || noOfPoints == 3) {
|
||||
@@ -124,36 +146,51 @@ public class PathPolyline {
|
||||
// nor a 3-turns line.
|
||||
} else {
|
||||
|
||||
TwoDPoint newOrigin = computeNewOrigin(indexOfMovedPoint);
|
||||
LatLng newPositionOfMovedPoint = getNewPositionOfMovedPoint(indexOfMovedPoint);
|
||||
|
||||
LatLng oldPositionOfFirstBeforeMovedPoint = turnPoints[indexOfMovedPoint - 1];
|
||||
LatLng oldPositionOfMovedPoint = turnPoints[indexOfMovedPoint];
|
||||
LatLng oldPositionOfAfterBeforeMovedPoint = turnPoints[indexOfMovedPoint + 1];
|
||||
|
||||
if (indexOfMovedPoint == 1) {
|
||||
turnPoints[indexOfMovedPoint + 1] = toLatLng(computeAfterNewOrigin(indexOfMovedPoint, newOrigin));
|
||||
// if the indexOfMovedPoint == 1, only the next point will be changed, as the start one
|
||||
// cannot be moved
|
||||
turnPoints[indexOfMovedPoint + 1] = getNewPositionOfPointAfterMoved(indexOfMovedPoint, newPositionOfMovedPoint);
|
||||
secondPart = true;
|
||||
|
||||
} else if (indexOfMovedPoint == noOfPoints - 2) {
|
||||
turnPoints[indexOfMovedPoint - 1] = toLatLng(computeBeforeNewOrigin(indexOfMovedPoint, newOrigin));
|
||||
// if indexOfMovedPoint == noOfPoints - 2, only the previous point will be changed, as the
|
||||
// end one cannot be moved.
|
||||
turnPoints[indexOfMovedPoint - 1] = getNewPositionOfPointBeforeMoved(indexOfMovedPoint, newPositionOfMovedPoint);
|
||||
secondPart = false;
|
||||
|
||||
} else {
|
||||
|
||||
temp = toLatLng(computeBeforeNewOrigin(indexOfMovedPoint, newOrigin));
|
||||
if (PathPolyline.equals(temp, turnPoints[indexOfMovedPoint - 1], 0.0001) == false) {
|
||||
LatLng possibleNewPositionOfPointBeforeMoved = getNewPositionOfPointBeforeMoved(indexOfMovedPoint, newPositionOfMovedPoint);
|
||||
if (PathPolyline.equals(possibleNewPositionOfPointBeforeMoved, turnPoints[indexOfMovedPoint - 1]) == false) {
|
||||
|
||||
secondPart = false;
|
||||
turnPoints[indexOfMovedPoint - 1] = temp;
|
||||
turnPoints[indexOfMovedPoint - 1] = possibleNewPositionOfPointBeforeMoved;
|
||||
|
||||
}
|
||||
|
||||
temp = toLatLng(computeAfterNewOrigin(indexOfMovedPoint, newOrigin));
|
||||
if (PathPolyline.equals(temp, turnPoints[indexOfMovedPoint + 1], 0.0001) == false) {
|
||||
LatLng possibleNewPositionOfPointAfterMoved = getNewPositionOfPointAfterMoved(indexOfMovedPoint, newPositionOfMovedPoint);
|
||||
if (PathPolyline.equals(possibleNewPositionOfPointAfterMoved, turnPoints[indexOfMovedPoint + 1]) == false) {
|
||||
|
||||
secondPart = true;
|
||||
turnPoints[indexOfMovedPoint + 1] = temp;
|
||||
turnPoints[indexOfMovedPoint + 1] = possibleNewPositionOfPointAfterMoved;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
turnPoints[indexOfMovedPoint] = toLatLng(newOrigin);
|
||||
turnPoints[indexOfMovedPoint] = newPositionOfMovedPoint;
|
||||
|
||||
turnPoints = fix_againstTheWindMovement(turnPoints, indexOfMovedPoint, secondPart);
|
||||
turnPoints = checkIfAnyTurnsMustGo(turnPoints, indexOfMovedPoint, secondPart, oldPositionOfFirstBeforeMovedPoint,
|
||||
oldPositionOfMovedPoint, oldPositionOfAfterBeforeMovedPoint);
|
||||
|
||||
turnPoints = fix_spikesOnCourse(turnPoints);
|
||||
turnPoints = eliminateSpikes(turnPoints);
|
||||
|
||||
turnPoints = fix_trianglesOnCourse(turnPoints);
|
||||
turnPoints = eliminateTriangles(turnPoints);
|
||||
}
|
||||
|
||||
drawPolylineOnMap();
|
||||
@@ -168,6 +205,9 @@ public class PathPolyline {
|
||||
this.getTotalTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a GWT marker to the map. Used only for debugging purposes.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private void addMarker(LatLng point, String title) {
|
||||
|
||||
@@ -179,129 +219,49 @@ public class PathPolyline {
|
||||
this.map.addOverlay(marker);
|
||||
}
|
||||
|
||||
private LatLng[] fix_againstTheWindMovement(LatLng[] turnPoints, int indexOfMovedPoint, boolean secondPart) {
|
||||
/**
|
||||
* This member checks if the point before the moved point must be eliminated or not from the turns array. If so, a
|
||||
* new turn array is returned, if not the old one is returned.
|
||||
*
|
||||
* @param turnPoints
|
||||
* - the array of turns as LatLng objects
|
||||
* @param indexOfMovedPoint
|
||||
* - the index of the moved point
|
||||
* @param secondBefore
|
||||
* - the second point before the moved one as a TwoDPoint object
|
||||
* @param firstBefore
|
||||
* - the new position of the point before the moved one as a TwoDPoint object
|
||||
* @param neww
|
||||
* - the new position of the moved point.
|
||||
* @param firstAfter
|
||||
* - the new position of the point after the moved one as a TwoDPoint object
|
||||
* @param firstAfterEdge
|
||||
* - the edge after the moved point, defined by the moved point and the point after it, defined as a
|
||||
* TwoDSegment.
|
||||
* @returns a LatLng[] array.
|
||||
*/
|
||||
private LatLng[] checkIfPreviousMustGo(LatLng[] turnPoints, int indexOfMovedPoint, TwoDPoint secondBefore, TwoDPoint firstBefore, TwoDPoint neww,
|
||||
TwoDPoint firstAfter, TwoDSegment firstAfterEdge) {
|
||||
|
||||
int noOfTurnPoints = turnPoints.length;
|
||||
List<LatLng> newTurnPoints = new ArrayList<LatLng>();
|
||||
|
||||
TwoDPoint neww = this.toTwoDPoint(turnPoints[indexOfMovedPoint]);
|
||||
TwoDPoint new_before = this.toTwoDPoint(turnPoints[indexOfMovedPoint - 1]);
|
||||
TwoDPoint new_after = this.toTwoDPoint(turnPoints[indexOfMovedPoint + 1]);
|
||||
|
||||
boolean newList = false;
|
||||
|
||||
if (secondPart) {
|
||||
TwoDVector vector = new TwoDVector(neww, firstBefore);
|
||||
TwoDPoint projection = secondBefore.getProjectionByVector(firstAfterEdge, vector);
|
||||
TwoDSegment segment = new TwoDSegment(firstAfter, projection);
|
||||
|
||||
TwoDPoint after_after = this.toTwoDPoint(turnPoints[indexOfMovedPoint + 2]);
|
||||
if (segment.contains(neww, true) == false) {
|
||||
|
||||
if (indexOfMovedPoint + 4 <= noOfTurnPoints) {
|
||||
newList = true;
|
||||
|
||||
TwoDPoint after_after_after = this.toTwoDPoint(turnPoints[indexOfMovedPoint + 3]);
|
||||
TwoDSegment after_edge = new TwoDSegment(after_after, after_after_after);
|
||||
TwoDSegment current_edge_before = new TwoDSegment(new_before, neww);
|
||||
TwoDPoint intersection = after_edge.intersectionPointWith(current_edge_before);
|
||||
TwoDSegment segment = new TwoDSegment(new_before, intersection);
|
||||
// the current moved point must be replaced with projection
|
||||
// the previous point must be eliminated
|
||||
|
||||
neww = segment.projectionOfPointOnLine(neww);
|
||||
|
||||
TwoDSegment current_edge_after = new TwoDSegment(neww, new_after);
|
||||
TwoDPoint intersection2 = after_edge.intersectionPointWith(current_edge_after);
|
||||
TwoDSegment segment2 = new TwoDSegment(after_after, intersection);
|
||||
|
||||
if (segment.contains(neww) == false || segment2.contains(intersection2)) {
|
||||
|
||||
newList = true;
|
||||
|
||||
for (int index = 0; index < noOfTurnPoints; index++) {
|
||||
if (index == indexOfMovedPoint) {
|
||||
newTurnPoints.add(this.toLatLng(intersection));
|
||||
} else if (index == indexOfMovedPoint + 1 || index == indexOfMovedPoint + 2) {
|
||||
// eliminate turnPoints[index + 1] as well as turnPoints[index + 2]
|
||||
} else {
|
||||
newTurnPoints.add(turnPoints[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
TwoDSegment line = new TwoDSegment(neww, new_before);
|
||||
TwoDVector vector = new TwoDVector(neww, new_after);
|
||||
TwoDPoint projection = TwoDPoint.projectToLineByVector(after_after, line, vector);
|
||||
TwoDSegment segment = new TwoDSegment(new_before, projection);
|
||||
|
||||
neww = segment.projectionOfPointOnLine(neww);
|
||||
|
||||
if (segment.contains(neww) == false) {
|
||||
|
||||
newList = true;
|
||||
|
||||
for (int index = 0; index < noOfTurnPoints; index++) {
|
||||
if (index == indexOfMovedPoint) {
|
||||
newTurnPoints.add(this.toLatLng(projection));
|
||||
} else if (index == indexOfMovedPoint + 1) {
|
||||
// eliminate turnPoints[index + 1]
|
||||
} else {
|
||||
newTurnPoints.add(turnPoints[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
TwoDPoint before_before = toTwoDPoint(turnPoints[indexOfMovedPoint - 2]);
|
||||
|
||||
if (indexOfMovedPoint >= 3) {
|
||||
|
||||
TwoDPoint before_before_before = this.toTwoDPoint(turnPoints[indexOfMovedPoint - 3]);
|
||||
TwoDSegment before_edge = new TwoDSegment(before_before, before_before_before);
|
||||
TwoDSegment current_edge_after = new TwoDSegment(neww, new_after);
|
||||
TwoDPoint intersection = before_edge.intersectionPointWith(current_edge_after);
|
||||
TwoDSegment segment = new TwoDSegment(new_after, intersection);
|
||||
|
||||
neww = segment.projectionOfPointOnLine(neww);
|
||||
|
||||
TwoDSegment current_edge_before = new TwoDSegment(neww, new_before);
|
||||
TwoDPoint intersection2 = before_edge.intersectionPointWith(current_edge_before);
|
||||
TwoDSegment segment2 = new TwoDSegment(before_before, intersection);
|
||||
|
||||
if (segment.contains(neww) == false || segment2.contains(intersection2)) {
|
||||
|
||||
newList = true;
|
||||
|
||||
for (int index = 0; index < noOfTurnPoints; index++) {
|
||||
if (index == indexOfMovedPoint) {
|
||||
newTurnPoints.add(this.toLatLng(intersection));
|
||||
} else if (index == indexOfMovedPoint - 1 || index == indexOfMovedPoint - 2) {
|
||||
// eliminate turnPoints[index - 1] as well as turnPoints[index - 2]
|
||||
} else {
|
||||
newTurnPoints.add(turnPoints[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
TwoDSegment line = new TwoDSegment(neww, new_after);
|
||||
TwoDVector vector = new TwoDVector(neww, new_before);
|
||||
TwoDPoint projection = TwoDPoint.projectToLineByVector(before_before, line, vector);
|
||||
TwoDSegment segment = new TwoDSegment(new_after, projection);
|
||||
|
||||
neww = segment.projectionOfPointOnLine(neww);
|
||||
|
||||
if (segment.contains(neww) == false) {
|
||||
|
||||
newList = true;
|
||||
|
||||
for (int index = 0; index < noOfTurnPoints; index++) {
|
||||
if (index == indexOfMovedPoint) {
|
||||
newTurnPoints.add(this.toLatLng(projection));
|
||||
} else if (index == indexOfMovedPoint - 1) {
|
||||
// eliminate turnPoints[index - 1]
|
||||
} else {
|
||||
newTurnPoints.add(turnPoints[index]);
|
||||
}
|
||||
}
|
||||
for (int index = 0; index < turnPoints.length; index++) {
|
||||
if (index == indexOfMovedPoint) {
|
||||
newTurnPoints.add(this.toLatLng(projection));
|
||||
} else if (index != indexOfMovedPoint - 1) {
|
||||
newTurnPoints.add(turnPoints[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -313,10 +273,381 @@ public class PathPolyline {
|
||||
}
|
||||
}
|
||||
|
||||
private double getAngleDegreesBetween(LatLng previous, LatLng current, LatLng next) {
|
||||
/**
|
||||
* This member checks if the previous two points before the moved point must be eliminated or not from the turns
|
||||
* array. If so, a new turn array is returned, if not the old one is returned.
|
||||
*
|
||||
* @param turnPoints
|
||||
* - the array of turns as LatLng objects
|
||||
* @param indexOfMovedPoint
|
||||
* - the index of the moved point
|
||||
* @param secondBefore
|
||||
* - the second point before the moved one as a TwoDPoint object
|
||||
* @param newFirstBefore
|
||||
* - the new position of the point before the moved one as a TwoDPoint object
|
||||
* @param old
|
||||
* - the old position of the moved point.
|
||||
* @param neww
|
||||
* - the new position of the moved point.
|
||||
* @param firstAfter
|
||||
* - the new position of the point after the moved one as a TwoDPoint object
|
||||
* @param firstAfterEdge
|
||||
* - the edge after the moved point, defined by the moved point and the point after it, defined as a
|
||||
* TwoDSegment.
|
||||
* @returns a LatLng[] array.
|
||||
*/
|
||||
private LatLng[] checkIfPreviousTwoMustGo(LatLng[] turnPoints, int indexOfMovedPoint, TwoDPoint secondBefore, TwoDPoint oldFirstBefore,
|
||||
TwoDPoint newFirstBefore, TwoDPoint old, TwoDPoint neww, TwoDPoint firstAfter, TwoDSegment firstAfterEdge) {
|
||||
|
||||
TwoDVector first = new TwoDVector(this.toTwoDPoint(current), this.toTwoDPoint(previous));
|
||||
TwoDVector second = new TwoDVector(this.toTwoDPoint(current), this.toTwoDPoint(next));
|
||||
List<LatLng> newTurnPoints = new ArrayList<LatLng>();
|
||||
boolean newList = false;
|
||||
|
||||
TwoDPoint thirdBefore = this.toTwoDPoint(turnPoints[indexOfMovedPoint - 3]);
|
||||
TwoDSegment thirdBeforeEdge = new TwoDSegment(secondBefore, thirdBefore);
|
||||
TwoDPoint intersection = thirdBeforeEdge.getIntersection(firstAfterEdge);
|
||||
TwoDSegment segment = new TwoDSegment(firstAfter, intersection);
|
||||
|
||||
TwoDSegment firstBeforeEdge = new TwoDSegment(neww, newFirstBefore);
|
||||
TwoDPoint intersection2 = thirdBeforeEdge.getIntersection(firstBeforeEdge);
|
||||
TwoDSegment segment2 = new TwoDSegment(secondBefore, intersection);
|
||||
|
||||
double distanceToNewFirstAfter = neww.getDistanceTo(firstAfter);
|
||||
double distanceToOld = neww.getDistanceTo(old);
|
||||
TwoDSegment oldFirstAfterEdge = new TwoDSegment(old, firstAfter);
|
||||
|
||||
if (distanceToNewFirstAfter < distanceToOld && oldFirstAfterEdge.contains(neww, true) == false) {
|
||||
|
||||
if (indexOfMovedPoint + 2 < turnPoints.length) {
|
||||
|
||||
TwoDPoint secondAfter = this.toTwoDPoint(turnPoints[indexOfMovedPoint + 2]);
|
||||
TwoDSegment secondAfterEdge = new TwoDSegment(firstAfter, secondAfter);
|
||||
TwoDSegment secondBeforeEdge = new TwoDSegment(newFirstBefore, secondBefore);
|
||||
TwoDPoint intersection3 = secondBeforeEdge.getIntersection(secondAfterEdge);
|
||||
|
||||
newList = true;
|
||||
|
||||
// the moved point and the next one must be eliminated
|
||||
// the previous point must be replaced with intersection3
|
||||
|
||||
for (int index = 0; index < turnPoints.length; index++) {
|
||||
|
||||
if (index == indexOfMovedPoint - 1) {
|
||||
newTurnPoints.add(this.toLatLng(intersection3));
|
||||
} else if (index != indexOfMovedPoint && index != indexOfMovedPoint + 1) {
|
||||
newTurnPoints.add(turnPoints[index]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
TwoDVector vector = new TwoDVector(old, oldFirstBefore);
|
||||
TwoDSegment secondBeforeEdge = new TwoDSegment(newFirstBefore, secondBefore);
|
||||
TwoDPoint intersection3 = firstAfter.getProjectionByVector(secondBeforeEdge, vector);
|
||||
|
||||
newList = true;
|
||||
|
||||
// the moved point must be eliminated
|
||||
// the previous point must be replaced with intersection3
|
||||
|
||||
for (int index = 0; index < turnPoints.length; index++) {
|
||||
|
||||
if (index == indexOfMovedPoint - 1) {
|
||||
newTurnPoints.add(this.toLatLng(intersection3));
|
||||
} else if (index != indexOfMovedPoint) {
|
||||
newTurnPoints.add(turnPoints[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (segment.contains(neww, true) == false || segment2.contains(intersection2, true)) {
|
||||
|
||||
newList = true;
|
||||
|
||||
// the moved point must be replaced with intersection
|
||||
// the previous two points must be eliminated
|
||||
|
||||
for (int index = 0; index < turnPoints.length; index++) {
|
||||
|
||||
if (index == indexOfMovedPoint) {
|
||||
newTurnPoints.add(this.toLatLng(intersection));
|
||||
} else if (index != indexOfMovedPoint - 1 && index != indexOfMovedPoint - 2) {
|
||||
newTurnPoints.add(turnPoints[index]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newList) {
|
||||
return newTurnPoints.toArray(new LatLng[0]);
|
||||
} else {
|
||||
return turnPoints;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This member checks if the next two points after the moved point must be eliminated or not from the turns array.
|
||||
* If so, a new turn array is returned, if not the old one is returned.
|
||||
*
|
||||
* @param turnPoints
|
||||
* - the array of turns as LatLng objects
|
||||
* @param indexOfMovedPoint
|
||||
* - the index of the moved point
|
||||
* @param firstBefore
|
||||
* - the new position of the point before the moved one as a TwoDPoint object
|
||||
* @param old
|
||||
* - the old position of the moved point.
|
||||
* @param neww
|
||||
* - the new position of the moved point.
|
||||
* @param newFirstAfter
|
||||
* - the new position of the point after the moved one as a TwoDPoint object
|
||||
* @param secondAfter
|
||||
* - the second point after the moved one as a TwoDPoint object
|
||||
* @param firstBeforeEdge
|
||||
* - the edge before the moved point, defined by the moved point and the point before it, defined as a
|
||||
* TwoDSegment.
|
||||
* @returns a LatLng[] array.
|
||||
*/
|
||||
private LatLng[] checkIfNextTwoMustGo(LatLng[] turnPoints, int indexOfMovedPoint, TwoDPoint firstBefore, TwoDPoint old, TwoDPoint neww,
|
||||
TwoDPoint oldFirstAfter, TwoDPoint newFirstAfter, TwoDPoint secondAfter, TwoDSegment firstBeforeEdge) {
|
||||
|
||||
List<LatLng> newTurnPoints = new ArrayList<LatLng>();
|
||||
boolean newList = false;
|
||||
|
||||
TwoDPoint thirdAfter = this.toTwoDPoint(turnPoints[indexOfMovedPoint + 3]);
|
||||
TwoDSegment thirdAfterEdge = new TwoDSegment(secondAfter, thirdAfter);
|
||||
TwoDPoint intersection = thirdAfterEdge.getIntersection(firstBeforeEdge);
|
||||
TwoDSegment segment = new TwoDSegment(firstBefore, intersection);
|
||||
|
||||
TwoDSegment firstAfterEdge = new TwoDSegment(neww, newFirstAfter);
|
||||
TwoDPoint intersection2 = thirdAfterEdge.getIntersection(firstAfterEdge);
|
||||
TwoDSegment segment2 = new TwoDSegment(secondAfter, intersection);
|
||||
|
||||
double distanceToNewFirstBefore = neww.getDistanceTo(firstBefore);
|
||||
double distanceToOld = neww.getDistanceTo(old);
|
||||
TwoDSegment oldFirstBeforeEdge = new TwoDSegment(old, firstBefore);
|
||||
|
||||
if (distanceToNewFirstBefore < distanceToOld && oldFirstBeforeEdge.contains(neww, true) == false) {
|
||||
|
||||
if (indexOfMovedPoint - 2 >= 0) {
|
||||
|
||||
TwoDPoint secondBefore = this.toTwoDPoint(turnPoints[indexOfMovedPoint - 2]);
|
||||
TwoDSegment secondBeforeEdge = new TwoDSegment(secondBefore, firstBefore);
|
||||
TwoDSegment secondAfterEdge = new TwoDSegment(newFirstAfter, secondAfter);
|
||||
TwoDPoint intersection3 = secondAfterEdge.getIntersection(secondBeforeEdge);
|
||||
|
||||
newList = true;
|
||||
|
||||
// the moved point and the previous one must be eliminated
|
||||
// the next point must be replaced with intersection3
|
||||
|
||||
for (int index = 0; index < turnPoints.length; index++) {
|
||||
|
||||
if (index == indexOfMovedPoint + 1) {
|
||||
newTurnPoints.add(this.toLatLng(intersection3));
|
||||
} else if (index != indexOfMovedPoint && index != indexOfMovedPoint - 1) {
|
||||
newTurnPoints.add(turnPoints[index]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
TwoDVector vector = new TwoDVector(old, oldFirstAfter);
|
||||
TwoDSegment secondAfterEdge = new TwoDSegment(newFirstAfter, secondAfter);
|
||||
TwoDPoint intersection3 = firstBefore.getProjectionByVector(secondAfterEdge, vector);
|
||||
|
||||
newList = true;
|
||||
|
||||
// the current moved point must be eliminated
|
||||
// the next point must be replaced with intersection3
|
||||
|
||||
for (int index = 0; index < turnPoints.length; index++) {
|
||||
|
||||
if (index == indexOfMovedPoint + 1) {
|
||||
newTurnPoints.add(this.toLatLng(intersection3));
|
||||
} else if (index != indexOfMovedPoint) {
|
||||
newTurnPoints.add(turnPoints[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (segment.contains(neww, true) == false || segment2.contains(intersection2, true)) {
|
||||
|
||||
newList = true;
|
||||
|
||||
// the current moved point must be replaced with intersection
|
||||
// the next two points must be eliminated
|
||||
|
||||
for (int index = 0; index < turnPoints.length; index++) {
|
||||
|
||||
if (index == indexOfMovedPoint) {
|
||||
newTurnPoints.add(this.toLatLng(intersection));
|
||||
} else if (index != indexOfMovedPoint + 1 && index != indexOfMovedPoint + 2) {
|
||||
newTurnPoints.add(turnPoints[index]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newList) {
|
||||
return newTurnPoints.toArray(new LatLng[0]);
|
||||
} else {
|
||||
return turnPoints;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This member checks if the point after the moved point must be eliminated or not from the turns array. If so, a
|
||||
* new turn array is returned, if not the old one is returned.
|
||||
*
|
||||
* @param turnPoints
|
||||
* - the array of turns as LatLng objects
|
||||
* @param indexOfMovedPoint
|
||||
* - the index of the moved point
|
||||
* @param firstBefore
|
||||
* - the new position of the point before the moved one as a TwoDPoint object
|
||||
* @param neww
|
||||
* - the new position of the moved point.
|
||||
* @param firstAfter
|
||||
* - the new position of the point after the moved one as a TwoDPoint object
|
||||
* @param secondAfter
|
||||
* - the second after point after the moved one as a TwoDPoint object
|
||||
* @param firstBeforeEdge
|
||||
* - the edge before the moved point, defined by the moved point and the point before it, defined as a
|
||||
* TwoDSegment.
|
||||
* @returns a LatLng[] array.
|
||||
*/
|
||||
private LatLng[] checkIfNextMustGo(LatLng[] turnPoints, int indexOfMovedPoint, TwoDPoint firstBefore, TwoDPoint neww, TwoDPoint firstAfter,
|
||||
TwoDPoint secondAfter, TwoDSegment firstBeforeEdge) {
|
||||
|
||||
List<LatLng> newTurnPoints = new ArrayList<LatLng>();
|
||||
boolean newList = false;
|
||||
|
||||
TwoDVector vector = new TwoDVector(neww, firstAfter);
|
||||
TwoDPoint projection = secondAfter.getProjectionByVector(firstBeforeEdge, vector);
|
||||
TwoDSegment segment = new TwoDSegment(firstBefore, projection);
|
||||
|
||||
if (segment.contains(neww, true) == false) {
|
||||
|
||||
newList = true;
|
||||
|
||||
// the current moved point must be replaced with projection
|
||||
// the next point must be eliminated
|
||||
|
||||
for (int index = 0; index < turnPoints.length; index++) {
|
||||
if (index == indexOfMovedPoint) {
|
||||
newTurnPoints.add(this.toLatLng(projection));
|
||||
} else if (index != indexOfMovedPoint + 1) {
|
||||
newTurnPoints.add(turnPoints[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newList) {
|
||||
return newTurnPoints.toArray(new LatLng[0]);
|
||||
} else {
|
||||
return turnPoints;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This member checks if any of the previous points before the moved point or next points after the moved point must
|
||||
* be eliminated or not. If so, a new array of turn points is returned, if not, the old array is returned.
|
||||
*
|
||||
* @param turnPoints
|
||||
* - the array of turn points as LatLng objects
|
||||
* @param indexOfMovedPoint
|
||||
* - the index of the moved point
|
||||
* @param secondPart
|
||||
* - this flag shows which part of the turn points array must be checked for changes. If secondPart ==
|
||||
* false, then this method will check for either previous point or previous two points to be eliminated
|
||||
* or not. If secondPart == true, then this method will check for either next point or next two points to
|
||||
* be eliminated or not.
|
||||
* @param old_MP
|
||||
* - The old position of the moved point as a LatLng object
|
||||
* @returns a LatLng[] array.
|
||||
*/
|
||||
private LatLng[] checkIfAnyTurnsMustGo(LatLng[] turnPoints, int indexOfMovedPoint, boolean secondPart, LatLng oldPositionOfFirstBeforeMovedPoint,
|
||||
LatLng oldPositionOfMovedPoint, LatLng oldPositionOfAfterBeforeMovedPoint) {
|
||||
|
||||
LatLng[] result = null;
|
||||
|
||||
TwoDPoint oldFirstBefore = this.toTwoDPoint(oldPositionOfFirstBeforeMovedPoint);
|
||||
TwoDPoint old = this.toTwoDPoint(oldPositionOfMovedPoint);
|
||||
TwoDPoint oldFirstAfter = this.toTwoDPoint(oldPositionOfAfterBeforeMovedPoint);
|
||||
|
||||
TwoDPoint neww = this.toTwoDPoint(turnPoints[indexOfMovedPoint]);
|
||||
|
||||
TwoDPoint newFirstBefore = this.toTwoDPoint(turnPoints[indexOfMovedPoint - 1]);
|
||||
TwoDPoint newFirstAfter = this.toTwoDPoint(turnPoints[indexOfMovedPoint + 1]);
|
||||
|
||||
if (secondPart) {
|
||||
|
||||
// check the points AFTER the moved point
|
||||
|
||||
TwoDPoint secondAfter = this.toTwoDPoint(turnPoints[indexOfMovedPoint + 2]);
|
||||
TwoDSegment firstBeforeEdge = new TwoDSegment(newFirstBefore, neww);
|
||||
|
||||
if (indexOfMovedPoint == turnPoints.length - 3) {
|
||||
|
||||
// check if the next 2 points must be eliminated
|
||||
result = this.checkIfNextMustGo(turnPoints, indexOfMovedPoint, newFirstBefore, neww, newFirstAfter, secondAfter, firstBeforeEdge);
|
||||
|
||||
} else {
|
||||
|
||||
// check if only the next point must be eliminated
|
||||
|
||||
result = this.checkIfNextTwoMustGo(turnPoints, indexOfMovedPoint, newFirstBefore, old, neww, oldFirstAfter, newFirstAfter, secondAfter,
|
||||
firstBeforeEdge);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// check the points BEFORE the moved point
|
||||
|
||||
TwoDPoint secondBefore = toTwoDPoint(turnPoints[indexOfMovedPoint - 2]);
|
||||
TwoDSegment firstAfterEdge = new TwoDSegment(neww, newFirstAfter);
|
||||
|
||||
if (indexOfMovedPoint == 2) {
|
||||
|
||||
// check if the previous 2 points must be eliminated
|
||||
|
||||
result = this.checkIfPreviousMustGo(turnPoints, indexOfMovedPoint, secondBefore, newFirstBefore, neww, newFirstAfter, firstAfterEdge);
|
||||
|
||||
} else {
|
||||
|
||||
// check if only the previous point must be eliminated
|
||||
|
||||
result = this.checkIfPreviousTwoMustGo(turnPoints, indexOfMovedPoint, secondBefore, oldFirstBefore, newFirstBefore, old, neww, newFirstAfter,
|
||||
firstAfterEdge);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This member computes the angle between two vectors with the same origin
|
||||
*
|
||||
* @param head1
|
||||
* - the head of the first vector
|
||||
* @param origin
|
||||
* - the common origin of the two vectors
|
||||
* @param head2
|
||||
* - the head of the second vector
|
||||
* @returns the angle between these two vectors in degrees.
|
||||
*/
|
||||
private double getAngleDegreesBetween(LatLng head1, LatLng origin, LatLng head2) {
|
||||
|
||||
TwoDVector first = new TwoDVector(this.toTwoDPoint(origin), this.toTwoDPoint(head1));
|
||||
TwoDVector second = new TwoDVector(this.toTwoDPoint(origin), this.toTwoDPoint(head2));
|
||||
|
||||
double dotProduct = first.dotProduct(second);
|
||||
|
||||
@@ -334,7 +665,16 @@ public class PathPolyline {
|
||||
return angle;
|
||||
}
|
||||
|
||||
private LatLng[] fix_spikesOnCourse(LatLng[] turnPoints) {
|
||||
/**
|
||||
* Eliminates the spikes from the array of turns. In order to do so, it will compare the "inside" angle defined by
|
||||
* each pair of 3 consecutive turns with a default value. If this angle is smaller, than the top of it will be
|
||||
* removed.
|
||||
*
|
||||
* @param turnPoints
|
||||
* - the array of turn points.
|
||||
* @returns a LatLng object - the new array of turn points.
|
||||
*/
|
||||
private LatLng[] eliminateSpikes(LatLng[] turnPoints) {
|
||||
|
||||
if (turnPoints.length < 4) {
|
||||
return turnPoints;
|
||||
@@ -342,20 +682,21 @@ public class PathPolyline {
|
||||
|
||||
List<LatLng> points = new ArrayList<LatLng>();
|
||||
|
||||
int noOfPointsMinus1 = turnPoints.length - 1;
|
||||
|
||||
TwoDSegment before = null;
|
||||
TwoDSegment after = null;
|
||||
TwoDSegment beforeEdge = null;
|
||||
TwoDSegment afterEdge = null;
|
||||
|
||||
int newIndex = -1;
|
||||
TwoDPoint newAtIndex = null;
|
||||
|
||||
for (int index = 2; index < noOfPointsMinus1; index++) {
|
||||
for (int index = 2; index < turnPoints.length - 1; index++) {
|
||||
|
||||
if (this.getAngleDegreesBetween(turnPoints[index - 1], turnPoints[index], turnPoints[index + 1]) < SMOOTHNESS_MAX_DEG) {
|
||||
before = new TwoDSegment(toTwoDPoint(turnPoints[index - 2]), toTwoDPoint(turnPoints[index - 1]));
|
||||
after = new TwoDSegment(toTwoDPoint(turnPoints[index]), toTwoDPoint(turnPoints[index + 1]));
|
||||
newAtIndex = after.intersectionPointWith(before);
|
||||
|
||||
beforeEdge = new TwoDSegment(toTwoDPoint(turnPoints[index - 2]), toTwoDPoint(turnPoints[index - 1]));
|
||||
afterEdge = new TwoDSegment(toTwoDPoint(turnPoints[index]), toTwoDPoint(turnPoints[index + 1]));
|
||||
|
||||
newAtIndex = afterEdge.getIntersection(beforeEdge);
|
||||
|
||||
newIndex = index;
|
||||
}
|
||||
}
|
||||
@@ -373,7 +714,15 @@ public class PathPolyline {
|
||||
return points.toArray(new LatLng[0]);
|
||||
}
|
||||
|
||||
private LatLng[] fix_trianglesOnCourse(LatLng[] turnPoints) {
|
||||
/**
|
||||
* Eliminates the triangles that might appear on the course.
|
||||
*
|
||||
* @param turnPoints
|
||||
* - the array of turn points.
|
||||
* @returns a LatLng object - the new array of turn points.
|
||||
*/
|
||||
private LatLng[] eliminateTriangles(LatLng[] turnPoints) {
|
||||
|
||||
int noOfPoints = turnPoints.length;
|
||||
|
||||
if (noOfPoints < 4) {
|
||||
@@ -401,7 +750,7 @@ public class PathPolyline {
|
||||
if (index2 == index + 1) {
|
||||
continue;
|
||||
} else if (index2 == index + 2) {
|
||||
newTurnPoints.add(toLatLng(firstSegment.intersectionPointWith(secondSegment)));
|
||||
newTurnPoints.add(toLatLng(firstSegment.getIntersection(secondSegment)));
|
||||
} else {
|
||||
newTurnPoints.add(turnPoints[index2]);
|
||||
}
|
||||
@@ -414,69 +763,104 @@ public class PathPolyline {
|
||||
return turnPoints;
|
||||
}
|
||||
|
||||
private TwoDPoint computeNewOrigin(int indexOfMovedPoint) {
|
||||
/**
|
||||
* This member computes the correct new position of the moved point. In order to do so, it will take into
|
||||
* consideration the "before edge" - the edge defined by the old position of the moved point and the previous point,
|
||||
* and the "after edge" - the edge defined by the old position of the moved point and the next point. After this, it
|
||||
* will compute the projections of the proposed new position of the moved point on both of these edges, and it will
|
||||
* chose the one closer to it.
|
||||
*
|
||||
* @param indexOfMovedPoint
|
||||
* - the index of the moved turn point.
|
||||
* @returns a LatLng object - the correct new position of the moved point.
|
||||
*/
|
||||
private LatLng getNewPositionOfMovedPoint(int indexOfMovedPoint) {
|
||||
|
||||
double distance = (this.map.getZoomLevel() - 11) * DEFAULT_DISTANCE_PX;
|
||||
TwoDPoint firstBefore = this.toTwoDPoint(this.turnPoints[indexOfMovedPoint - 1]);
|
||||
TwoDPoint oldPositionMovedPoint = this.toTwoDPoint(this.turnPoints[indexOfMovedPoint]);
|
||||
TwoDPoint firstAfter = this.toTwoDPoint(this.turnPoints[indexOfMovedPoint + 1]);
|
||||
|
||||
TwoDPoint beforeMovedPoint = toTwoDPoint(this.turnPoints[indexOfMovedPoint - 1]);
|
||||
TwoDPoint oldPositionMovedPoint = toTwoDPoint(this.turnPoints[indexOfMovedPoint]);
|
||||
TwoDPoint afterMovedPoint = toTwoDPoint(this.turnPoints[indexOfMovedPoint + 1]);
|
||||
TwoDPoint newPositionMovedPoint = toTwoDPoint(this.polyline.getVertex(indexOfMovedPoint));
|
||||
TwoDPoint newPositionMovedPointBeforeFix = this.toTwoDPoint(this.polyline.getVertex(indexOfMovedPoint));
|
||||
|
||||
TwoDPoint head1 = oldPositionMovedPoint.getDistancedPoint(distance, beforeMovedPoint);
|
||||
TwoDSegment oh1 = new TwoDSegment(oldPositionMovedPoint, head1);
|
||||
TwoDPoint p1 = oh1.projectionOfPointOnLine(newPositionMovedPoint);
|
||||
double d1 = newPositionMovedPoint.distanceBetween(p1);
|
||||
TwoDSegment beforeEdge = new TwoDSegment(oldPositionMovedPoint, firstBefore);
|
||||
double distanceToBeforeEdge = newPositionMovedPointBeforeFix.getDistanceTo(beforeEdge);
|
||||
|
||||
TwoDPoint head2 = oldPositionMovedPoint.getDistancedPoint(distance, afterMovedPoint);
|
||||
TwoDSegment oh2 = new TwoDSegment(oldPositionMovedPoint, head2);
|
||||
TwoDPoint p2 = oh2.projectionOfPointOnLine(newPositionMovedPoint);
|
||||
double d2 = newPositionMovedPoint.distanceBetween(p2);
|
||||
TwoDSegment afterEdge = new TwoDSegment(oldPositionMovedPoint, firstAfter);
|
||||
double distanceToAfterEdge = newPositionMovedPointBeforeFix.getDistanceTo(afterEdge);
|
||||
|
||||
LatLng projectionOnBeforeEdge = this.toLatLng(newPositionMovedPointBeforeFix.getProjection(beforeEdge));
|
||||
LatLng projectionOfAfterEdge = this.toLatLng(newPositionMovedPointBeforeFix.getProjection(afterEdge));
|
||||
|
||||
if (indexOfMovedPoint == 1) {
|
||||
return p1;
|
||||
return projectionOnBeforeEdge;
|
||||
} else if (indexOfMovedPoint == this.turnPoints.length - 2) {
|
||||
return p2;
|
||||
return projectionOfAfterEdge;
|
||||
} else {
|
||||
return (d1 < d2) ? p1 : p2;
|
||||
return (distanceToBeforeEdge < distanceToAfterEdge) ? projectionOnBeforeEdge : projectionOfAfterEdge;
|
||||
}
|
||||
}
|
||||
|
||||
private TwoDPoint computeAfterNewOrigin(int indexOfMovedPoint, TwoDPoint newOrigin) {
|
||||
/**
|
||||
* This member computes the correct new position of the point after the moved one. In order to do so, it will
|
||||
* compute the projection by vector of the new position of the moved point on the line defined by the first after
|
||||
* point and the second after point, considering the vector starting from the old position of the moved point to the
|
||||
* first after point.
|
||||
*
|
||||
* @param indexOfMovedPoint
|
||||
* - the index of the moved point.
|
||||
* @param newPositionOfMovedPoint
|
||||
* - the new position of the moved point
|
||||
* @returns a LatLng object - the correct new position of the point after the moved one.
|
||||
*/
|
||||
private LatLng getNewPositionOfPointAfterMoved(int indexOfMovedPoint, LatLng newPositionOfMovedPoint) {
|
||||
|
||||
TwoDPoint origin = toTwoDPoint(this.turnPoints[indexOfMovedPoint]);
|
||||
TwoDPoint afterOrigin = toTwoDPoint(this.turnPoints[indexOfMovedPoint + 1]);
|
||||
TwoDPoint afterAfterOrigin = toTwoDPoint(this.turnPoints[indexOfMovedPoint + 2]);
|
||||
TwoDPoint oldPositionOfMovedPoint = toTwoDPoint(this.turnPoints[indexOfMovedPoint]);
|
||||
TwoDPoint firstAfter = toTwoDPoint(this.turnPoints[indexOfMovedPoint + 1]);
|
||||
TwoDPoint secondAfter = toTwoDPoint(this.turnPoints[indexOfMovedPoint + 2]);
|
||||
|
||||
TwoDSegment afterLine = new TwoDSegment(afterOrigin, afterAfterOrigin);
|
||||
TwoDVector afterVector = new TwoDVector(origin, afterOrigin);
|
||||
return TwoDPoint.projectToLineByVector(newOrigin, afterLine, afterVector);
|
||||
TwoDSegment firstAfterEdge = new TwoDSegment(firstAfter, secondAfter);
|
||||
TwoDVector afterVector = new TwoDVector(oldPositionOfMovedPoint, firstAfter);
|
||||
|
||||
return this.toLatLng(this.toTwoDPoint(newPositionOfMovedPoint).getProjectionByVector(firstAfterEdge, afterVector));
|
||||
}
|
||||
|
||||
private TwoDPoint computeBeforeNewOrigin(int indexOfMovedPoint, TwoDPoint newOrigin) {
|
||||
/**
|
||||
* This member computes the correct new position of the point before the moved one. In order to do so, it will
|
||||
* compute the projection by vector of the new position of the moved point on the line defined by the first before
|
||||
* point and the second before point, considering the vector starting from the old position of the moved point to
|
||||
* the first before point.
|
||||
*
|
||||
* @param indexOfMovedPoint
|
||||
* - the index of the moved point.
|
||||
* @param newPositionOfMovedPoint
|
||||
* - the new position of the moved point
|
||||
* @returns a LatLng object - the correct new position of the point before the moved one.
|
||||
*/
|
||||
private LatLng getNewPositionOfPointBeforeMoved(int indexOfMovedPoint, LatLng newPositionOfMovedPoint) {
|
||||
|
||||
TwoDPoint beforeOrigin = toTwoDPoint(this.turnPoints[indexOfMovedPoint - 1]);
|
||||
TwoDPoint beforeBeforeOrigin = toTwoDPoint(this.turnPoints[indexOfMovedPoint - 2]);
|
||||
TwoDPoint origin = toTwoDPoint(this.turnPoints[indexOfMovedPoint]);
|
||||
TwoDPoint firstBefore = toTwoDPoint(this.turnPoints[indexOfMovedPoint - 1]);
|
||||
TwoDPoint secondBefore = toTwoDPoint(this.turnPoints[indexOfMovedPoint - 2]);
|
||||
TwoDPoint oldPositionOfMovedPoint = toTwoDPoint(this.turnPoints[indexOfMovedPoint]);
|
||||
|
||||
TwoDSegment beforeLine = new TwoDSegment(beforeBeforeOrigin, beforeOrigin);
|
||||
TwoDVector beforeVector = new TwoDVector(beforeOrigin, origin);
|
||||
TwoDSegment firstBeforeEdge = new TwoDSegment(secondBefore, firstBefore);
|
||||
TwoDVector beforeVector = new TwoDVector(oldPositionOfMovedPoint, firstBefore);
|
||||
|
||||
return TwoDPoint.projectToLineByVector(newOrigin, beforeLine, beforeVector);
|
||||
return this.toLatLng(this.toTwoDPoint(newPositionOfMovedPoint).getProjectionByVector(firstBeforeEdge, beforeVector));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the moved point by comparing each position of the "saved" array of turn points and the
|
||||
* polyline array of vertices.
|
||||
*
|
||||
* @returns the index of the moved point.
|
||||
*/
|
||||
private int getIndexOfMovedPoint() {
|
||||
|
||||
int index = 0;
|
||||
int noOfVertexes = this.polyline.getVertexCount();
|
||||
LatLng oldPointPosition = null;
|
||||
LatLng newPointPosition = null;
|
||||
|
||||
for (; index < noOfVertexes; index++) {
|
||||
oldPointPosition = this.turnPoints[index];
|
||||
newPointPosition = this.polyline.getVertex(index);
|
||||
for (; index < this.turnPoints.length; index++) {
|
||||
|
||||
if (equals(oldPointPosition, newPointPosition) == false) {
|
||||
if (equals(this.turnPoints[index], this.polyline.getVertex(index)) == false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -484,28 +868,59 @@ public class PathPolyline {
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a LatLng object to a TwoD object. Considering that a LatLng represent a point on a sphere, and that the
|
||||
* TwoDPoint represent one on a plane, it will use the MapWidget aproximation to a container pixel in order to do
|
||||
* so.
|
||||
*
|
||||
* @param latLng
|
||||
* - the LatLng object to be converted to a TwoDPoint
|
||||
* @returns a TwoDPoint object.
|
||||
*/
|
||||
private TwoDPoint toTwoDPoint(LatLng latLng) {
|
||||
Point point = this.map.convertLatLngToContainerPixel(latLng);
|
||||
return new TwoDPoint(point.getX(), point.getY());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a TwoDPoint object to a LatLng object. Considering that a TwoDPoint represent a point on a plane and
|
||||
* that a LatLng object represents one on a sphere, it will use the MapWidget aproximation to a container pixel in
|
||||
* ordr to do so.
|
||||
*
|
||||
* @param point
|
||||
* - the TwoDPoint object to be converted to a LatLng
|
||||
* @returns a LatLng object.
|
||||
*/
|
||||
private LatLng toLatLng(TwoDPoint point) {
|
||||
return this.map.convertContainerPixelToLatLng(Point.newInstance((int) point.getX(), (int) point.getY()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a LatLng object to a PositionDTO.
|
||||
*
|
||||
* @param position
|
||||
* - the LatLng object used
|
||||
* @returns a PositionDTO object.
|
||||
*/
|
||||
private static PositionDTO toPositionDTO(LatLng position) {
|
||||
return new PositionDTO(position.getLatitude(), position.getLongitude());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if two LatLng points are equal by comparing their latitude and longitude with a certain epsilon (0.0001);
|
||||
*
|
||||
* @param first
|
||||
* - the first LatLng object
|
||||
* @param second
|
||||
* - the second LatLng object
|
||||
* @returns a boolean, true for equality, false otherwise.
|
||||
*/
|
||||
private static boolean equals(LatLng first, LatLng second) {
|
||||
return (first.getLatitude() == second.getLatitude() && first.getLongitude() == second.getLongitude());
|
||||
}
|
||||
|
||||
private static boolean equals(LatLng first, LatLng second, double delta) {
|
||||
double latDiff = Math.abs(first.getLatitude() - second.getLatitude());
|
||||
double lngDiff = Math.abs(first.getLongitude() - second.getLongitude());
|
||||
|
||||
return latDiff <= delta && lngDiff <= delta;
|
||||
return latDiff <= DELTA && lngDiff <= DELTA;
|
||||
}
|
||||
|
||||
private void getTotalTime() {
|
||||
@@ -542,11 +957,14 @@ public class PathPolyline {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the boatClassIndex property.
|
||||
*/
|
||||
public void setBoatClassID(int boatClassIndex) {
|
||||
this.selectedBoatClassIndex = boatClassIndex;
|
||||
}
|
||||
|
||||
private static double FACTOR_KN2MPS = 0.514444;
|
||||
private static final double FACTOR_KN2MPS = 0.514444;
|
||||
|
||||
/**
|
||||
* Converts knots to meters per second
|
||||
@@ -554,5 +972,4 @@ public class PathPolyline {
|
||||
public static double knotsToMetersPerSecond(double knots) {
|
||||
return knots * FACTOR_KN2MPS;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user