feat: Refactor to use TreeMap directly for layers
This commit is contained in:
parent
764688e58a
commit
6d541bbe49
2 changed files with 44 additions and 30 deletions
|
@ -21,6 +21,7 @@ import java.io.IOException;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.NavigableMap;
|
||||
import java.util.TreeMap;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -72,58 +73,61 @@ public class Cli {
|
|||
eyePosition.getLatLon(), eyeHeight, minDistance, maxDistance, initStop - initStart);
|
||||
|
||||
long layersStart = System.currentTimeMillis();
|
||||
Collection<DistanceLayer> reversedLayers = new ArrayList<>(maxDistance);
|
||||
final NavigableMap<Integer, DistanceLayer> dLayers = new TreeMap<>();
|
||||
|
||||
for (int d = maxDistance; d > minDistance; d -= SLICE_DISTANCE) {
|
||||
final int cDist = d;
|
||||
double[] data = computeAtDistance(tileMap, cDist, dc);
|
||||
reversedLayers.add(new DistanceLayer(d - SLICE_DISTANCE, d, data));
|
||||
dLayers.put(d, new DistanceLayer(d - SLICE_DISTANCE, d, data));
|
||||
}
|
||||
|
||||
long layersEnd = System.currentTimeMillis();
|
||||
LOG.info("Computed {} layers ({} ms)", reversedLayers.size(), layersEnd - layersStart);
|
||||
LOG.info("Computed {} layers ({} ms)", dLayers.size(), layersEnd - layersStart);
|
||||
|
||||
long horizonStart = System.currentTimeMillis();
|
||||
// We compute the horizon and delete any layer that is behind the horizon
|
||||
// and is not used at all for the landscape.
|
||||
// For this, we are using the fact that we computed the layers starting
|
||||
// with the farthest ones in the build loop.
|
||||
DistanceLayer horizonLayer = reversedLayers.stream()
|
||||
DistanceLayer horizonLayer = dLayers.values().stream()
|
||||
.reduce((a, b) -> a.mergeWith(b))
|
||||
.get();
|
||||
|
||||
reversedLayers = reversedLayers.stream()
|
||||
.dropWhile(l -> horizonLayer.isLower(l))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
LOG.info("Horizon is from {} to {}", horizonLayer.nearDistance, horizonLayer.farDistance);
|
||||
|
||||
Integer fKey = dLayers.firstKey();
|
||||
Integer lKey = dLayers.ceilingKey(horizonLayer.farDistance);
|
||||
|
||||
LOG.info("Split horizon from {} ({}) to {} ({})", fKey, fKey, lKey, horizonLayer.farDistance);
|
||||
final NavigableMap<Integer, DistanceLayer> hLayers = dLayers.subMap(fKey, true, lKey, true);
|
||||
|
||||
// We recompute the min and max distances after the cleanup of layers that
|
||||
// are not useful for the display.
|
||||
maxDistance = reversedLayers.stream()
|
||||
maxDistance = hLayers.values().stream()
|
||||
.map(l -> l.farDistance)
|
||||
.max(Integer::compareTo)
|
||||
.get();
|
||||
|
||||
minDistance = reversedLayers.stream()
|
||||
minDistance = hLayers.values().stream()
|
||||
.map(l -> l.nearDistance)
|
||||
.min(Integer::compareTo)
|
||||
.get();
|
||||
|
||||
dc.updateMinMaxVertAngle(reversedLayers);
|
||||
dc.updateMinMaxVertAngle(hLayers.values());
|
||||
|
||||
long horizonEnd = System.currentTimeMillis();
|
||||
LOG.info("There are {} layers remaining after horizon cleanup at distances {} to {} ({} ms)",
|
||||
reversedLayers.size(), minDistance, maxDistance, horizonEnd - horizonStart);
|
||||
hLayers.size(), minDistance, maxDistance, horizonEnd - horizonStart);
|
||||
|
||||
long labelsStart = System.currentTimeMillis();
|
||||
TreeMap<Integer, DistanceLayer> dLayers = reversedLayers.stream()
|
||||
.collect(Collectors.toMap(l -> l.nearDistance, l -> l, (a, b) -> a.mergeWith(b), TreeMap::new));
|
||||
|
||||
|
||||
// We start processing the features to avoid overlapping features in the
|
||||
// labels as well as displaying features that are hidden from the observation
|
||||
// point.
|
||||
|
||||
Predicate<ObservedFeature> isVisibleFilter = (feature) -> {
|
||||
int x = dc.getXAtBearing(feature.bearing);
|
||||
return DistanceLayer.isVisible(dLayers.values(), feature.distance, x, feature.visibleAngle);
|
||||
return DistanceLayer.isVisible(hLayers.values(), feature.distance, x, feature.visibleAngle);
|
||||
};
|
||||
|
||||
TreeMap<Integer, ObservedFeature> labeledFeatures = allFeatures.stream()
|
||||
|
@ -152,7 +156,7 @@ public class Cli {
|
|||
}
|
||||
|
||||
for (ObservedFeature feature : labeledFeatures.values()) {
|
||||
var featureLayer = dLayers.floorEntry(feature.distance);
|
||||
var featureLayer = hLayers.floorEntry(feature.distance);
|
||||
if (featureLayer == null) {
|
||||
LOG.info("Unable to find layer for feature {}", feature);
|
||||
continue;
|
||||
|
@ -166,12 +170,12 @@ public class Cli {
|
|||
|
||||
long mergeStart = System.currentTimeMillis();
|
||||
List<DistanceLayer> sortedLayers = new ArrayList<>();
|
||||
Integer cDist = dLayers.firstKey();
|
||||
Integer cDist = hLayers.firstKey();
|
||||
|
||||
DistanceLayer cLayer = dLayers.get(cDist);
|
||||
while (cDist < dLayers.lastKey()) {
|
||||
Integer nDist = dLayers.higherKey(cDist);
|
||||
DistanceLayer nLayer = dLayers.get(nDist);
|
||||
DistanceLayer cLayer = hLayers.get(cDist);
|
||||
while (cDist < hLayers.lastKey()) {
|
||||
Integer nDist = hLayers.higherKey(cDist);
|
||||
DistanceLayer nLayer = hLayers.get(nDist);
|
||||
|
||||
var bothFeatures = Stream.concat(cLayer.getHorizonFeatures().stream(),nLayer.getHorizonFeatures().stream())
|
||||
.filter(isVisibleFilter)
|
||||
|
@ -209,7 +213,7 @@ public class Cli {
|
|||
LOG.info(" Removed {}", missingFeatures);
|
||||
}
|
||||
|
||||
continueMerge = mergeScore >= bothScore * 0.1;
|
||||
continueMerge = mergeScore >= bothScore;
|
||||
}
|
||||
|
||||
if (!continueMerge) {
|
||||
|
@ -258,7 +262,7 @@ public class Cli {
|
|||
int x = dc.getXAtBearing(feature.bearing);
|
||||
int y = dc.getYAtAngle(feature.visibleAngle);
|
||||
|
||||
boolean isVisible = DistanceLayer.isVisible(dLayers.values(), feature.distance, x, feature.visibleAngle);
|
||||
boolean isVisible = DistanceLayer.isVisible(hLayers.values(), feature.distance, x, feature.visibleAngle);
|
||||
if (!isVisible) {
|
||||
LOG.debug("Feature {} is hidden behind terrain", feature.name);
|
||||
continue;
|
||||
|
@ -286,7 +290,7 @@ public class Cli {
|
|||
|
||||
int x = dc.getXAtBearing(feature.bearing);
|
||||
|
||||
boolean isVisible = DistanceLayer.isVisible(dLayers.values(), feature.distance, x, feature.visibleAngle);
|
||||
boolean isVisible = DistanceLayer.isVisible(hLayers.values(), feature.distance, x, feature.visibleAngle);
|
||||
if (!isVisible) {
|
||||
LOG.debug("Feature {} is not visible, hidden behind terrain.", feature.name);
|
||||
continue;
|
||||
|
|
|
@ -56,21 +56,31 @@ public class DistanceLayer implements Comparable<DistanceLayer>, Cloneable {
|
|||
|
||||
double[] output = new double[near.data.length];
|
||||
|
||||
boolean anyNear = false;
|
||||
int countNear = 0;
|
||||
int countFar = 0;
|
||||
|
||||
for (int d = 0; d < near.data.length; d += 1) {
|
||||
double yNear = near.data[d];
|
||||
double yFar = far.data[d];
|
||||
|
||||
if (yNear > yFar) {
|
||||
if (yNear >= yFar) {
|
||||
output[d] = yNear;
|
||||
anyNear = true;
|
||||
countNear += 1;
|
||||
} else {
|
||||
output[d] = yFar;
|
||||
countFar += 1;
|
||||
}
|
||||
}
|
||||
|
||||
int tolerance = near.data.length / 100;
|
||||
|
||||
int outputNearDistance = anyNear ? near.nearDistance : far.nearDistance;
|
||||
int outputNearDistance = (countNear > tolerance) ? near.nearDistance : far.nearDistance;
|
||||
int outputFarDistance = (countFar > tolerance) ? far.farDistance : near.farDistance;
|
||||
|
||||
LOG.debug("Merging {}-{} ({}) with {}-{} ({}) {}",
|
||||
near.nearDistance, near.farDistance, countNear,
|
||||
far.nearDistance, far.farDistance, countFar,
|
||||
tolerance);
|
||||
|
||||
List<ObservedFeature> outHorizonFeatures = Stream.concat(this.horizonFeatures.parallelStream(), other.horizonFeatures.parallelStream())
|
||||
.filter(f -> isAtHorizon(f, output))
|
||||
|
@ -80,7 +90,7 @@ public class DistanceLayer implements Comparable<DistanceLayer>, Cloneable {
|
|||
outNonHorizonFeatures.addAll(this.nonHorizonFeatures);
|
||||
outNonHorizonFeatures.addAll(other.nonHorizonFeatures);
|
||||
|
||||
return new DistanceLayer(outputNearDistance, far.farDistance, output, outHorizonFeatures, outNonHorizonFeatures);
|
||||
return new DistanceLayer(outputNearDistance, outputFarDistance, output, outHorizonFeatures, outNonHorizonFeatures);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Reference in a new issue