private void LoadAlignmentPoints() { var dir = Path.GetDirectoryName(_configFile); if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) { Directory.CreateDirectory(dir); } if (File.Exists(_configFile)) { AlignmentPoints.Clear(); using (var file = File.OpenText(_configFile)) { var serializer = new JsonSerializer(); var loaded = (AlignmentPointCollection)serializer.Deserialize(file, typeof(AlignmentPointCollection)); if (loaded != null) { foreach (var alignmentPoint in loaded) { AlignmentPoints.Add(alignmentPoint); } } } } ReportAlignmentPoints(); }
private void AddAlignmentPoint(double[] mountAltAz, double[] observedAltAz, AxisPosition mountAxes, AxisPosition observedAxes, PierSide pierSide, DateTime syncTime) { lock (_accessLock) { if (AlignmentPoints.Count > 2 && ProximityLimit > 0.0) { // Remove any existing alignment points that are too close to the new one. var nearPoints = AlignmentPoints .Where(p => p.MountAxes.IncludedAngleTo(mountAxes) <= ProximityLimit).ToList(); foreach (AlignmentPoint deletePt in nearPoints) { AlignmentPoints.Remove(deletePt); } } CarteseanCoordinate mountXy = AltAzToCartesean(mountAltAz); CarteseanCoordinate observedXy = AltAzToCartesean(observedAltAz); AlignmentPoints.Add(new AlignmentPoint(observedAltAz, mountAxes, observedAxes, mountXy, observedXy, pierSide, syncTime)); _currentChecksum = int.MinValue; // Reset checksum so that offsets are recalculated OneStarAdjustment[0] = observedAxes[0] - mountAxes[0]; OneStarAdjustment[1] = observedAxes[1] - mountAxes[1]; SaveAlignmentPoints(); } }
private AlignmentPoint[] GetNearestObservedPoints(AxisPosition axisPosition, PierSide pierSide, int numberOfPoints, out int checkSum) { AlignmentPoint[] points = AlignmentPoints .Where(p => p.PierSide == pierSide && p.ObservedAxes.IncludedAngleTo(axisPosition) <= NearbyLimit) .OrderBy(d => d.ObservedAxes.IncludedAngleTo(axisPosition)).Take(numberOfPoints).ToArray(); checkSum = GetChecksum(points.Select(p => p.Id).ToArray()); return(points); }
private AlignmentPoint GetNearestObservedPoint(AxisPosition axisPosition, PierSide pierSide, out int checkSum) { AlignmentPoint alignmentPoint = AlignmentPoints .Where(p => p.PierSide == pierSide) .OrderBy(d => d.ObservedAxes.IncludedAngleTo(axisPosition)).FirstOrDefault(); checkSum = alignmentPoint != null?GetChecksum(alignmentPoint.Id) : int.MinValue; return(alignmentPoint); }
public void ClearAlignmentPoints() { try { AlignmentPoints.Clear(); SaveAlignmentPoints(); } catch (Exception ex) { LogException(ex, true); } }
private void AlignmentPoints_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.Action == NotifyCollectionChangedAction.Add) { SelectedAlignmentPoint = AlignmentPoints[e.NewStartingIndex + e.NewItems.Count - 1]; } else { if (!AlignmentPoints.Contains(SelectedAlignmentPoint)) { SelectedAlignmentPoint = AlignmentPoints.FirstOrDefault(); } } ClearAllPointsCommand.RaiseCanExecuteChanged(); DeleteSelectedPointCommand.RaiseCanExecuteChanged(); }
public bool RemoveAlignmentPoint(AlignmentPoint pointToDelete) { try { bool result = AlignmentPoints.Remove(pointToDelete); if (result) { SaveAlignmentPoints(); } return(result); } catch (Exception ex) { LogException(ex, true); return(false); } }
/// <summary> /// Gets the observed axis positions for a given mount axis position. /// </summary> /// <param name="mountAxes">Mount Ra and Dec axis positions</param> /// <param name="pierSide">The pier side to use 0 = East, 1 = West, 2 = Unknown</param> /// <returns></returns> public double[] GetObservedAxes(double[] mountAxes, int pierSide) { if (!IsAlignmentOn || !AlignmentPoints.Any()) { return(mountAxes); // Fast exit as alignment modeling is switched off or there are no points. } lock (_accessLock) { try { AxisPosition mAxes = new AxisPosition(mountAxes); if (mAxes.IncludedAngleTo(_homePosition) < ProximityLimit) { return(mountAxes); // Fast exist if we are going home. } RaiseNotification(NotificationType.Information, MethodBase.GetCurrentMethod().Name, $"GetObservedAxes for {mountAxes[0]}/{mountAxes[1]}"); PierSide pSide = (PierSide)pierSide; WriteLastAccessTime(); Matrix offsets = Matrix.CreateInstance(1, 2); if (AlignmentPoints.Count == 1) { offsets[0, 0] = AlignmentPoints[0].ObservedAxes[0] - AlignmentPoints[0].MountAxes[0]; offsets[0, 1] = AlignmentPoints[0].ObservedAxes[1] - AlignmentPoints[0].MountAxes[1]; RaiseNotification(NotificationType.Data, MethodBase.GetCurrentMethod().Name, $"Single alignment point selected {AlignmentPoints[0].Id:D3}, Mount axes: {AlignmentPoints[0].MountAxes.RaAxis}/{AlignmentPoints[0].MountAxes.RaAxis}, Observed axes: {AlignmentPoints[0].ObservedAxes.RaAxis}/{AlignmentPoints[0].ObservedAxes.RaAxis}"); } else { AlignmentPoint[] alignmentPoints = GetNearestMountPoints(mAxes, pSide, SampleSize); int rows = alignmentPoints.Length; if (rows > 2) { // Build features and values from registered points Matrix features = Matrix.CreateInstance(rows, 3); Matrix values = Matrix.CreateInstance(rows, 2); _stringBuilder.Clear(); _stringBuilder.Append("Points chosen are"); for (int i = 0; i < rows; i++) { var pt = alignmentPoints[i]; _stringBuilder.Append($" ({pt.Id:D3})"); features[i, 0] = 1f; features[i, 1] = pt.MountAxes[0] * pt.MountAxes[0]; features[i, 2] = pt.MountAxes[1] * pt.MountAxes[1]; values[i, 0] = Range.RangePlusOrMinus180(pt.ObservedAxes[0] - pt.MountAxes[0]); values[i, 1] = Range.RangePlusOrMinus180(pt.ObservedAxes[1] - pt.MountAxes[1]); } _stringBuilder.AppendLine("."); // Solve the normal equation to get theta Matrix theta = SolveNormalEquation(features, values); // Calculate the difference for the incoming points Matrix target = Matrix.CreateInstance(1, 3); target[0, 0] = 1f; target[0, 1] = mAxes[0] * mAxes[0]; target[0, 2] = mAxes[1] * mAxes[1]; offsets = target * theta; _stringBuilder.AppendLine("Features"); _stringBuilder.AppendLine(features.ToString()); _stringBuilder.AppendLine("Values"); _stringBuilder.AppendLine(values.ToString()); _stringBuilder.AppendLine("Theta"); _stringBuilder.AppendLine(theta.ToString()); _stringBuilder.AppendLine("Target"); _stringBuilder.AppendLine(target.ToString()); _stringBuilder.AppendLine("Offsets"); _stringBuilder.AppendLine(offsets.ToString()); RaiseNotification(NotificationType.Data, MethodBase.GetCurrentMethod().Name, _stringBuilder.ToString()); _stringBuilder.Clear(); } else if (rows > 0) { // Just use the nearest point of the two. offsets[0, 0] = alignmentPoints[0].ObservedAxes[0] - alignmentPoints[0].MountAxes[0]; offsets[0, 1] = alignmentPoints[0].ObservedAxes[1] - alignmentPoints[0].MountAxes[1]; RaiseNotification(NotificationType.Data, MethodBase.GetCurrentMethod().Name, $"Using nearest point of two {alignmentPoints[0].Id:D3}, Mount axes: {alignmentPoints[0].MountAxes.RaAxis}/{alignmentPoints[0].MountAxes.RaAxis}, Observed axes: {alignmentPoints[0].ObservedAxes.RaAxis}/{alignmentPoints[0].ObservedAxes.RaAxis}"); } // Otherwise default to using no correcting offset } var observedAxes = new[] { mountAxes[0] + offsets[0, 0], mountAxes[1] + offsets[0, 1] }; RaiseNotification(NotificationType.Data, MethodBase.GetCurrentMethod().Name, $"Correction -> Observer = {offsets[0, 0]}/{offsets[0, 1]}"); RaiseNotification(NotificationType.Information, MethodBase.GetCurrentMethod().Name, $"Mount axes: {mountAxes[0]}/{mountAxes[1]} -> Observed axes: {observedAxes[0]}/{observedAxes[1]}"); return(observedAxes); } catch (Exception ex) { LogException(ex, true); return(mountAxes); } } }
private AlignmentPoint[] GetNearestMountPoints(AxisPosition axisPosition, PierSide pierSide, int numberOfPoints) { return(AlignmentPoints .Where(p => p.PierSide == pierSide && p.MountAxes.IncludedAngleTo(axisPosition) <= NearbyLimit) .OrderBy(d => d.MountAxes.IncludedAngleTo(axisPosition)).Take(numberOfPoints).ToArray()); }
/// <summary> /// Gets the mount axis positions for a given observed axis position. /// </summary> /// <param name="observedAxes">Observed Ra and Dec axis positions</param> /// <param name="pierSide">The pier side to use 0 = East, 1 = West, 2 = Unknown</param> /// <returns></returns> public double[] GetMountAxes(double[] observedAxes, int pierSide) { if (!IsAlignmentOn || !AlignmentPoints.Any()) { return(observedAxes); // Fast exit as alignment modeling is switched off or there are no points. } lock (_accessLock) { try { bool postLogMessages = false; AxisPosition sAxes = new AxisPosition(observedAxes); if (sAxes.IncludedAngleTo(_homePosition) < ProximityLimit) { return(observedAxes); // Fast exit if we are going home. } PierSide pSide = (PierSide)pierSide; WriteLastAccessTime(); Matrix offsets = Matrix.CreateInstance(1, 2); int checksum; if (AlignmentPoints.Count == 1) { checksum = GetChecksum(AlignmentPoints[0].Id); if (checksum == _currentChecksum) { // Checksum hasn't changed so use the last offsets offsets = _lastOffsets; } else { RaiseNotification(NotificationType.Information, MethodBase.GetCurrentMethod().Name, $"GetMountAxes for {observedAxes[0]}/{observedAxes[1]}"); ClearSelectedPoints(); offsets[0, 0] = AlignmentPoints[0].MountAxes[0] - AlignmentPoints[0].ObservedAxes[0]; offsets[0, 1] = AlignmentPoints[0].MountAxes[1] - AlignmentPoints[0].ObservedAxes[1]; AlignmentPoints[0].Selected = true; _selectedPoints.Add(AlignmentPoints[0]); // Cache the offsets and checksum _lastOffsets = offsets; _currentChecksum = checksum; RaiseNotification(NotificationType.Data, MethodBase.GetCurrentMethod().Name, $"Single alignment point selected {AlignmentPoints[0].Id:D3}, Mount axes: {AlignmentPoints[0].MountAxes.RaAxis}/{AlignmentPoints[0].MountAxes.RaAxis}, Observed axes: {AlignmentPoints[0].ObservedAxes.RaAxis}/{AlignmentPoints[0].ObservedAxes.RaAxis}"); postLogMessages = true; } } else { // Get the nearest points and their corresponding checksum value AlignmentPoint[] alignmentPoints = GetNearestObservedPoints(sAxes, pSide, SampleSize, out checksum); if (checksum == _currentChecksum) { // Checksum hasn't changed to use the last offsets offsets = _lastOffsets; } else { int rows = alignmentPoints.Length; if (rows > 2) { RaiseNotification(NotificationType.Information, MethodBase.GetCurrentMethod().Name, $"GetMountAxes for {observedAxes[0]}/{observedAxes[1]}"); ClearSelectedPoints(); // Build features and values from registered points Matrix features = Matrix.CreateInstance(rows, 3); Matrix values = Matrix.CreateInstance(rows, 2); _stringBuilder.Clear(); _stringBuilder.Append("Points chosen are"); for (int i = 0; i < rows; i++) { var pt = alignmentPoints[i]; _stringBuilder.Append($" ({pt.Id:D3})"); features[i, 0] = 1f; features[i, 1] = pt.ObservedAxes[0] * pt.ObservedAxes[0]; features[i, 2] = pt.ObservedAxes[1] * pt.ObservedAxes[1]; values[i, 0] = Range.RangePlusOrMinus180(pt.MountAxes[0] - pt.ObservedAxes[0]); values[i, 1] = Range.RangePlusOrMinus180(pt.MountAxes[1] - pt.ObservedAxes[1]); pt.Selected = true; _selectedPoints.Add(pt); } _stringBuilder.AppendLine("."); // Solve the normal equation to get theta Matrix theta = SolveNormalEquation(features, values); // Calculate the difference for the incoming points Matrix target = Matrix.CreateInstance(1, 3); target[0, 0] = 1f; target[0, 1] = sAxes[0] * sAxes[0]; target[0, 2] = sAxes[1] * sAxes[1]; offsets = target * theta; _stringBuilder.AppendLine("Features"); _stringBuilder.AppendLine(features.ToString()); _stringBuilder.AppendLine("Values"); _stringBuilder.AppendLine(values.ToString()); _stringBuilder.AppendLine("Theta"); _stringBuilder.AppendLine(theta.ToString()); _stringBuilder.AppendLine("Target"); _stringBuilder.AppendLine(target.ToString()); _stringBuilder.AppendLine("Offsets"); _stringBuilder.AppendLine(offsets.ToString()); RaiseNotification(NotificationType.Data, MethodBase.GetCurrentMethod().Name, _stringBuilder.ToString()); _stringBuilder.Clear(); // Cache the offsets and the checksum _lastOffsets = offsets; _currentChecksum = checksum; postLogMessages = true; } else if (rows > 0) { checksum = GetChecksum(AlignmentPoints[0].Id); if (checksum == _currentChecksum) { // Checksum hasn't changed so use the last offsets offsets = _lastOffsets; } else { RaiseNotification(NotificationType.Information, MethodBase.GetCurrentMethod().Name, $"GetMountAxes for {observedAxes[0]}/{observedAxes[1]}"); ClearSelectedPoints(); // Use the nearest point of the two. offsets[0, 0] = alignmentPoints[0].MountAxes[0] - alignmentPoints[0].ObservedAxes[0]; offsets[0, 1] = alignmentPoints[0].MountAxes[1] - alignmentPoints[0].ObservedAxes[1]; alignmentPoints[0].Selected = true; _selectedPoints.Add(alignmentPoints[0]); // Cache the offsets and checksum _lastOffsets = offsets; _currentChecksum = checksum; postLogMessages = true; RaiseNotification(NotificationType.Data, MethodBase.GetCurrentMethod().Name, $"Using nearest point of two {alignmentPoints[0].Id:D3}, Mount axes: {alignmentPoints[0].MountAxes.RaAxis}/{alignmentPoints[0].MountAxes.RaAxis}, Observed axes: {alignmentPoints[0].ObservedAxes.RaAxis}/{alignmentPoints[0].ObservedAxes.RaAxis}"); } } else { if (_currentChecksum != int.MinValue) { _currentChecksum = int.MinValue; RaiseNotification(NotificationType.Warning, MethodBase.GetCurrentMethod().Name, $"No alignment points selected, Mount axes: {alignmentPoints[0].MountAxes.RaAxis}/{alignmentPoints[0].MountAxes.RaAxis}, Observed axes: {alignmentPoints[0].ObservedAxes.RaAxis}/{alignmentPoints[0].ObservedAxes.RaAxis}"); } } } // Otherwise default to using zero offset } var mountAxes = new[] { observedAxes[0] + offsets[0, 0], observedAxes[1] + offsets[0, 1] }; if (postLogMessages) { RaiseNotification(NotificationType.Data, MethodBase.GetCurrentMethod().Name, $"Correction -> Mount = {offsets[0, 0]}/{offsets[0, 1]}"); RaiseNotification(NotificationType.Information, MethodBase.GetCurrentMethod().Name, $"Observed axes: {observedAxes[0]}/{observedAxes[1]} -> Mount axes: {mountAxes[0]}/{mountAxes[1]}"); } return(mountAxes); } catch (Exception ex) { LogException(ex); return(observedAxes); } } }
private AlignmentPoint GetNearestMountPoint(AxisPosition axisPosition, PierSide pierSide) { return(AlignmentPoints .Where(p => p.PierSide == pierSide) .OrderBy(d => d.MountAxes.IncludedAngleTo(axisPosition)).FirstOrDefault()); }