using CartographerSharp.Mapping;
using RobotNet10.RobotApp.SLAM.Cartographer.Geometry;
namespace RobotNet10.RobotApp.SLAM.Cartographer.Helpers;
///
/// Helper class for calculating covariance from Cartographer constraints
///
public static class CovarianceCalculator
{
///
/// Result of covariance calculation
///
public record Result(
Matrix3x3? Covariance,
int ConstraintCount,
double AverageConstraintQuality);
///
/// Calculate covariance and quality metrics from constraints
///
/// List of pose graph constraints
/// Covariance calculation result
public static Result Calculate(IList constraints)
{
if (constraints == null || constraints.Count == 0)
{
return new Result(null, 0, 0.0);
}
int constraintCount = constraints.Count;
// Calculate average constraint weights
var avgTranslationWeight = constraints.Average(c => c.ConstraintPose.TranslationWeight);
var avgRotationWeight = constraints.Average(c => c.ConstraintPose.RotationWeight);
// Calculate constraint quality score (0.0 - 1.0)
var normalizedTranslationQuality = Math.Min(1.0, avgTranslationWeight / 100.0);
var normalizedRotationQuality = Math.Min(1.0, avgRotationWeight / 100.0);
var averageConstraintQuality = (normalizedTranslationQuality + normalizedRotationQuality) / 2.0;
// Calculate covariance from constraint weights
var translationWeightVariance = constraints
.Select(c => c.ConstraintPose.TranslationWeight)
.Select(w => Math.Pow(w - avgTranslationWeight, 2))
.Average();
var rotationWeightVariance = constraints
.Select(c => c.ConstraintPose.RotationWeight)
.Select(w => Math.Pow(w - avgRotationWeight, 2))
.Average();
// Convert weights to covariance (inverse relationship)
var translationCovBase = 1.0 / (avgTranslationWeight + 1e-6);
var rotationCovBase = 1.0 / (avgRotationWeight + 1e-6);
// Adjust covariance based on variance
var translationVarianceFactor = 1.0 + (translationWeightVariance / (avgTranslationWeight * avgTranslationWeight + 1e-6));
var rotationVarianceFactor = 1.0 + (rotationWeightVariance / (avgRotationWeight * avgRotationWeight + 1e-6));
var translationCov = translationCovBase * translationVarianceFactor;
var rotationCov = rotationCovBase * rotationVarianceFactor;
// Adjust covariance based on number of constraints
var constraintCountFactor = 1.0 / (1.0 + Math.Log10(Math.Max(1, constraintCount)));
translationCov *= constraintCountFactor;
rotationCov *= constraintCountFactor;
// Create covariance matrix for 2D pose (x, y, theta)
var covariance = Matrix3x3.Covariance(
xx: translationCov,
yy: translationCov,
tt: rotationCov,
xy: 0.0,
xt: 0.0,
yt: 0.0
);
return new Result(covariance, constraintCount, averageConstraintQuality);
}
}