46e12030490571fa0e1a9fc3467de57dc11f6085
java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/CourseChangeBasedTrackApproximation.java
| ... | ... | @@ -30,6 +30,7 @@ import com.sap.sse.common.impl.TimeRangeImpl; |
| 30 | 30 | import com.sap.sse.common.scalablevalue.KadaneExtremeSubsequenceFinder; |
| 31 | 31 | import com.sap.sse.common.scalablevalue.KadaneExtremeSubsequenceFinderLinkedNodesImpl; |
| 32 | 32 | import com.sap.sse.common.scalablevalue.ScalableDouble; |
| 33 | +import com.sap.sse.common.scalablevalue.ScalableValueWithDistance; |
|
| 33 | 34 | |
| 34 | 35 | /** |
| 35 | 36 | * Given a {@link GPSFixTrack} containing {@link GPSFixMoving}, an instance of this class finds areas on the track where |
| ... | ... | @@ -161,7 +162,7 @@ public class CourseChangeBasedTrackApproximation implements Serializable, GPSTra |
| 161 | 162 | GPSFixMoving add(GPSFixMoving next) { |
| 162 | 163 | assert window.isEmpty() || !next.getTimePoint().before(window.peekFirst().getTimePoint()); |
| 163 | 164 | final GPSFixMoving result; |
| 164 | - final SpeedWithBearing nextSpeed = /* TODO this was the original code that can depend on fixes newer than next: next.isEstimatedSpeedCached() ? next.getCachedEstimatedSpeed() : track.getEstimatedSpeed(next.getTimePoint()) */ |
|
| 165 | + final SpeedWithBearing nextSpeed = /* TODO this was the original code that can depend on fixes newer than next: next.isEstimatedSpeedCached() ? next.getCachedEstimatedSpeed() : track.getEstimatedSpeed(next.getTimePoint()); */ |
|
| 165 | 166 | next.getSpeed(); int TODO; // TODO bug6209: try without dependency on newer fixes and see if it helps produce equal results for early/late initialization |
| 166 | 167 | if (nextSpeed != null) { // TODO bug6209: this gets messy... if we drop a fix because no estimated speed can be determined for it, and later fix additions may change this, where would we get this fix from again? |
| 167 | 168 | numberOfFixesAdded++; |
| ... | ... | @@ -187,7 +188,7 @@ public class CourseChangeBasedTrackApproximation implements Serializable, GPSTra |
| 187 | 188 | // rather expensive ceil/floor search on the track; resort to track.getEstimatedSpeed if not cached |
| 188 | 189 | assert previousSpeed != null; // we wouldn't have added the fix in the previous run if it hadn't had a valid speed |
| 189 | 190 | final double courseChangeBetweenPreviousAndNextInDegrees = previousSpeed.getBearing().getDifferenceTo(nextSpeed.getBearing()).getDegrees(); |
| 190 | - if (insertPosition == window.size()-1) { // if not appended to the end, the window duration won't change |
|
| 191 | + if (insertPosition == window.size()-1) { // if appended to the end, the window duration changes |
|
| 191 | 192 | windowDuration = windowDuration.plus(previous.getTimePoint().until(next.getTimePoint())); |
| 192 | 193 | } |
| 193 | 194 | if (courseChangeBetweenFixesInWindow.isEmpty()) { |
| ... | ... | @@ -254,10 +255,10 @@ public class CourseChangeBasedTrackApproximation implements Serializable, GPSTra |
| 254 | 255 | private void removeFirst(int howManyElementsToRemove) { |
| 255 | 256 | assert !window.isEmpty(); |
| 256 | 257 | for (int i=0; i<howManyElementsToRemove; i++) { |
| 257 | - final GPSFixMoving removed = window.removeFirst(); |
|
| 258 | + window.removeFirst(); |
|
| 258 | 259 | speedForFixesInWindow.removeFirst(); |
| 259 | - windowDuration = window.isEmpty() ? Duration.NULL : windowDuration.minus(removed.getTimePoint().until(window.getFirst().getTimePoint())); |
|
| 260 | 260 | } |
| 261 | + windowDuration = window.isEmpty() ? Duration.NULL : window.getFirst().getTimePoint().until(window.getLast().getTimePoint()); |
|
| 261 | 262 | // adjust totalCourseChangeFromBeginningOfWindow by subtracting the first course change from all others |
| 262 | 263 | // and shifting all by one position to the "left" |
| 263 | 264 | if (!courseChangeBetweenFixesInWindow.isEmpty()) { |
| ... | ... | @@ -280,8 +281,10 @@ public class CourseChangeBasedTrackApproximation implements Serializable, GPSTra |
| 280 | 281 | */ |
| 281 | 282 | private Pair<GPSFixMoving, Integer> getManeuverCandidate() { |
| 282 | 283 | final GPSFixMoving result; |
| 283 | - final double maximumCourseChangeToStarboard = courseChangeBetweenFixesInWindow.getMaxSum().divide(1); |
|
| 284 | - final double maximumCourseChangeToPort = -courseChangeBetweenFixesInWindow.getMinSum().divide(1); |
|
| 284 | + final ScalableValueWithDistance<Double, Double> maxSum = courseChangeBetweenFixesInWindow.getMaxSum(); |
|
| 285 | + final double maximumCourseChangeToStarboard = maxSum == null ? Double.NEGATIVE_INFINITY : maxSum.divide(1); |
|
| 286 | + final ScalableValueWithDistance<Double, Double> minSum = courseChangeBetweenFixesInWindow.getMinSum(); |
|
| 287 | + final double maximumCourseChangeToPort = minSum == null ? Double.NEGATIVE_INFINITY : -minSum.divide(1); |
|
| 285 | 288 | final double absoluteMaximumTotalCourseChangeFromBeginningOfWindowInDegrees = Math.max(maximumCourseChangeToStarboard, maximumCourseChangeToPort); |
| 286 | 289 | int indexOfMaximumAbsoluteCourseChangeInCorrectDirection = -1; |
| 287 | 290 | if (absoluteMaximumTotalCourseChangeFromBeginningOfWindowInDegrees >= maneuverAngleInDegreesThreshold) { |
java/com.sap.sse.common/src/com/sap/sse/common/scalablevalue/KadaneExtremeSubsequenceFinderLinkedNodesImpl.java
| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | package com.sap.sse.common.scalablevalue; |
| 2 | 2 | |
| 3 | +import java.io.Serializable; |
|
| 3 | 4 | import java.util.Collections; |
| 4 | -import java.util.Comparator; |
|
| 5 | 5 | import java.util.Iterator; |
| 6 | 6 | import java.util.TreeSet; |
| 7 | 7 | import java.util.function.BiFunction; |
| ... | ... | @@ -9,6 +9,7 @@ import java.util.function.Consumer; |
| 9 | 9 | import java.util.function.Function; |
| 10 | 10 | |
| 11 | 11 | import com.sap.sse.common.Util; |
| 12 | +import com.sap.sse.common.impl.SerializableComparator; |
|
| 12 | 13 | |
| 13 | 14 | /** |
| 14 | 15 | * An implementation of Kadane's algorithm for "maximum sub-sequence sum" that works incrementally, |
| ... | ... | @@ -57,7 +58,8 @@ public class KadaneExtremeSubsequenceFinderLinkedNodesImpl<ValueType, AveragesTo |
| 57 | 58 | * |
| 58 | 59 | * @author Axel Uhl (d043530) |
| 59 | 60 | */ |
| 60 | - private static class Node<ValueType, AveragesTo extends Comparable<AveragesTo>, T extends ComparableScalableValueWithDistance<ValueType, AveragesTo>> { |
|
| 61 | + private static class Node<ValueType, AveragesTo extends Comparable<AveragesTo>, T extends ComparableScalableValueWithDistance<ValueType, AveragesTo>> implements Serializable { |
|
| 62 | + private static final long serialVersionUID = -2547142048423135013L; |
|
| 61 | 63 | private static int idCounter = 0; |
| 62 | 64 | private final T value; |
| 63 | 65 | private final int id; |
| ... | ... | @@ -235,11 +237,11 @@ public class KadaneExtremeSubsequenceFinderLinkedNodesImpl<ValueType, AveragesTo |
| 235 | 237 | this.size = 0; |
| 236 | 238 | this.first = null; |
| 237 | 239 | this.last = null; |
| 238 | - final Comparator<? super Node<ValueType, AveragesTo, T>> idComparator = (n1, n2)->Integer.compare(n1.getId(), n2.getId()); |
|
| 239 | - final Comparator<Node<ValueType, AveragesTo, T>> minSumComparator = (n1, n2)->compare(n1.getMinSumEndingHere(), n2.getMinSumEndingHere()); |
|
| 240 | - final Comparator<Node<ValueType, AveragesTo, T>> maxSumComparator = (n1, n2)->compare(n1.getMaxSumEndingHere(), n2.getMaxSumEndingHere()); |
|
| 241 | - final Comparator<? super Node<ValueType, AveragesTo, T>> minSumOuterComparator = (n1,n2)->(n1==n2?0:minSumComparator.thenComparing(idComparator).compare(n1, n2)); |
|
| 242 | - final Comparator<? super Node<ValueType, AveragesTo, T>> maxSumOuterComparator = (n1,n2)->(n1==n2?0:maxSumComparator.thenComparing(idComparator).compare(n1, n2)); |
|
| 240 | + final SerializableComparator<? super Node<ValueType, AveragesTo, T>> idComparator = (n1, n2)->Integer.compare(n1.getId(), n2.getId()); |
|
| 241 | + final SerializableComparator<Node<ValueType, AveragesTo, T>> minSumComparator = (n1, n2)->compare(n1.getMinSumEndingHere(), n2.getMinSumEndingHere()); |
|
| 242 | + final SerializableComparator<Node<ValueType, AveragesTo, T>> maxSumComparator = (n1, n2)->compare(n1.getMaxSumEndingHere(), n2.getMaxSumEndingHere()); |
|
| 243 | + final SerializableComparator<? super Node<ValueType, AveragesTo, T>> minSumOuterComparator = (n1,n2)->(n1==n2?0:minSumComparator.thenComparing(idComparator).compare(n1, n2)); |
|
| 244 | + final SerializableComparator<? super Node<ValueType, AveragesTo, T>> maxSumOuterComparator = (n1,n2)->(n1==n2?0:maxSumComparator.thenComparing(idComparator).compare(n1, n2)); |
|
| 243 | 245 | this.nodesOrderedByMinSum = new TreeSet<>(minSumOuterComparator); |
| 244 | 246 | this.nodesOrderedByMaxSum = new TreeSet<>(maxSumOuterComparator); |
| 245 | 247 | } |
| ... | ... | @@ -557,7 +559,7 @@ public class KadaneExtremeSubsequenceFinderLinkedNodesImpl<ValueType, AveragesTo |
| 557 | 559 | @Override |
| 558 | 560 | public String toString() { |
| 559 | 561 | return "KadaneExtremeSubsequenceFinderLinkedNodesImpl [size=" + size |
| 560 | - + ", minChangePropagationStepsAvg=" + minChangePropagationStepsSum / minChangePropagationsCount |
|
| 561 | - + ", maxChangePropagationStepsAvg=" + maxChangePropagationStepsSum / maxChangePropagationsCount + "]"; |
|
| 562 | + + ", minChangePropagationStepsAvg=" + (minChangePropagationsCount==0?null:(minChangePropagationStepsSum / minChangePropagationsCount)) |
|
| 563 | + + ", maxChangePropagationStepsAvg=" + (maxChangePropagationsCount==0?null:(maxChangePropagationStepsSum / maxChangePropagationsCount)) + "]"; |
|
| 562 | 564 | } |
| 563 | 565 | } |
java/com.sap.sse.common/src/com/sap/sse/common/scalablevalue/ScalableDouble.java
| ... | ... | @@ -1,6 +1,9 @@ |
| 1 | 1 | package com.sap.sse.common.scalablevalue; |
| 2 | 2 | |
| 3 | -public class ScalableDouble implements AbstractScalarValue<Double> { |
|
| 3 | +import java.io.Serializable; |
|
| 4 | + |
|
| 5 | +public class ScalableDouble implements AbstractScalarValue<Double>, Serializable { |
|
| 6 | + private static final long serialVersionUID = -354261484569358609L; |
|
| 4 | 7 | private final double value; |
| 5 | 8 | |
| 6 | 9 | public ScalableDouble(double value) { |