using CartographerSharp.Mapping;
using Microsoft.Extensions.Logging;
namespace RobotNet10.RobotApp.SLAM.Cartographer.Helpers;
///
/// Cache for pose graph constraints of a single trajectory.
/// Used by CartographerService to avoid repeatedly querying constraints when calculating covariance.
///
///
/// Creates a constraint cache with the given refresh interval.
///
public sealed class TrajectoryConstraintCache(TimeSpan _updateInterval)
{
private readonly Lock _lock = new();
private List? _cachedConstraints;
private DateTime _lastUpdate = DateTime.MinValue;
private IMapBuilder? _lastMapBuilder;
private int _lastTrajectoryId = -1;
///
/// Gets constraints for the given trajectory, refreshing from the pose graph when the cache is stale
/// or when map builder / trajectory id change.
///
/// Current map builder (may be null)
/// Trajectory id to filter constraints
/// Optional logger for warnings
/// Cached or freshly fetched constraints, or null if mapBuilder is null or fetch failed
public List? GetOrUpdate(
IMapBuilder? mapBuilder,
int trajectoryId,
ILogger? logger = null)
{
var now = DateTime.UtcNow;
bool needsUpdate = false;
lock (_lock)
{
if (mapBuilder != _lastMapBuilder || trajectoryId != _lastTrajectoryId)
{
needsUpdate = true;
}
else if (_cachedConstraints == null || (now - _lastUpdate) > _updateInterval)
{
needsUpdate = true;
}
}
if (!needsUpdate)
{
lock (_lock)
{
return _cachedConstraints;
}
}
if (mapBuilder == null)
{
return null;
}
try
{
var constraints = mapBuilder.PoseGraph.Constraints().Where(c => c.NodeId.TrajectoryId == trajectoryId).ToList();
lock (_lock)
{
_cachedConstraints = constraints;
_lastUpdate = now;
_lastMapBuilder = mapBuilder;
_lastTrajectoryId = trajectoryId;
}
return constraints;
}
catch (Exception ex)
{
logger?.LogWarning(ex, "TrajectoryConstraintCache: Failed to update constraint cache");
lock (_lock)
{
return _cachedConstraints;
}
}
}
///
/// Clears the cache (e.g. when switching map or trajectory).
///
public void Invalidate()
{
lock (_lock)
{
_cachedConstraints = null;
_lastUpdate = DateTime.MinValue;
_lastMapBuilder = null;
_lastTrajectoryId = -1;
}
}
}