public void RegisterThreeStarFit(ThreeStarFit coarseFit) { CoarseFit = coarseFit; }
private LeastSquareFittedAstrometry SolveStarPairs( IStarMap starMap, Dictionary<ImagePixel, IStar> matchedPairs, Dictionary<int, ulong> matchedFeatureIdToStarIdIndexes, ThreeStarFit.StarPair pair_i, ThreeStarFit.StarPair pair_j, ThreeStarFit.StarPair pair_k, double fittedFocalLength, PyramidEntry pyramidLog, int? minMatchedStars = null) { double RA0Deg, DE0Deg; ThreeStarFit coarseFit = new ThreeStarFit(m_PlateConfig, pair_i, pair_j, pair_k); if (!coarseFit.IsSolved) { if (coarseFit.IsSingularity) { if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) Trace.WriteLine("ThreeStarFit.Var1 - Singularity"); Dictionary<ImagePixel, IStar> threeStarDict = new Dictionary<ImagePixel, IStar>(); try { threeStarDict.Add(ImagePixel.CreateImagePixelWithFeatureId(0, 255, pair_i.XImage, pair_i.YImage), pair_i.Star); threeStarDict.Add(ImagePixel.CreateImagePixelWithFeatureId(1, 255, pair_j.XImage, pair_j.YImage), pair_j.Star); threeStarDict.Add(ImagePixel.CreateImagePixelWithFeatureId(2, 255, pair_k.XImage, pair_k.YImage), pair_k.Star); } catch(ArgumentException) { if (pyramidLog != null) pyramidLog.FailureReason = PyramidEntryFailureReason.ThreeStarFitFailed; if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) Trace.WriteLine("ThreeStarFit.Var2 - Failed with ArgumentException"); return null; } DirectTransRotAstrometry threeStarSolution = DirectTransRotAstrometry.SolveByThreeStars(m_PlateConfig, threeStarDict, 2); if (threeStarSolution == null) { if (pyramidLog != null) pyramidLog.FailureReason = PyramidEntryFailureReason.ThreeStarFitFailed; if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) Trace.WriteLine("ThreeStarFit.Var2 - Failed"); return null; } else { RA0Deg = threeStarSolution.RA0Deg; DE0Deg = threeStarSolution.DE0Deg; } } else { if (pyramidLog != null) pyramidLog.FailureReason = PyramidEntryFailureReason.ThreeStarFitFailed; if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) Trace.WriteLine("ThreeStarFit.Var1 - Failed"); return null; } } else { if (pyramidLog != null) pyramidLog.RegisterThreeStarFit(coarseFit); RA0Deg = coarseFit.RA0Deg; DE0Deg = coarseFit.DE0Deg; } #if DEBUG || PYRAMID_DEBUG if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) { foreach (int key in matchedFeatureIdToStarIdIndexes.Keys) #if PYRAMID_DEBUG Trace #else Debug #endif .WriteLine(string.Format("Star({0}) -> Feature({1})", matchedFeatureIdToStarIdIndexes[key], key)); } #endif PlateConstantsSolver solver = new PlateConstantsSolver(m_PlateConfig); solver.InitPlateSolution(RA0Deg, DE0Deg); foreach (ImagePixel feature in matchedPairs.Keys) { IStar star = matchedPairs[feature]; var kvp = matchedFeatureIdToStarIdIndexes.Single(x => x.Value == star.StarNo); int featureId = kvp.Key; solver.AddStar(feature, star, featureId); } LeastSquareFittedAstrometry leastSquareFittedAstrometry = null; LeastSquareFittedAstrometry firstFit = null; try { // This is a linear regression when doing simple field alignment. We always use a Linear Fit leastSquareFittedAstrometry = solver.SolveWithLinearRegression( FitOrder.Linear, CorePyramidConfig.Default.MinPyramidAlignedStars, m_MaxLeastSquareResidual, out firstFit); } catch (DivideByZeroException) { } if (leastSquareFittedAstrometry != null) { if (pyramidLog != null) pyramidLog.RegisterLinearFit(leastSquareFittedAstrometry); if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) Trace.WriteLine("Checking possible solution. "); List<ulong> usedStarIds = leastSquareFittedAstrometry.FitInfo.AllStarPairs .Where(p => p.FitInfo.UsedInSolution) .Select(p => p.StarNo) .ToList(); int usedStars = usedStarIds.Count; matchedFeatureIdToStarIdIndexes = matchedFeatureIdToStarIdIndexes .Where(kvp => usedStarIds.Contains(kvp.Value)) .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); List<double> residuals = leastSquareFittedAstrometry.FitInfo.AllStarPairs .Where(p => !p.FitInfo.ExcludedForHighResidual) .Select(p => p.FitInfo.ResidualArcSec) .ToList(); double secondLargeResidual = 0; if (residuals.Count > 0) { residuals = residuals.OrderByDescending(r => r).ToList(); secondLargeResidual = residuals.Count > 1 ? residuals[1] : residuals[0]; } double onePixDistArcSec = m_PlateConfig.GetDistanceInArcSec(0, 0, 1, 1); if (secondLargeResidual > onePixDistArcSec * CorePyramidConfig.Default.MaxAllowedResidualInPixelsInSuccessfulFit) { if (pyramidLog != null) pyramidLog.FailureReason = PyramidEntryFailureReason.SecondLargestResidualIsTooLarge; if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) Trace.WriteLine(string.Format( "Failing preliminary solution because the second largest residual {0}\" is larger than {1}px", secondLargeResidual.ToString("0.0"), CorePyramidConfig.Default.MaxAllowedResidualInPixelsInSuccessfulFit)); return null; } if (minMatchedStars.HasValue) { if (usedStars < minMatchedStars.Value) { if (pyramidLog != null) pyramidLog.FailureReason = PyramidEntryFailureReason.InsufficientStarsForCalibration; if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) Trace.WriteLine(string.Format( "Failing preliminary solution because on {0} stars are used but {1} are required as a minimum for calibration.", usedStars, CorePyramidConfig.Default.MinMatchedStarsForCalibration)); return null; } } } else { if (pyramidLog != null) pyramidLog.FailureReason = PyramidEntryFailureReason.LinearFitFailed; if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) { Debug.WriteLine("DistanceBasedContext.LeastSquareFittedAstrometry Failed!"); foreach (PlateConstStarPair pair in solver.Pairs) { #if PYRAMID_DEBUG Trace #else Debug #endif .WriteLine(string.Format("{0} ({1}) -> Residuals: {2}\", {3}\"", pair.StarNo, pair.FitInfo.UsedInSolution ? "Included" : "Excluded", pair.FitInfo.ResidualRAArcSec.ToString("0.00"), pair.FitInfo.ResidualDEArcSec.ToString("0.00"))); } } } if (leastSquareFittedAstrometry != null) { leastSquareFittedAstrometry.FitInfo.FittedFocalLength = fittedFocalLength; if (pyramidLog != null) pyramidLog.RegisterFocalLength(fittedFocalLength); } return leastSquareFittedAstrometry; }