From 268ffc097fb11fb597af5b811999ff437ac2570a Mon Sep 17 00:00:00 2001 From: Sylvain Guillet Date: Sat, 28 Sep 2024 12:28:13 +0200 Subject: [PATCH] feature/dataprovider (#210) * Add async operation on dataprovider * Update version --- .../IO.Astrodynamics.CLI.csproj | 2 +- .../IO.Astrodynamics.Tests/APITest.cs | 7 +- IO.Astrodynamics.Net/IO.Astrodynamics/API.cs | 1422 +++++++++-------- .../IO.Astrodynamics/Body/CelestialItem.cs | 1 - .../DataProvider/IDataProvider.cs | 13 +- .../DataProvider/SpiceDataProvider.cs | 29 +- .../IO.Astrodynamics/Frames/Frame.cs | 23 +- .../IO.Astrodynamics/IO.Astrodynamics.nuspec | 2 +- 8 files changed, 766 insertions(+), 733 deletions(-) diff --git a/IO.Astrodynamics.Net/IO.Astrodynamics.CLI/IO.Astrodynamics.CLI.csproj b/IO.Astrodynamics.Net/IO.Astrodynamics.CLI/IO.Astrodynamics.CLI.csproj index eac9f42e..1210f2a4 100644 --- a/IO.Astrodynamics.Net/IO.Astrodynamics.CLI/IO.Astrodynamics.CLI.csproj +++ b/IO.Astrodynamics.Net/IO.Astrodynamics.CLI/IO.Astrodynamics.CLI.csproj @@ -9,7 +9,7 @@ 0.0.1 true astro - 0.5.0-preview-5 + 0.5.0-preview-6 Astrodynamics command line interface Sylvain Guillet This CLI allows end user to exploit IO.Astrodynamics framework diff --git a/IO.Astrodynamics.Net/IO.Astrodynamics.Tests/APITest.cs b/IO.Astrodynamics.Net/IO.Astrodynamics.Tests/APITest.cs index 6139af59..80c653e3 100644 --- a/IO.Astrodynamics.Net/IO.Astrodynamics.Tests/APITest.cs +++ b/IO.Astrodynamics.Net/IO.Astrodynamics.Tests/APITest.cs @@ -497,8 +497,7 @@ void GetCelestialBodyInformationWithoutJ() void TransformFrame() { //Get the quaternion to transform - var res = API.Instance.TransformFrame(Frames.Frame.ICRF, new Frames.Frame(PlanetsAndMoons.EARTH.Frame), - TimeSystem.Time.J2000TDB); + var res = API.Instance.TransformFrame(TimeSystem.Time.J2000TDB,Frames.Frame.ICRF, new Frames.Frame(PlanetsAndMoons.EARTH.Frame)); Assert.Equal(0.76713121207787449, res.Rotation.W, 6); Assert.Equal(-1.8618836714990174E-05, res.Rotation.VectorPart.X, 6); Assert.Equal(8.4688405480964646E-07, res.Rotation.VectorPart.Y, 6); @@ -513,9 +512,9 @@ void TransformFrameExceptions() { //Get the quaternion to transform Assert.Throws(() => - API.Instance.TransformFrame(Frames.Frame.ICRF, null, TimeSystem.Time.J2000TDB)); + API.Instance.TransformFrame(TimeSystem.Time.J2000TDB,Frames.Frame.ICRF, null)); Assert.Throws(() => - API.Instance.TransformFrame(null, new Frames.Frame(PlanetsAndMoons.EARTH.Frame), TimeSystem.Time.J2000TDB)); + API.Instance.TransformFrame(TimeSystem.Time.J2000TDB,null, new Frames.Frame(PlanetsAndMoons.EARTH.Frame))); } [Fact] diff --git a/IO.Astrodynamics.Net/IO.Astrodynamics/API.cs b/IO.Astrodynamics.Net/IO.Astrodynamics/API.cs index d478ad01..821059f5 100644 --- a/IO.Astrodynamics.Net/IO.Astrodynamics/API.cs +++ b/IO.Astrodynamics.Net/IO.Astrodynamics/API.cs @@ -159,711 +159,719 @@ private static IntPtr Resolver(string libraryName, Assembly assembly, DllImportS //Use the same lock for all cspice calls because it doesn't support multithreading. private static object lockObject = new object(); - /// - /// Get spice toolkit version number - /// - /// - public string GetSpiceVersion() - { - lock (lockObject) - { - var strptr = GetSpiceVersionProxy(); - var str = Marshal.PtrToStringAnsi(strptr); - Marshal.FreeHGlobal(strptr); - return str; - } - } - - public IEnumerable GetLoadedKernels() - { - return _kernels; - } - - /// - /// Load kernel at given path - /// - /// Path where kernels are located. This could be a file path or a directory path - public void LoadKernels(FileSystemInfo path) - { - if (path == null) throw new ArgumentNullException(nameof(path)); - lock (lockObject) - { - if (_kernels.Any(x => path.FullName.Contains(x.FullName))) - { - foreach (var kernel in _kernels.Where(x => path.FullName.Contains(x.FullName)).ToArray()) - { - UnloadKernels(kernel); - LoadKernels(kernel); - } - - return; - } - - - var existingKernels = _kernels.Where(x => x.FullName.Contains(path.FullName)).ToArray(); - foreach (var existingKernel in existingKernels) - { - UnloadKernels(existingKernel); - } - - if (path.Exists) - { - if (!LoadKernelsProxy(path.FullName)) - { - throw new InvalidOperationException($"Kernel {path.FullName} can't be loaded. You can have more details on standard output"); - } - - _kernels.Add(path); - } - } - } - - /// - /// Unload kernel at given path - /// - /// Path where kernels are located. This could be a file path or a directory path - public void UnloadKernels(FileSystemInfo path) - { - if (path == null) return; - lock (lockObject) - { - if (path.Exists) - { - if (!UnloadKernelsProxy(path.FullName)) - { - throw new InvalidOperationException($"Kernel {path.FullName} can't be unloaded. You can have more details on standard output"); - } - - _kernels.RemoveAll(x => x.FullName == path.FullName); - foreach (var kernel in _kernels.Where(x => x.FullName.Contains(path.FullName)).ToArray()) - { - UnloadKernels(kernel); - } - } - } - } - - public void ClearKernels() - { - lock (lockObject) - { - foreach (var kernel in _kernels.ToArray()) - { - UnloadKernels(kernel); - } - - KClearProxy(); - } - } - - /// - /// Find launch windows - /// - /// - /// - /// - public IEnumerable FindLaunchWindows(Maneuver.Launch launch, - in TimeSystem.Window window, DirectoryInfo outputDirectory) - { - if (launch == null) throw new ArgumentNullException(nameof(launch)); - lock (lockObject) - { - //Convert data - Launch launchDto = launch.Convert(); - launchDto.Window = window.Convert(); - launchDto.LaunchSite.DirectoryPath = outputDirectory.CreateSubdirectory("Sites").FullName; - launchDto.RecoverySite.DirectoryPath = outputDirectory.CreateSubdirectory("Sites").FullName; - - //Execute request - LaunchProxy(ref launchDto); - - //Filter result - var windows = launchDto.Windows.Where(x => x.Start != 0 && x.End != 0).ToArray(); - - //Build result - List launchWindows = []; - - for (int i = 0; i < windows.Length; i++) - { - launchWindows.Add(new LaunchWindow(windows[i].Convert(), - launchDto.InertialInsertionVelocity[i], launchDto.NonInertialInsertionVelocity[i], - launchDto.InertialAzimuth[i], launchDto.NonInertialAzimuth[i])); - } - - return launchWindows; - } - } - - /// - /// Find time windows based on distance constraint - /// - /// - /// - /// - /// - /// - /// - /// - /// - public IEnumerable FindWindowsOnDistanceConstraint(TimeSystem.Window searchWindow, INaifObject observer, - INaifObject target, RelationnalOperator relationalOperator, double value, Aberration aberration, - TimeSpan stepSize) - { - if (observer == null) throw new ArgumentNullException(nameof(observer)); - if (target == null) throw new ArgumentNullException(nameof(target)); - lock (lockObject) - { - return FindWindowsOnDistanceConstraint(searchWindow, observer.NaifId, target.NaifId, relationalOperator, value, aberration, stepSize); - } - } - - public IEnumerable FindWindowsOnDistanceConstraint(TimeSystem.Window searchWindow, int observerId, - int targetId, RelationnalOperator relationalOperator, double value, Aberration aberration, - TimeSpan stepSize) - { - lock (lockObject) - { - var windows = new Window[1000]; - for (var i = 0; i < 1000; i++) - { - windows[i] = new Window(double.NaN, double.NaN); - } - - FindWindowsOnDistanceConstraintProxy(searchWindow.Convert(), observerId, targetId, relationalOperator.GetDescription(), value, - aberration.GetDescription(), stepSize.TotalSeconds, windows); - return windows.Where(x => !double.IsNaN(x.Start)).Select(x => x.Convert()); - } - } - - /// - /// Find time windows based on occultation constraint - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public IEnumerable FindWindowsOnOccultationConstraint(TimeSystem.Window searchWindow, INaifObject observer, - INaifObject target, ShapeType targetShape, INaifObject frontBody, ShapeType frontShape, - OccultationType occultationType, Aberration aberration, TimeSpan stepSize) - { - if (observer == null) throw new ArgumentNullException(nameof(observer)); - if (target == null) throw new ArgumentNullException(nameof(target)); - if (frontBody == null) throw new ArgumentNullException(nameof(frontBody)); - lock (lockObject) - { - string frontFrame = frontShape == ShapeType.Ellipsoid - ? (frontBody as Body.CelestialBody)?.Frame.Name - : string.Empty; - string targetFrame = targetShape == ShapeType.Ellipsoid - ? (target as Body.CelestialBody)?.Frame.Name - : String.Empty; - var windows = new Window[1000]; - for (var i = 0; i < 1000; i++) - { - windows[i] = new Window(double.NaN, double.NaN); - } - - FindWindowsOnOccultationConstraintProxy(searchWindow.Convert(), observer.NaifId, target.NaifId, - targetFrame, targetShape.GetDescription(), - frontBody.NaifId, frontFrame, frontShape.GetDescription(), occultationType.GetDescription(), - aberration.GetDescription(), stepSize.TotalSeconds, windows); - return windows.Where(x => !double.IsNaN(x.Start)).Select(x => x.Convert()); - } - } - - /// - /// Find time windows based on occultation constraint - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public IEnumerable FindWindowsOnOccultationConstraint(TimeSystem.Window searchWindow, int observerId, - int targetId, ShapeType targetShape, int frontBodyId, ShapeType frontShape, - OccultationType occultationType, Aberration aberration, TimeSpan stepSize) - { - lock (lockObject) - { - IO.Astrodynamics.Body.CelestialBody frontBody = new IO.Astrodynamics.Body.CelestialBody(frontBodyId); - IO.Astrodynamics.Body.CelestialBody targetBody = new IO.Astrodynamics.Body.CelestialBody(targetId); - string frontFrame = frontShape == ShapeType.Ellipsoid - ? frontBody.Frame.Name - : string.Empty; - string targetFrame = targetShape == ShapeType.Ellipsoid - ? targetBody.Frame.Name - : String.Empty; - var windows = new Window[1000]; - for (var i = 0; i < 1000; i++) - { - windows[i] = new Window(double.NaN, double.NaN); - } - - FindWindowsOnOccultationConstraintProxy(searchWindow.Convert(), observerId, targetId, targetFrame, targetShape.GetDescription(), - frontBody.NaifId, frontFrame, frontShape.GetDescription(), occultationType.GetDescription(), aberration.GetDescription(), stepSize.TotalSeconds, windows); - return windows.Where(x => !double.IsNaN(x.Start)).Select(x => x.Convert()); - } - } - - /// - /// Find time windows based on coordinate constraint - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public IEnumerable FindWindowsOnCoordinateConstraint(TimeSystem.Window searchWindow, INaifObject observer, - INaifObject target, Frame frame, CoordinateSystem coordinateSystem, Coordinate coordinate, - RelationnalOperator relationalOperator, double value, double adjustValue, Aberration aberration, - TimeSpan stepSize) - { - if (observer == null) throw new ArgumentNullException(nameof(observer)); - if (target == null) throw new ArgumentNullException(nameof(target)); - if (frame == null) throw new ArgumentNullException(nameof(frame)); - lock (lockObject) - { - var windows = new Window[1000]; - for (var i = 0; i < 1000; i++) - { - windows[i] = new Window(double.NaN, double.NaN); - } - - FindWindowsOnCoordinateConstraintProxy(searchWindow.Convert(), observer.NaifId, target.NaifId, - frame.Name, coordinateSystem.GetDescription(), - coordinate.GetDescription(), relationalOperator.GetDescription(), value, adjustValue, - aberration.GetDescription(), stepSize.TotalSeconds, windows); - return windows.Where(x => !double.IsNaN(x.Start)).Select(x => x.Convert()); - } - } - - /// - /// Find time windows based on coordinate constraint - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public IEnumerable FindWindowsOnCoordinateConstraint(TimeSystem.Window searchWindow, int observerId, - int targetId, Frame frame, CoordinateSystem coordinateSystem, Coordinate coordinate, - RelationnalOperator relationalOperator, double value, double adjustValue, Aberration aberration, - TimeSpan stepSize) - { - if (frame == null) throw new ArgumentNullException(nameof(frame)); - lock (lockObject) - { - var windows = new Window[1000]; - for (var i = 0; i < 1000; i++) - { - windows[i] = new Window(double.NaN, double.NaN); - } - - FindWindowsOnCoordinateConstraintProxy(searchWindow.Convert(), observerId, targetId, - frame.Name, coordinateSystem.GetDescription(), - coordinate.GetDescription(), relationalOperator.GetDescription(), value, adjustValue, - aberration.GetDescription(), stepSize.TotalSeconds, windows); - return windows.Where(x => !double.IsNaN(x.Start)).Select(x => x.Convert()); - } - } - - /// - /// Find time windows based on illumination constraint - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public IEnumerable FindWindowsOnIlluminationConstraint(TimeSystem.Window searchWindow, INaifObject observer, - INaifObject targetBody, Frame fixedFrame, - Coordinates.Planetodetic planetodetic, IlluminationAngle illuminationType, RelationnalOperator relationalOperator, - double value, double adjustValue, Aberration aberration, TimeSpan stepSize, INaifObject illuminationSource, - string method = "Ellipsoid") - { - if (observer == null) throw new ArgumentNullException(nameof(observer)); - if (targetBody == null) throw new ArgumentNullException(nameof(targetBody)); - if (fixedFrame == null) throw new ArgumentNullException(nameof(fixedFrame)); - if (illuminationSource == null) throw new ArgumentNullException(nameof(illuminationSource)); - if (method == null) throw new ArgumentNullException(nameof(method)); - lock (lockObject) - { - var windows = new Window[1000]; - for (var i = 0; i < 1000; i++) - { - windows[i] = new Window(double.NaN, double.NaN); - } - - FindWindowsOnIlluminationConstraintProxy(searchWindow.Convert(), observer.NaifId, - illuminationSource.Name, targetBody.NaifId, fixedFrame.Name, - planetodetic.Convert(), - illuminationType.GetDescription(), relationalOperator.GetDescription(), value, adjustValue, - aberration.GetDescription(), stepSize.TotalSeconds, method, windows); - return windows.Where(x => !double.IsNaN(x.Start)).Select(x => x.Convert()); - } - } - - public IEnumerable FindWindowsOnIlluminationConstraint(TimeSystem.Window searchWindow, int observerId, - int targetBodyId, Frame fixedFrame, Coordinates.Planetodetic planetodetic, IlluminationAngle illuminationType, RelationnalOperator relationalOperator, - double value, double adjustValue, Aberration aberration, TimeSpan stepSize, int illuminationSourceId, - string method = "Ellipsoid") - { - if (fixedFrame == null) throw new ArgumentNullException(nameof(fixedFrame)); - if (method == null) throw new ArgumentNullException(nameof(method)); - lock (lockObject) - { - var windows = new Window[1000]; - for (var i = 0; i < 1000; i++) - { - windows[i] = new Window(double.NaN, double.NaN); - } - - FindWindowsOnIlluminationConstraintProxy(searchWindow.Convert(), observerId, - illuminationSourceId.ToString(), targetBodyId, fixedFrame.Name, - planetodetic.Convert(), - illuminationType.GetDescription(), relationalOperator.GetDescription(), value, adjustValue, - aberration.GetDescription(), stepSize.TotalSeconds, method, windows); - return windows.Where(x => !double.IsNaN(x.Start)).Select(x => x.Convert()); - } - } - - /// - /// Find time window when a target is in instrument's field of view - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public IEnumerable FindWindowsInFieldOfViewConstraint(TimeSystem.Window searchWindow, Spacecraft observer, - Instrument instrument, INaifObject target, Frame targetFrame, ShapeType targetShape, Aberration aberration, - TimeSpan stepSize) - { - if (observer == null) throw new ArgumentNullException(nameof(observer)); - if (instrument == null) throw new ArgumentNullException(nameof(instrument)); - if (target == null) throw new ArgumentNullException(nameof(target)); - if (targetFrame == null) throw new ArgumentNullException(nameof(targetFrame)); - lock (lockObject) - { - return FindWindowsInFieldOfViewConstraint(searchWindow, observer.NaifId, instrument.NaifId, target.NaifId, targetFrame, targetShape, aberration, stepSize); - } - } - - /// - /// Find time window when a target is in instrument's field of view - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public IEnumerable FindWindowsInFieldOfViewConstraint(TimeSystem.Window searchWindow, int observerId, - int instrumentId, int targetId, Frame targetFrame, ShapeType targetShape, Aberration aberration, TimeSpan stepSize) - { - if (targetFrame == null) throw new ArgumentNullException(nameof(targetFrame)); - lock (lockObject) - { - var windows = new Window[1000]; - for (var i = 0; i < 1000; i++) - { - windows[i] = new Window(double.NaN, double.NaN); - } - - var searchWindowDto = searchWindow.Convert(); - - FindWindowsInFieldOfViewConstraintProxy(searchWindowDto, observerId, instrumentId, targetId, targetFrame.Name, targetShape.GetDescription(), - aberration.GetDescription(), stepSize.TotalSeconds, windows); - - return windows.Where(x => !double.IsNaN(x.Start)).Select(x => x.Convert()); - } - } - - /// - /// Read object ephemeris for a given period - /// - /// - /// - /// - /// - /// - /// - /// - public IEnumerable ReadEphemeris(TimeSystem.Window searchWindow, - ILocalizable observer, ILocalizable target, Frame frame, - Aberration aberration, TimeSpan stepSize) - { - ArgumentNullException.ThrowIfNull(observer); - ArgumentNullException.ThrowIfNull(target); - ArgumentNullException.ThrowIfNull(frame); - lock (lockObject) - { - const int messageSize = 10000; - List orbitalParameters = []; - int occurrences = (int)(searchWindow.Length / stepSize / messageSize); - - for (int i = 0; i <= occurrences; i++) - { - var start = searchWindow.StartDate + i * messageSize * stepSize; - var end = start + messageSize * stepSize > searchWindow.EndDate ? searchWindow.EndDate : (start + messageSize * stepSize) - stepSize; - var window = new TimeSystem.Window(start, end); - var stateVectors = new StateVector[messageSize]; - ReadEphemerisProxy(window.Convert(), observer.NaifId, target.NaifId, frame.Name, - aberration.GetDescription(), stepSize.TotalSeconds, - stateVectors); - orbitalParameters.AddRange(stateVectors.Where(x => !string.IsNullOrEmpty(x.Frame)).Select(x => - new OrbitalParameters.StateVector(x.Position.Convert(), x.Velocity.Convert(), observer, Time.Create(x.Epoch, TimeFrame.TDBFrame), frame))); - } - - return orbitalParameters; - } - } - - /// - /// Return state vector at given epoch - /// - /// - /// - /// - /// - /// - /// - /// - public OrbitalParameters.OrbitalParameters ReadEphemeris(Time epoch, ILocalizable observer, - ILocalizable target, Frame frame, Aberration aberration) - { - ArgumentNullException.ThrowIfNull(observer); - ArgumentNullException.ThrowIfNull(target); - ArgumentNullException.ThrowIfNull(frame); - lock (lockObject) - { - if (frame == null) throw new ArgumentNullException(nameof(frame)); - var stateVector = ReadEphemerisAtGivenEpochProxy(epoch.TimeSpanFromJ2000().TotalSeconds, observer.NaifId, - target.NaifId, frame.Name, aberration.GetDescription()); - return new OrbitalParameters.StateVector(stateVector.Position.Convert(), stateVector.Velocity.Convert(), observer, - Time.Create(stateVector.Epoch, TimeFrame.TDBFrame), frame); - } - } - - /// - /// Read spacecraft orientation for a given period - /// - /// - /// - /// - /// - /// - /// - public IEnumerable ReadOrientation(TimeSystem.Window searchWindow, - Spacecraft spacecraft, TimeSpan tolerance, - Frame referenceFrame, TimeSpan stepSize) - { - if (spacecraft == null) throw new ArgumentNullException(nameof(spacecraft)); - if (referenceFrame == null) throw new ArgumentNullException(nameof(referenceFrame)); - lock (lockObject) - { - var stateOrientations = new StateOrientation[10000]; - ReadOrientationProxy(searchWindow.Convert(), spacecraft.NaifId, tolerance.TotalSeconds, - referenceFrame.Name, stepSize.TotalSeconds, - stateOrientations); - return stateOrientations.Where(x => x.Frame != null).Select(x => new OrbitalParameters.StateOrientation( - x.Rotation.Convert(), x.AngularVelocity.Convert(), Time.Create(x.Epoch, TimeFrame.TDBFrame), referenceFrame)); - } - } - - /// - /// Write ephemeris file - /// - /// - /// - /// - /// - public bool WriteEphemeris(FileInfo filePath, INaifObject naifObject, - IEnumerable stateVectors) - { - if (naifObject == null) throw new ArgumentNullException(nameof(naifObject)); - if (filePath == null) throw new ArgumentNullException(nameof(filePath)); - if (stateVectors == null) throw new ArgumentNullException(nameof(stateVectors)); - lock (lockObject) - { - var enumerable = stateVectors as OrbitalParameters.StateVector[] ?? stateVectors.ToArray(); - if (!enumerable.Any()) - throw new ArgumentException("Value cannot be an empty collection.", nameof(stateVectors)); - bool res = WriteEphemerisProxy(filePath.FullName, naifObject.NaifId, stateVectors.Select(x => x.Convert()).ToArray(), - (uint)enumerable.Length); - if (res == false) - { - throw new InvalidOperationException( - "An error occurred while writing ephemeris. You can have more details on standard output."); - } - - return true; - } - } - - public bool WriteOrientation(FileInfo filePath, INaifObject naifObject, IEnumerable stateOrientations) - { - if (naifObject == null) throw new ArgumentNullException(nameof(naifObject)); - if (filePath == null) throw new ArgumentNullException(nameof(filePath)); - if (stateOrientations == null) throw new ArgumentNullException(nameof(stateOrientations)); - lock (lockObject) - { - var enumerable = stateOrientations as OrbitalParameters.StateOrientation[] ?? stateOrientations.ToArray(); - if (!enumerable.Any()) - throw new ArgumentException("Value cannot be an empty collection.", nameof(stateOrientations)); - bool res = WriteOrientationProxy(filePath.FullName, naifObject.NaifId, stateOrientations.Select(x => x.Convert()).ToArray(), (uint)enumerable.Length); - if (res == false) - { - throw new InvalidOperationException( - "An error occurred while writing orientation. You can have more details on standard output."); - } - - return true; - } - } - - /// - /// Get celestial celestialItem information like radius, GM, name, associated frame, ... - /// - /// - /// - public CelestialBody GetCelestialBodyInfo(int naifId) - { - lock (lockObject) - { - return GetCelestialBodyInfoProxy(naifId); - } - } - - /// - /// Transform a frame to another - /// - /// - /// - /// - /// - /// - public OrbitalParameters.StateOrientation TransformFrame(Frame fromFrame, Frame toFrame, Time epoch) - { - lock (lockObject) - { - if (fromFrame == null) throw new ArgumentNullException(nameof(fromFrame)); - if (toFrame == null) throw new ArgumentNullException(nameof(toFrame)); - var res = TransformFrameProxy(fromFrame.Name, toFrame.Name, epoch.ToTDB().TimeSpanFromJ2000().TotalSeconds); - - return new OrbitalParameters.StateOrientation( - new Quaternion(res.Rotation.W, res.Rotation.X, res.Rotation.Y, res.Rotation.Z), - new Vector3(res.AngularVelocity.X, res.AngularVelocity.Y, res.AngularVelocity.Z), epoch, fromFrame); - } - } - - /// - /// Convert TLE to state vector at given epoch - /// - /// - /// - /// - /// - /// - public OrbitalParameters.OrbitalParameters ConvertTleToStateVector(string line1, string line2, string line3, - Time epoch) - { - lock (lockObject) - { - var res = ConvertTLEToStateVectorProxy(line1, line2, line3, epoch.ToTDB().TimeSpanFromJ2000().TotalSeconds); - return new OrbitalParameters.StateVector(res.Position.Convert(), res.Velocity.Convert(), - new Body.CelestialBody(PlanetsAndMoons.EARTH, Frame.ECLIPTIC_J2000, epoch), epoch, - new Frame(res.Frame)).ToFrame(Frame.ICRF); - } - } - - public IO.Astrodynamics.OrbitalParameters.KeplerianElements ConvertStateVectorToConicOrbitalElement(IO.Astrodynamics.OrbitalParameters.StateVector stateVector) - { - lock (lockObject) - { - var svDto = stateVector.Convert(); - return ConvertStateVectorToConicOrbitalElementProxy(svDto, stateVector.Observer.GM).Convert(); - } - } - - public IO.Astrodynamics.OrbitalParameters.StateVector ConvertEquinoctialElementsToStateVector(IO.Astrodynamics.OrbitalParameters.EquinoctialElements equinoctialElements) - { - lock (lockObject) - { - return ConvertEquinoctialElementsToStateVectorProxy(equinoctialElements.Convert()).Convert(); - } - } - - public IO.Astrodynamics.OrbitalParameters.StateVector ConvertConicElementsToStateVector(IO.Astrodynamics.OrbitalParameters.KeplerianElements keplerianElements) - { - lock (lockObject) - { - return ConvertConicElementsToStateVectorProxy(keplerianElements.Convert()).Convert(); - } - } - - public IO.Astrodynamics.OrbitalParameters.StateVector ConvertConicElementsToStateVector(IO.Astrodynamics.OrbitalParameters.KeplerianElements keplerianElements, Time epoch) - { - lock (lockObject) - { - return ConvertConicElementsToStateVectorAtEpochProxy(keplerianElements.Convert(), epoch.ToTDB().TimeSpanFromJ2000().TotalSeconds, keplerianElements.Observer.GM) - .Convert(); - } - } - - public OrbitalParameters.StateVector Propagate2Bodies(OrbitalParameters.StateVector stateVector, TimeSpan dt) - { - lock (lockObject) - { - return Propagate2BodiesProxy(stateVector.Convert(), stateVector.Observer.GM, dt.TotalSeconds).Convert(); - } - } - - public OrbitalParameters.StateVector Propagate2Bodies(OrbitalParameters.StateVector stateVector, Time targetEpoch) - { - return Propagate2Bodies(stateVector, targetEpoch - stateVector.Epoch); - } + /// + /// Get spice toolkit version number + /// + /// + public string GetSpiceVersion() + { + lock (lockObject) + { + var strptr = GetSpiceVersionProxy(); + var str = Marshal.PtrToStringAnsi(strptr); + Marshal.FreeHGlobal(strptr); + return str; + } + } + + public IEnumerable GetLoadedKernels() + { + return _kernels; + } + + /// + /// Load kernel at given path + /// + /// Path where kernels are located. This could be a file path or a directory path + public void LoadKernels(FileSystemInfo path) + { + if (path == null) throw new ArgumentNullException(nameof(path)); + lock (lockObject) + { + if (_kernels.Any(x => path.FullName.Contains(x.FullName))) + { + foreach (var kernel in _kernels.Where(x => path.FullName.Contains(x.FullName)).ToArray()) + { + UnloadKernels(kernel); + LoadKernels(kernel); + } + + return; + } + + + var existingKernels = _kernels.Where(x => x.FullName.Contains(path.FullName)).ToArray(); + foreach (var existingKernel in existingKernels) + { + UnloadKernels(existingKernel); + } + + if (path.Exists) + { + if (!LoadKernelsProxy(path.FullName)) + { + throw new InvalidOperationException($"Kernel {path.FullName} can't be loaded. You can have more details on standard output"); + } + + _kernels.Add(path); + } + } + } + + /// + /// Unload kernel at given path + /// + /// Path where kernels are located. This could be a file path or a directory path + public void UnloadKernels(FileSystemInfo path) + { + if (path == null) return; + lock (lockObject) + { + if (path.Exists) + { + if (!UnloadKernelsProxy(path.FullName)) + { + throw new InvalidOperationException($"Kernel {path.FullName} can't be unloaded. You can have more details on standard output"); + } + + _kernels.RemoveAll(x => x.FullName == path.FullName); + foreach (var kernel in _kernels.Where(x => x.FullName.Contains(path.FullName)).ToArray()) + { + UnloadKernels(kernel); + } + } + } + } + + public void ClearKernels() + { + lock (lockObject) + { + foreach (var kernel in _kernels.ToArray()) + { + UnloadKernels(kernel); + } + + KClearProxy(); + } + } + + /// + /// Find launch windows + /// + /// + /// + /// + public IEnumerable FindLaunchWindows(Maneuver.Launch launch, + in TimeSystem.Window window, DirectoryInfo outputDirectory) + { + if (launch == null) throw new ArgumentNullException(nameof(launch)); + lock (lockObject) + { + //Convert data + Launch launchDto = launch.Convert(); + launchDto.Window = window.Convert(); + launchDto.LaunchSite.DirectoryPath = outputDirectory.CreateSubdirectory("Sites").FullName; + launchDto.RecoverySite.DirectoryPath = outputDirectory.CreateSubdirectory("Sites").FullName; + + //Execute request + LaunchProxy(ref launchDto); + + //Filter result + var windows = launchDto.Windows.Where(x => x.Start != 0 && x.End != 0).ToArray(); + + //Build result + List launchWindows = []; + + for (int i = 0; i < windows.Length; i++) + { + launchWindows.Add(new LaunchWindow(windows[i].Convert(), + launchDto.InertialInsertionVelocity[i], launchDto.NonInertialInsertionVelocity[i], + launchDto.InertialAzimuth[i], launchDto.NonInertialAzimuth[i])); + } + + return launchWindows; + } + } + + /// + /// Find time windows based on distance constraint + /// + /// + /// + /// + /// + /// + /// + /// + /// + public IEnumerable FindWindowsOnDistanceConstraint(TimeSystem.Window searchWindow, INaifObject observer, + INaifObject target, RelationnalOperator relationalOperator, double value, Aberration aberration, + TimeSpan stepSize) + { + if (observer == null) throw new ArgumentNullException(nameof(observer)); + if (target == null) throw new ArgumentNullException(nameof(target)); + lock (lockObject) + { + return FindWindowsOnDistanceConstraint(searchWindow, observer.NaifId, target.NaifId, relationalOperator, value, aberration, stepSize); + } + } + + public IEnumerable FindWindowsOnDistanceConstraint(TimeSystem.Window searchWindow, int observerId, + int targetId, RelationnalOperator relationalOperator, double value, Aberration aberration, + TimeSpan stepSize) + { + lock (lockObject) + { + var windows = new Window[1000]; + for (var i = 0; i < 1000; i++) + { + windows[i] = new Window(double.NaN, double.NaN); + } + + FindWindowsOnDistanceConstraintProxy(searchWindow.Convert(), observerId, targetId, relationalOperator.GetDescription(), value, + aberration.GetDescription(), stepSize.TotalSeconds, windows); + return windows.Where(x => !double.IsNaN(x.Start)).Select(x => x.Convert()); + } + } + + /// + /// Find time windows based on occultation constraint + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public IEnumerable FindWindowsOnOccultationConstraint(TimeSystem.Window searchWindow, INaifObject observer, + INaifObject target, ShapeType targetShape, INaifObject frontBody, ShapeType frontShape, + OccultationType occultationType, Aberration aberration, TimeSpan stepSize) + { + if (observer == null) throw new ArgumentNullException(nameof(observer)); + if (target == null) throw new ArgumentNullException(nameof(target)); + if (frontBody == null) throw new ArgumentNullException(nameof(frontBody)); + lock (lockObject) + { + string frontFrame = frontShape == ShapeType.Ellipsoid + ? (frontBody as Body.CelestialBody)?.Frame.Name + : string.Empty; + string targetFrame = targetShape == ShapeType.Ellipsoid + ? (target as Body.CelestialBody)?.Frame.Name + : String.Empty; + var windows = new Window[1000]; + for (var i = 0; i < 1000; i++) + { + windows[i] = new Window(double.NaN, double.NaN); + } + + FindWindowsOnOccultationConstraintProxy(searchWindow.Convert(), observer.NaifId, target.NaifId, + targetFrame, targetShape.GetDescription(), + frontBody.NaifId, frontFrame, frontShape.GetDescription(), occultationType.GetDescription(), + aberration.GetDescription(), stepSize.TotalSeconds, windows); + return windows.Where(x => !double.IsNaN(x.Start)).Select(x => x.Convert()); + } + } + + /// + /// Find time windows based on occultation constraint + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public IEnumerable FindWindowsOnOccultationConstraint(TimeSystem.Window searchWindow, int observerId, + int targetId, ShapeType targetShape, int frontBodyId, ShapeType frontShape, + OccultationType occultationType, Aberration aberration, TimeSpan stepSize) + { + lock (lockObject) + { + IO.Astrodynamics.Body.CelestialBody frontBody = new IO.Astrodynamics.Body.CelestialBody(frontBodyId); + IO.Astrodynamics.Body.CelestialBody targetBody = new IO.Astrodynamics.Body.CelestialBody(targetId); + string frontFrame = frontShape == ShapeType.Ellipsoid + ? frontBody.Frame.Name + : string.Empty; + string targetFrame = targetShape == ShapeType.Ellipsoid + ? targetBody.Frame.Name + : String.Empty; + var windows = new Window[1000]; + for (var i = 0; i < 1000; i++) + { + windows[i] = new Window(double.NaN, double.NaN); + } + + FindWindowsOnOccultationConstraintProxy(searchWindow.Convert(), observerId, targetId, targetFrame, targetShape.GetDescription(), + frontBody.NaifId, frontFrame, frontShape.GetDescription(), occultationType.GetDescription(), aberration.GetDescription(), stepSize.TotalSeconds, windows); + return windows.Where(x => !double.IsNaN(x.Start)).Select(x => x.Convert()); + } + } + + /// + /// Find time windows based on coordinate constraint + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public IEnumerable FindWindowsOnCoordinateConstraint(TimeSystem.Window searchWindow, INaifObject observer, + INaifObject target, Frame frame, CoordinateSystem coordinateSystem, Coordinate coordinate, + RelationnalOperator relationalOperator, double value, double adjustValue, Aberration aberration, + TimeSpan stepSize) + { + if (observer == null) throw new ArgumentNullException(nameof(observer)); + if (target == null) throw new ArgumentNullException(nameof(target)); + if (frame == null) throw new ArgumentNullException(nameof(frame)); + lock (lockObject) + { + var windows = new Window[1000]; + for (var i = 0; i < 1000; i++) + { + windows[i] = new Window(double.NaN, double.NaN); + } + + FindWindowsOnCoordinateConstraintProxy(searchWindow.Convert(), observer.NaifId, target.NaifId, + frame.Name, coordinateSystem.GetDescription(), + coordinate.GetDescription(), relationalOperator.GetDescription(), value, adjustValue, + aberration.GetDescription(), stepSize.TotalSeconds, windows); + return windows.Where(x => !double.IsNaN(x.Start)).Select(x => x.Convert()); + } + } + + /// + /// Find time windows based on coordinate constraint + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public IEnumerable FindWindowsOnCoordinateConstraint(TimeSystem.Window searchWindow, int observerId, + int targetId, Frame frame, CoordinateSystem coordinateSystem, Coordinate coordinate, + RelationnalOperator relationalOperator, double value, double adjustValue, Aberration aberration, + TimeSpan stepSize) + { + if (frame == null) throw new ArgumentNullException(nameof(frame)); + lock (lockObject) + { + var windows = new Window[1000]; + for (var i = 0; i < 1000; i++) + { + windows[i] = new Window(double.NaN, double.NaN); + } + + FindWindowsOnCoordinateConstraintProxy(searchWindow.Convert(), observerId, targetId, + frame.Name, coordinateSystem.GetDescription(), + coordinate.GetDescription(), relationalOperator.GetDescription(), value, adjustValue, + aberration.GetDescription(), stepSize.TotalSeconds, windows); + return windows.Where(x => !double.IsNaN(x.Start)).Select(x => x.Convert()); + } + } + + /// + /// Find time windows based on illumination constraint + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public IEnumerable FindWindowsOnIlluminationConstraint(TimeSystem.Window searchWindow, INaifObject observer, + INaifObject targetBody, Frame fixedFrame, + Coordinates.Planetodetic planetodetic, IlluminationAngle illuminationType, RelationnalOperator relationalOperator, + double value, double adjustValue, Aberration aberration, TimeSpan stepSize, INaifObject illuminationSource, + string method = "Ellipsoid") + { + if (observer == null) throw new ArgumentNullException(nameof(observer)); + if (targetBody == null) throw new ArgumentNullException(nameof(targetBody)); + if (fixedFrame == null) throw new ArgumentNullException(nameof(fixedFrame)); + if (illuminationSource == null) throw new ArgumentNullException(nameof(illuminationSource)); + if (method == null) throw new ArgumentNullException(nameof(method)); + lock (lockObject) + { + var windows = new Window[1000]; + for (var i = 0; i < 1000; i++) + { + windows[i] = new Window(double.NaN, double.NaN); + } + + FindWindowsOnIlluminationConstraintProxy(searchWindow.Convert(), observer.NaifId, + illuminationSource.Name, targetBody.NaifId, fixedFrame.Name, + planetodetic.Convert(), + illuminationType.GetDescription(), relationalOperator.GetDescription(), value, adjustValue, + aberration.GetDescription(), stepSize.TotalSeconds, method, windows); + return windows.Where(x => !double.IsNaN(x.Start)).Select(x => x.Convert()); + } + } + + public IEnumerable FindWindowsOnIlluminationConstraint(TimeSystem.Window searchWindow, int observerId, + int targetBodyId, Frame fixedFrame, Coordinates.Planetodetic planetodetic, IlluminationAngle illuminationType, RelationnalOperator relationalOperator, + double value, double adjustValue, Aberration aberration, TimeSpan stepSize, int illuminationSourceId, + string method = "Ellipsoid") + { + if (fixedFrame == null) throw new ArgumentNullException(nameof(fixedFrame)); + if (method == null) throw new ArgumentNullException(nameof(method)); + lock (lockObject) + { + var windows = new Window[1000]; + for (var i = 0; i < 1000; i++) + { + windows[i] = new Window(double.NaN, double.NaN); + } + + FindWindowsOnIlluminationConstraintProxy(searchWindow.Convert(), observerId, + illuminationSourceId.ToString(), targetBodyId, fixedFrame.Name, + planetodetic.Convert(), + illuminationType.GetDescription(), relationalOperator.GetDescription(), value, adjustValue, + aberration.GetDescription(), stepSize.TotalSeconds, method, windows); + return windows.Where(x => !double.IsNaN(x.Start)).Select(x => x.Convert()); + } + } + + /// + /// Find time window when a target is in instrument's field of view + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public IEnumerable FindWindowsInFieldOfViewConstraint(TimeSystem.Window searchWindow, Spacecraft observer, + Instrument instrument, INaifObject target, Frame targetFrame, ShapeType targetShape, Aberration aberration, + TimeSpan stepSize) + { + if (observer == null) throw new ArgumentNullException(nameof(observer)); + if (instrument == null) throw new ArgumentNullException(nameof(instrument)); + if (target == null) throw new ArgumentNullException(nameof(target)); + if (targetFrame == null) throw new ArgumentNullException(nameof(targetFrame)); + lock (lockObject) + { + return FindWindowsInFieldOfViewConstraint(searchWindow, observer.NaifId, instrument.NaifId, target.NaifId, targetFrame, targetShape, aberration, stepSize); + } + } + + /// + /// Find time window when a target is in instrument's field of view + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public IEnumerable FindWindowsInFieldOfViewConstraint(TimeSystem.Window searchWindow, int observerId, + int instrumentId, int targetId, Frame targetFrame, ShapeType targetShape, Aberration aberration, TimeSpan stepSize) + { + if (targetFrame == null) throw new ArgumentNullException(nameof(targetFrame)); + lock (lockObject) + { + var windows = new Window[1000]; + for (var i = 0; i < 1000; i++) + { + windows[i] = new Window(double.NaN, double.NaN); + } + + var searchWindowDto = searchWindow.Convert(); + + FindWindowsInFieldOfViewConstraintProxy(searchWindowDto, observerId, instrumentId, targetId, targetFrame.Name, targetShape.GetDescription(), + aberration.GetDescription(), stepSize.TotalSeconds, windows); + + return windows.Where(x => !double.IsNaN(x.Start)).Select(x => x.Convert()); + } + } + + /// + /// Read object ephemeris for a given period + /// + /// + /// + /// + /// + /// + /// + /// + public IEnumerable ReadEphemeris(TimeSystem.Window searchWindow, + ILocalizable observer, ILocalizable target, Frame frame, + Aberration aberration, TimeSpan stepSize) + { + ArgumentNullException.ThrowIfNull(observer); + ArgumentNullException.ThrowIfNull(target); + ArgumentNullException.ThrowIfNull(frame); + lock (lockObject) + { + const int messageSize = 10000; + List orbitalParameters = []; + int occurrences = (int)(searchWindow.Length / stepSize / messageSize); + + for (int i = 0; i <= occurrences; i++) + { + var start = searchWindow.StartDate + i * messageSize * stepSize; + var end = start + messageSize * stepSize > searchWindow.EndDate ? searchWindow.EndDate : (start + messageSize * stepSize) - stepSize; + var window = new TimeSystem.Window(start, end); + var stateVectors = new StateVector[messageSize]; + ReadEphemerisProxy(window.Convert(), observer.NaifId, target.NaifId, frame.Name, + aberration.GetDescription(), stepSize.TotalSeconds, + stateVectors); + orbitalParameters.AddRange(stateVectors.Where(x => !string.IsNullOrEmpty(x.Frame)).Select(x => + new OrbitalParameters.StateVector(x.Position.Convert(), x.Velocity.Convert(), observer, Time.Create(x.Epoch, TimeFrame.TDBFrame), frame))); + } + + return orbitalParameters; + } + } + + /// + /// Return state vector at given epoch + /// + /// + /// + /// + /// + /// + /// + /// + public OrbitalParameters.OrbitalParameters ReadEphemeris(Time epoch, ILocalizable observer, + ILocalizable target, Frame frame, Aberration aberration) + { + ArgumentNullException.ThrowIfNull(observer); + ArgumentNullException.ThrowIfNull(target); + ArgumentNullException.ThrowIfNull(frame); + lock (lockObject) + { + if (frame == null) throw new ArgumentNullException(nameof(frame)); + var stateVector = ReadEphemerisAtGivenEpochProxy(epoch.TimeSpanFromJ2000().TotalSeconds, observer.NaifId, + target.NaifId, frame.Name, aberration.GetDescription()); + return new OrbitalParameters.StateVector(stateVector.Position.Convert(), stateVector.Velocity.Convert(), observer, + Time.Create(stateVector.Epoch, TimeFrame.TDBFrame), frame); + } + } + + /// + /// Read spacecraft orientation for a given period + /// + /// + /// + /// + /// + /// + /// + public IEnumerable ReadOrientation(TimeSystem.Window searchWindow, + Spacecraft spacecraft, TimeSpan tolerance, + Frame referenceFrame, TimeSpan stepSize) + { + if (spacecraft == null) throw new ArgumentNullException(nameof(spacecraft)); + if (referenceFrame == null) throw new ArgumentNullException(nameof(referenceFrame)); + lock (lockObject) + { + var stateOrientations = new StateOrientation[10000]; + ReadOrientationProxy(searchWindow.Convert(), spacecraft.NaifId, tolerance.TotalSeconds, + referenceFrame.Name, stepSize.TotalSeconds, + stateOrientations); + return stateOrientations.Where(x => x.Frame != null).Select(x => new OrbitalParameters.StateOrientation( + x.Rotation.Convert(), x.AngularVelocity.Convert(), Time.Create(x.Epoch, TimeFrame.TDBFrame), referenceFrame)); + } + } + + /// + /// Write ephemeris file + /// + /// + /// + /// + /// + public bool WriteEphemeris(FileInfo filePath, INaifObject naifObject, + IEnumerable stateVectors) + { + if (naifObject == null) throw new ArgumentNullException(nameof(naifObject)); + if (filePath == null) throw new ArgumentNullException(nameof(filePath)); + if (stateVectors == null) throw new ArgumentNullException(nameof(stateVectors)); + lock (lockObject) + { + var enumerable = stateVectors as OrbitalParameters.StateVector[] ?? stateVectors.ToArray(); + if (!enumerable.Any()) + throw new ArgumentException("Value cannot be an empty collection.", nameof(stateVectors)); + bool res = WriteEphemerisProxy(filePath.FullName, naifObject.NaifId, stateVectors.Select(x => x.Convert()).ToArray(), + (uint)enumerable.Length); + if (res == false) + { + throw new InvalidOperationException( + "An error occurred while writing ephemeris. You can have more details on standard output."); + } + + return true; + } + } + + public bool WriteOrientation(FileInfo filePath, INaifObject naifObject, IEnumerable stateOrientations) + { + if (naifObject == null) throw new ArgumentNullException(nameof(naifObject)); + if (filePath == null) throw new ArgumentNullException(nameof(filePath)); + if (stateOrientations == null) throw new ArgumentNullException(nameof(stateOrientations)); + lock (lockObject) + { + var enumerable = stateOrientations as OrbitalParameters.StateOrientation[] ?? stateOrientations.ToArray(); + if (!enumerable.Any()) + throw new ArgumentException("Value cannot be an empty collection.", nameof(stateOrientations)); + bool res = WriteOrientationProxy(filePath.FullName, naifObject.NaifId, stateOrientations.Select(x => x.Convert()).ToArray(), (uint)enumerable.Length); + if (res == false) + { + throw new InvalidOperationException( + "An error occurred while writing orientation. You can have more details on standard output."); + } + + return true; + } + } + + /// + /// Get celestial celestialItem information like radius, GM, name, associated frame, ... + /// + /// + /// + public CelestialBody GetCelestialBodyInfo(int naifId) + { + lock (lockObject) + { + return GetCelestialBodyInfoProxy(naifId); + } + } + + /// + /// Transform a frame to another + /// + /// + /// + /// + /// + /// + public OrbitalParameters.StateOrientation TransformFrame(Time epoch, Frame fromFrame, Frame toFrame) + { + lock (lockObject) + { + if (fromFrame == null) throw new ArgumentNullException(nameof(fromFrame)); + if (toFrame == null) throw new ArgumentNullException(nameof(toFrame)); + var res = TransformFrameProxy(fromFrame.Name, toFrame.Name, epoch.ToTDB().TimeSpanFromJ2000().TotalSeconds); + + return new OrbitalParameters.StateOrientation( + new Quaternion(res.Rotation.W, res.Rotation.X, res.Rotation.Y, res.Rotation.Z), + new Vector3(res.AngularVelocity.X, res.AngularVelocity.Y, res.AngularVelocity.Z), epoch, fromFrame); + } + } + + public IEnumerable TransformFrame(TimeSystem.Window window, Frame fromFrame, Frame toFrame, TimeSpan stepSize) + { + for (Time i = window.StartDate; i < window.EndDate; i += stepSize) + { + yield return TransformFrame(i, fromFrame, toFrame); + } + } + + /// + /// Convert TLE to state vector at given epoch + /// + /// + /// + /// + /// + /// + public OrbitalParameters.OrbitalParameters ConvertTleToStateVector(string line1, string line2, string line3, + Time epoch) + { + lock (lockObject) + { + var res = ConvertTLEToStateVectorProxy(line1, line2, line3, epoch.ToTDB().TimeSpanFromJ2000().TotalSeconds); + return new OrbitalParameters.StateVector(res.Position.Convert(), res.Velocity.Convert(), + new Body.CelestialBody(PlanetsAndMoons.EARTH, Frame.ECLIPTIC_J2000, epoch), epoch, + new Frame(res.Frame)).ToFrame(Frame.ICRF); + } + } + + public IO.Astrodynamics.OrbitalParameters.KeplerianElements ConvertStateVectorToConicOrbitalElement(IO.Astrodynamics.OrbitalParameters.StateVector stateVector) + { + lock (lockObject) + { + var svDto = stateVector.Convert(); + return ConvertStateVectorToConicOrbitalElementProxy(svDto, stateVector.Observer.GM).Convert(); + } + } + + public IO.Astrodynamics.OrbitalParameters.StateVector ConvertEquinoctialElementsToStateVector(IO.Astrodynamics.OrbitalParameters.EquinoctialElements equinoctialElements) + { + lock (lockObject) + { + return ConvertEquinoctialElementsToStateVectorProxy(equinoctialElements.Convert()).Convert(); + } + } + + public IO.Astrodynamics.OrbitalParameters.StateVector ConvertConicElementsToStateVector(IO.Astrodynamics.OrbitalParameters.KeplerianElements keplerianElements) + { + lock (lockObject) + { + return ConvertConicElementsToStateVectorProxy(keplerianElements.Convert()).Convert(); + } + } + + public IO.Astrodynamics.OrbitalParameters.StateVector ConvertConicElementsToStateVector(IO.Astrodynamics.OrbitalParameters.KeplerianElements keplerianElements, Time epoch) + { + lock (lockObject) + { + return ConvertConicElementsToStateVectorAtEpochProxy(keplerianElements.Convert(), epoch.ToTDB().TimeSpanFromJ2000().TotalSeconds, keplerianElements.Observer.GM) + .Convert(); + } + } + + public OrbitalParameters.StateVector Propagate2Bodies(OrbitalParameters.StateVector stateVector, TimeSpan dt) + { + lock (lockObject) + { + return Propagate2BodiesProxy(stateVector.Convert(), stateVector.Observer.GM, dt.TotalSeconds).Convert(); + } + } + + public OrbitalParameters.StateVector Propagate2Bodies(OrbitalParameters.StateVector stateVector, Time targetEpoch) + { + return Propagate2Bodies(stateVector, targetEpoch - stateVector.Epoch); + } } \ No newline at end of file diff --git a/IO.Astrodynamics.Net/IO.Astrodynamics/Body/CelestialItem.cs b/IO.Astrodynamics.Net/IO.Astrodynamics/Body/CelestialItem.cs index 043bb3fd..d3670676 100644 --- a/IO.Astrodynamics.Net/IO.Astrodynamics/Body/CelestialItem.cs +++ b/IO.Astrodynamics.Net/IO.Astrodynamics/Body/CelestialItem.cs @@ -119,7 +119,6 @@ public abstract class CelestialItem : ILocalizable, IEquatable /// Initial orbital parameters frame /// Epoch /// - /// protected CelestialItem(int naifId, Frame frame, in Time epoch, GeopotentialModelParameters geopotentialModelParameters = null) { _dataProvider = Configuration.Instance.DataProvider; diff --git a/IO.Astrodynamics.Net/IO.Astrodynamics/DataProvider/IDataProvider.cs b/IO.Astrodynamics.Net/IO.Astrodynamics/DataProvider/IDataProvider.cs index 29571baa..46e8cf47 100644 --- a/IO.Astrodynamics.Net/IO.Astrodynamics/DataProvider/IDataProvider.cs +++ b/IO.Astrodynamics.Net/IO.Astrodynamics/DataProvider/IDataProvider.cs @@ -1,5 +1,7 @@ +using System; using System.Collections.Generic; using System.IO; +using System.Threading.Tasks; using IO.Astrodynamics.Body; using IO.Astrodynamics.Frames; using IO.Astrodynamics.OrbitalParameters; @@ -9,9 +11,12 @@ namespace IO.Astrodynamics.DataProvider; public interface IDataProvider { - StateOrientation FrameTransformation(Frame source, Frame target, in Time date); - OrbitalParameters.OrbitalParameters GetEphemeris(in Time epoch, ILocalizable target, ILocalizable observer, Frame frame, Aberration aberration); + Task> FrameTransformationAsync(Window window, Frame source, Frame target, TimeSpan stepSize); + StateOrientation FrameTransformation(in Time date, Frame source, Frame target); + OrbitalParameters.OrbitalParameters GetEphemeris(in Time date, ILocalizable target, ILocalizable observer, Frame frame, Aberration aberration); + Task> GetEphemerisAsync(Window window, ILocalizable target, ILocalizable observer, Frame frame, Aberration aberration, TimeSpan stepSize); + Task GetCelestialBodyInfoAsync(int naifId); DTO.CelestialBody GetCelestialBodyInfo(int naifId); - void WriteEphemeris(FileInfo outputFile,INaifObject naifObject, IEnumerable stateVectors); - void WriteOrientation(FileInfo outputFile,INaifObject naifObject, IEnumerable stateOrientations); + void WriteEphemeris(FileInfo outputFile, INaifObject naifObject, IEnumerable stateVectors); + void WriteOrientation(FileInfo outputFile, INaifObject naifObject, IEnumerable stateOrientations); } \ No newline at end of file diff --git a/IO.Astrodynamics.Net/IO.Astrodynamics/DataProvider/SpiceDataProvider.cs b/IO.Astrodynamics.Net/IO.Astrodynamics/DataProvider/SpiceDataProvider.cs index aa181f69..a289329c 100644 --- a/IO.Astrodynamics.Net/IO.Astrodynamics/DataProvider/SpiceDataProvider.cs +++ b/IO.Astrodynamics.Net/IO.Astrodynamics/DataProvider/SpiceDataProvider.cs @@ -1,27 +1,46 @@ +using System; using System.Collections.Generic; using System.IO; +using System.Threading.Tasks; using IO.Astrodynamics.Body; using IO.Astrodynamics.Frames; using IO.Astrodynamics.Math; using IO.Astrodynamics.OrbitalParameters; using IO.Astrodynamics.SolarSystemObjects; using IO.Astrodynamics.TimeSystem; +using CelestialBody = IO.Astrodynamics.DTO.CelestialBody; namespace IO.Astrodynamics.DataProvider; public class SpiceDataProvider : IDataProvider { - public StateOrientation FrameTransformation(Frame source, Frame target, in Time date) + public Task> FrameTransformationAsync(Window window, Frame source, Frame target, TimeSpan stepSize) { - return API.Instance.TransformFrame(source, target, date); + return Task.Run(() => API.Instance.TransformFrame(window, source, target, stepSize)); } - public OrbitalParameters.OrbitalParameters GetEphemeris(in Time epoch, ILocalizable target, ILocalizable observer, Frame frame, Aberration aberration) + public StateOrientation FrameTransformation(in Time date, Frame source, Frame target) { - return API.Instance.ReadEphemeris(epoch, observer, target, frame, aberration); + return API.Instance.TransformFrame(date, source, target); } - public DTO.CelestialBody GetCelestialBodyInfo(int naifId) + public OrbitalParameters.OrbitalParameters GetEphemeris(in Time date, ILocalizable target, ILocalizable observer, Frame frame, Aberration aberration) + { + return API.Instance.ReadEphemeris(date, observer, target, frame, aberration); + } + + public Task> GetEphemerisAsync(Window window, ILocalizable target, ILocalizable observer, Frame frame, Aberration aberration, + TimeSpan stepSize) + { + return Task.Run(() => API.Instance.ReadEphemeris(window, observer, target, frame, aberration, stepSize)); + } + + public Task GetCelestialBodyInfoAsync(int naifId) + { + return Task.Run(() => API.Instance.GetCelestialBodyInfo(naifId)); + } + + CelestialBody IDataProvider.GetCelestialBodyInfo(int naifId) { return API.Instance.GetCelestialBodyInfo(naifId); } diff --git a/IO.Astrodynamics.Net/IO.Astrodynamics/Frames/Frame.cs b/IO.Astrodynamics.Net/IO.Astrodynamics/Frames/Frame.cs index 5d848c29..054b1651 100644 --- a/IO.Astrodynamics.Net/IO.Astrodynamics/Frames/Frame.cs +++ b/IO.Astrodynamics.Net/IO.Astrodynamics/Frames/Frame.cs @@ -4,6 +4,7 @@ using System.Collections.Immutable; using System.IO; using System.Linq; +using System.Threading.Tasks; using IO.Astrodynamics.DataProvider; using IO.Astrodynamics.Math; using IO.Astrodynamics.OrbitalParameters; @@ -17,7 +18,7 @@ public class Frame : IEquatable public string Name { get; } public int? Id { get; } - protected SortedDictionary _stateOrientationsToICRF = new(); + protected SortedDictionary _stateOrientationsToICRF = new(); protected ImmutableSortedDictionary StateOrientationsToICRF => _stateOrientationsToICRF.ToImmutableSortedDictionary(); /// @@ -67,25 +68,25 @@ public Frame(string name, int? id = null) Name = name; Id = id; } - - public virtual StateOrientation GetStateOrientationToICRF(Time epoch) + + public virtual StateOrientation GetStateOrientationToICRF(Time date) { - return _stateOrientationsToICRF.GetOrAdd(epoch, _ => _dataProvider.FrameTransformation(this, ICRF, epoch)); + return _stateOrientationsToICRF.GetOrAdd(date, dt => _dataProvider.FrameTransformation(dt, this, ICRF)); } - + public bool AddStateOrientationToICRF(StateOrientation stateOrientation) { return _stateOrientationsToICRF.TryAdd(stateOrientation.Epoch, stateOrientation); } - + public StateOrientation GetLatestStateOrientationToICRF() { - return _stateOrientationsToICRF.Values.OrderBy(x=>x.Epoch).LastOrDefault(); + return _stateOrientationsToICRF.Values.OrderBy(x => x.Epoch).LastOrDefault(); } - + public IEnumerable GetStateOrientationsToICRF() { - return _stateOrientationsToICRF.OrderBy(x=>x.Key).Select(x=>x.Value).ToArray(); + return _stateOrientationsToICRF.OrderBy(x => x.Key).Select(x => x.Value).ToArray(); } public StateOrientation ToFrame(Frame targetFrame, Time epoch) @@ -104,13 +105,14 @@ public StateOrientation ToFrame(Frame targetFrame, Time epoch) return new StateOrientation(rotation, angularVelocity, epoch, this); } - + public void ClearStateOrientations() { _stateOrientationsToICRF.Clear(); } #region Operators + public override string ToString() { return Name; @@ -145,5 +147,6 @@ public override int GetHashCode() { return !Equals(left, right); } + #endregion } \ No newline at end of file diff --git a/IO.Astrodynamics.Net/IO.Astrodynamics/IO.Astrodynamics.nuspec b/IO.Astrodynamics.Net/IO.Astrodynamics/IO.Astrodynamics.nuspec index cda4adea..d94f1c10 100644 --- a/IO.Astrodynamics.Net/IO.Astrodynamics/IO.Astrodynamics.nuspec +++ b/IO.Astrodynamics.Net/IO.Astrodynamics/IO.Astrodynamics.nuspec @@ -4,7 +4,7 @@ IO.Astrodynamics Sylvain Guillet Sylvain Guillet - 6.0.0-preview-5 + 6.0.0-preview-6 Astrodynamics framework images\dragonfly-dark-trans.png docs\README.md