Skip to content
Snippets Groups Projects
Commit 7f1f2448 authored by Luc Maisonobe's avatar Luc Maisonobe
Browse files

Added a CONSTANT_ELEVATION_OVER_ELLIPSOID algorithm.

This algorithm is similar in spirit to the IGNORE_DEM_USE_ELLIPSOID, but
with a user-specified elevation instead of always using 0.0 elevation.

Implements feature #187.
parent b85e6442
No related branches found
No related tags found
No related merge requests found
......@@ -57,10 +57,25 @@ public enum AlgorithmId {
*/
BASIC_SLOW_EXHAUSTIVE_SCAN_FOR_TESTS_ONLY,
/** Algorithm that simply uses a constant elevation over ellipsoid.
* <p>
* Intersections are computed only with respect to the reference ellipsoid
* and a user-specified elevation. If the user-specified elevation is 0.0,
* then this algorithm is equivalent to {@link #IGNORE_DEM_USE_ELLIPSOID},
* only slower.
* </p>
*/
CONSTANT_ELEVATION_OVER_ELLIPSOID,
/** Dummy algorithm that simply ignores the Digital Elevation Model.
* <p>
* Intersections are computed only with respect to the reference ellipsoid.
* </p>
* <p>
* This algorithm is equivalent to {@link #CONSTANT_ELEVATION_OVER_ELLIPSOID}
* when the elevation is set to 0.0, but this one is much faster in this
* specific case.
* </p>
*/
IGNORE_DEM_USE_ELLIPSOID
......
......@@ -39,6 +39,7 @@ import org.orekit.propagation.sampling.OrekitFixedStepHandler;
import org.orekit.rugged.errors.RuggedException;
import org.orekit.rugged.errors.RuggedMessages;
import org.orekit.rugged.intersection.BasicScanAlgorithm;
import org.orekit.rugged.intersection.ConstantElevationAlgorithm;
import org.orekit.rugged.intersection.IgnoreDEMAlgorithm;
import org.orekit.rugged.intersection.IntersectionAlgorithm;
import org.orekit.rugged.intersection.duvenhage.DuvenhageAlgorithm;
......@@ -96,6 +97,10 @@ public class RuggedBuilder {
/** Updater used to load Digital Elevation Model tiles. */
private TileUpdater tileUpdater;
/** Constant elevation over ellipsoid.
* used only with {@link AlgorithmId#CONSTANT_ELEVATION_OVER_ELLIPSOID. */
private double constantElevation;
/** Maximum number of tiles stored in the cache. */
private int maxCachedTiles;
......@@ -162,6 +167,7 @@ public class RuggedBuilder {
*/
public RuggedBuilder() {
sensors = new ArrayList<LineSensor>();
constantElevation = Double.NaN;
lightTimeCorrection = true;
aberrationOfLightCorrection = true;
}
......@@ -211,10 +217,21 @@ public class RuggedBuilder {
/** Set the algorithm to use for Digital Elevation Model intersection.
* <p>
* Note that when the specified algorithm is {@link AlgorithmId#IGNORE_DEM_USE_ELLIPSOID},
* then calling {@link #setDigitalElevationModel(TileUpdater, int)} is irrelevant and can either
* be completely avoided, or the method can be called with an updater set to {@code null}.
* For all other algorithms, the updater must be properly configured.
* Note that some algorithms require specific other methods to be called too:
* <ul>
* <li>{@link AlgorithmId#DUVENHAGE DUVENHAGE},
* {@link AlgorithmId#DUVENHAGE_FLAT_BODY DUVENHAGE_FLAT_BODY}
* and {@link AlgorithmId#BASIC_SLOW_EXHAUSTIVE_SCAN_FOR_TESTS_ONLY
* BASIC_SLOW_EXHAUSTIVE_SCAN_FOR_TESTS_ONLY} all
* require {@link #setDigitalElevationModel(TileUpdater, int) setDigitalElevationModel}
* to be called,</li>
* <li>{@link AlgorithmId#CONSTANT_ELEVATION_OVER_ELLIPSOID
* CONSTANT_ELEVATION_OVER_ELLIPSOID} requires
* {@link #setConstantElevation(double) setConstantElevation} to be called,</li>
* <li>{@link AlgorithmId#IGNORE_DEM_USE_ELLIPSOID
* IGNORE_DEM_USE_ELLIPSOID} does not require
* any methods tobe called.</li>
* </ul>
* </p>
* @param algorithmID identifier of algorithm to use for Digital Elevation Model intersection
* @return the builder instance
......@@ -239,9 +256,12 @@ public class RuggedBuilder {
/** Set the user-provided {@link TileUpdater tile updater}.
* <p>
* Note that when the algorithm specified in {@link #setAlgorithm(AlgorithmId)}
* is {@link AlgorithmId#IGNORE_DEM_USE_ELLIPSOID},then this method becomes irrelevant
* and can either be not called at all, or it can be called with an updater set to
* {@code null}. For all other algorithms, the updater must be properly configured.
* is either {@link AlgorithmId#CONSTANT_ELEVATION_OVER_ELLIPSOID
* CONSTANT_ELEVATION_OVER_ELLIPSOID} or {@link
* AlgorithmId#IGNORE_DEM_USE_ELLIPSOID IGNORE_DEM_USE_ELLIPSOID},
* then this method becomes irrelevant and can either be not called at all,
* or it can be called with an updater set to {@code null}. For all other
* algorithms, the updater must be properly configured.
* </p>
* @param tileUpdater updater used to load Digital Elevation Model tiles
* @param maxCachedTiles maximum number of tiles stored in the cache
......@@ -267,6 +287,33 @@ public class RuggedBuilder {
return tileUpdater;
}
/** Set the user-provided constant elevation model.
* <p>
* Note that this method is relevant <em>only</em> if the algorithm specified
* in {@link #setAlgorithm(AlgorithmId)} is {@link
* AlgorithmId#CONSTANT_ELEVATION_OVER_ELLIPSOID CONSTANT_ELEVATION_OVER_ELLIPSOID}.
* If it is called for this algorithm, the elevation set here will be ignored.
* </p>
* @param constantElevation constant elevation to use
* @return the builder instance
* @see #setAlgorithm(AlgorithmId)
* @see #getConstantElevation()
*/
// CHECKSTYLE: stop HiddenField check
public RuggedBuilder setConstantElevation(final double constantElevation) {
// CHECKSTYLE: resume HiddenField check
this.constantElevation = constantElevation;
return this;
}
/** Get the constant elevation over ellipsoid to use with {@link AlgorithmId#CONSTANT_ELEVATION_OVER_ELLIPSOID}.
* @return updater used to load Digital Elevation Model tiles
* @see #setConstantElevation(double)
*/
public double getConstantElevation() {
return constantElevation;
}
/** Get the maximum number of tiles stored in the cache.
* @return maximum number of tiles stored in the cache
* @see #setDigitalElevationModel(TileUpdater, int)
......@@ -903,10 +950,12 @@ public class RuggedBuilder {
* @param algorithmID intersection algorithm identifier
* @param updater updater used to load Digital Elevation Model tiles
* @param maxCachedTiles maximum number of tiles stored in the cache
* @param constantElevation constant elevation over ellipsoid
* @return selected algorithm
*/
private static IntersectionAlgorithm createAlgorithm(final AlgorithmId algorithmID,
final TileUpdater updater, final int maxCachedTiles) {
final TileUpdater updater, final int maxCachedTiles,
final double constantElevation) {
// set up the algorithm
switch (algorithmID) {
......@@ -916,6 +965,8 @@ public class RuggedBuilder {
return new DuvenhageAlgorithm(updater, maxCachedTiles, true);
case BASIC_SLOW_EXHAUSTIVE_SCAN_FOR_TESTS_ONLY :
return new BasicScanAlgorithm(updater, maxCachedTiles);
case CONSTANT_ELEVATION_OVER_ELLIPSOID :
return new ConstantElevationAlgorithm(constantElevation);
case IGNORE_DEM_USE_ELLIPSOID :
return new IgnoreDEMAlgorithm();
default :
......@@ -934,11 +985,17 @@ public class RuggedBuilder {
if (algorithmID == null) {
throw new RuggedException(RuggedMessages.UNINITIALIZED_CONTEXT, "RuggedBuilder.setAlgorithmID()");
}
if (algorithmID != AlgorithmId.IGNORE_DEM_USE_ELLIPSOID && (tileUpdater == null)) {
throw new RuggedException(RuggedMessages.UNINITIALIZED_CONTEXT, "RuggedBuilder.setDigitalElevationModel()");
if (algorithmID == AlgorithmId.CONSTANT_ELEVATION_OVER_ELLIPSOID) {
if (Double.isNaN(constantElevation)) {
throw new RuggedException(RuggedMessages.UNINITIALIZED_CONTEXT, "RuggedBuilder.setConstantElevation()");
}
} else if (algorithmID != AlgorithmId.IGNORE_DEM_USE_ELLIPSOID) {
if (tileUpdater == null) {
throw new RuggedException(RuggedMessages.UNINITIALIZED_CONTEXT, "RuggedBuilder.setDigitalElevationModel()");
}
}
createInterpolatorIfNeeded();
return new Rugged(createAlgorithm(algorithmID, tileUpdater, maxCachedTiles), ellipsoid,
return new Rugged(createAlgorithm(algorithmID, tileUpdater, maxCachedTiles, constantElevation), ellipsoid,
lightTimeCorrection, aberrationOfLightCorrection, scToBody, sensors);
}
......
/* Copyright 2013-2015 CS Systèmes d'Information
* Licensed to CS Systèmes d'Information (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.rugged.intersection;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
import org.orekit.bodies.GeodeticPoint;
import org.orekit.errors.OrekitException;
import org.orekit.rugged.errors.RuggedException;
import org.orekit.rugged.utils.ExtendedEllipsoid;
import org.orekit.rugged.utils.NormalizedGeodeticPoint;
/** Intersection ignoring Digital Elevation Model.
* <p>
* This dummy implementation simply uses the ellipsoid itself.
* </p>
* @author Luc Maisonobe
*/
public class ConstantElevationAlgorithm implements IntersectionAlgorithm {
/** Constant elevation over ellipsoid. */
private final double constantElevation;
/** Simple constructor.
* @param constantElevation constant elevation over ellipsoid
*/
public ConstantElevationAlgorithm(final double constantElevation) {
this.constantElevation = constantElevation;
}
/** {@inheritDoc} */
@Override
public NormalizedGeodeticPoint intersection(final ExtendedEllipsoid ellipsoid,
final Vector3D position, final Vector3D los)
throws RuggedException {
try {
final Vector3D p = ellipsoid.pointAtAltitude(position, los, constantElevation);
final GeodeticPoint gp = ellipsoid.transform(p, ellipsoid.getFrame(), null);
return new NormalizedGeodeticPoint(gp.getLatitude(), gp.getLongitude(), gp.getAltitude(), 0.0);
} catch (OrekitException oe) {
throw new RuggedException(oe, oe.getSpecifier(), oe.getParts());
}
}
/** {@inheritDoc} */
@Override
public NormalizedGeodeticPoint refineIntersection(final ExtendedEllipsoid ellipsoid,
final Vector3D position, final Vector3D los,
final NormalizedGeodeticPoint closeGuess)
throws RuggedException {
try {
final Vector3D p = ellipsoid.pointAtAltitude(position, los, constantElevation);
final GeodeticPoint gp = ellipsoid.transform(p, ellipsoid.getFrame(), null);
return new NormalizedGeodeticPoint(gp.getLatitude(), gp.getLongitude(), gp.getAltitude(),
closeGuess.getLongitude());
} catch (OrekitException oe) {
throw new RuggedException(oe, oe.getSpecifier(), oe.getParts());
}
}
/** {@inheritDoc}
* <p>
* As this algorithm uses a constant elevation,
* this method always returns the same value.
* </p>
*/
@Override
public double getElevation(final double latitude, final double longitude) {
return constantElevation;
}
}
......@@ -26,12 +26,13 @@ a nadir view), some algorithms are more suitable than others. This computation i
programming unit possible in the Rugged library and an interface is defined with several different
implementations among which user can select.
Four different algorithms are predefined in Rugged:
Five different algorithms are predefined in Rugged:
* a recursive algorithm based on Bernardt Duvenhage's 2009 paper
[Using An Implicit Min/Max KD-Tree for Doing Efficient Terrain Line of Sight Calculations](http://researchspace.csir.co.za/dspace/bitstream/10204/3041/1/Duvenhage_2009.pdf)
* an alternate version of the Duvenhage algorithm using flat-body hypothesis,
* a basic scan algorithm sequentially checking all pixels in the rectangular array defined by Digital Elevation Model entry and exit points,
* an algorithm that ignores the Digital Elevation Model and uses a constant elevation over the ellipsoid.
* a no-operation algorithm that ignores the Digital Elevation Model and uses only the ellipsoid.
It is expected that other algorithms like line-stepping (perhaps using Bresenham line algorithm) will be added afterwards.
......
......@@ -22,6 +22,12 @@
<body>
<release version="1.0" date="TBD"
description="TBD">
<action dev="luc" type="add" >
Added a CONSTANT_ELEVATION_OVER_ELLIPSOID algorithm, similar in spirit
to the IGNORE_DEM_USE_ELLIPSOID, but with a user-specified elevation
instead of always using 0.0 elevation.
Implements feature #187.
</action>
<action dev="luc" type="add" due-to="Espen Bjørntvedt">
Added Norwegian translation of error messages.
</action>
......
......@@ -147,6 +147,7 @@ public abstract class AbstractAlgorithmTest {
Vector3D position = state.getPVCoordinates(earth.getBodyFrame()).getPosition();
Vector3D los = groundP.subtract(position);
System.out.println(los.normalize());
GeodeticPoint result = algorithm.refineIntersection(earth, position, los,
algorithm.intersection(earth, position, los));
checkIntersection(position, los, result);
......
/* Copyright 2013-2015 CS Systèmes d'Information
* Licensed to CS Systèmes d'Information (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.rugged.intersection;
import java.io.File;
import java.net.URISyntaxException;
import org.apache.commons.math3.geometry.euclidean.threed.Rotation;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
import org.apache.commons.math3.util.FastMath;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.orekit.attitudes.Attitude;
import org.orekit.data.DataProvidersManager;
import org.orekit.data.DirectoryCrawler;
import org.orekit.errors.OrekitException;
import org.orekit.frames.FramesFactory;
import org.orekit.orbits.CartesianOrbit;
import org.orekit.propagation.SpacecraftState;
import org.orekit.rugged.errors.RuggedException;
import org.orekit.rugged.intersection.duvenhage.DuvenhageAlgorithm;
import org.orekit.rugged.raster.CheckedPatternElevationUpdater;
import org.orekit.rugged.raster.TileUpdater;
import org.orekit.rugged.utils.ExtendedEllipsoid;
import org.orekit.rugged.utils.NormalizedGeodeticPoint;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.TimeScalesFactory;
import org.orekit.utils.Constants;
import org.orekit.utils.IERSConventions;
import org.orekit.utils.PVCoordinates;
public class ConstantElevationAlgorithmTest {
@Test
public void testDuvenhageComparison() throws RuggedException {
final Vector3D los = new Vector3D(-0.626242839, 0.0124194184, -0.7795291301);
IntersectionAlgorithm duvenhage = new DuvenhageAlgorithm(new CheckedPatternElevationUpdater(FastMath.toRadians(1.0),
256, 150.0, 150.0),
8, false);
IntersectionAlgorithm constantElevation = new ConstantElevationAlgorithm(150.0);
NormalizedGeodeticPoint gpRef = duvenhage.intersection(earth, state.getPVCoordinates().getPosition(), los);
NormalizedGeodeticPoint gpConst = constantElevation.intersection(earth, state.getPVCoordinates().getPosition(), los);
Assert.assertEquals(gpRef.getLatitude(), gpConst.getLatitude(), 1.0e-6);
Assert.assertEquals(gpRef.getLongitude(), gpConst.getLongitude(), 1.0e-6);
Assert.assertEquals(gpRef.getAltitude(), gpConst.getAltitude(), 1.0e-3);
Assert.assertEquals(150.0, constantElevation.getElevation(0.0, 0.0), 1.0e-3);
// shift longitude 2π
NormalizedGeodeticPoint shifted =
constantElevation.refineIntersection(earth, state.getPVCoordinates().getPosition(), los,
new NormalizedGeodeticPoint(gpConst.getLatitude(),
gpConst.getLongitude(),
gpConst.getAltitude(),
2 * FastMath.PI));
Assert.assertEquals(2 * FastMath.PI + gpConst.getLongitude(), shifted.getLongitude(), 1.0e-6);
}
@Test
public void testIgnoreDEMComparison() throws RuggedException {
final Vector3D los = new Vector3D(-0.626242839, 0.0124194184, -0.7795291301);
IntersectionAlgorithm ignore = new IgnoreDEMAlgorithm();
IntersectionAlgorithm constantElevation = new ConstantElevationAlgorithm(0.0);
NormalizedGeodeticPoint gpRef = ignore.intersection(earth, state.getPVCoordinates().getPosition(), los);
NormalizedGeodeticPoint gpConst = constantElevation.intersection(earth, state.getPVCoordinates().getPosition(), los);
Assert.assertEquals(gpRef.getLatitude(), gpConst.getLatitude(), 1.0e-6);
Assert.assertEquals(gpRef.getLongitude(), gpConst.getLongitude(), 1.0e-6);
Assert.assertEquals(gpRef.getAltitude(), gpConst.getAltitude(), 1.0e-3);
Assert.assertEquals(0.0, constantElevation.getElevation(0.0, 0.0), 1.0e-3);
// shift longitude 2π
NormalizedGeodeticPoint shifted =
constantElevation.refineIntersection(earth, state.getPVCoordinates().getPosition(), los,
new NormalizedGeodeticPoint(gpConst.getLatitude(),
gpConst.getLongitude(),
gpConst.getAltitude(),
2 * FastMath.PI));
Assert.assertEquals(2 * FastMath.PI + gpConst.getLongitude(), shifted.getLongitude(), 1.0e-6);
}
@Before
public void setUp()
throws OrekitException, URISyntaxException {
String path = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
DataProvidersManager.getInstance().addProvider(new DirectoryCrawler(new File(path)));
earth = new ExtendedEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
Constants.WGS84_EARTH_FLATTENING,
FramesFactory.getITRF(IERSConventions.IERS_2010, true));
AbsoluteDate crossing = new AbsoluteDate("2012-01-07T11:50:04.935272115", TimeScalesFactory.getUTC());
state = new SpacecraftState(new CartesianOrbit(new PVCoordinates(new Vector3D( 412324.544397459,
-4325872.329311633,
5692124.593989491),
new Vector3D(-1293.174701214779,
-5900.764863603793,
-4378.671036383179)),
FramesFactory.getEME2000(),
crossing,
Constants.EIGEN5C_EARTH_MU),
new Attitude(crossing,
FramesFactory.getEME2000(),
new Rotation(-0.17806699079182878,
0.60143347387211290,
-0.73251248177468900,
-0.26456641385623986,
true),
new Vector3D(-4.289600857433520e-05,
-1.039151496480297e-03,
5.811423736843181e-05),
Vector3D.ZERO));
}
@After
public void tearDown() {
earth = null;
updater = null;
state = null;
}
protected ExtendedEllipsoid earth;
protected TileUpdater updater;
protected SpacecraftState state;
}
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