/*
* Copyright 2016 The Cartographer Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using CartographerSharp.Sensor;
using CartographerSharp.Transform;
using RobotNet10.Shared.Numbers;
namespace CartographerSharp.Mapping;
///
/// Interface for pose graph operations.
///
public interface IPoseGraph
{
///
/// A "constraint" as in the paper by Konolige, Kurt, et al. "Efficient sparse
/// pose adjustment for 2d mapping." Intelligent Robots and Systems (IROS),
/// 2010 IEEE/RSJ International Conference on (pp. 22--29). IEEE, 2010.
///
public struct Constraint(SubmapId submapId, NodeId nodeId, Constraint.Pose pose, Constraint.Tag tag, double score = 0.0, Constraint.State state = Constraint.State.Enabled)
{
///
/// Constraint pose information.
///
public struct Pose(Rigid3d zbarIj, double translationWeight, double rotationWeight)
{
public Rigid3d ZbarIj { get; set; } = zbarIj;
public double TranslationWeight { get; set; } = translationWeight;
public double RotationWeight { get; set; } = rotationWeight;
}
public SubmapId SubmapId { get; set; } = submapId;
public NodeId NodeId { get; set; } = nodeId;
///
/// Pose of the node 'j' relative to submap 'i'.
///
public Pose ConstraintPose { get; set; } = pose;
///
/// Differentiates between intra-submap (where node 'j' was inserted into
/// submap 'i') and inter-submap constraints (where node 'j' was not inserted
/// into submap 'i').
///
public enum Tag
{
IntraSubmap,
InterSubmap
}
public Tag ConstraintTag { get; set; } = tag;
///
/// Match C++: score field for constraint quality.
///
public double Score { get; set; } = score;
///
/// Match C++: state enum for enabled/disabled constraints.
///
public enum State
{
Enabled,
Disabled
}
public State ConstraintState { get; set; } = state;
}
///
/// Landmark node information.
///
public struct LandmarkNode(
List? landmarkObservations = null,
Rigid3d? globalLandmarkPose = null,
bool frozen = false)
{
///
/// Landmark observation.
///
public struct LandmarkObservation(
int trajectoryId,
long time,
Rigid3d landmarkToTrackingTransform,
double translationWeight,
double rotationWeight)
{
public int TrajectoryId { get; set; } = trajectoryId;
public long Time { get; set; } = time;
public Rigid3d LandmarkToTrackingTransform { get; set; } = landmarkToTrackingTransform;
public double TranslationWeight { get; set; } = translationWeight;
public double RotationWeight { get; set; } = rotationWeight;
}
public List LandmarkObservations { get; set; } = landmarkObservations ?? [];
public Rigid3d? GlobalLandmarkPose { get; set; } = globalLandmarkPose;
public bool Frozen { get; set; } = frozen;
}
///
/// Submap pose information.
///
public struct SubmapPose(int version, Rigid3d pose)
{
public int Version { get; set; } = version;
public Rigid3d Pose { get; set; } = pose;
}
///
/// Submap data with pose.
///
public struct SubmapData(Submap? submap, Rigid3d pose)
{
public Submap? Submap { get; set; } = submap;
public Rigid3d Pose { get; set; } = pose;
}
///
/// Trajectory data.
///
public struct TrajectoryData(
double gravityConstant = 9.8,
Quaternion? imuCalibration = null,
Rigid3d? fixedFrameOriginInMap = null)
{
public double GravityConstant { get; set; } = gravityConstant;
public Quaternion ImuCalibration { get; set; } = imuCalibration ?? Quaternion.Identity;
public Rigid3d? FixedFrameOriginInMap { get; set; } = fixedFrameOriginInMap;
}
///
/// Trajectory state enumeration.
///
public enum TrajectoryState
{
Active,
Finished,
Frozen,
Deleted
}
///
/// Gets the total number of work items added to the work queue.
///
public int WorkItemsAdded { get; }
///
/// Gets the total number of work items completed by the work queue.
///
public int WorkItemsCompleted { get; }
///
/// Gets the number of work items currently pending in the work queue.
///
public int WorkItemsPending { get; }
///
/// Gets the current number of items in the work queue.
///
public int WorkQueueCount { get; }
///
/// Gets the number of nodes started in the constraint builder.
///
public int ConstraintBuilderNodesStarted { get; }
///
/// Gets the number of nodes finished in the constraint builder.
///
public int ConstraintBuilderNodesFinished { get; }
///
/// Gets the total number of trajectory nodes in the pose graph.
/// Used for progress tracking during optimization.
///
public int TrajectoryNodesCount { get; }
///
/// Gets the total number of constraint tasks dispatched for scan matching.
///
public int ConstraintTasksTotal { get; }
///
/// Gets the number of constraint tasks that have finished scan matching.
///
public int ConstraintTasksFinished { get; }
///
/// Inserts an IMU measurement.
///
void AddImuData(int trajectoryId, ImuData imuData);
///
/// Inserts an odometry measurement.
///
void AddOdometryData(int trajectoryId, OdometryData odometryData);
///
/// Inserts a fixed frame pose measurement.
///
void AddFixedFramePoseData(int trajectoryId, FixedFramePoseData fixedFramePoseData);
///
/// Inserts landmarks observations.
///
void AddLandmarkData(int trajectoryId, LandmarkData landmarkData);
///
/// Drains the work queue to ensure all pending operations are completed.
/// This should be called before finishing a trajectory to avoid race conditions.
///
void DrainWorkQueue();
///
/// Finishes the given trajectory.
///
void FinishTrajectory(int trajectoryId);
///
/// Freezes a trajectory. Poses in this trajectory will not be optimized.
///
void FreezeTrajectory(int trajectoryId);
///
/// Adds a 'submap' from a proto with the given 'global_pose' to the
/// appropriate trajectory.
///
void AddSubmapFromProto(Rigid3d globalPose, Models.Mapping.Submap submap);
///
/// Adds a 'node' from a proto with the given 'global_pose' to the
/// appropriate trajectory.
///
void AddNodeFromProto(Rigid3d globalPose, Models.Mapping.Node node);
///
/// Sets the trajectory data from a proto.
///
void SetTrajectoryDataFromProto(Models.Mapping.TrajectoryData data);
///
/// Adds information that 'node_id' was inserted into 'submap_id'. The submap
/// has to be deserialized first.
///
void AddNodeToSubmap(NodeId nodeId, SubmapId submapId);
///
/// Adds serialized constraints. The corresponding trajectory nodes and submaps
/// have to be deserialized before calling this function.
///
void AddSerializedConstraints(List constraints);
///
/// Adds a 'trimmer'. It will be used after all data added before it has been
/// included in the pose graph.
///
void AddTrimmer(PoseGraphTrimmer trimmer);
///
/// Returns the current trajectory clusters.
///
List> GetConnectedTrajectories();
///
/// Returns the IMU data.
///
Dictionary> GetImuData();
///
/// Returns the odometry data.
///
Dictionary> GetOdometryData();
///
/// Returns the fixed frame pose data.
///
Dictionary> GetFixedFramePoseData();
///
/// Returns the landmark data.
///
Dictionary GetLandmarkNodes();
///
/// Sets a relative initial pose 'relative_pose' for 'from_trajectory_id' with
/// respect to 'to_trajectory_id' at time 'time'.
///
void SetInitialTrajectoryPose(
int fromTrajectoryId,
int toTrajectoryId,
Rigid3d pose,
long time);
///
/// Waits for all computations to finish and computes optimized poses.
///
void RunFinalOptimization();
///
/// Returns data for all submaps.
///
MapById GetAllSubmapData();
///
/// Returns the current optimized transform and submap itself for the given
/// 'submap_id'. Returns 'null' for the 'submap' member if the submap does
/// not exist (anymore).
///
SubmapData GetSubmapData(SubmapId submapId);
///
/// Returns the global poses for all submaps.
///
MapById GetAllSubmapPoses();
///
/// Returns the transform converting data in the local map frame (i.e. the
/// continuous, non-loop-closed frame) into the global map frame (i.e. the
/// discontinuous, loop-closed frame).
///
Rigid3d GetLocalToGlobalTransform(int trajectoryId);
///
/// Returns the current optimized trajectories.
///
MapById GetTrajectoryNodes();
///
/// Returns the current optimized trajectory poses.
///
MapById GetTrajectoryNodePoses();
///
/// Returns the states of trajectories.
///
Dictionary GetTrajectoryStates();
///
/// Returns the current optimized landmark poses.
///
Dictionary GetLandmarkPoses();
///
/// Sets global pose of landmark 'landmark_id' to given 'global_pose'.
///
void SetLandmarkPose(string landmarkId, Rigid3d globalPose, bool frozen = false);
///
/// Deletes a trajectory asynchronously.
///
void DeleteTrajectory(int trajectoryId);
///
/// Checks if the given trajectory is finished.
///
bool IsTrajectoryFinished(int trajectoryId);
///
/// Checks if the given trajectory is frozen.
///
bool IsTrajectoryFrozen(int trajectoryId);
///
/// Returns the trajectory data.
///
Dictionary GetTrajectoryData();
///
/// Returns the collection of constraints.
///
List Constraints();
///
/// Serializes the constraints and trajectories. If
/// 'include_unfinished_submaps' is set to 'true', unfinished submaps, i.e.
/// submaps that have not yet received all rangefinder data insertions, will
/// be included, otherwise not.
///
Models.Mapping.PoseGraph ToProto(bool includeUnfinishedSubmaps);
///
/// Sets the callback function that is invoked whenever the global optimization
/// problem is solved.
///
void SetGlobalSlamOptimizationCallback(GlobalSlamOptimizationCallback callback);
///
/// Sets the transform from local map frame to global map frame (map origin).
/// Used when loading state from pbstream; matches C++ SetTransformToMap.
///
void SetTransformToMap(Rigid3d transform);
///
/// Returns the transform from local map frame to global map frame.
/// Matches C++ GetTransformToMap.
///
Rigid3d GetTransformToMap();
///
/// Manually compute a constraint between a node and submap using global scan matching.
/// Match C++: manualComputeConstraint (pose_graph_interface.h:181-192)
///
(double Score, Constraint? Constraint) ManualComputeConstraint(NodeId nodeId, SubmapId submapId);
///
/// Manually compute constraint score from an initial pose estimate.
/// Match C++: manualComputeConstraintScore (pose_graph_interface.h:194-197)
///
double ManualComputeConstraintScore(NodeId nodeId, SubmapId submapId, Rigid3d initialPose);
///
/// Manually compute scan matcher score with refined pose output.
/// Match C++: manualComputeScanMatcher (pose_graph_interface.h:199-202)
///
double ManualComputeScanMatcher(NodeId nodeId, SubmapId submapId, Rigid3d initialPose, out Rigid3d poseManualEstimate);
///
/// Manually relocalize a trajectory against finished submaps.
/// Match C++: ManualRelocalization (pose_graph_interface.h:212-216)
///
bool ManualRelocalization(int trajectoryId, out double score, Rigid2d initialPose, LocalizationResultCallback? callback);
}
///
/// Callback for global SLAM optimization.
///
public delegate void GlobalSlamOptimizationCallback(
Dictionary submapIds,
Dictionary nodeIds);
///
/// Result of manual relocalization operation.
/// Match C++: LocalizationResultCallback (pose_graph_interface.h)
///
public struct LocalizationResult
{
public NodeId NodeId { get; init; }
public SubmapId SubmapId { get; init; }
public Rigid3d GlobalPose { get; init; }
public double Score { get; init; }
}
///
/// Callback for localization/relocalization results.
/// Match C++: LocalizationResultCallback (pose_graph_interface.h)
///
public delegate void LocalizationResultCallback(LocalizationResult result);