public async Task Successful_Centering_NoSeparation_Test() { var seq = new CaptureSequence(); var coordinates = new Coordinates(Angle.ByDegree(5), Angle.ByDegree(3), Epoch.JNOW); var parameter = new CenterSolveParameter() { Coordinates = coordinates.Transform(Epoch.JNOW), FocalLength = 700, Threshold = 1 }; var testResult = new PlateSolveResult() { Success = true, Coordinates = coordinates.Transform(Epoch.JNOW) }; captureSolverMock .Setup(x => x.Solve(seq, It.IsAny <CaptureSolverParameter>(), It.IsAny <IProgress <PlateSolveProgress> >(), It.IsAny <IProgress <ApplicationStatus> >(), It.IsAny <CancellationToken>())) .ReturnsAsync(testResult); telescopeMediatorMock .Setup(x => x.GetCurrentPosition()) .Returns(coordinates); var sut = new CenteringSolver(plateSolverMock.Object, blindSolverMock.Object, null, telescopeMediatorMock.Object); sut.CaptureSolver = captureSolverMock.Object; var result = await sut.Center(seq, parameter, default, default, default);
protected override async Task <PlateSolveResult> SolveAsyncImpl( IImageData source, PlateSolveParameter parameter, PlateSolveImageProperties imageProperties, IProgress <ApplicationStatus> progress, CancellationToken cancelToken) { PlateSolveResult result = new PlateSolveResult(); try { progress.Report(new ApplicationStatus() { Status = "Authenticating to Astrometery.net..." }); var session = await GetAuthenticationToken(cancelToken); progress.Report(new ApplicationStatus() { Status = "Uploading image to Astrometry.net..." }); var jobId = await SubmitImageJob(progress, source, session, cancelToken); progress.Report(new ApplicationStatus() { Status = $"Getting result for Astrometry.net job {jobId}..." }); JobResult jobinfo = await GetJobResult(jobId, cancelToken); result.Orientation = jobinfo.calibration.orientation; /* The orientation is mirrored on the x-axis */ result.Flipped = jobinfo.calibration.parity < 0; result.Orientation = 180 - result.Orientation + 360; result.Pixscale = jobinfo.calibration.pixscale; result.Coordinates = new Utility.Astrometry.Coordinates(jobinfo.calibration.ra, jobinfo.calibration.dec, Utility.Astrometry.Epoch.J2000, Utility.Astrometry.Coordinates.RAType.Degrees); result.Radius = jobinfo.calibration.radius; } catch (OperationCanceledException) { result.Success = false; } catch (Exception ex) { result.Success = false; Notification.ShowError($"Error plate solving with Astrometry.net. {ex.Message}"); } if (result.Success) { progress.Report(new ApplicationStatus() { Status = "Solved" }); } else { progress.Report(new ApplicationStatus() { Status = "Solve failed" }); } return(result); }
protected override async Task <PlateSolveResult> SolveAsyncImpl( IImageData source, PlateSolveParameter parameter, PlateSolveImageProperties imageProperties, IProgress <ApplicationStatus> progress, CancellationToken cancelToken) { var result = new PlateSolveResult() { Success = false }; string imagePath = null, outputPath = null; try { //Copy Image to local app data imagePath = await PrepareAndSaveImage(source, cancelToken); progress.Report(new ApplicationStatus() { Status = Locale.Loc.Instance["LblSolving"] }); outputPath = GetOutputPath(imagePath); await StartCLI(imagePath, outputPath, parameter, imageProperties, progress, cancelToken); //Extract solution coordinates result = ReadResult(outputPath, parameter, imageProperties); } finally { progress.Report(new ApplicationStatus() { Status = string.Empty }); if (imagePath != null && File.Exists(imagePath)) { File.Delete(imagePath); } if (outputPath != null && File.Exists(outputPath)) { File.Delete(outputPath); } } return(result); }
protected override PlateSolveResult ReadResult( string outputFilePath, PlateSolveParameter parameter, PlateSolveImageProperties imageProperties) { var result = new PlateSolveResult() { Success = false }; if (File.Exists(outputFilePath)) { string[] lines = File.ReadAllLines(outputFilePath, Encoding.UTF8); if (lines.Length > 0) { if (lines[0] == "OK" && lines.Length >= 8) { var ra = double.Parse(lines[1]); var dec = double.Parse(lines[2]); result.Coordinates = new Coordinates(ra, dec, Epoch.J2000, Coordinates.RAType.Degrees); var fovW = lines[3]; var fovH = lines[4]; result.Pixscale = double.Parse(lines[5]); result.Orientation = double.Parse(lines[6]); /* Due to the way N.I.N.A. writes FITS files, the orientation is mirrored on the x-axis */ result.Orientation = 180 - result.Orientation + 360; var focalLength = lines[7]; result.Success = true; } } } return(result); }
public async Task Successful_CaptureAndSolving_Test() { var imageDataMock = new Mock <IImageData>(); var renderedImageMock = new Mock <IRenderedImage>(); renderedImageMock.SetupGet(x => x.RawImageData).Returns(imageDataMock.Object); var testResult = new PlateSolveResult() { Success = true }; var seq = new CaptureSequence(); var parameter = new CaptureSolverParameter() { FocalLength = 700 }; imagingMediatorMock.Setup(x => x.CaptureAndPrepareImage(seq, It.IsAny <PrepareImageParameters>(), It.IsAny <CancellationToken>(), It.IsAny <IProgress <ApplicationStatus> >())).ReturnsAsync(renderedImageMock.Object); imageSolverMock.Setup(x => x.Solve(imageDataMock.Object, It.IsAny <PlateSolveParameter>(), It.IsAny <IProgress <ApplicationStatus> >(), It.IsAny <CancellationToken>())).ReturnsAsync(testResult); var sut = new CaptureSolver(plateSolverMock.Object, blindSolverMock.Object, imagingMediatorMock.Object); sut.ImageSolver = imageSolverMock.Object; var result = await sut.Solve(seq, parameter, default, default, default);
/// <summary> /// Extract result out of generated .axy file. File consists of three rows /// 1. row: RA,Dec,Code /// 2. row: Scale,Orientation,?,?,Stars /// </summary> /// <returns>PlateSolveResult</returns> protected override PlateSolveResult ReadResult( string outputFilePath, PlateSolveParameter parameter, PlateSolveImageProperties imageProperties) { PlateSolveResult result = new PlateSolveResult() { Success = false }; if (File.Exists(outputFilePath)) { using (var s = new StreamReader(outputFilePath)) { string line; int linenr = 0; while ((line = s.ReadLine()) != null) { string[] resultArr = line.Split(','); if (linenr == 0) { if (resultArr.Length > 2) { double ra, dec; int status; if (resultArr.Length == 5) { /* workaround for when decimal separator is comma instead of point. * won't work when result contains even numbers tho... */ status = int.Parse(resultArr[4]); if (status != 1) { /* error */ result.Success = false; break; } ra = double.Parse(resultArr[0] + "." + resultArr[1], CultureInfo.InvariantCulture); dec = double.Parse(resultArr[2] + "." + resultArr[3], CultureInfo.InvariantCulture); } else { status = int.Parse(resultArr[2]); if (status != 1) { /* error */ result.Success = false; break; } ra = double.Parse(resultArr[0], CultureInfo.InvariantCulture); dec = double.Parse(resultArr[1], CultureInfo.InvariantCulture); } /* success */ result.Success = true; result.Coordinates = new Coordinates(Astrometry.ToDegree(ra), Astrometry.ToDegree(dec), Epoch.J2000, Coordinates.RAType.Degrees); } } if (linenr == 1) { if (resultArr.Length > 2) { if (resultArr.Length > 5) { /* workaround for when decimal separator is comma instead of point. * won't work when result contains even numbers tho... */ result.Pixscale = double.Parse(resultArr[0] + "." + resultArr[1], CultureInfo.InvariantCulture); result.Orientation = double.Parse(resultArr[2] + "." + resultArr[3], CultureInfo.InvariantCulture); result.Flipped = !(double.Parse(resultArr[4] + "." + resultArr[5], CultureInfo.InvariantCulture) < 0); if (result.Flipped) { result.Orientation = result.Orientation - 180; } } else { result.Pixscale = double.Parse(resultArr[0], CultureInfo.InvariantCulture); result.Orientation = double.Parse(resultArr[1], CultureInfo.InvariantCulture); result.Flipped = !(double.Parse(resultArr[2], CultureInfo.InvariantCulture) < 0); if (result.Flipped) { result.Orientation = result.Orientation - 180; } } } } linenr++; } } } return(result); }
protected override PlateSolveResult ReadResult( string outputFilePath, PlateSolveParameter parameter, PlateSolveImageProperties imageProperties) { var result = new PlateSolveResult() { Success = false }; if (!File.Exists(outputFilePath)) { Notification.ShowError("ASTAP - Plate solve failed. No output file found."); return(result); } var dict = File.ReadLines(outputFilePath) .Where(line => !string.IsNullOrWhiteSpace(line)) .Select(line => line.Split(new char[] { '=' }, 2, 0)) .ToDictionary(parts => parts[0], parts => parts[1]); dict.TryGetValue("WARNING", out var warning); if (!dict.ContainsKey("PLTSOLVD") || dict["PLTSOLVD"] != "T") { dict.TryGetValue("ERROR", out var error); Notification.ShowError($"ASTAP - Plate solve failed.{Environment.NewLine}{warning}{Environment.NewLine}{error}"); return(result); } if (!string.IsNullOrWhiteSpace(warning)) { Notification.ShowWarning($"ASTAP - {warning}"); } var wcs = new WorldCoordinateSystem( double.Parse(dict["CRVAL1"], CultureInfo.InvariantCulture), double.Parse(dict["CRVAL2"], CultureInfo.InvariantCulture), double.Parse(dict["CRPIX1"], CultureInfo.InvariantCulture), double.Parse(dict["CRPIX2"], CultureInfo.InvariantCulture), double.Parse(dict["CD1_1"], CultureInfo.InvariantCulture), double.Parse(dict["CD1_2"], CultureInfo.InvariantCulture), double.Parse(dict["CD2_1"], CultureInfo.InvariantCulture), double.Parse(dict["CD2_2"], CultureInfo.InvariantCulture) ); result.Success = true; result.Coordinates = new Coordinates( double.Parse(dict["CRVAL1"], CultureInfo.InvariantCulture), double.Parse(dict["CRVAL2"], CultureInfo.InvariantCulture), Epoch.J2000, Coordinates.RAType.Degrees ); result.Orientation = double.Parse(dict["CROTA2"], CultureInfo.InvariantCulture); /* * CDELT1 and CDELT2 are obsolete. * To calculate pixel scale, we should add the squares of CD1_2 and CD2_2 and take the square root to get degrees. */ if (dict.ContainsKey("CD1_2") && dict.ContainsKey("CD2_2")) { double.TryParse(dict["CD1_2"], NumberStyles.Any, CultureInfo.InvariantCulture, out double cr1y); double.TryParse(dict["CD2_2"], NumberStyles.Any, CultureInfo.InvariantCulture, out double cr2y); result.Pixscale = Astrometry.DegreeToArcsec(Math.Sqrt(Math.Pow(cr1y, 2) + Math.Pow(cr2y, 2))); } /* Due to the way N.I.N.A. writes FITS files, the orientation is mirrored on the x-axis */ result.Orientation = wcs.Rotation - 180; result.Flipped = !wcs.Flipped; return(result); }
protected override PlateSolveResult ReadResult(string outputFilePath, PlateSolveParameter parameter, PlateSolveImageProperties imageProperties) { var result = new PlateSolveResult() { Success = false }; if (File.Exists(outputFilePath)) { var startInfo = new System.Diagnostics.ProcessStartInfo(); startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal; startInfo.FileName = "cmd.exe"; startInfo.UseShellExecute = false; startInfo.RedirectStandardOutput = true; startInfo.CreateNoWindow = true; startInfo.Arguments = string.Format("/C \"\"{0}\" --login -c 'wcsinfo \"{1}\"'\"", bashLocation, outputFilePath.Replace("\\", "/")); using (var process = new System.Diagnostics.Process()) { process.StartInfo = startInfo; process.Start(); Dictionary <string, string> wcsinfo = new Dictionary <string, string>(); while (!process.StandardOutput.EndOfStream) { var line = process.StandardOutput.ReadLine(); if (line != null) { var valuepair = line.Split(' '); if (valuepair != null && valuepair.Length == 2) { wcsinfo[valuepair[0]] = valuepair[1]; } } } if (wcsinfo.ContainsKey("crval0") && wcsinfo.ContainsKey("crval1") && wcsinfo.ContainsKey("crpix0") && wcsinfo.ContainsKey("crpix1") && wcsinfo.ContainsKey("cd11") && wcsinfo.ContainsKey("cd12") && wcsinfo.ContainsKey("cd21") && wcsinfo.ContainsKey("cd22")) { var crval1 = double.Parse(wcsinfo["crval0"]); var crval2 = double.Parse(wcsinfo["crval1"]); var crpix1 = double.Parse(wcsinfo["crpix0"]); var crpix2 = double.Parse(wcsinfo["crpix1"]); var cd11 = double.Parse(wcsinfo["cd11"]); var cd12 = double.Parse(wcsinfo["cd12"]); var cd21 = double.Parse(wcsinfo["cd21"]); var cd22 = double.Parse(wcsinfo["cd22"]); var wcs = new WorldCoordinateSystem( crval1, crval2, crpix1, crpix2, cd11, cd12, cd21, cd22 ); /* Due to the way N.I.N.A. writes FITS files, the orientation is mirrored on the x-axis */ result.Flipped = !wcs.Flipped; } double ra = 0, dec = 0; if (wcsinfo.ContainsKey("ra_center")) { ra = double.Parse(wcsinfo["ra_center"], CultureInfo.InvariantCulture); } if (wcsinfo.ContainsKey("dec_center")) { dec = double.Parse(wcsinfo["dec_center"], CultureInfo.InvariantCulture); } if (wcsinfo.ContainsKey("orientation_center")) { result.Orientation = double.Parse(wcsinfo["orientation_center"], CultureInfo.InvariantCulture); /* Due to the way N.I.N.A. writes FITS files, the orientation is mirrored on the x-axis */ result.Orientation = 180 - result.Orientation + 360; } if (wcsinfo.ContainsKey("pixscale")) { result.Pixscale = double.Parse(wcsinfo["pixscale"], CultureInfo.InvariantCulture); } result.Coordinates = new Coordinates(ra, dec, Epoch.J2000, Coordinates.RAType.Degrees); result.Success = true; } } return(result); }