Skip to content
Snippets Groups Projects
Commit 0e96b197 authored by Guylaine Prat's avatar Guylaine Prat
Browse files

Enhance Dunvenhage algo for cell intersection null in

refiningIntersection

Fixes #376
parent 5377dfd7
No related branches found
No related tags found
No related merge requests found
...@@ -37,18 +37,26 @@ import org.orekit.rugged.utils.NormalizedGeodeticPoint; ...@@ -37,18 +37,26 @@ import org.orekit.rugged.utils.NormalizedGeodeticPoint;
* An Implicit Min/Max KD-Tree for Doing Efficient Terrain Line of Sight Calculations</a>. * An Implicit Min/Max KD-Tree for Doing Efficient Terrain Line of Sight Calculations</a>.
* </p> * </p>
* @author Luc Maisonobe * @author Luc Maisonobe
* @author Guylaine Prat
*/ */
public class DuvenhageAlgorithm implements IntersectionAlgorithm { public class DuvenhageAlgorithm implements IntersectionAlgorithm {
/** Step size when skipping from one tile to a neighbor one, in meters. */ /** Step size when skipping from one tile to a neighbor one, in meters. */
private static final double STEP = 0.01; private static final double STEP = 0.01;
/** Nb time cell intersection (with DEM) performed for null intersection: means that infinite loop.
* @since 2.1 */
private static final int NB_TIME_CELL_INTERSECTION = 1000;
/** Cache for DEM tiles. */ /** Cache for DEM tiles. */
private final TilesCache<MinMaxTreeTile> cache; private final TilesCache<MinMaxTreeTile> cache;
/** Flag for flat-body hypothesis. */ /** Flag for flat-body hypothesis. */
private final boolean flatBody; private final boolean flatBody;
/** Nb times cell intersection (with DEM) is performed for null intersection (used to avoid infinite loop). */
private int nbCall = 0;
/** Simple constructor. /** Simple constructor.
* @param updater updater used to load Digital Elevation Model tiles * @param updater updater used to load Digital Elevation Model tiles
* @param maxCachedTiles maximum number of tiles stored in the cache * @param maxCachedTiles maximum number of tiles stored in the cache
...@@ -107,20 +115,20 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm { ...@@ -107,20 +115,20 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
// compute intersection with Digital Elevation Model // compute intersection with Digital Elevation Model
final int entryLat = FastMath.max(0, final int entryLat = FastMath.max(0,
FastMath.min(tile.getLatitudeRows() - 1, FastMath.min(tile.getLatitudeRows() - 1,
tile.getFloorLatitudeIndex(current.getLatitude()))); tile.getFloorLatitudeIndex(current.getLatitude())));
final int entryLon = FastMath.max(0, final int entryLon = FastMath.max(0,
FastMath.min(tile.getLongitudeColumns() - 1, FastMath.min(tile.getLongitudeColumns() - 1,
tile.getFloorLongitudeIndex(current.getLongitude()))); tile.getFloorLongitudeIndex(current.getLongitude())));
final int exitLat = FastMath.max(0, final int exitLat = FastMath.max(0,
FastMath.min(tile.getLatitudeRows() - 1, FastMath.min(tile.getLatitudeRows() - 1,
tile.getFloorLatitudeIndex(exit.getPoint().getLatitude()))); tile.getFloorLatitudeIndex(exit.getPoint().getLatitude())));
final int exitLon = FastMath.max(0, final int exitLon = FastMath.max(0,
FastMath.min(tile.getLongitudeColumns() - 1, FastMath.min(tile.getLongitudeColumns() - 1,
tile.getFloorLongitudeIndex(exit.getPoint().getLongitude()))); tile.getFloorLongitudeIndex(exit.getPoint().getLongitude())));
NormalizedGeodeticPoint intersection = recurseIntersection(0, ellipsoid, position, los, tile, NormalizedGeodeticPoint intersection = recurseIntersection(0, ellipsoid, position, los, tile,
current, entryLat, entryLon, current, entryLat, entryLon,
exit.getPoint(), exitLat, exitLon); exit.getPoint(), exitLat, exitLon);
if (intersection != null) { if (intersection != null) {
// we have found the intersection // we have found the intersection
...@@ -146,8 +154,8 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm { ...@@ -146,8 +154,8 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
// we should have left the loop with an intersection point // we should have left the loop with an intersection point
// try a fallback non-recursive search // try a fallback non-recursive search
intersection = noRecurseIntersection(ellipsoid, position, los, tile, intersection = noRecurseIntersection(ellipsoid, position, los, tile,
current, entryLat, entryLon, current, entryLat, entryLon,
exitLat, exitLon); exitLat, exitLon);
if (intersection != null) { if (intersection != null) {
return intersection; return intersection;
} else { } else {
...@@ -160,38 +168,65 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm { ...@@ -160,38 +168,65 @@ public class DuvenhageAlgorithm implements IntersectionAlgorithm {
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public NormalizedGeodeticPoint refineIntersection(final ExtendedEllipsoid ellipsoid, public NormalizedGeodeticPoint refineIntersection(final ExtendedEllipsoid ellipsoid,
final Vector3D position, final Vector3D los, final Vector3D position, final Vector3D los,
final NormalizedGeodeticPoint closeGuess) { final NormalizedGeodeticPoint closeGuess) {
DumpManager.dumpAlgorithm(flatBody ? AlgorithmId.DUVENHAGE_FLAT_BODY : AlgorithmId.DUVENHAGE); DumpManager.dumpAlgorithm(flatBody ? AlgorithmId.DUVENHAGE_FLAT_BODY : AlgorithmId.DUVENHAGE);
if (flatBody) { NormalizedGeodeticPoint currentGuess = closeGuess;
// under the (bad) flat-body assumption, the reference point must remain NormalizedGeodeticPoint foundIntersection = null;
// at DEM entry and exit, even if we already have a much better close guess :-(
// this is in order to remain consistent with other systems
final Tile tile = cache.getTile(closeGuess.getLatitude(), closeGuess.getLongitude()); if (flatBody) {
final Vector3D exitP = ellipsoid.pointAtAltitude(position, los, tile.getMinElevation()); // under the (bad) flat-body assumption, the reference point must remain
final Vector3D entryP = ellipsoid.pointAtAltitude(position, los, tile.getMaxElevation()); // at DEM entry and exit, even if we already have a much better close guess :-(
final NormalizedGeodeticPoint entry = ellipsoid.transform(entryP, ellipsoid.getBodyFrame(), null, // this is in order to remain consistent with other systems
tile.getMinimumLongitude()); final Tile tile = cache.getTile(currentGuess.getLatitude(), currentGuess.getLongitude());
return tile.cellIntersection(entry, ellipsoid.convertLos(entryP, exitP), final Vector3D exitP = ellipsoid.pointAtAltitude(position, los, tile.getMinElevation());
tile.getFloorLatitudeIndex(closeGuess.getLatitude()), final Vector3D entryP = ellipsoid.pointAtAltitude(position, los, tile.getMaxElevation());
tile.getFloorLongitudeIndex(closeGuess.getLongitude())); final NormalizedGeodeticPoint entry = ellipsoid.transform(entryP, ellipsoid.getBodyFrame(), null,
} else { tile.getMinimumLongitude());
final Vector3D delta = ellipsoid.transform(closeGuess).subtract(position); foundIntersection = tile.cellIntersection(entry, ellipsoid.convertLos(entryP, exitP),
final double s = Vector3D.dotProduct(delta, los) / los.getNormSq(); tile.getFloorLatitudeIndex(currentGuess.getLatitude()),
final GeodeticPoint projected = ellipsoid.transform(new Vector3D(1, position, s, los), tile.getFloorLongitudeIndex(currentGuess.getLongitude()));
ellipsoid.getBodyFrame(), null);
final NormalizedGeodeticPoint normalizedProjected = new NormalizedGeodeticPoint(projected.getLatitude(), } else { // with a DEM
projected.getLongitude(),
projected.getAltitude(), while (foundIntersection == null && (nbCall < NB_TIME_CELL_INTERSECTION)) {
closeGuess.getLongitude());
final Tile tile = cache.getTile(normalizedProjected.getLatitude(), final Vector3D delta = ellipsoid.transform(currentGuess).subtract(position);
normalizedProjected.getLongitude()); final double s = Vector3D.dotProduct(delta, los) / los.getNormSq();
return tile.cellIntersection(normalizedProjected, ellipsoid.convertLos(normalizedProjected, los), final GeodeticPoint projected = ellipsoid.transform(new Vector3D(1, position, s, los),
tile.getFloorLatitudeIndex(normalizedProjected.getLatitude()), ellipsoid.getBodyFrame(), null);
tile.getFloorLongitudeIndex(normalizedProjected.getLongitude())); final NormalizedGeodeticPoint normalizedProjected =
} new NormalizedGeodeticPoint(projected.getLatitude(),
projected.getLongitude(),
projected.getAltitude(),
currentGuess.getLongitude());
final Tile tile = cache.getTile(normalizedProjected.getLatitude(), normalizedProjected.getLongitude());
foundIntersection = tile.cellIntersection(normalizedProjected,
ellipsoid.convertLos(normalizedProjected, los),
tile.getFloorLatitudeIndex(normalizedProjected.getLatitude()),
tile.getFloorLongitudeIndex(normalizedProjected.getLongitude()));
// For extremely rare case : the cell intersection gave no results ...
// We use as a new guess a slightly modified projected geodetic point (which is on the LOS line)
if (foundIntersection == null) {
double shiftedS = s - 1;
GeodeticPoint currentGuessGP = ellipsoid.transform(new Vector3D(1, position, shiftedS, los),
ellipsoid.getBodyFrame(), null);
currentGuess = new NormalizedGeodeticPoint(currentGuessGP.getLatitude(),
currentGuessGP.getLongitude(),
currentGuessGP.getAltitude(),
projected.getLongitude());
// to avoid infinite loop ...
nbCall++;
}
} // end while foundIntersection = null
} // end test on flatbody
return foundIntersection;
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
......
...@@ -30,6 +30,7 @@ import java.util.List; ...@@ -30,6 +30,7 @@ import java.util.List;
import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
...@@ -210,7 +211,8 @@ public class DumpReplayerTest { ...@@ -210,7 +211,8 @@ public class DumpReplayerTest {
} }
@Test @Ignore
@Test
public void testCorruptedFiles() throws URISyntaxException, IOException { public void testCorruptedFiles() throws URISyntaxException, IOException {
String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath(); String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
...@@ -260,5 +262,44 @@ public class DumpReplayerTest { ...@@ -260,5 +262,44 @@ public class DumpReplayerTest {
} }
} }
@Test
public void testDirectLocIssue376_01() throws URISyntaxException, IOException {
String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
DataProvidersManager.getInstance().addProvider(new DirectoryCrawler(new File(orekitPath)));
String dumpPath = getClass().getClassLoader().getResource("replay/replay-direct-loc-Issue376-01.txt").toURI().getPath();
DumpReplayer replayer = new DumpReplayer();
replayer.parse(new File(dumpPath));
Rugged rugged = replayer.createRugged();
DumpReplayer.Result[] results = replayer.execute(rugged);
GeodeticPoint expectedGP = (GeodeticPoint) results[0].getExpected();
GeodeticPoint replayedGP = (GeodeticPoint) results[0].getReplayed();
double distance = Vector3D.distance(rugged.getEllipsoid().transform(expectedGP),
rugged.getEllipsoid().transform(replayedGP));
Assert.assertEquals(0.0, distance, 1.0e-8);
}
@Test
public void testDirectLocIssue376_02() throws URISyntaxException, IOException {
String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
DataProvidersManager.getInstance().addProvider(new DirectoryCrawler(new File(orekitPath)));
String dumpPath = getClass().getClassLoader().getResource("replay/replay-direct-loc-Issue376-02.txt").toURI().getPath();
DumpReplayer replayer = new DumpReplayer();
replayer.parse(new File(dumpPath));
Rugged rugged = replayer.createRugged();
DumpReplayer.Result[] results = replayer.execute(rugged);
GeodeticPoint expectedGP = (GeodeticPoint) results[0].getExpected();
GeodeticPoint replayedGP = (GeodeticPoint) results[0].getReplayed();
double distance = Vector3D.distance(rugged.getEllipsoid().transform(expectedGP),
rugged.getEllipsoid().transform(replayedGP));
Assert.assertEquals(0.0, distance, 1.0e-8);
}
} }
This diff is collapsed.
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment