From c74acdd61284714204ec543f7eb877df3aee0160 Mon Sep 17 00:00:00 2001
From: Luc Maisonobe <luc@orekit.org>
Date: Tue, 11 Mar 2014 21:28:20 +0100
Subject: [PATCH] Split top level class from DEM intersection algorithm.

---
 .../java/org/orekit/rugged/api/Rugged.java    |  20 +-
 .../{AbstractRugged.java => RuggedImpl.java}  | 196 ++++++++++--------
 .../java/org/orekit/rugged/core/Sensor.java   | 112 ++++++++++
 .../rugged/core/SpacecraftToObservedBody.java |  86 ++++++++
 .../core/dem/IntersectionAlgorithm.java       |  44 ++++
 ...gedRugged.java => DuvenhageAlgorithm.java} |  16 +-
 6 files changed, 379 insertions(+), 95 deletions(-)
 rename rugged-core/src/main/java/org/orekit/rugged/core/{AbstractRugged.java => RuggedImpl.java} (70%)
 create mode 100644 rugged-core/src/main/java/org/orekit/rugged/core/Sensor.java
 create mode 100644 rugged-core/src/main/java/org/orekit/rugged/core/SpacecraftToObservedBody.java
 create mode 100644 rugged-core/src/main/java/org/orekit/rugged/core/dem/IntersectionAlgorithm.java
 rename rugged-core/src/main/java/org/orekit/rugged/core/duvenhage/{DuvenhagedRugged.java => DuvenhageAlgorithm.java} (77%)

diff --git a/rugged-api/src/main/java/org/orekit/rugged/api/Rugged.java b/rugged-api/src/main/java/org/orekit/rugged/api/Rugged.java
index 543b0130..a140df95 100644
--- a/rugged-api/src/main/java/org/orekit/rugged/api/Rugged.java
+++ b/rugged-api/src/main/java/org/orekit/rugged/api/Rugged.java
@@ -39,25 +39,31 @@ public interface Rugged {
         ITRF, GTOD
     }
 
+    /** Enumerate for Digital Elevation Model intersection. */
+    enum Algorithm {
+        DUVENHAGE
+    }
+
     /** Set up general context.
      * <p>
      * This method is the first one that must be called, otherwise the
      * other methods will fail due to uninitialized context.
      * </p>
      * @param orekitDataDir top directory for Orekit data
-     * @param referenceDate reference date from which all other dates
-     * are computed
-     * @param ellipsoid reference ellipsoid
-     * @param inertialFrameName inertial frame
-     * @param bodyRotatingFrame body rotating frame
+     * @param referenceDate reference date from which all other dates are computed
+     * @param algorithmID identifier of algorithm to use for Digital Elevation Model intersection
+     * @param ellipsoidID identifier of reference ellipsoid
+     * @param inertialFrameID identifier of inertial frame
+     * @param bodyRotatingFrameID identifier of body rotating frame
      * @param positionsVelocities satellite position and velocity
      * @param pvInterpolationOrder order to use for position/velocity interpolation
      * @param quaternions satellite quaternions
      * @param aInterpolationOrder order to use for attitude interpolation
      * @exception RuggedException if data needed for some frame cannot be loaded
      */
-    void setGeneralContext(File orekitDataDir, String referenceDate, Ellipsoid ellipsoid,
-                           InertialFrame inertialFrame, BodyRotatingFrame bodyRotatingFrame,
+    void setGeneralContext(File orekitDataDir, String referenceDate,
+                           Algorithm algorithmID, Ellipsoid ellipsoidID,
+                           InertialFrame inertialFrameID, BodyRotatingFrame bodyRotatingFrameID,
                            List<SatellitePV> positionsVelocities, int pvInterpolationOrder,
                            List<SatelliteQ> quaternions, int aInterpolationOrder)
         throws RuggedException;
diff --git a/rugged-core/src/main/java/org/orekit/rugged/core/AbstractRugged.java b/rugged-core/src/main/java/org/orekit/rugged/core/RuggedImpl.java
similarity index 70%
rename from rugged-core/src/main/java/org/orekit/rugged/core/AbstractRugged.java
rename to rugged-core/src/main/java/org/orekit/rugged/core/RuggedImpl.java
index 732fa085..cb4db05a 100644
--- a/rugged-core/src/main/java/org/orekit/rugged/core/AbstractRugged.java
+++ b/rugged-core/src/main/java/org/orekit/rugged/core/RuggedImpl.java
@@ -29,12 +29,14 @@ import org.orekit.attitudes.Attitude;
 import org.orekit.attitudes.AttitudeProvider;
 import org.orekit.attitudes.TabulatedProvider;
 import org.orekit.bodies.BodyShape;
+import org.orekit.bodies.GeodeticPoint;
 import org.orekit.bodies.OneAxisEllipsoid;
 import org.orekit.data.DataProvidersManager;
 import org.orekit.data.DirectoryCrawler;
 import org.orekit.errors.OrekitException;
 import org.orekit.frames.Frame;
 import org.orekit.frames.FramesFactory;
+import org.orekit.frames.Transform;
 import org.orekit.orbits.CartesianOrbit;
 import org.orekit.orbits.Orbit;
 import org.orekit.propagation.Propagator;
@@ -47,6 +49,9 @@ import org.orekit.rugged.api.RuggedMessages;
 import org.orekit.rugged.api.SatellitePV;
 import org.orekit.rugged.api.SatelliteQ;
 import org.orekit.rugged.api.SensorPixel;
+import org.orekit.rugged.api.TileUpdater;
+import org.orekit.rugged.core.dem.IntersectionAlgorithm;
+import org.orekit.rugged.core.duvenhage.DuvenhageAlgorithm;
 import org.orekit.time.AbsoluteDate;
 import org.orekit.time.TimeScale;
 import org.orekit.time.TimeScalesFactory;
@@ -56,10 +61,10 @@ import org.orekit.utils.ImmutableTimeStampedCache;
 import org.orekit.utils.PVCoordinates;
 import org.orekit.utils.PVCoordinatesProvider;
 
-/** Boilerplate part for direct and inverse localization.
+/** Top level Rugged class.
  * @author Luc Maisonobe
  */
-public abstract class AbstractRugged implements Rugged {
+public class RuggedImpl implements Rugged {
 
     /** UTC time scale. */
     private TimeScale utc;
@@ -73,37 +78,48 @@ public abstract class AbstractRugged implements Rugged {
     /** Reference ellipsoid. */
     private BodyShape shape;
 
-    /** Orbit propagator/interpolator. */
-    private PVCoordinatesProvider pvProvider;
-
-    /** Attitude propagator/interpolator. */
-    private AttitudeProvider aProvider;
+    /** Converter between spacecraft and body. */
+    private SpacecraftToObservedBody scToBody;
 
     /** Sensors. */
     private final Map<String, Sensor> sensors;
 
+    /** DEM intersection algorithm. */
+    private IntersectionAlgorithm algorithm;
+
     /** Simple constructor.
      */
-    protected AbstractRugged() {
+    protected RuggedImpl() {
         sensors = new HashMap<String, Sensor>();
     }
 
     /** {@inheritDoc} */
     @Override
     public  void setGeneralContext(final File orekitDataDir, final String referenceDate,
-                                   final Ellipsoid ellipsoid,
-                                   final InertialFrame inertialFrame,
-                                   final BodyRotatingFrame bodyRotatingFrame,
+                                   final Algorithm algorithmID, final Ellipsoid ellipsoidID,
+                                   final InertialFrame inertialFrameID,
+                                   final BodyRotatingFrame bodyRotatingFrameID,
                                    final List<SatellitePV> positionsVelocities, final int pvInterpolationOrder,
                                    final List<SatelliteQ> quaternions, final int aInterpolationOrder)
         throws RuggedException {
         try {
+
+            // time reference
             utc                = selectTimeScale(orekitDataDir);
             this.referenceDate = new AbsoluteDate(referenceDate, utc);
-            frame              = selectInertialFrame(inertialFrame);
-            shape              = selectEllipsoid(ellipsoid, selectBodyRotatingFrame(bodyRotatingFrame));
-            pvProvider         = selectPVCoordinatesProvider(positionsVelocities, pvInterpolationOrder);
-            aProvider          = selectAttitudeProvider(quaternions, aInterpolationOrder);
+
+            // space reference
+            frame = selectInertialFrame(inertialFrameID);
+            shape = selectEllipsoid(ellipsoidID, selectBodyRotatingFrame(bodyRotatingFrameID));
+
+            // orbit/attitude to body converter
+            final PVCoordinatesProvider pvProvider = selectPVCoordinatesProvider(positionsVelocities, pvInterpolationOrder);
+            final AttitudeProvider aProvider = selectAttitudeProvider(quaternions, aInterpolationOrder);
+            scToBody = new SpacecraftToObservedBody(frame, shape.getBodyFrame(), pvProvider, aProvider);
+
+            // intersection algorithm
+            algorithm = selectAlgorithm(algorithmID);
+
         } catch (OrekitException oe) {
             throw new RuggedException(oe, oe.getSpecifier(), oe.getParts().clone());
         }
@@ -115,45 +131,64 @@ public abstract class AbstractRugged implements Rugged {
      * other methods will fail due to uninitialized context.
      * </p>
      * @param orekitDataDir top directory for Orekit data
-     * @param referenceDate reference date
-     * @param ellipsoid reference ellipsoid
-     * @param inertialFrameName inertial frame
-     * @param bodyRotatingFrame body rotating frame
+     * @param referenceDate reference date from which all other dates are computed
+     * @param algorithmID identifier of algorithm to use for Digital Elevation Model intersection
+     * @param ellipsoidID identifier of reference ellipsoid
+     * @param inertialFrameID identifier of inertial frame
+     * @param bodyRotatingFrameID identifier of body rotating frame
      * @param propagator global propagator
      * @exception RuggedException if data needed for some frame cannot be loaded
      */
     public void setGeneralContext(final File orekitDataDir, final AbsoluteDate referenceDate,
-                                  final Ellipsoid ellipsoid,
-                                  final InertialFrame inertialFrame,
-                                  final BodyRotatingFrame bodyRotatingFrame,
+                                  final Algorithm algorithmID, final Ellipsoid ellipsoidID,
+                                  final InertialFrame inertialFrameID,
+                                  final BodyRotatingFrame bodyRotatingFrameID,
                                   final Propagator propagator)
         throws RuggedException {
         try {
+
+            // time reference
             utc                = selectTimeScale(orekitDataDir);
             this.referenceDate = referenceDate;
-            frame              = selectInertialFrame(inertialFrame);
-            shape              = selectEllipsoid(ellipsoid, selectBodyRotatingFrame(bodyRotatingFrame));
-            pvProvider         = propagator;
-            aProvider          = propagator.getAttitudeProvider();
+
+            // space reference
+            frame = selectInertialFrame(inertialFrameID);
+            shape = selectEllipsoid(ellipsoidID, selectBodyRotatingFrame(bodyRotatingFrameID));
+
+            // orbit/attitude to body converter
+            scToBody = new SpacecraftToObservedBody(frame, shape.getBodyFrame(),
+                                                    propagator, propagator.getAttitudeProvider());
+
+            // intersection algorithm
+            algorithm = selectAlgorithm(algorithmID);
+
         } catch (OrekitException oe) {
             throw new RuggedException(oe, oe.getSpecifier(), oe.getParts().clone());
         }
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public void setUpTilesManagement(TileUpdater updater, int maxCachedTiles) {
+        algorithm.setUpTilesManagement(updater, maxCachedTiles);
+    }
+
     /** {@inheritDoc} */
     @Override
     public void setSensor(final String sensorName, final List<PixelLOS> linesOfSigth, final LineDatation datationModel) {
-        final List<Line> los = new ArrayList<Line>(linesOfSigth.size());
+        final List<Vector3D> positions = new ArrayList<Vector3D>(linesOfSigth.size());
+        final List<Line>     los       = new ArrayList<Line>(linesOfSigth.size());
         for (final PixelLOS plos : linesOfSigth) {
-            los.add(new Line(new Vector3D(plos.getPx(),
-                                          plos.getPy(),
-                                          plos.getPz()),
+            Vector3D p = new Vector3D(plos.getPx(), plos.getPy(), plos.getPz());
+            positions.add(p);
+            los.add(new Line(p,
                              new Vector3D(plos.getPx() + plos.getDx(),
                                           plos.getPy() + plos.getDy(),
                                           plos.getPz() + plos.getDz()),
                              1.0e-3));
         }
-        sensors.put(sensorName, new Sensor(sensorName, los, datationModel));
+        final Sensor sensor = new Sensor(sensorName, referenceDate, datationModel, positions, los);
+        sensors.put(sensor.getName(), sensor);
     }
 
     /** Select time scale Orekit data.
@@ -171,7 +206,7 @@ public abstract class AbstractRugged implements Rugged {
     }
 
     /** Select inertial frame.
-     * @param inertialFrameName inertial frame
+     * @param inertialFrameName inertial frame identifier
      * @return inertial frame
      * @exception OrekitException if data needed for some frame cannot be loaded
      */
@@ -198,7 +233,7 @@ public abstract class AbstractRugged implements Rugged {
     }
 
     /** Select body rotating frame.
-     * @param bodyRotatingFrame body rotating frame
+     * @param bodyRotatingFrame body rotating frame identifier
      * @return body rotating frame
      * @exception OrekitException if data needed for some frame cannot be loaded
      */
@@ -219,7 +254,7 @@ public abstract class AbstractRugged implements Rugged {
     }
 
     /** Select ellipsoid.
-     * @param ellipsoid reference ellipsoid
+     * @param ellipsoid reference ellipsoid identifier
      * @param bodyFrame body rotating frame
      * @exception OrekitException if data needed for some frame cannot be loaded
      */
@@ -302,6 +337,23 @@ public abstract class AbstractRugged implements Rugged {
 
     }
 
+    /** Select DEM intersection algorithm.
+     * @param algorithm intersection algorithm identifier
+     * @return selected algorithm
+     */
+    private IntersectionAlgorithm selectAlgorithm(final Algorithm algorithm) {
+        
+        // set up the algorithm
+        switch (algorithm) {
+            case DUVENHAGE :
+                return new DuvenhageAlgorithm();
+            default :
+                // this should never happen
+                throw RuggedException.createInternalError(null);
+        }
+
+    }
+
     /** {@inheritDoc} */
     @Override
     public GroundPoint[] directLocalization(String sensorName, double lineNumber)
@@ -313,13 +365,32 @@ public abstract class AbstractRugged implements Rugged {
             // select the sensor
             final Sensor sensor = getSensor(sensorName);
 
-            // find the spacecraft state when line is active
-            final AbsoluteDate date = referenceDate.shiftedBy(sensor.getDatationModel().getDate(lineNumber));
-            final PVCoordinates pv  = pvProvider.getPVCoordinates(date, shape.getBodyFrame());
-            final Attitude attitude = aProvider.getAttitude(pvProvider, date, shape.getBodyFrame());
+            // compute once the transform between spacecraft and observed body
+            final AbsoluteDate date = sensor.getDate(lineNumber);
+            final Transform t = scToBody.getTransform(date);
+
+            // compute localization of each pixel
+            final GroundPoint[] gp = new GroundPoint[sensor.getNbPixels()];
+            for (int i = 0; i < gp.length; ++i) {
+
+                // compute intersection with ellipsoid
+                final Vector3D position = t.transformPosition(sensor.getPosition(i));
+                final Line     line     = t.transformLine(sensor.getLos(i));
+                final GeodeticPoint ellipsoidIntersection =
+                        shape.getIntersectionPoint(line, position, shape.getBodyFrame(), date);
+                final Vector3D directionTopo =
+                        new Vector3D(Vector3D.dotProduct(line.getDirection(), ellipsoidIntersection.getEast()),
+                                     Vector3D.dotProduct(line.getDirection(), ellipsoidIntersection.getNorth()),
+                                     Vector3D.dotProduct(line.getDirection(), ellipsoidIntersection.getZenith()));
+
+                // compute intersection with Digital Elevation Model
+                gp[i] = algorithm.intersection(ellipsoidIntersection.getLatitude(),
+                                               ellipsoidIntersection.getLongitude(),
+                                               directionTopo);
 
-            // TODO: implement direct localization
-            throw RuggedException.createInternalError(null);
+            }
+
+            return gp;
 
         } catch (OrekitException oe) {
             throw new RuggedException(oe, oe.getSpecifier(), oe.getParts());
@@ -361,49 +432,4 @@ public abstract class AbstractRugged implements Rugged {
         return sensor;
     }
 
-    /** Local container for sensor data. */
-    private static class Sensor {
-
-        /** Name of the sensor. */
-        private String name;
-
-        /** Pixels lines-of-sight. */
-        private List<Line> los;
-
-        /** Datation model. */
-        private LineDatation datationModel;
-
-        /** Simple constructor.
-         * @param name name of the sensor
-         * @param los pixels lines-of-sight
-         * @param datationModel datation model
-         */
-        public Sensor(final String name, final List<Line> los, final LineDatation datationModel) {
-            this.name          = name;
-            this.los           = los;
-            this.datationModel = datationModel;
-        }
-
-        /** Get the name of the sensor.
-         * @preturn name of the sensor
-         */
-        public String getName() {
-            return name;
-        }
-
-        /** Get the pixels lines-of-sight.
-         * @return pixels lines-of-sight
-         */
-        public List<Line> getLos() {
-            return los;
-        }
-
-        /** Get the datation model.
-         * @return datation model
-         */
-        public LineDatation getDatationModel() {
-            return datationModel;
-        }
-
-    }
 }
diff --git a/rugged-core/src/main/java/org/orekit/rugged/core/Sensor.java b/rugged-core/src/main/java/org/orekit/rugged/core/Sensor.java
new file mode 100644
index 00000000..22bd2bb8
--- /dev/null
+++ b/rugged-core/src/main/java/org/orekit/rugged/core/Sensor.java
@@ -0,0 +1,112 @@
+/* Copyright 2013-2014 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.core;
+
+import java.util.List;
+
+import org.apache.commons.math3.geometry.euclidean.threed.Line;
+import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
+import org.orekit.rugged.api.LineDatation;
+import org.orekit.time.AbsoluteDate;
+
+/** Container for sensor data.
+ * <p>
+ * Instances of this class are guaranteed to be immutable.
+ * </p>
+ * @author Luc Maisonobe
+ */
+class Sensor {
+
+    /** Name of the sensor. */
+    private final String name;
+
+    /** Reference date. */
+    private final AbsoluteDate referenceDate;
+
+    /** Pixels positions. */
+    private final List<Vector3D> positions;
+
+    /** Pixels lines-of-sight. */
+    private final List<Line> los;
+
+    /** Datation model. */
+    private final LineDatation datationModel;
+
+    /** Simple constructor.
+     * @param name name of the sensor
+     * @param referenceDate reference date
+     * @param positions pixels positions
+     * @param los pixels lines-of-sight
+     * @param datationModel datation model
+     */
+    public Sensor(final String name,
+                  final AbsoluteDate referenceDate, final LineDatation datationModel,
+                  final List<Vector3D> positions, final List<Line> los) {
+        this.name          = name;
+        this.referenceDate = referenceDate;
+        this.positions     = positions;
+        this.los           = los;
+        this.datationModel = datationModel;
+    }
+
+    /** Get the name of the sensor.
+     * @preturn name of the sensor
+     */
+    public String getName() {
+        return name;
+    }
+
+    /** Get the number of pixels.
+     * @return number of pixels
+     */
+    public int getNbPixels() {
+        return positions.size();
+    }
+
+    /** Get pixel position.
+     * @param i pixel index (must be between 0 and {@link #getNbPixels()}
+     * @return pixel position
+     */
+    public Vector3D getPosition(final int i) {
+        return positions.get(i);
+    }
+
+    /** Get the pixel line-of-sight.
+     * @param i pixel index (must be between 0 and {@link #getNbPixels()}
+     * @return pixel line-of-sight
+     */
+    public Line getLos(final int i) {
+        return los.get(i);
+    }
+
+    /** Get the date.
+     * @param lineNumber line number
+     * @return date corresponding to line number
+     */
+    public AbsoluteDate getDate(final double lineNumber) {
+        return referenceDate.shiftedBy(datationModel.getDate(lineNumber));
+    }
+
+    /** Get the line number.
+     * @param date date
+     * @return line number corresponding to date
+     */
+    public double getLine(final AbsoluteDate date) {
+        return datationModel.getLine(date.durationFrom(referenceDate));
+    }
+
+}
diff --git a/rugged-core/src/main/java/org/orekit/rugged/core/SpacecraftToObservedBody.java b/rugged-core/src/main/java/org/orekit/rugged/core/SpacecraftToObservedBody.java
new file mode 100644
index 00000000..5ec98eec
--- /dev/null
+++ b/rugged-core/src/main/java/org/orekit/rugged/core/SpacecraftToObservedBody.java
@@ -0,0 +1,86 @@
+/* Copyright 2013-2014 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.core;
+
+import org.orekit.attitudes.Attitude;
+import org.orekit.attitudes.AttitudeProvider;
+import org.orekit.errors.OrekitException;
+import org.orekit.frames.Frame;
+import org.orekit.frames.Transform;
+import org.orekit.frames.TransformProvider;
+import org.orekit.time.AbsoluteDate;
+import org.orekit.utils.PVCoordinates;
+import org.orekit.utils.PVCoordinatesProvider;
+
+/** Transform provider from Spacecraft frame to observed body frame.
+ * @author Luc Maisonobe
+ */
+class SpacecraftToObservedBody implements TransformProvider {
+
+    /** Serializable UID. */
+    private static final long serialVersionUID = 20140311L;
+
+    /** Inertial frame. */
+    private Frame inertialFrame;
+
+    /** Observed body frame. */
+    private Frame bodyFrame;
+
+    /** Orbit propagator/interpolator. */
+    private PVCoordinatesProvider pvProvider;
+
+    /** Attitude propagator/interpolator. */
+    private AttitudeProvider aProvider;
+
+    /** Simple constructor.
+     * @param inertialFrame inertial frame
+     * @param bodyFrame observed body frame
+     * @param pvProvider orbit propagator/interpolator
+     * @param aProvider attitude propagator/interpolator
+     */
+    protected SpacecraftToObservedBody(final Frame inertialFrame, final Frame bodyFrame,
+                                       final PVCoordinatesProvider pvProvider,
+                                       final AttitudeProvider aProvider) {
+        this.inertialFrame = inertialFrame;
+        this.bodyFrame     = bodyFrame;
+        this.pvProvider    = pvProvider;
+        this.aProvider     = aProvider;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Transform getTransform(final AbsoluteDate date)
+        throws OrekitException {
+
+        // propagate/interpolate orbit and attitude
+        final PVCoordinates pv    = pvProvider.getPVCoordinates(date, inertialFrame);
+        final Attitude attitude   = aProvider.getAttitude(pvProvider, date, inertialFrame);
+
+        // compute transform from spacecraft frame to inertial frame
+        final Transform scToInert = new Transform(date,
+                                                  new Transform(date, attitude.getOrientation().revert()),
+                                                  new Transform(date, pv));
+
+        // compute transform from inertial frame to body frame
+        final Transform inertToBody = inertialFrame.getTransformTo(bodyFrame, date);
+
+        // combine transforms
+        return new Transform(date, scToInert, inertToBody);
+
+    }
+
+}
diff --git a/rugged-core/src/main/java/org/orekit/rugged/core/dem/IntersectionAlgorithm.java b/rugged-core/src/main/java/org/orekit/rugged/core/dem/IntersectionAlgorithm.java
new file mode 100644
index 00000000..d50fc051
--- /dev/null
+++ b/rugged-core/src/main/java/org/orekit/rugged/core/dem/IntersectionAlgorithm.java
@@ -0,0 +1,44 @@
+/* Copyright 2013-2014 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.core.dem;
+
+import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
+import org.orekit.bodies.GeodeticPoint;
+import org.orekit.rugged.api.GroundPoint;
+import org.orekit.rugged.api.TileUpdater;
+
+/** Interface for Digital Elevation Model algorithm.
+ * @author Luc Maisonobe
+ */
+public interface IntersectionAlgorithm {
+
+    /** Set up the tiles management.
+     * @param updater updater used to load Digital Elevation Model tiles
+     * @param maxCachedTiles maximum number of tiles stored in the cache
+     */
+    void setUpTilesManagement(TileUpdater updater, int maxCachedTiles);
+
+    /** Compute intersection of line with Digital Elevation Model.
+     * @param latitude latitude of line arrival at zero altitude
+     * @param longitude longitude of line arrival at zero altitude
+     * @param direction arrival direction in (East, North, Zenith) frame
+     * (the direction is from spacecraft to ground)
+     * @return point at which the line first enters ground
+     */
+    GroundPoint intersection(double latitude0, double longitude0, Vector3D direction);
+
+}
diff --git a/rugged-core/src/main/java/org/orekit/rugged/core/duvenhage/DuvenhagedRugged.java b/rugged-core/src/main/java/org/orekit/rugged/core/duvenhage/DuvenhageAlgorithm.java
similarity index 77%
rename from rugged-core/src/main/java/org/orekit/rugged/core/duvenhage/DuvenhagedRugged.java
rename to rugged-core/src/main/java/org/orekit/rugged/core/duvenhage/DuvenhageAlgorithm.java
index 59bc991a..cd9b889d 100644
--- a/rugged-core/src/main/java/org/orekit/rugged/core/duvenhage/DuvenhagedRugged.java
+++ b/rugged-core/src/main/java/org/orekit/rugged/core/duvenhage/DuvenhageAlgorithm.java
@@ -16,8 +16,10 @@
  */
 package org.orekit.rugged.core.duvenhage;
 
+import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
+import org.orekit.rugged.api.GroundPoint;
 import org.orekit.rugged.api.TileUpdater;
-import org.orekit.rugged.core.AbstractRugged;
+import org.orekit.rugged.core.dem.IntersectionAlgorithm;
 import org.orekit.rugged.core.dem.TilesCache;
 
 /** Direct and inverse localization using Duvenhage's algorithm.
@@ -28,14 +30,14 @@ import org.orekit.rugged.core.dem.TilesCache;
  * </p>
  * @author Luc Maisonobe
  */
-public class DuvenhagedRugged extends AbstractRugged {
+public class DuvenhageAlgorithm implements IntersectionAlgorithm {
 
     /** Cache for DEM tiles. */
     private TilesCache<MinMaxTreeTile> cache;
 
     /** Simple constructor.
      */
-    public DuvenhagedRugged() {
+    public DuvenhageAlgorithm() {
     }
 
     /** {@inheritDoc} */
@@ -45,4 +47,12 @@ public class DuvenhagedRugged extends AbstractRugged {
                                                updater, maxCachedTiles);
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public GroundPoint intersection(double latitude0, double longitude0,
+                                    Vector3D direction) {
+        // TODO: compute intersection
+        return null;
+    }
+
 }
-- 
GitLab