blob: 1b256dc8b91e2e722516b607a2d0d473c7036614 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2018 Agence spatiale canadienne / Canadian Space Agency
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pierre Allard,
* Regent L'Archeveque - initial API and implementation
*
* SPDX-License-Identifier: EPL-1.0
*
*******************************************************************************/
package org.eclipse.apogy.core.environment.orbit.earth.impl;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
import org.eclipse.apogy.core.environment.earth.ApogyEarthFacade;
import org.eclipse.apogy.core.environment.earth.GeographicCoordinates;
import org.eclipse.apogy.core.environment.orbit.earth.ApogyCoreEnvironmentOrbitEarthFacade;
import org.eclipse.apogy.core.environment.orbit.earth.ApogyCoreEnvironmentOrbitEarthFactory;
import org.eclipse.apogy.core.environment.orbit.earth.VisibilityPass;
import org.eclipse.apogy.core.environment.orbit.earth.VisibilityPassSpacecraftPosition;
import org.orekit.bodies.BodyShape;
import org.orekit.bodies.GeodeticPoint;
import org.orekit.bodies.OneAxisEllipsoid;
import org.orekit.frames.Frame;
import org.orekit.frames.FramesFactory;
import org.orekit.frames.LOFType;
import org.orekit.frames.LocalOrbitalFrame;
import org.orekit.frames.TopocentricFrame;
import org.orekit.propagation.Propagator;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.TimeScale;
import org.orekit.time.TimeScalesFactory;
import org.orekit.utils.Constants;
import org.orekit.utils.IERSConventions;
import org.orekit.utils.PVCoordinates;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class VisibilityPassSpacecraftPositionHistoryCustomImpl extends VisibilityPassSpacecraftPositionHistoryImpl {
private static final Logger Logger = LoggerFactory.getLogger(VisibilityPassSpacecraftPositionHistoryImpl.class);
@Override
public VisibilityPassSpacecraftPosition getClosestRangePosition() {
VisibilityPassSpacecraftPosition smallestRangePosition = null;
if (!getPositions().isEmpty()) {
// Finds the position with the highest elevation.
double closestRange = Double.POSITIVE_INFINITY;
Iterator<VisibilityPassSpacecraftPosition> it = getPositions().iterator();
while (it.hasNext()) {
VisibilityPassSpacecraftPosition p = it.next();
if (p.getRange() < closestRange) {
closestRange = p.getRange();
smallestRangePosition = p;
}
}
}
return smallestRangePosition;
}
@Override
public VisibilityPassSpacecraftPosition getHighestElevationPosition() {
VisibilityPassSpacecraftPosition higestElevationPosition = null;
if (!getPositions().isEmpty()) {
// Finds the position with the highest elevation.
double highestElevation = Double.NEGATIVE_INFINITY;
Iterator<VisibilityPassSpacecraftPosition> it = getPositions().iterator();
while (it.hasNext()) {
VisibilityPassSpacecraftPosition p = it.next();
if (p.getElevation() > highestElevation) {
highestElevation = p.getElevation();
higestElevationPosition = p;
}
}
}
return higestElevationPosition;
}
@Override
public VisibilityPassSpacecraftPosition getSmallestSpacecraftCrossTrackAnglePosition() {
VisibilityPassSpacecraftPosition smallestSpacecraftCrossTrackAnglePosition = null;
if (!getPositions().isEmpty()) {
// Finds the position with the smallest cross-track angle.
double smallestCrossTrackAngle = Double.MAX_VALUE;
Iterator<VisibilityPassSpacecraftPosition> it = getPositions().iterator();
while (it.hasNext()) {
VisibilityPassSpacecraftPosition p = it.next();
double crossTrackAngle = Math.abs(p.getSpacecraftCrossTrackAngle());
if (crossTrackAngle < smallestCrossTrackAngle) {
smallestCrossTrackAngle = crossTrackAngle;
smallestSpacecraftCrossTrackAnglePosition = p;
}
}
}
return smallestSpacecraftCrossTrackAnglePosition;
}
@Override
public void updateHistory() {
getPositions().clear();
// Computes the pass history
List<VisibilityPassSpacecraftPosition> pos = getVisibilityPassPositionHistory(getVisibilityPass(),
getTimeInterval());
getPositions().addAll(pos);
}
protected List<VisibilityPassSpacecraftPosition> getVisibilityPassPositionHistory(VisibilityPass pass,
double timeInterval) {
List<VisibilityPassSpacecraftPosition> positions = new ArrayList<VisibilityPassSpacecraftPosition>();
try {
Propagator propagator = pass.getOrbitModel().getOreKitPropagator();
Frame inertialFrame = FramesFactory.getEME2000();
LocalOrbitalFrame lof = new LocalOrbitalFrame(inertialFrame, LOFType.QSW, propagator, "QSW");
GeographicCoordinates coord = pass.getSurfaceLocation();
GeodeticPoint location = new GeodeticPoint(coord.getLatitude(), coord.getLongitude(), coord.getElevation());
Frame earthFrame = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
BodyShape earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
Constants.WGS84_EARTH_FLATTENING, earthFrame);
TopocentricFrame loc = new TopocentricFrame(earth, location, "location");
TimeScale utc = TimeScalesFactory.getUTC();
AbsoluteDate startAbsoluteDate = ApogyCoreEnvironmentOrbitEarthFacade.INSTANCE
.createAbsoluteDate(pass.getStartTime());
AbsoluteDate endAbsoluteDate = new AbsoluteDate(startAbsoluteDate, pass.getDuration());
AbsoluteDate extrapDate = startAbsoluteDate;
while (extrapDate.compareTo(endAbsoluteDate) <= 0) {
// We can simply get the position and velocity of spacecraft in
// LOC frame at any
// time
PVCoordinates pv = lof.getTransformTo(loc, extrapDate).transformPVCoordinates(PVCoordinates.ZERO);
// Calculate the range.
double range = pv.getPosition().getNorm();
// Calculate the range rate.
double rangeRate = Vector3D.dotProduct(pv.getPosition(), pv.getVelocity()) / pv.getPosition().getNorm();
// Calculate the azimuth.
double azimuth = Math.atan2(pv.getPosition().getX(), pv.getPosition().getY());
// Calculate the elevation.
double l = Math.sqrt((pv.getPosition().getX() * pv.getPosition().getX()
+ pv.getPosition().getY() * pv.getPosition().getY()));
double elevation = Math.atan2(pv.getPosition().getZ(), l);
PVCoordinates sc = lof.getTransformTo(earth.getBodyFrame(), extrapDate)
.transformPVCoordinates(PVCoordinates.ZERO);
PVCoordinates tgt = loc.getTransformTo(earth.getBodyFrame(), extrapDate)
.transformPVCoordinates(PVCoordinates.ZERO);
// Spacecraft position vector
Vector3D p = sc.getPosition();
// Spacecraft velocity vector
Vector3D v = sc.getVelocity();
// Spacecraft cross track vector.
Vector3D crossTrack = p.crossProduct(v);
// Target position vector.
Vector3D target = tgt.getPosition();
// Spacecraft to target vector.
Vector3D scToTarget = p.subtract(target);
// Projection of scToTarget onto the orbital plane.
Vector3D scToTargetOntoOrbitalPlane = projectOntoPlane(scToTarget, crossTrack.normalize());
// Projection of scToTarget onto the crosstrack plane.
Vector3D scToTargetOntoCrossTrackPlane = projectOntoPlane(scToTarget, v.normalize());
// double scAlongTrackAngle = getAngle(p,
// scToTargetOntoOrbitalPlane);
double scAlongTrackAngle = getAlongTrackAngle(p, scToTargetOntoOrbitalPlane, crossTrack);
// double scCrossTrackAngle = getAngle(p,
// scToTargetOntoCrossTrackPlane);
double scCrossTrackAngle = getCrossTrackAngle(p, scToTargetOntoCrossTrackPlane, v);
VisibilityPassSpacecraftPosition position = ApogyCoreEnvironmentOrbitEarthFactory.eINSTANCE
.createVisibilityPassSpacecraftPosition();
position.setTime(ApogyCoreEnvironmentOrbitEarthFacade.INSTANCE.createDate(extrapDate));
position.setRange(range);
position.setRangeRate(rangeRate);
position.setAzimuth(azimuth);
position.setElevation(elevation);
position.setSpacecraftCrossTrackAngle(scCrossTrackAngle);
position.setSpacecraftAlongTrackAngle(scAlongTrackAngle);
// Computes the position of the spacecraft.
GeodeticPoint scCoords = earth.transform(sc.getPosition(), earth.getBodyFrame(), extrapDate);
GeographicCoordinates geo = ApogyEarthFacade.INSTANCE.createGeographicCoordinates(
scCoords.getLongitude(), scCoords.getLatitude(), scCoords.getAltitude());
position.setSpacecraftCoordinates(geo);
positions.add(position);
extrapDate = new AbsoluteDate(extrapDate, timeInterval, utc);
}
// Start orbit propagation.
propagator.propagate(new AbsoluteDate(startAbsoluteDate, pass.getDuration()));
} catch (Throwable t) {
Logger.error(t.getMessage(), t);
}
return positions;
}
/**
* Computes the along track angle.
*
* @param p
* The position of the S/C.
* @param scToTargetOntoOrbitalPlane
* he position of the target projected onto the orbital plane.
* @param crossTrackVector
* The cross track vector.
* @return The along track angle.
*/
private double getAlongTrackAngle(Vector3D p, Vector3D scToTargetOntoOrbitalPlane, Vector3D crossTrackVector) {
// Finds the angle between the spacecraft position and the target
// position on
// the orbital plane.
double angle = getAngle(p, scToTargetOntoOrbitalPlane);
// Figures out the sign of the angle.
Vector3D rotation = p.crossProduct(scToTargetOntoOrbitalPlane).normalize();
double dotProduct = rotation.dotProduct(crossTrackVector.normalize());
if (dotProduct < 0) {
angle = -angle;
}
// return angle;
// DEBUG
return Math.abs(angle);
}
/**
* Computes the cross track angle.
*
* @param p
* The position of the S/C.
* @param scToTargetOntoCrossTrackPlane
* The position of the target projected onto the plane
* perpendicular to the orbital plane.
* @param alongTrackVector
* The along track vector.
* @return The cross track angle.
*/
private double getCrossTrackAngle(Vector3D p, Vector3D scToTargetOntoCrossTrackPlane, Vector3D alongTrackVector) {
// Finds the angle between the spacecraft position and the target
// position on
// the plane perpendicular to the orbital plane.
double angle = getAngle(p, scToTargetOntoCrossTrackPlane);
// Figures out the sign of the angle.
Vector3D rotation = p.crossProduct(scToTargetOntoCrossTrackPlane).normalize();
double dotProduct = rotation.dotProduct(alongTrackVector.normalize());
if (dotProduct > 0) {
angle = -angle;
}
return angle;
}
private double getAngle(Vector3D v1, Vector3D v2) {
double dotProduct = v1.dotProduct(v2);
return Math.acos(dotProduct / (v1.getNorm() * v2.getNorm()));
}
private Vector3D projectOntoPlane(Vector3D u, Vector3D planeNormal) {
double projUOnNormalLenght = u.dotProduct(planeNormal) / (planeNormal.getNormSq());
Vector3D projUOnNormal = planeNormal.scalarMultiply(projUOnNormalLenght);
return u.subtract(projUOnNormal);
}
} // VisibilityPassSpacecraftPositionHistoryImpl