I think I've finally fixed the spikes.

This commit is contained in:
I077899 committed 2013-02-05 16:38:05 +02:00
1 parent 8728d87a16
commit 8e98eae938
3 files changed
+205 -106

No files matched your search

@@ -6,7 +6,7 @@ import com.sap.sailing.domain.common.impl.RadianPosition;
public class AbstractPosition implements Position {
private static final double TRESHOLD_DEGREES = 30.0;
private static final double TRESHOLD_DEGREES = 25.0;
private static final long serialVersionUID = -3057027562787541064L;
@Override
@@ -8,15 +8,13 @@ public class TwoDSegment {
private TwoDPoint firstPoint = null;
private TwoDPoint secondPoint = null;
public TwoDSegment(final TwoDPoint p1, final TwoDPoint p2) {
public TwoDSegment(TwoDPoint p1, TwoDPoint p2) {
this(p1.getX(), p1.getY(), p2.getX(), p2.getY());
}
public TwoDSegment(final double x1, final double y1, final double x2, final double y2) {
public TwoDSegment(double x1, double y1, double x2, double y2) {
if (x1 == x2) {
// FIXME:
// this.slope = Double.MAX_VALUE;
} else {
this.lineSlope = (y2 - y1) / (x2 - x1);
this.lineIntercept = (x2 * y1 - x1 * y2) / (x2 - x1);
@@ -34,15 +32,15 @@ public class TwoDSegment {
return this.lineIntercept;
}
public TwoDPoint projectionOfPointOnLine(final TwoDPoint p) {
final double x = (this.lineSlope * p.getY() + p.getX() - this.lineSlope * this.lineIntercept)
public TwoDPoint projectionOfPointOnLine(TwoDPoint p) {
double x = (this.lineSlope * p.getY() + p.getX() - this.lineSlope * this.lineIntercept)
/ (this.lineSlope * this.lineSlope + 1);
final double y = this.lineSlope * x + this.lineIntercept;
double y = this.lineSlope * x + this.lineIntercept;
return new TwoDPoint(x, y);
}
public double distanceToLine(final TwoDPoint p) {
public double distanceToLine(TwoDPoint p) {
return TwoDPoint.distanceBetween(p, this.projectionOfPointOnLine(p));
}
@@ -63,36 +61,37 @@ public class TwoDSegment {
return new TwoDVector(this.firstPoint, this.secondPoint);
}
public static boolean areIntersecting(final TwoDSegment s1, final TwoDSegment s2) {
public static boolean areIntersecting(TwoDSegment s1, TwoDSegment s2) {
return TwoDPoint.areIntersecting(s1.firstPoint, s1.secondPoint, s2.firstPoint, s2.secondPoint);
}
public TwoDPoint intersectionPointWith(final TwoDSegment segment2) {
return getIntersectionPoint(this, segment2);
public TwoDPoint intersectionPointWith(TwoDSegment segment2) {
return getIntersection(this, segment2);
}
public static TwoDPoint getIntersectionPoint(final TwoDSegment segment1, final TwoDSegment segment2) {
public static TwoDPoint getIntersection(TwoDSegment segment1, TwoDSegment segment2) {
final double x1 = segment1.firstPoint.getX();
final double x2 = segment1.secondPoint.getX();
final double x3 = segment2.firstPoint.getX();
final double x4 = segment2.secondPoint.getX();
double xA = segment1.firstPoint.getX();
double yA = segment1.firstPoint.getY();
final double y1 = segment1.firstPoint.getY();
final double y2 = segment1.secondPoint.getY();
final double y3 = segment2.firstPoint.getY();
final double y4 = segment2.secondPoint.getY();
double xC = segment2.firstPoint.getX();
double yC = segment2.firstPoint.getY();
final double temp1 = (y2 - y1) / (x2 - x1);
final double temp2 = (y4 - y3) / (x4 - x3);
double m1 = segment1.lineSlope;
double m2 = segment2.lineSlope;
final double x = (y3 - y1 + x1 * temp1 - x3 * temp2) / (temp1 - temp2);
final double y = x * temp1 + y1 - x1 * temp1;
double x = (yC - yA + m1 * xA - m2 * xC) / (m1 - m2);
double y = (yC - yA + m2 * (xA - xC)) * m1 / (m1 - m2) + yA;
return new TwoDPoint(x, y);
}
public boolean contains(TwoDPoint point) {
if (Math.abs(point.getY() - (this.lineSlope * point.getX() + this.lineIntercept)) > 0.00001) {
return false;
}
double maxX = Math.max(this.firstPoint.getX(), this.secondPoint.getX());
double minX = Math.min(this.firstPoint.getX(), this.secondPoint.getX());
@@ -17,9 +17,7 @@ import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.gwt.ui.client.ErrorReporter;
import com.sap.sailing.gwt.ui.client.SimulatorServiceAsync;
import com.sap.sailing.gwt.ui.shared.PositionDTO;
import com.sap.sailing.gwt.ui.shared.Request1TurnerDTO;
import com.sap.sailing.gwt.ui.shared.RequestTotalTimeDTO;
import com.sap.sailing.gwt.ui.shared.Response1TurnerDTO;
import com.sap.sailing.gwt.ui.shared.ResponseTotalTimeDTO;
import com.sap.sailing.gwt.ui.shared.SimulatorWindDTO;
import com.sap.sailing.gwt.ui.shared.racemap.TwoDPoint;
@@ -61,6 +59,9 @@ public class PathPolyline {
private static int STEP_DURATION_MILLISECONDS = 2000;
private static boolean USE_REAL_AVERAGE_WIND = true;
private static boolean FIX_CUT_SPIKES = true;
private static boolean FIX_CUT_TRIANGLES = true;
public static PathPolyline createPathPolyline(List<SimulatorWindDTO> pathPoints, ErrorReporter errorReporter, SimulatorServiceAsync simulatorService,
MapWidget map, SimulatorMap simulatorMap, int boatClassID) {
@@ -112,6 +113,17 @@ public class PathPolyline {
});
}
@SuppressWarnings("unused")
private void printTurnPoints() {
System.out.println("-----------------------------");
for (int index = 0; index < this.turnPoints.length; index++) {
System.out.println("Point no. " + index + " at " + this.turnPoints[index].toString());
}
System.out.println("-----------------------------");
}
private void drawPolylineOnMap() {
if (this.polyline != null) {
this.map.removeOverlay(this.polyline);
@@ -130,16 +142,17 @@ public class PathPolyline {
if (indexOfMovedPoint == 0 || indexOfMovedPoint == noOfPoints - 1) {
// start and end points cannot be moved!
} else {
// System.err.println("INDEX OF MOVED POINT = " + indexOfMovedPoint);
TwoDPoint newOrigin = computeNewOrigin(indexOfMovedPoint);
final boolean projectionOnBeforeLine = projectedToBeforeLine(indexOfMovedPoint);
SpecialCaseResult specialCase = null;
if (indexOfMovedPoint == 1) {
turnPoints[indexOfMovedPoint + 1] = toLatLng(computeAfterNewOrigin(indexOfMovedPoint, newOrigin));
} else if (indexOfMovedPoint == noOfPoints - 2) {
turnPoints[indexOfMovedPoint - 1] = toLatLng(computeBeforeNewOrigin(indexOfMovedPoint, newOrigin));
} else {
specialCase = isSepecialCase(indexOfMovedPoint, newOrigin);
turnPoints[indexOfMovedPoint - 1] = toLatLng(computeBeforeNewOrigin(indexOfMovedPoint, newOrigin));
turnPoints[indexOfMovedPoint + 1] = toLatLng(computeAfterNewOrigin(indexOfMovedPoint, newOrigin));
}
@@ -148,87 +161,58 @@ public class PathPolyline {
LatLng newOriginLng = turnPoints[indexOfMovedPoint];
// start of "cut the triangles" fix
if (noOfPoints > 3) {
LatLng first = null;
LatLng second = null;
LatLng third = null;
LatLng fourth = null;
if (FIX_CUT_SPIKES) {
fix_cutSpikes(specialCase, indexOfMovedPoint);
}
for (int index = 0; (index + 3) < noOfPoints; index++) {
first = turnPoints[index];
second = turnPoints[index + 1];
third = turnPoints[index + 2];
fourth = turnPoints[index + 3];
if (TwoDPoint.areIntersecting(toTwoDPoint(first), toTwoDPoint(second), toTwoDPoint(third), toTwoDPoint(fourth))) {
TwoDSegment firstSegment = new TwoDSegment(toTwoDPoint(first), toTwoDPoint(second));
TwoDSegment secondSegment = new TwoDSegment(toTwoDPoint(third), toTwoDPoint(fourth));
List<LatLng> newTurnPoints = new ArrayList<LatLng>();
for (int index2 = 0; index2 < noOfPoints; index2++) {
if (index2 == index + 1) {
continue;
} else if (index2 == index + 2) {
newTurnPoints.add(toLatLng(firstSegment.intersectionPointWith(secondSegment)));
} else {
newTurnPoints.add(LatLng.newInstance(turnPoints[index2].getLatitude(), turnPoints[index2].getLongitude()));
}
}
turnPoints = null;
turnPoints = newTurnPoints.toArray(new LatLng[0]);
break;
}
}
if (FIX_CUT_TRIANGLES) {
fix_cutTriangles();
}
// end of "cut the triangles" fix
// start of "optimal towards wind" fix
SimulatorWindDTO firstPoint = toSimulatorWindDTO(originalOriginLng);
PositionDTO secondPoint = toPositionDTO(newOriginLng);
Request1TurnerDTO requestData = new Request1TurnerDTO(boatClassID, allPoints, firstPoint, secondPoint, USE_REAL_AVERAGE_WIND,
STEP_DURATION_MILLISECONDS, !projectionOnBeforeLine);
simulatorService.get1Turner(requestData, new AsyncCallback<Response1TurnerDTO>() {
@Override
public void onFailure(Throwable error) {
System.out.println("eroare");
errorReporter.reportError("Failed to initialize boat classes!\r\n" + error.getMessage());
}
@Override
public void onSuccess(Response1TurnerDTO receiveData) {
System.out.println("succes");
SimulatorWindDTO oneTurner = receiveData.oneTurner;
List<LatLng> newTurnPoints = new ArrayList<LatLng>();
for (int index2 = 0; index2 < noOfPoints; index2++) {
if (index2 == indexOfMovedPoint) {
if (projectionOnBeforeLine) {
newTurnPoints.add(originalOriginLng);
newTurnPoints.add(LatLng.newInstance(oneTurner.position.latDeg, oneTurner.position.lngDeg));
newTurnPoints.add(turnPoints[index2]);
} else {
newTurnPoints.add(turnPoints[index2]);
newTurnPoints.add(LatLng.newInstance(oneTurner.position.latDeg, oneTurner.position.lngDeg));
newTurnPoints.add(originalOriginLng);
}
} else {
newTurnPoints.add(turnPoints[index2]);
}
}
turnPoints = null;
turnPoints = newTurnPoints.toArray(new LatLng[0]);
}
});
// SimulatorWindDTO firstPoint = toSimulatorWindDTO(originalOriginLng);
// PositionDTO secondPoint = toPositionDTO(newOriginLng);
//
// Request1TurnerDTO requestData = new Request1TurnerDTO(boatClassID, allPoints, firstPoint,
// secondPoint, USE_REAL_AVERAGE_WIND,
// STEP_DURATION_MILLISECONDS, !projectionOnBeforeLine);
//
// simulatorService.get1Turner(requestData, new AsyncCallback<Response1TurnerDTO>() {
//
// @Override
// public void onFailure(Throwable error) {
// System.out.println("eroare");
// errorReporter.reportError("Failed to initialize boat classes!\r\n" + error.getMessage());
//
// }
//
// @Override
// public void onSuccess(Response1TurnerDTO receiveData) {
// System.out.println("succes");
//
// SimulatorWindDTO oneTurner = receiveData.oneTurner;
// List<LatLng> newTurnPoints = new ArrayList<LatLng>();
//
// for (int index2 = 0; index2 < noOfPoints; index2++) {
// if (index2 == indexOfMovedPoint) {
// if (projectionOnBeforeLine) {
// newTurnPoints.add(originalOriginLng);
// newTurnPoints.add(LatLng.newInstance(oneTurner.position.latDeg, oneTurner.position.lngDeg));
// newTurnPoints.add(turnPoints[index2]);
// } else {
// newTurnPoints.add(turnPoints[index2]);
// newTurnPoints.add(LatLng.newInstance(oneTurner.position.latDeg, oneTurner.position.lngDeg));
// newTurnPoints.add(originalOriginLng);
// }
// } else {
// newTurnPoints.add(turnPoints[index2]);
// }
// }
//
// turnPoints = null;
// turnPoints = newTurnPoints.toArray(new LatLng[0]);
// }
// });
// end of "optimal towards wind" fix
}
@@ -244,6 +228,77 @@ public class PathPolyline {
this.getTotalTime_new();
}
private void fix_cutSpikes(SpecialCaseResult specialCase, int indexOfMovedPoint) {
int noOfPoints = this.turnPoints.length;
if (specialCase != null && specialCase.isSpecialCase) {
List<LatLng> newTurnPoints = new ArrayList<LatLng>();
if (specialCase.isBefore) {
for (int index2 = 0; index2 < noOfPoints; index2++) {
if (index2 == indexOfMovedPoint + 1) {
continue;
} else {
newTurnPoints.add(LatLng.newInstance(this.turnPoints[index2].getLatitude(), this.turnPoints[index2].getLongitude()));
}
}
} else {
for (int index2 = 0; index2 < noOfPoints; index2++) {
if (index2 == indexOfMovedPoint - 1) {
continue;
} else {
newTurnPoints.add(LatLng.newInstance(this.turnPoints[index2].getLatitude(), this.turnPoints[index2].getLongitude()));
}
}
}
this.turnPoints[indexOfMovedPoint] = toLatLng(specialCase.intersection);
this.turnPoints = null;
this.turnPoints = newTurnPoints.toArray(new LatLng[0]);
}
}
private void fix_cutTriangles() {
int noOfPoints = this.turnPoints.length;
if (noOfPoints > 3) {
LatLng first = null;
LatLng second = null;
LatLng third = null;
LatLng fourth = null;
for (int index = 0; (index + 3) < noOfPoints; index++) {
first = this.turnPoints[index];
second = this.turnPoints[index + 1];
third = this.turnPoints[index + 2];
fourth = this.turnPoints[index + 3];
if (TwoDPoint.areIntersecting(toTwoDPoint(first), toTwoDPoint(second), toTwoDPoint(third), toTwoDPoint(fourth))) {
TwoDSegment firstSegment = new TwoDSegment(toTwoDPoint(first), toTwoDPoint(second));
TwoDSegment secondSegment = new TwoDSegment(toTwoDPoint(third), toTwoDPoint(fourth));
List<LatLng> newTurnPoints = new ArrayList<LatLng>();
for (int index2 = 0; index2 < noOfPoints; index2++) {
if (index2 == index + 1) {
continue;
} else if (index2 == index + 2) {
newTurnPoints.add(toLatLng(firstSegment.intersectionPointWith(secondSegment)));
} else {
newTurnPoints.add(LatLng.newInstance(this.turnPoints[index2].getLatitude(), this.turnPoints[index2].getLongitude()));
}
}
this.turnPoints = null;
this.turnPoints = newTurnPoints.toArray(new LatLng[0]);
break;
}
}
}
}
private SimulatorWindDTO toSimulatorWindDTO(LatLng latLng) {
int index = 0;
@@ -260,6 +315,51 @@ public class PathPolyline {
return temp;
}
private class SpecialCaseResult {
boolean isSpecialCase = false;
TwoDPoint intersection = null;
boolean isBefore = false;
}
private SpecialCaseResult isSepecialCase(int indexOfMovedPoint, TwoDPoint newC) {
TwoDPoint A = toTwoDPoint(this.turnPoints[indexOfMovedPoint - 2]);
TwoDPoint B = toTwoDPoint(this.turnPoints[indexOfMovedPoint - 1]);
TwoDPoint C = toTwoDPoint(this.turnPoints[indexOfMovedPoint]);
TwoDPoint D = toTwoDPoint(this.turnPoints[indexOfMovedPoint + 1]);
TwoDPoint E = toTwoDPoint(this.turnPoints[indexOfMovedPoint + 2]);
TwoDSegment BC = new TwoDSegment(B, C);
TwoDSegment DE = new TwoDSegment(D, E);
TwoDPoint intersection_BC_and_DE = TwoDSegment.getIntersection(BC, DE);
TwoDSegment AB = new TwoDSegment(A, B);
TwoDSegment CD = new TwoDSegment(C, D);
TwoDPoint intersection_AB_and_CD = TwoDSegment.getIntersection(AB, CD);
SpecialCaseResult result = new SpecialCaseResult();
if (BC.contains(intersection_BC_and_DE)) {
TwoDSegment firstPartOfBC = new TwoDSegment(B, intersection_BC_and_DE);
if (firstPartOfBC.contains(newC)) {
result.isSpecialCase = true;
result.isBefore = true;
result.intersection = intersection_BC_and_DE;
return result;
}
} else if (CD.contains(intersection_AB_and_CD)) {
TwoDSegment secondPartOfCD = new TwoDSegment(intersection_AB_and_CD, D);
if (secondPartOfCD.contains(newC)) {
result.isSpecialCase = true;
result.isBefore = false;
result.intersection = intersection_AB_and_CD;
return result;
}
}
return result;
}
private TwoDPoint computeNewOrigin(int indexOfMovedPoint) {
double distance = (map.getZoomLevel() - 11) * DEFAULT_DISTANCE_PX;