using RobotNet10.RobotApp.SLAM.Cartographer.Geometry;
using RobotNet10.RobotApp.SLAM.Cartographer.Helpers;
using RobotNet10.Shared.Geometry;
namespace RobotNet10.RobotApp.SLAM.Cartographer;
///
/// Immutable snapshot of robot pose with confidence metrics and drift detection status.
/// Reference type enables lock-free atomic swap via volatile field.
///
public sealed class PoseSnapshot
{
public static readonly PoseSnapshot Empty = new();
/// Pose in GLOBAL (map) frame.
public Pose Pose { get; }
/// Pose covariance (Localizing mode only).
public Matrix3x3? Covariance { get; }
///
/// Confidence score:
/// - ScanMapping: PoseConfidence from scan matcher
/// - Localizing: LocalizationScore from covariance/constraints/scanMatchScore
/// - Relocalizing: MCL reliability
///
public double? Score { get; }
///
/// Scan match score (PoseConfidence) from Cartographer.
/// This is the most direct indicator of how well the current scan matches the map.
/// Available in both ScanMapping and Localizing states.
///
public double? ScanMatchScore { get; }
///
/// Drift detection status (Localizing mode only).
/// Indicates whether the robot may be experiencing map drift.
///
public DriftDetector.DriftStatus DriftStatus { get; }
/// Timestamp when this snapshot was created.
public long TimestampTicks { get; }
public PoseSnapshot()
{
Pose = new Pose();
DriftStatus = DriftDetector.DriftStatus.Stable;
TimestampTicks = DateTime.UtcNow.Ticks;
}
public PoseSnapshot(Pose pose, Matrix3x3? covariance = null, double? score = null)
{
Pose = pose;
Covariance = covariance;
Score = score;
DriftStatus = DriftDetector.DriftStatus.Stable;
TimestampTicks = DateTime.UtcNow.Ticks;
}
///
/// Creates a PoseSnapshot with full drift detection information.
///
public PoseSnapshot(
Pose pose,
Matrix3x3? covariance,
double? score,
double? scanMatchScore,
DriftDetector.DriftStatus driftStatus)
{
Pose = pose;
Covariance = covariance;
Score = score;
ScanMatchScore = scanMatchScore;
DriftStatus = driftStatus;
TimestampTicks = DateTime.UtcNow.Ticks;
}
}