package com.momega.spacesimulator.model; import org.apache.commons.math3.util.FastMath; /** * Created by martin on 8/12/14. */ public class CartesianState { private final static double MINOR_ERROR = Math.pow(10, -12); private Vector3d position; private Vector3d velocity; public Vector3d getPosition() { return position; } public void setPosition(Vector3d position) { this.position = position; } public Vector3d getVelocity() { return velocity; } public void setVelocity(Vector3d velocity) { this.velocity = velocity; } public CartesianState add(CartesianState other) { CartesianState result = new CartesianState(); result.setPosition(getPosition().add(other.getPosition())); result.setVelocity(getVelocity().add(other.getVelocity())); return result; } public CartesianState subtract(CartesianState other) { CartesianState result = new CartesianState(); result.setPosition(getPosition().subtract(other.getPosition())); result.setVelocity(getVelocity().subtract(other.getVelocity())); return result; } /** * Computes angular momentum * @return the angular momentum */ public Vector3d getAngularMomentum() { return position.cross(velocity); } public KeplerianElements toKeplerianElements(CelestialBody celestialBody, Timestamp newTimestamp) { double mi = celestialBody.getGravitationParameter(); return toKeplerianElements(celestialBody, newTimestamp, mi); } /** * Computes the keplerian elements from the cartesian coordinates. * @param referenceFrame the the reference frame of the central point. * @param newTimestamp new timestamp * @param mi the gravitation parameter (mass * G) * @return new instance of the keplerian elements. */ public KeplerianElements toKeplerianElements(ReferenceFrame referenceFrame, Timestamp newTimestamp, double mi) { Vector3d position = getPosition(); Vector3d velocity = getVelocity(); Vector3d hVector = getAngularMomentum(); double h = hVector.length(); double i = FastMath.acos(hVector.getZ() / h); Vector3d eVector = velocity.cross(hVector).scale(1/mi).subtract(position.normalize()); double e = eVector.length(); double a = h*h / (1- e*e) / mi; double OMEGA = 0d; double omega = 0d; // this is for circular, equatorial orbit double theta; if (i > MINOR_ERROR) { Vector3d nVector = new Vector3d(0, 0, 1).cross(hVector); double n = nVector.length(); OMEGA = FastMath.acos(nVector.getX() / n); if (nVector.getY() < 0) { OMEGA = 2 * Math.PI - OMEGA; } if (e>MINOR_ERROR) { omega = FastMath.acos(nVector.dot(eVector) / n / e); if (eVector.getZ() < 0) { omega = 2 * Math.PI - omega; } double thetaCos = eVector.dot(position) / position.length() / e; if (thetaCos<-1) { thetaCos = -1; } else if (thetaCos > 1) { thetaCos = 1; } theta = FastMath.acos(thetaCos); if (position.dot(velocity) <0) { theta = 2* Math.PI - theta; } } else { theta = FastMath.acos(nVector.dot(position) / n / position.length()); if (position.getZ()<0) { theta = 2* Math.PI - theta; } } } else { if (e>MINOR_ERROR) { omega = FastMath.acos(eVector.getX() / e); if (eVector.getY() < 0) { omega = 2 * Math.PI - omega; } theta = FastMath.acos(eVector.dot(position) / e / position.length()); if (position.dot(velocity) <0) { theta = 2* Math.PI - theta; } } else { theta = FastMath.acos(position.getX() / position.length()); if (position.getY() <0) { theta = 2* Math.PI - theta; } } } KeplerianElements keplerianElements = new KeplerianElements(); KeplerianOrbit keplerianOrbit = new KeplerianOrbit(); keplerianElements.setKeplerianOrbit(keplerianOrbit); keplerianOrbit.setReferenceFrame(referenceFrame); keplerianOrbit.setInclination(i); keplerianOrbit.setEccentricity(e); keplerianOrbit.setSemimajorAxis(a); keplerianOrbit.setAscendingNode(OMEGA); keplerianOrbit.setArgumentOfPeriapsis(omega); keplerianElements.setTrueAnomaly(theta); double meanMotion; if (keplerianOrbit.isHyperbolic()) { meanMotion = FastMath.sqrt(-mi / (a * a * a)); } else { meanMotion = FastMath.sqrt(mi / (a * a * a)); } double period = 2* Math.PI / meanMotion; keplerianOrbit.setMi(mi); keplerianOrbit.setMeanMotion(Double.valueOf(meanMotion)); keplerianOrbit.setPeriod(period); Timestamp TT = keplerianElements.timeToAngle(newTimestamp, 0.0, false); keplerianOrbit.setTimeOfPeriapsis(TT); return keplerianElements; } /** * Computers the relative keplerian elements of this cartesian state relative to some celestial body and * its current/future cartesian state * @param celestialBody * @param celestialBodyCartesianState * @param timestamp the timestamp * @return new instance of the keplerian elements */ public KeplerianElements computeRelativeKeplerianElements(ReferenceFrame referenceFrame, double gravitationalParameter, Timestamp timestamp) { CartesianState relativeCartesianState = subtract(referenceFrame.getCartesianState()); KeplerianElements relativeKeplerianElements = relativeCartesianState.toKeplerianElements(referenceFrame, timestamp, gravitationalParameter); return relativeKeplerianElements; } @Override public String toString() { return "CartesianState [position=" + position + ", velocity=" + velocity + "]"; } }