257 lines
7.7 KiB
C#
257 lines
7.7 KiB
C#
using RobotNet10.Shared.Geometry;
|
|
using RobotNet10.Shared.Numbers;
|
|
using QuaternionGeometry = RobotNet10.Shared.Geometry.Quaternion;
|
|
|
|
namespace RobotNet10.RobotApp.Client.Shared.SLAM;
|
|
|
|
/// <summary>
|
|
/// DTO cho Pose với covariance (3x3 matrix flattened to 9 values)
|
|
/// </summary>
|
|
public class PoseDto
|
|
{
|
|
public RobotNet10.Shared.Numbers.Vector3 Position { get; set; } = new();
|
|
public QuaternionGeometry Orientation { get; set; } = new();
|
|
|
|
/// <summary>
|
|
/// Covariance matrix (3x3) flattened to 9 values: [xx, xy, xθ, yx, yy, yθ, θx, θy, θθ]
|
|
/// null if covariance is not available
|
|
/// </summary>
|
|
public double[]? Covariance { get; set; }
|
|
|
|
public double Score { get; set; }
|
|
|
|
public DateTime Timestamp { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// DTO cho OccupancyGrid (optimized sparse format for SignalR transmission)
|
|
/// Chỉ chứa các cell đã biết (known cells) và occupied cells để giảm bandwidth
|
|
/// </summary>
|
|
public class OccupancyGridDto
|
|
{
|
|
public double Resolution { get; set; }
|
|
public int Width { get; set; }
|
|
public int Height { get; set; }
|
|
public Pose Origin { get; set; } = new();
|
|
|
|
/// <summary>
|
|
/// Sparse format: chỉ chứa các cell đã biết (value >= 0)
|
|
/// Format: byte[] với mỗi cell = 5 bytes: [index_byte0, index_byte1, index_byte2, index_byte3, value]
|
|
/// Index: 4 bytes little-endian (32-bit unsigned integer, max 4,294,967,295)
|
|
/// Value: 1 byte (0-100 = occupancy probability, 0 = free, 100 = occupied)
|
|
/// Index được tính: y * Width + x (row-major order)
|
|
/// </summary>
|
|
public byte[] KnownCells { get; set; } = [];
|
|
|
|
/// <summary>
|
|
/// Version number để detect changes (increment mỗi khi grid thay đổi)
|
|
/// </summary>
|
|
public long Version { get; set; }
|
|
|
|
/// <summary>
|
|
/// Thời gian cuối cùng update grid base (từ CartographerService.LastUpdatedBase).
|
|
/// </summary>
|
|
public DateTime LastBaseUpdated { get; set; }
|
|
|
|
/// <summary>
|
|
/// Thời gian cuối cùng update OccupancyGridUpdating (từ CartographerService.LastUpdatedUpdating).
|
|
/// </summary>
|
|
public DateTime LastUpdated { get; set; }
|
|
|
|
/// <summary>
|
|
/// Trajectory nodes (từ pose graph) kèm theo grid; dùng để vẽ trajectory polyline.
|
|
/// Có khi lấy grid base hoặc grid updating.
|
|
/// </summary>
|
|
public TrajectoryNodeDto[]? TrajectoryNodes { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// DTO cho TrajectoryNode
|
|
/// </summary>
|
|
public class TrajectoryNodeDto
|
|
{
|
|
public int NodeId { get; set; }
|
|
public Pose Pose { get; set; } = new();
|
|
public DateTime Timestamp { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// DTO cho MapInfo
|
|
/// </summary>
|
|
public class MapInfoDto
|
|
{
|
|
public string Name { get; set; } = string.Empty;
|
|
public DateTime CreatedDate { get; set; }
|
|
public double Resolution { get; set; }
|
|
/// <summary>
|
|
/// Width of map in meters
|
|
/// </summary>
|
|
public double Width { get; set; }
|
|
/// <summary>
|
|
/// Height of map in meters
|
|
/// </summary>
|
|
public double Height { get; set; }
|
|
public int TrajectoryNodeCount { get; set; }
|
|
/// <summary>
|
|
/// Origin X coordinate in meters
|
|
/// </summary>
|
|
public double OriginX { get; set; }
|
|
/// <summary>
|
|
/// Origin Y coordinate in meters
|
|
/// </summary>
|
|
public double OriginY { get; set; }
|
|
|
|
/// <summary>
|
|
/// Indicates if the map is currently being processed on the server
|
|
/// </summary>
|
|
public bool IsProcessing { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// DTO cho error information
|
|
/// </summary>
|
|
public class ErrorDto
|
|
{
|
|
public string Message { get; set; } = string.Empty;
|
|
public DateTime Timestamp { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Strategy for merging multiple submaps into a single occupancy grid.
|
|
/// </summary>
|
|
public enum SubmapMergeStrategyDto
|
|
{
|
|
/// <summary>
|
|
/// Porter-Duff Source-Over compositing (Cairo-style).
|
|
/// </summary>
|
|
PorterDuff = 0,
|
|
|
|
/// <summary>
|
|
/// Sum log-odds from all submaps (Bayesian approach).
|
|
/// </summary>
|
|
LogOddsSum = 1,
|
|
|
|
/// <summary>
|
|
/// Take maximum probability (most pessimistic/conservative).
|
|
/// </summary>
|
|
MaxProbability = 2
|
|
}
|
|
|
|
/// <summary>
|
|
/// DTO cho OccupancyGridConfiguration - dùng để customize cách render occupancy grid
|
|
/// </summary>
|
|
public class OccupancyGridConfigurationDto
|
|
{
|
|
#region Merge Strategy
|
|
|
|
/// <summary>
|
|
/// Strategy for merging overlapping cells from multiple submaps.
|
|
/// Default: LogOddsSum (clearer free/occupied distinction)
|
|
/// </summary>
|
|
public SubmapMergeStrategyDto MergeStrategy { get; set; } = SubmapMergeStrategyDto.LogOddsSum;
|
|
|
|
/// <summary>
|
|
/// Clamp log-odds to prevent extreme values from dominating.
|
|
/// Range: [1, 20], Default: 10
|
|
/// </summary>
|
|
public double LogOddsClamp { get; set; } = 10.0;
|
|
|
|
/// <summary>
|
|
/// When true, use average log-odds instead of sum.
|
|
/// Default: true
|
|
/// </summary>
|
|
public bool UseLogOddsAverage { get; set; } = true;
|
|
|
|
#endregion
|
|
|
|
#region Threshold Configuration
|
|
|
|
/// <summary>
|
|
/// Threshold for classifying a cell as FREE.
|
|
/// Higher value = stricter (fewer free cells).
|
|
/// Range: [0, 255], Default: 100
|
|
/// </summary>
|
|
public int FreeSpaceThreshold { get; set; } = 100;
|
|
|
|
/// <summary>
|
|
/// Threshold for classifying a cell as OCCUPIED.
|
|
/// Higher value = stricter (fewer occupied cells, thinner walls).
|
|
/// Range: [0, 255], Default: 0
|
|
/// </summary>
|
|
public int OccupiedSpaceThreshold { get; set; } = 0;
|
|
|
|
#endregion
|
|
|
|
#region Output Mode
|
|
|
|
/// <summary>
|
|
/// When true, output only binary values (0=free, 100=occupied, -1=unknown).
|
|
/// When false, output gradient values (0-100) based on probability.
|
|
/// Default: true
|
|
/// </summary>
|
|
public bool UseBinaryOutput { get; set; } = true;
|
|
|
|
#endregion
|
|
|
|
#region Wall Thinning (Post-processing)
|
|
|
|
/// <summary>
|
|
/// Enable morphological erosion to thin walls in the occupancy grid.
|
|
/// Default: false
|
|
/// </summary>
|
|
public bool EnableWallThinning { get; set; } = false;
|
|
|
|
/// <summary>
|
|
/// Number of erosion iterations for wall thinning.
|
|
/// Range: [1, 5], Default: 1
|
|
/// </summary>
|
|
public int WallThinningIterations { get; set; } = 1;
|
|
|
|
/// <summary>
|
|
/// Minimum wall thickness to preserve (in pixels) during wall thinning.
|
|
/// Range: [1, 10], Default: 1
|
|
/// </summary>
|
|
public int MinWallThicknessPixels { get; set; } = 1;
|
|
|
|
#endregion
|
|
|
|
#region Ambiguous Cell Handling
|
|
|
|
/// <summary>
|
|
/// How to handle ambiguous cells (probability ~0.5).
|
|
/// Values: -1 = Unknown, 0 = Free, 100 = Occupied
|
|
/// Default: -1
|
|
/// </summary>
|
|
public sbyte AmbiguousCellValue { get; set; } = -1;
|
|
|
|
/// <summary>
|
|
/// Lower bound of the ambiguous range (probability).
|
|
/// Default: 0.35
|
|
/// </summary>
|
|
public double AmbiguousRangeLower { get; set; } = 0.35;
|
|
|
|
/// <summary>
|
|
/// Upper bound of the ambiguous range (probability).
|
|
/// Default: 0.65
|
|
/// </summary>
|
|
public double AmbiguousRangeUpper { get; set; } = 0.65;
|
|
|
|
#endregion
|
|
|
|
#region Advanced Options
|
|
|
|
/// <summary>
|
|
/// Apply median filter to reduce noise.
|
|
/// Default: false
|
|
/// </summary>
|
|
public bool EnableMedianFilter { get; set; } = false;
|
|
|
|
/// <summary>
|
|
/// Kernel size for median filter (must be odd number).
|
|
/// Range: [3, 7], Default: 3
|
|
/// </summary>
|
|
public int MedianFilterKernelSize { get; set; } = 3;
|
|
|
|
#endregion
|
|
}
|