public static PyramidStarsDensityDistributor BuildPyramidMatchingByMagnitude( List<IStar> pyramidStars, AstroPlate image, IAstrometrySettings settings, Dictionary<int, ulong> debugResolvedStarsWithAppliedExclusions, List<ulong> alwaysIncludeStars, out List<DistanceEntry> distancesByMagnitude, out Dictionary<ulong, Dictionary<ulonglong, DistanceEntry>> starsDistanceCache) { // 1) This should be the first N brightest (or all stars) // 2) The memory structure should be a dictionary of Pairs with values all other pairs that include one of the pair // 3) The dictionary should be sorted by brightness i.e. brightest pairs should be on the top/ NOTE: Exclude the brightest // stars until the mag difference between the next 2 bright stars becomes less than 1 mag // 4) Matching should be done by searching the distance match checking the brightest pairs first. distancesByMagnitude = new List<DistanceEntry>(); starsDistanceCache = new Dictionary<ulong, Dictionary<ulonglong, DistanceEntry>>(); if (pyramidStars.Count == 0) return null; PyramidStarsDensityDistributor distributor; pyramidStars.Sort((s1, s2) => s1.Mag.CompareTo(s2.Mag)); int n = pyramidStars.Count; double maxFovInDeg = image.GetMaxFOVInArcSec() / 3600.0; distributor = new PyramidStarsDensityDistributor(pyramidStars, image, settings); distributor.DebugResolvedStarsWithAppliedExclusions = debugResolvedStarsWithAppliedExclusions; distributor.Initialize(alwaysIncludeStars); distancesByMagnitude.Clear(); starsDistanceCache.Clear(); List<ulong> resolvedDebugStarsNos = null; if (debugResolvedStarsWithAppliedExclusions != null) { // This is disabled at the moment resolvedDebugStarsNos = debugResolvedStarsWithAppliedExclusions.Values.ToList(); int pyramidStarsLocated = 0; for (int i = resolvedDebugStarsNos.Count - 1; i >= 0 ; i--) { ulong starNo = resolvedDebugStarsNos[i]; IStar star = pyramidStars.FirstOrDefault(s => s.StarNo == starNo); if (star != null) pyramidStarsLocated++; else resolvedDebugStarsNos.Remove(starNo); Trace.Assert(star != null, string.Format("Debug Star {0} not found in the pyramid stars!", starNo)); } if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) Trace.WriteLine( string.Format("DEBUG ALIGN: {0} out of {1} Debug Stars found among the pyramid stars ({2})", pyramidStarsLocated, resolvedDebugStarsNos.Count, resolvedDebugStarsNos.Count > 1 ? resolvedDebugStarsNos.Select(s => s.ToString()).Aggregate((a, b) => string.Concat(a, " ", b)) : "")); } // Start building the pairs for (int j = 0; j < n; j++) { IStar jStar = pyramidStars[j]; if (!distributor.CheckStar(jStar)) { if (resolvedDebugStarsNos != null) { if (resolvedDebugStarsNos.Contains(jStar.StarNo)) { //Trace.Assert(false, "DebugResolved star pair not added to the pyramid areas because the distributor rejected it."); } } continue; } for (int i = j + 1; i < n; i++) { IStar iStar = pyramidStars[i]; double distDeg = AngleUtility.Elongation(iStar.RADeg, iStar.DEDeg, jStar.RADeg, jStar.DEDeg); if (distDeg > maxFovInDeg) { if (resolvedDebugStarsNos != null) { if (resolvedDebugStarsNos.Contains(iStar.StarNo) && resolvedDebugStarsNos.Contains(jStar.StarNo)) { //Trace.Assert(false, "DebugResolved star pair not added to the pyramid areas because the distance is too large."); } } continue; } if (!distributor.CheckStar(iStar)) { if (resolvedDebugStarsNos != null) { if (resolvedDebugStarsNos.Contains(iStar.StarNo)) { //Trace.Assert(false, string.Format("DebugResolved star {0} not added to the pyramid areas because the distributor rejected it.", iStar.StarNo)); } } continue; } distributor.MarkStar(iStar); distributor.MarkStar(jStar); DistanceEntry entry = new DistanceEntry(iStar, jStar, distDeg * 3600); distancesByMagnitude.Add(entry); #region PerStar distance cache ulonglong id1 = new ulonglong(iStar.StarNo, jStar.StarNo); ulonglong id2 = new ulonglong(jStar.StarNo, iStar.StarNo); Dictionary<ulonglong, DistanceEntry> map; if (!starsDistanceCache.TryGetValue(iStar.StarNo, out map)) { map = new Dictionary<ulonglong, DistanceEntry>(); starsDistanceCache.Add(iStar.StarNo, map); } map.Add(id1, entry); if (!starsDistanceCache.TryGetValue(jStar.StarNo, out map)) { map = new Dictionary<ulonglong, DistanceEntry>(); starsDistanceCache.Add(jStar.StarNo, map); } map.Add(id2, entry); #endregion } } //if (resolvedDebugStarsNos != null) //{ // foreach(uint starNo in resolvedDebugStarsNos) // { // DensityArea area = distributor.m_Areas.FirstOrDefault(a => a.m_IncludedStarNos.Contains(starNo)); // if (area != null) // Trace.WriteLine(string.Format("DEBUG ALIGN: Star {0} located to area [{1:0.00}, {2:0.0}]", starNo, area.XMiddle, area.YMiddle)); // Trace.Assert(area != null); // } //} return distributor; }
private void BuildPyramidMatchingByMagnitude() { Stopwatch sw = new Stopwatch(); sw.Start(); try { Dictionary<int, ulong> debugResolvesdStarsWithAppliedExclusions = DebugResolvedStars == null ? null : DebugResolvedStars .Where(kvp => DebugExcludeStars == null || !DebugExcludeStars.ContainsKey(kvp.Key)) .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); List<ulong> alwaysIncludeStars = null; if (m_ManualPairs != null && m_ManualPairs.Count > 0) alwaysIncludeStars = m_ManualPairs.Values.Select(x => x.StarNo).ToList(); m_Distributor = BuildPyramidMatchingByMagnitude( m_CelestialPyramidStars, m_PlateConfig, m_Settings, debugResolvesdStarsWithAppliedExclusions, alwaysIncludeStars, out m_DistancesByMagnitude, out m_StarsDistanceCache); } finally { sw.Stop(); if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) Trace.WriteLine(string.Format( "Building pyramid pairs from a total of {0} stars. Time taken: {1:0}ms", m_CelestialAllStars.Count, sw.ElapsedMilliseconds)); if (m_Distributor != null) { if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) Trace.WriteLine(string.Format( "{0} stars used in {1} zones and {2} pairs.", m_StarsDistanceCache.Count, m_Distributor.Areas.Count, m_DistancesByMagnitude.Count)); } } }