/// <summary> /// Creates a new instance of the class given XYZ coordinates. /// </summary> private Geo(Vector pos, double theta) { theta = theta % Globals.TwoPi; if (theta < 0.0) { // "wrap" negative modulo theta += Globals.TwoPi; } double r = Math.Sqrt(Globals.Sqr(pos.X) + Globals.Sqr(pos.Y)); double e2 = Globals.F * (2.0 - Globals.F); double lat = Globals.AcTan(pos.Z, r); const double DELTA = 1.0e-07; double phi; double c; do { phi = lat; c = 1.0 / Math.Sqrt(1.0 - e2 * Globals.Sqr(Math.Sin(phi))); lat = Globals.AcTan(pos.Z + Globals.Xkmper * c * e2 * Math.Sin(phi), r); } while (Math.Abs(lat - phi) > DELTA); LatitudeRad = lat; LongitudeRad = theta; Altitude = (r / Math.Cos(lat)) - Globals.Xkmper * c; }
/// <summary> /// Creates a new instance of the class with the given position and /// velocity components. /// </summary> /// <param name="pos">The position vector.</param> /// <param name="vel">The velocity vector.</param> public Eci(Vector pos, Vector vel, Julian date, bool IsAeUnits) { Position = pos; Velocity = vel; jDate = date; Units = (IsAeUnits ? VectorUnits.Ae : VectorUnits.None); }
/// <summary> /// Creates a instance of the class from geodetic coordinates. /// </summary> /// <param name="geo">The geocentric coordinates.</param> /// <param name="date">The Julian date.</param> /// <remarks> /// Assumes the Earth is an oblate spheroid. /// Reference: The 1992 Astronomical Almanac, page K11 /// Reference: www.celestrak.com (Dr. T.S. Kelso) /// </remarks> public Eci(Geo geo, Julian date) { double lat = geo.LatitudeRad; double lon = geo.LongitudeRad; double alt = geo.Altitude; // Calculate Local Mean Sidereal Time (theta) double theta = date.ToLmst(lon); double c = 1.0 / Math.Sqrt(1.0 + Globals.F * (Globals.F - 2.0) * Globals.Sqr(Math.Sin(lat))); double s = Globals.Sqr(1.0 - Globals.F) * c; double achcp = (Globals.Xkmper * c + alt) * Math.Cos(lat); Position = new Vector(); Position.X = achcp * Math.Cos(theta); // km Position.Y = achcp * Math.Sin(theta); // km Position.Z = (Globals.Xkmper * s + alt) * Math.Sin(lat); // km Position.W = Math.Sqrt(Globals.Sqr(Position.X) + Globals.Sqr(Position.Y) + Globals.Sqr(Position.Z)); // range, km Velocity = new Vector(); double mfactor = Globals.TwoPi * (Globals.OmegaE / Globals.SecPerDay); Velocity.X = -mfactor * Position.Y; // km / sec Velocity.Y = mfactor * Position.X; // km / sec Velocity.Z = 0.0; // km / sec Velocity.W = Math.Sqrt(Globals.Sqr(Velocity.X) + // range rate km/sec^2 Globals.Sqr(Velocity.Y)); }
/// <summary> /// Creates a new instance of the class with the given position and /// velocity components. /// </summary> /// <param name="pos">The position vector.</param> /// <param name="vel">The velocity vector.</param> public Eci(Vector pos, Vector vel) { Position = pos; Velocity = vel; }
/// <summary> /// Creates a new instance of the class from XYZ coordinates. /// </summary> /// <param name="pos">The XYZ coordinates.</param> public Eci(Vector pos) : this(pos, new Vector()) { }
/// <summary> /// Creates an instance of the class with the given position, velocity, and time. /// </summary> /// <param name="pos">The position vector.</param> /// <param name="vel">The velocity vector.</param> /// <param name="date">The time associated with the position.</param> public EciTime(Vector pos, Vector vel, Julian date) : base(pos, vel) { Date = date; }
// ///////////////////////////////////////////////////////////////////// protected EciTime FinalPosition(double incl, double omega, double e, double a, double xl, double xnode, double xn, double tsince) { if ((e * e) > 1.0) { throw new PropagationException("Error in satellite data"); } double beta = Math.Sqrt(1.0 - e * e); // Long period periodics double axn = e * Math.Cos(omega); double temp = 1.0 / (a * beta * beta); double xll = temp * m_xlcof * axn; double aynl = temp * m_aycof; double xlt = xl + xll; double ayn = e * Math.Sin(omega) + aynl; // Solve Kepler's Equation double capu = Globals.Fmod2p(xlt - xnode); double temp2 = capu; double temp3 = 0.0; double temp4 = 0.0; double temp5 = 0.0; double temp6 = 0.0; double sinepw = 0.0; double cosepw = 0.0; bool fDone = false; for (int i = 1; (i <= 10) && !fDone; i++) { sinepw = Math.Sin(temp2); cosepw = Math.Cos(temp2); temp3 = axn * sinepw; temp4 = ayn * cosepw; temp5 = axn * cosepw; temp6 = ayn * sinepw; double epw = (capu - temp4 + temp3 - temp2) / (1.0 - temp5 - temp6) + temp2; if (Math.Abs(epw - temp2) <= 1.0e-06) { fDone = true; } else { temp2 = epw; } } // Short period preliminary quantities double ecose = temp5 + temp6; double esine = temp3 - temp4; double elsq = axn * axn + ayn * ayn; temp = 1.0 - elsq; double pl = a * temp; double r = a * (1.0 - ecose); double temp1 = 1.0 / r; double rdot = Globals.Xke * Math.Sqrt(a) * esine * temp1; double rfdot = Globals.Xke * Math.Sqrt(pl) * temp1; temp2 = a * temp1; double betal = Math.Sqrt(temp); temp3 = 1.0 / (1.0 + betal); double cosu = temp2 * (cosepw - axn + ayn * esine * temp3); double sinu = temp2 * (sinepw - ayn - axn * esine * temp3); double u = Globals.AcTan(sinu, cosu); double sin2u = 2.0 * sinu * cosu; double cos2u = 2.0 * cosu * cosu - 1.0; temp = 1.0 / pl; temp1 = Globals.Ck2 * temp; temp2 = temp1 * temp; // Update for short periodics double rk = r * (1.0 - 1.5 * temp2 * betal * m_x3thm1) + 0.5 * temp1 * m_x1mth2 * cos2u; double uk = u - 0.25 * temp2 * m_x7thm1 * sin2u; double xnodek = xnode + 1.5 * temp2 * m_cosio * sin2u; double xinck = incl + 1.5 * temp2 * m_cosio * m_sinio * cos2u; double rdotk = rdot - xn * temp1 * m_x1mth2 * sin2u; double rfdotk = rfdot + xn * temp1 * (m_x1mth2 * cos2u + 1.5 * m_x3thm1); // Orientation vectors double sinuk = Math.Sin(uk); double cosuk = Math.Cos(uk); double sinik = Math.Sin(xinck); double cosik = Math.Cos(xinck); double sinnok = Math.Sin(xnodek); double cosnok = Math.Cos(xnodek); double xmx = -sinnok * cosik; double xmy = cosnok * cosik; double ux = xmx * sinuk + cosnok * cosuk; double uy = xmy * sinuk + sinnok * cosuk; double uz = sinik * sinuk; double vx = xmx * cosuk - cosnok * sinuk; double vy = xmy * cosuk - sinnok * sinuk; double vz = sinik * cosuk; // Position double x = rk * ux; double y = rk * uy; double z = rk * uz; Vector vecPos = new Vector(x, y, z); DateTime gmt = Orbit.EpochTime.AddMinutes(tsince); // Validate on altitude double altKm = (vecPos.Magnitude() * (Globals.Xkmper / Globals.Ae)); if (altKm < Globals.Xkmper) { throw new DecayException(gmt, Orbit.SatNameLong); } // Velocity double xdot = rdotk * ux + rfdotk * vx; double ydot = rdotk * uy + rfdotk * vy; double zdot = rdotk * uz + rfdotk * vz; Vector vecVel = new Vector(xdot, ydot, zdot); return new EciTime(vecPos, vecVel, new Julian(gmt)); }
/// <summary> /// Subtracts a vector from this vector. /// </summary> /// <param name="vec">The vector to subtract.</param> public void Sub(Vector vec) { X -= vec.X; Y -= vec.Y; Z -= vec.Z; W -= vec.W; }
/// <summary> /// Creates a new vector from an existing vector. /// </summary> /// <param name="v">The existing vector to copy.</param> public Vector(Vector v) :this(v.X, v.Y, v.Z, v.W) { }
/// <summary> /// Creates an instance of the class with the given position, velocity, and time. /// </summary> /// <param name="pos">The position vector.</param> /// <param name="vel">The velocity vector.</param> /// <param name="date">The time associated with the position.</param> public EciTime(Vector pos, Vector vel, Julian date, bool IsAeUnits) : base(pos, vel, date, IsAeUnits) { Date = date; }
/// <summary> /// Calculates the dot product of this vector and another. /// </summary> /// <param name="vec">The second vector.</param> /// <returns>The dot product.</returns> public double Dot(Vector vec) => (X * vec.X) + (Y * vec.Y) + (Z * vec.Z);
/// <summary> /// Calculates the angle, in radians, between this vector and another. /// </summary> /// <param name="vec">The second vector.</param> /// <returns> /// The angle between the two vectors, in radians. /// </returns> public double Angle(Vector vec) => Math.Acos(Dot(vec) / (Magnitude() * vec.Magnitude()));
/// <summary> /// Calculates the dot product of this vector and another. /// </summary> /// <param name="vec">The second vector.</param> /// <returns>The dot product.</returns> public double Dot(Vector vec) { return (X * vec.X) + (Y * vec.Y) + (Z * vec.Z); }
/// <summary> /// Creates a new instance of the class from XYZ coordinates. /// </summary> /// <param name="pos">The XYZ coordinates.</param> public Eci(Vector pos) : this(pos, new Vector(), new Julian(), false) { }
/// <summary> /// Creates a new instance of the class from ECI coordinates. /// </summary> /// <param name="eci">The ECI coordinates.</param> public Eci(Eci eci) { Position = new Vector(eci.Position); Velocity = new Vector(eci.Velocity); }
/// <summary> /// Returns the topo-centric (azimuth, elevation, etc.) coordinates for /// a target object described by the given ECI coordinates. /// </summary> /// <param name="eci">The ECI coordinates of the target object.</param> /// <returns>The look angle to the target object.</returns> public TopoTime GetLookAngle(EciTime eci) { // Calculate the ECI coordinates for this Site object at the time // of interest. Julian date = eci.Date; EciTime eciSite = GetPosition(date); Vector vecRgRate = new Vector(eci.Velocity.X - eciSite.Velocity.X, eci.Velocity.Y - eciSite.Velocity.Y, eci.Velocity.Z - eciSite.Velocity.Z); double x = eci.Position.X - eciSite.Position.X; double y = eci.Position.Y - eciSite.Position.Y; double z = eci.Position.Z - eciSite.Position.Z; double w = Math.Sqrt(Globals.Sqr(x) + Globals.Sqr(y) + Globals.Sqr(z)); Vector vecRange = new Vector(x, y, z, w); // The site's Local Mean Sidereal Time at the time of interest. double theta = date.ToLmst(LongitudeRad); double sin_lat = Math.Sin(LatitudeRad); double cos_lat = Math.Cos(LatitudeRad); double sin_theta = Math.Sin(theta); double cos_theta = Math.Cos(theta); double top_s = sin_lat * cos_theta * vecRange.X + sin_lat * sin_theta * vecRange.Y - cos_lat * vecRange.Z; double top_e = -sin_theta * vecRange.X + cos_theta * vecRange.Y; double top_z = cos_lat * cos_theta * vecRange.X + cos_lat * sin_theta * vecRange.Y + sin_lat * vecRange.Z; double az = Math.Atan(-top_e / top_s); if (top_s > 0.0) { az += Globals.Pi; } if (az < 0.0) { az += 2.0 * Globals.Pi; } double el = Math.Asin(top_z / vecRange.W); double rate = (vecRange.X * vecRgRate.X + vecRange.Y * vecRgRate.Y + vecRange.Z * vecRgRate.Z) / vecRange.W; TopoTime topo = new TopoTime(az, // azimuth, radians el, // elevation, radians vecRange.W, // range, km rate, // rate, km / sec eci.Date); #if WANT_ATMOSPHERIC_CORRECTION // Elevation correction for atmospheric refraction. // Reference: Astronomical Algorithms by Jean Meeus, pp. 101-104 // Note: Correction is meaningless when apparent elevation is below horizon topo.m_El += Globals.ToRadians((1.02 / Math.Tan(Globals.ToRadians(Globals.ToDegrees(el) + 10.3 / (Globals.ToDegrees(el) + 5.11)))) / 60.0); if (topo.m_El < 0.0) { topo.m_El = el; // Reset to true elevation } if (topo.m_El > (Globals.PI / 2)) { topo.m_El = (Globals.PI / 2); } #endif return topo; }
/// <summary> /// Calculates the distance between two vectors as points in XYZ space. /// </summary> /// <param name="vec">The second vector.</param> /// <returns>The calculated distance.</returns> public double Distance(Vector vec) => Math.Sqrt(Math.Pow(X - vec.X, 2.0) + Math.Pow(Y - vec.Y, 2.0) + Math.Pow(Z - vec.Z, 2.0));