- /* Copyright 2013-2019 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.los;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.List;
- import java.util.stream.Stream;
- import org.hipparchus.analysis.differentiation.DerivativeStructure;
- import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
- import org.hipparchus.geometry.euclidean.threed.Vector3D;
- import org.orekit.rugged.utils.DSGenerator;
- import org.orekit.time.AbsoluteDate;
- import org.orekit.utils.ParameterDriver;
- import org.orekit.utils.ParameterObserver;
- /** Builder for lines-of-sight list.
- * <p>
- * This class implements the <em>builder pattern</em> to create {@link TimeDependentLOS} instances.
- * It does so by using a <em>fluent API</em> in order to clarify reading and allow
- * later extensions with new configuration parameters.
- * </p>
- * <p>
- * This builder aims at creating lines-of-sight directions which are
- * the result of several transforms applied to an initial list of raw
- * directions. It therefore allows to take into account the optical
- * path due to mirrors and the alignments of sensors frames with respect
- * to a spacecraft.
- * </p>
- * @see TimeDependentLOS
- * @see <a href="https://en.wikipedia.org/wiki/Builder_pattern">Builder pattern (wikipedia)</a>
- * @see <a href="https://en.wikipedia.org/wiki/Fluent_interface">Fluent interface (wikipedia)</a>
- * @author Luc Maisonobe
- */
- public class LOSBuilder {
- /** Raw fixed line-of-sights. */
- private final List<Vector3D> rawLOS;
- /** Transforms to be applied. */
- private final List<LOSTransform> transforms;
- /** Flag for time-independent only transforms. */
- private boolean timeIndependent;
- /** Create builder.
- * @param rawLOS raw fixed lines-of-sight
- */
- public LOSBuilder(final List<Vector3D> rawLOS) {
- this.rawLOS = rawLOS;
- this.transforms = new ArrayList<LOSTransform>();
- this.timeIndependent = true;
- }
- /** Add a transform to be applied after the already registered transforms.
- * @param transform transform to be applied to the lines-of-sight
- * @return the builder instance
- */
- public LOSBuilder addTransform(final TimeIndependentLOSTransform transform) {
- transforms.add(new TransformAdapter(transform));
- return this;
- }
- /** Add a transform to be applied after the already registered transforms.
- * @param transform transform to be applied to the lines-of-sight
- * @return the builder instance
- */
- public LOSBuilder addTransform(final LOSTransform transform) {
- transforms.add(transform);
- timeIndependent = false;
- return this;
- }
- /** Build a lines-of-sight provider.
- * @return lines-of-sight provider
- */
- public TimeDependentLOS build() {
- if (timeIndependent) {
- // fast implementation for time-independent lines-of-sight
- return new FixedLOS(rawLOS, transforms);
- } else {
- // regular implementation, for time-dependent lines-of-sight
- return new TransformsSequenceLOS(rawLOS, transforms);
- }
- }
- /** Adapter from time-independent transform to time-dependent transform. */
- private static class TransformAdapter implements LOSTransform {
- /** Underlying transform. */
- private final TimeIndependentLOSTransform transform;
- /** Simple constructor.
- * @param transform underlying time-independent transform
- */
- TransformAdapter(final TimeIndependentLOSTransform transform) {
- this.transform = transform;
- }
- /** {@inheritDoc} */
- @Override
- public Vector3D transformLOS(final int i, final Vector3D los, final AbsoluteDate date) {
- return transform.transformLOS(i, los);
- }
- /** {@inheritDoc} */
- @Override
- public FieldVector3D<DerivativeStructure> transformLOS(final int i, final FieldVector3D<DerivativeStructure> los,
- final AbsoluteDate date, final DSGenerator generator) {
- return transform.transformLOS(i, los, generator);
- }
- /** {@inheritDoc} */
- @Override
- public Stream<ParameterDriver> getParametersDrivers() {
- return transform.getParametersDrivers();
- }
- }
- /** Implement time-independent LOS by recomputing directions by applying all transforms each time. */
- private static class TransformsSequenceLOS implements TimeDependentLOS {
- /** Raw direction. */
- private final Vector3D[] raw;
- /** Transforms to be applied. */
- private final List<LOSTransform> transforms;
- /** Simple constructor.
- * @param raw raw directions
- * @param transforms transforms to apply
- */
- TransformsSequenceLOS(final List<Vector3D> raw, final List<LOSTransform> transforms) {
- // copy the lists, to ensure immutability of the built object,
- // in case addTransform is called again after build
- // or the raw LOS list is changed by caller
- this.raw = new Vector3D[raw.size()];
- for (int i = 0; i < raw.size(); ++i) {
- this.raw[i] = raw.get(i);
- }
- this.transforms = new ArrayList<LOSTransform>(transforms);
- }
- /** {@inheritDoc} */
- public int getNbPixels() {
- return raw.length;
- }
- /** {@inheritDoc} */
- @Override
- public Vector3D getLOS(final int index, final AbsoluteDate date) {
- Vector3D los = raw[index];
- for (final LOSTransform transform : transforms) {
- los = transform.transformLOS(index, los, date);
- }
- return los.normalize();
- }
- /** {@inheritDoc} */
- @Override
- public FieldVector3D<DerivativeStructure> getLOSDerivatives(final int index, final AbsoluteDate date,
- final DSGenerator generator) {
- // the raw line of sights are considered to be constant
- FieldVector3D<DerivativeStructure> los =
- new FieldVector3D<DerivativeStructure>(generator.constant(raw[index].getX()),
- generator.constant(raw[index].getY()),
- generator.constant(raw[index].getZ()));
- // apply the transforms, which depend on parameters and hence may introduce non-zero derivatives
- for (final LOSTransform transform : transforms) {
- los = transform.transformLOS(index, los, date, generator);
- }
- return los.normalize();
- }
- @Override
- public Stream<ParameterDriver> getParametersDrivers() {
- Stream<ParameterDriver> drivers = Stream.<ParameterDriver>empty();
- for (final LOSTransform transform : transforms) {
- drivers = Stream.concat(drivers, transform.getParametersDrivers());
- }
- return drivers;
- }
- }
- /** Implement time-independent LOS by computing directions only when parameters are changed. */
- private static class FixedLOS extends TransformsSequenceLOS {
- /** transformed direction for los. */
- private final Vector3D[] transformed;
- /** Simple constructor.
- * @param raw raw directions
- * @param transforms transforms to apply (must be time-independent!)
- */
- FixedLOS(final List<Vector3D> raw, final List<LOSTransform> transforms) {
- super(raw, transforms);
- transformed = new Vector3D[raw.size()];
- // we will reset the transforms to null when parameters are changed
- final ParameterObserver resettingObserver = new ParameterObserver() {
- /** {@inheritDoc} */
- @Override
- public void valueChanged(final double previousValue, final ParameterDriver driver) {
- Arrays.fill(transformed, null);
- }
- };
- getParametersDrivers().forEach(driver -> {
- driver.addObserver(resettingObserver);
- });
- }
- /** {@inheritDoc} */
- @Override
- public Vector3D getLOS(final int index, final AbsoluteDate date) {
- if (transformed[index] == null) {
- // recompute the transformed los direction only if needed
- transformed[index] = super.getLOS(index, date);
- }
- return transformed[index];
- }
- }
- }