LOSBuilder.java

  1. /* Copyright 2013-2019 CS Systèmes d'Information
  2.  * Licensed to CS Systèmes d'Information (CS) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * CS licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *   http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.orekit.rugged.los;

  18. import java.util.ArrayList;
  19. import java.util.Arrays;
  20. import java.util.List;
  21. import java.util.stream.Stream;

  22. import org.hipparchus.analysis.differentiation.DerivativeStructure;
  23. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  24. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  25. import org.orekit.rugged.utils.DSGenerator;
  26. import org.orekit.time.AbsoluteDate;
  27. import org.orekit.utils.ParameterDriver;
  28. import org.orekit.utils.ParameterObserver;

  29. /** Builder for lines-of-sight list.
  30.  * <p>
  31.  * This class implements the <em>builder pattern</em> to create {@link TimeDependentLOS} instances.
  32.  * It does so by using a <em>fluent API</em> in order to clarify reading and allow
  33.  * later extensions with new configuration parameters.
  34.  * </p>
  35.  * <p>
  36.  * This builder aims at creating lines-of-sight directions which are
  37.  * the result of several transforms applied to an initial list of raw
  38.  * directions. It therefore allows to take into account the optical
  39.  * path due to mirrors and the alignments of sensors frames with respect
  40.  * to a spacecraft.
  41.  * </p>
  42.  * @see TimeDependentLOS
  43.  * @see <a href="https://en.wikipedia.org/wiki/Builder_pattern">Builder pattern (wikipedia)</a>
  44.  * @see <a href="https://en.wikipedia.org/wiki/Fluent_interface">Fluent interface (wikipedia)</a>
  45.  * @author Luc Maisonobe
  46.  */
  47. public class LOSBuilder {

  48.     /** Raw fixed line-of-sights. */
  49.     private final List<Vector3D> rawLOS;

  50.     /** Transforms to be applied. */
  51.     private final List<LOSTransform> transforms;

  52.     /** Flag for time-independent only transforms. */
  53.     private boolean timeIndependent;

  54.     /** Create builder.
  55.      * @param rawLOS raw fixed lines-of-sight
  56.      */
  57.     public LOSBuilder(final List<Vector3D> rawLOS) {
  58.         this.rawLOS          = rawLOS;
  59.         this.transforms      = new ArrayList<LOSTransform>();
  60.         this.timeIndependent = true;
  61.     }

  62.     /** Add a transform to be applied after the already registered transforms.
  63.      * @param transform transform to be applied to the lines-of-sight
  64.      * @return the builder instance
  65.      */
  66.     public LOSBuilder addTransform(final TimeIndependentLOSTransform transform) {
  67.         transforms.add(new TransformAdapter(transform));
  68.         return this;
  69.     }

  70.     /** Add a transform to be applied after the already registered transforms.
  71.      * @param transform transform to be applied to the lines-of-sight
  72.      * @return the builder instance
  73.      */
  74.     public LOSBuilder addTransform(final LOSTransform transform) {
  75.         transforms.add(transform);
  76.         timeIndependent = false;
  77.         return this;
  78.     }

  79.     /** Build a lines-of-sight provider.
  80.      * @return lines-of-sight provider
  81.      */
  82.     public TimeDependentLOS build() {

  83.         if (timeIndependent) {
  84.             // fast implementation for time-independent lines-of-sight
  85.             return new FixedLOS(rawLOS, transforms);
  86.         } else {
  87.             // regular implementation, for time-dependent lines-of-sight
  88.             return new TransformsSequenceLOS(rawLOS, transforms);
  89.         }

  90.     }

  91.     /** Adapter from time-independent transform to time-dependent transform. */
  92.     private static class TransformAdapter implements LOSTransform {

  93.         /** Underlying transform. */
  94.         private final TimeIndependentLOSTransform transform;

  95.         /** Simple constructor.
  96.          * @param transform underlying time-independent transform
  97.          */
  98.         TransformAdapter(final TimeIndependentLOSTransform transform) {
  99.             this.transform = transform;
  100.         }

  101.         /** {@inheritDoc} */
  102.         @Override
  103.         public Vector3D transformLOS(final int i, final Vector3D los, final AbsoluteDate date) {
  104.             return transform.transformLOS(i, los);
  105.         }

  106.         /** {@inheritDoc} */
  107.         @Override
  108.         public FieldVector3D<DerivativeStructure> transformLOS(final int i, final FieldVector3D<DerivativeStructure> los,
  109.                                                                final AbsoluteDate date, final DSGenerator generator) {
  110.             return transform.transformLOS(i, los, generator);
  111.         }

  112.         /** {@inheritDoc} */
  113.         @Override
  114.         public Stream<ParameterDriver> getParametersDrivers() {
  115.             return transform.getParametersDrivers();
  116.         }

  117.     }

  118.     /** Implement time-independent LOS by recomputing directions by applying all transforms each time. */
  119.     private static class TransformsSequenceLOS implements TimeDependentLOS {

  120.         /** Raw direction. */
  121.         private final Vector3D[] raw;

  122.         /** Transforms to be applied. */
  123.         private final List<LOSTransform> transforms;

  124.         /** Simple constructor.
  125.          * @param raw raw directions
  126.          * @param transforms transforms to apply
  127.          */
  128.         TransformsSequenceLOS(final List<Vector3D> raw, final List<LOSTransform> transforms) {

  129.             // copy the lists, to ensure immutability of the built object,
  130.             // in case addTransform is called again after build
  131.             // or the raw LOS list is changed by caller
  132.             this.raw = new Vector3D[raw.size()];
  133.             for (int i = 0; i < raw.size(); ++i) {
  134.                 this.raw[i] = raw.get(i);
  135.             }

  136.             this.transforms = new ArrayList<LOSTransform>(transforms);

  137.         }

  138.         /** {@inheritDoc} */
  139.         public int getNbPixels() {
  140.             return raw.length;
  141.         }

  142.         /** {@inheritDoc} */
  143.         @Override
  144.         public Vector3D getLOS(final int index, final AbsoluteDate date) {
  145.             Vector3D los = raw[index];
  146.             for (final LOSTransform transform : transforms) {
  147.                 los = transform.transformLOS(index, los, date);
  148.             }
  149.             return los.normalize();
  150.         }

  151.         /** {@inheritDoc} */
  152.         @Override
  153.         public FieldVector3D<DerivativeStructure> getLOSDerivatives(final int index, final AbsoluteDate date,
  154.                                                                     final DSGenerator generator) {

  155.             // the raw line of sights are considered to be constant
  156.             FieldVector3D<DerivativeStructure> los =
  157.                             new FieldVector3D<DerivativeStructure>(generator.constant(raw[index].getX()),
  158.                                                                    generator.constant(raw[index].getY()),
  159.                                                                    generator.constant(raw[index].getZ()));

  160.             // apply the transforms, which depend on parameters and hence may introduce non-zero derivatives
  161.             for (final LOSTransform transform : transforms) {
  162.                 los = transform.transformLOS(index, los, date, generator);
  163.             }

  164.             return los.normalize();

  165.         }

  166.         @Override
  167.         public Stream<ParameterDriver> getParametersDrivers() {
  168.             Stream<ParameterDriver> drivers = Stream.<ParameterDriver>empty();
  169.             for (final LOSTransform transform : transforms) {
  170.                 drivers = Stream.concat(drivers, transform.getParametersDrivers());
  171.             }
  172.             return drivers;
  173.         }

  174.     }

  175.     /** Implement time-independent LOS by computing directions only when parameters are changed. */
  176.     private static class FixedLOS extends TransformsSequenceLOS {

  177.         /** transformed direction for los. */
  178.         private final Vector3D[] transformed;

  179.         /** Simple constructor.
  180.          * @param raw raw directions
  181.          * @param transforms transforms to apply (must be time-independent!)
  182.          */
  183.         FixedLOS(final List<Vector3D> raw, final List<LOSTransform> transforms) {

  184.             super(raw, transforms);
  185.             transformed = new Vector3D[raw.size()];

  186.             // we will reset the transforms to null when parameters are changed
  187.             final ParameterObserver resettingObserver = new ParameterObserver() {
  188.                 /** {@inheritDoc} */
  189.                 @Override
  190.                 public void valueChanged(final double previousValue, final ParameterDriver driver) {
  191.                     Arrays.fill(transformed, null);
  192.                 }
  193.             };
  194.             getParametersDrivers().forEach(driver -> {
  195.                 driver.addObserver(resettingObserver);
  196.             });
  197.         }

  198.         /** {@inheritDoc} */
  199.         @Override
  200.         public Vector3D getLOS(final int index, final AbsoluteDate date) {
  201.             if (transformed[index] == null) {
  202.                 // recompute the transformed los direction only if needed
  203.                 transformed[index] = super.getLOS(index, date);
  204.             }
  205.             return transformed[index];
  206.         }

  207.     }

  208. }