Initial commit
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
using RobotNet10.Shared.Enum;
|
||||
using RobotNet10.Shared.Numbers;
|
||||
|
||||
namespace RobotNet10.Shared.Detection;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Request to search for a specific marker
|
||||
/// </summary>
|
||||
public struct MarkerEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Marker ID from database
|
||||
/// </summary>
|
||||
public string MarkerId { get; set; }
|
||||
|
||||
public MarkerType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Search priority (1 = highest, 2 = second highest, etc.)
|
||||
/// Lower number = higher priority
|
||||
/// </summary>
|
||||
public int Priority { get; set; }
|
||||
|
||||
public string DeviceId { get; set; }
|
||||
|
||||
public string Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional: Override detection parameters for this session
|
||||
/// If null, use default parameters from marker definition
|
||||
/// Tọa độ trong marker frame
|
||||
/// </summary>
|
||||
public Vector2[] ReferencePoints { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace RobotNet10.Shared.Detection;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Configuration for a detection session
|
||||
/// Defines search area and which markers to look for
|
||||
/// </summary>
|
||||
public struct MarkersSearchRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Tọa độ dự đoán global X
|
||||
/// </summary>
|
||||
public double X { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Tọa độ dự đóan global Y
|
||||
/// </summary>
|
||||
public double Y { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Hướng dự đoán global
|
||||
/// </summary>
|
||||
public double Yaw { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Width (local X-axis, meters) kích thước tìm kiếm theo chiều rộng khi chưa xoay Yaw
|
||||
/// </summary>
|
||||
public double Width { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length (local Y-axis, meters) kích thước tìm kiếm theo chiều dài khi chưa xoay Yaw
|
||||
/// </summary>
|
||||
public double Length { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of markers to search for with their priorities
|
||||
/// </summary>
|
||||
public MarkerEntry[] MarkerSearchRequests { get; set; }
|
||||
}
|
||||
25
srcs/RobotNet10/Shared/RobotNet10.Shared/Enum/MarkerType.cs
Normal file
25
srcs/RobotNet10/Shared/RobotNet10.Shared/Enum/MarkerType.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
namespace RobotNet10.Shared.Enum;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Marker type enumeration
|
||||
/// </summary>
|
||||
public enum MarkerType
|
||||
{
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// QR Code marker (detected by camera)
|
||||
/// </summary>
|
||||
QRCode,
|
||||
|
||||
/// <summary>
|
||||
/// ArUco marker (detected by camera)
|
||||
/// </summary>
|
||||
ArUco,
|
||||
|
||||
/// <summary>
|
||||
/// Shape reflective marker - 2,3,4 reflective posts (detected by LiDAR)
|
||||
/// </summary>
|
||||
ShapeReflective,
|
||||
}
|
||||
39
srcs/RobotNet10/Shared/RobotNet10.Shared/Geometry/Accel.cs
Normal file
39
srcs/RobotNet10/Shared/RobotNet10.Shared/Geometry/Accel.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using RobotNet10.Shared.Numbers;
|
||||
|
||||
namespace RobotNet10.Shared.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Accel message (geometry_msgs/Accel)
|
||||
/// Expresses acceleration in free space broken into its linear and angular parts
|
||||
/// </summary>
|
||||
public struct Accel
|
||||
{
|
||||
/// <summary>
|
||||
/// Linear acceleration (Vector3)
|
||||
/// </summary>
|
||||
public Vector3 Linear { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Angular acceleration (Vector3)
|
||||
/// </summary>
|
||||
public Vector3 Angular { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public Accel()
|
||||
{
|
||||
Linear = new Vector3();
|
||||
Angular = new Vector3();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public Accel(Vector3 linear, Vector3 angular)
|
||||
{
|
||||
Linear = linear;
|
||||
Angular = angular;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
namespace RobotNet10.Shared.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// AccelStamped message (geometry_msgs/AccelStamped)
|
||||
/// An Accel with reference coordinate frame and timestamp
|
||||
/// </summary>
|
||||
public struct AccelStamped
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Acceleration
|
||||
/// </summary>
|
||||
public Accel Accel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public AccelStamped()
|
||||
{
|
||||
Header = new Header();
|
||||
Accel = new Accel();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public AccelStamped(Header header, Accel accel)
|
||||
{
|
||||
Header = header;
|
||||
Accel = accel;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
namespace RobotNet10.Shared.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// AccelWithCovariance message (geometry_msgs/AccelWithCovariance)
|
||||
/// An Accel with associated covariance matrix
|
||||
/// </summary>
|
||||
public struct AccelWithCovariance
|
||||
{
|
||||
/// <summary>
|
||||
/// Acceleration
|
||||
/// </summary>
|
||||
public Accel Accel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Covariance matrix (row-major order)
|
||||
/// The orientation parameters use a fixed-axis representation.
|
||||
/// In order, the parameters are:
|
||||
/// (ax, ay, az, wx, wy, wz)
|
||||
/// </summary>
|
||||
public double[] Covariance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of covariance matrix (6x6 = 36 elements)
|
||||
/// </summary>
|
||||
public const int CovarianceSize = 36;
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public AccelWithCovariance()
|
||||
{
|
||||
Accel = new Accel();
|
||||
Covariance = new double[CovarianceSize];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public AccelWithCovariance(Accel accel, double[] covariance)
|
||||
{
|
||||
Accel = accel;
|
||||
if (covariance == null || covariance.Length != CovarianceSize)
|
||||
{
|
||||
throw new ArgumentException($"Covariance array must have {CovarianceSize} elements", nameof(covariance));
|
||||
}
|
||||
Covariance = covariance;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
namespace RobotNet10.Shared.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// AccelWithCovarianceStamped message (geometry_msgs/AccelWithCovarianceStamped)
|
||||
/// An AccelWithCovariance with reference coordinate frame and timestamp
|
||||
/// </summary>
|
||||
public struct AccelWithCovarianceStamped
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Acceleration with covariance
|
||||
/// </summary>
|
||||
public AccelWithCovariance Accel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public AccelWithCovarianceStamped()
|
||||
{
|
||||
Header = new Header();
|
||||
Accel = new AccelWithCovariance();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public AccelWithCovarianceStamped(Header header, AccelWithCovariance accel)
|
||||
{
|
||||
Header = header;
|
||||
Accel = accel;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
using RobotNet10.Shared.Numbers;
|
||||
|
||||
namespace RobotNet10.Shared.Geometry;
|
||||
|
||||
public static class GeometryExtensions
|
||||
{
|
||||
extension(Quaternion q)
|
||||
{
|
||||
public double ToYawRadian()
|
||||
{
|
||||
var sinYaw = 2.0 * (q.W * q.Z + q.X * q.Y);
|
||||
var cosYaw = 1.0 - 2.0 * (q.Y * q.Y + q.Z * q.Z);
|
||||
return Math.Atan2(sinYaw, cosYaw);
|
||||
}
|
||||
|
||||
public double ToYawDegrees() => q.ToYawRadian() * 180 / Math.PI;
|
||||
}
|
||||
}
|
||||
44
srcs/RobotNet10/Shared/RobotNet10.Shared/Geometry/Point.cs
Normal file
44
srcs/RobotNet10/Shared/RobotNet10.Shared/Geometry/Point.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
namespace RobotNet10.Shared.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Point message (geometry_msgs/Point)
|
||||
/// Represents a point in free space with x, y, z coordinates
|
||||
/// </summary>
|
||||
public struct Point
|
||||
{
|
||||
/// <summary>
|
||||
/// X coordinate
|
||||
/// </summary>
|
||||
public double X { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Y coordinate
|
||||
/// </summary>
|
||||
public double Y { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Z coordinate
|
||||
/// </summary>
|
||||
public double Z { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public Point()
|
||||
{
|
||||
X = 0.0;
|
||||
Y = 0.0;
|
||||
Z = 0.0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public Point(double x, double y, double z)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Z = z;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
using RobotNet10.Shared.Numbers;
|
||||
|
||||
namespace RobotNet10.Shared.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// PointStamped message (geometry_msgs/PointStamped)
|
||||
/// A Point with reference coordinate frame and timestamp
|
||||
/// </summary>
|
||||
public struct PointStamped
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Point
|
||||
/// </summary>
|
||||
public Vector3 Point { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public PointStamped()
|
||||
{
|
||||
Header = new Header();
|
||||
Point = new Vector3();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public PointStamped(Header header, Vector3 point)
|
||||
{
|
||||
Header = header;
|
||||
Point = point;
|
||||
}
|
||||
}
|
||||
|
||||
32
srcs/RobotNet10/Shared/RobotNet10.Shared/Geometry/Polygon.cs
Normal file
32
srcs/RobotNet10/Shared/RobotNet10.Shared/Geometry/Polygon.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using RobotNet10.Shared.Numbers;
|
||||
|
||||
namespace RobotNet10.Shared.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Polygon message (geometry_msgs/Polygon)
|
||||
/// A specification of a polygon where the first and last points are assumed to be connected
|
||||
/// </summary>
|
||||
public struct Polygon
|
||||
{
|
||||
/// <summary>
|
||||
/// Array of points defining the polygon
|
||||
/// </summary>
|
||||
public Vector3[] Points { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public Polygon()
|
||||
{
|
||||
Points = [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public Polygon(Vector3[] points)
|
||||
{
|
||||
Points = points;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
namespace RobotNet10.Shared.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// PolygonStamped message (geometry_msgs/PolygonStamped)
|
||||
/// A Polygon with reference coordinate frame and timestamp
|
||||
/// </summary>
|
||||
public struct PolygonStamped
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Polygon
|
||||
/// </summary>
|
||||
public Polygon Polygon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public PolygonStamped()
|
||||
{
|
||||
Header = new Header();
|
||||
Polygon = new Polygon();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public PolygonStamped(Header header, Polygon polygon)
|
||||
{
|
||||
Header = header;
|
||||
Polygon = polygon;
|
||||
}
|
||||
}
|
||||
|
||||
37
srcs/RobotNet10/Shared/RobotNet10.Shared/Geometry/Pose.cs
Normal file
37
srcs/RobotNet10/Shared/RobotNet10.Shared/Geometry/Pose.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
namespace RobotNet10.Shared.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Pose message (geometry_msgs/Pose)
|
||||
/// Represents a pose in free space, composed of position and orientation
|
||||
/// </summary>
|
||||
public struct Pose
|
||||
{
|
||||
/// <summary>
|
||||
/// Position (Point)
|
||||
/// </summary>
|
||||
public Point Position { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Orientation (Quaternion)
|
||||
/// </summary>
|
||||
public Quaternion Orientation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public Pose()
|
||||
{
|
||||
Position = new Point();
|
||||
Orientation = new Quaternion();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public Pose(Point position, Quaternion orientation)
|
||||
{
|
||||
Position = position;
|
||||
Orientation = orientation;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
namespace RobotNet10.Shared.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// PoseStamped message (geometry_msgs/PoseStamped)
|
||||
/// A Pose with reference coordinate frame and timestamp
|
||||
/// </summary>
|
||||
public struct PoseStamped
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Pose
|
||||
/// </summary>
|
||||
public Pose Pose { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public PoseStamped()
|
||||
{
|
||||
Header = new Header();
|
||||
Pose = new Pose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public PoseStamped(Header header, Pose pose)
|
||||
{
|
||||
Header = header;
|
||||
Pose = pose;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
namespace RobotNet10.Shared.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// PoseWithCovariance message (geometry_msgs/PoseWithCovariance)
|
||||
/// A Pose with associated covariance matrix
|
||||
/// </summary>
|
||||
public struct PoseWithCovariance
|
||||
{
|
||||
/// <summary>
|
||||
/// Pose
|
||||
/// </summary>
|
||||
public Pose Pose { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Covariance matrix (row-major order)
|
||||
/// The orientation parameters use a fixed-axis representation.
|
||||
/// In order, the parameters are:
|
||||
/// (x, y, z, rotation about X axis, rotation about Y axis, rotation about Z axis)
|
||||
/// </summary>
|
||||
public double[] Covariance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of covariance matrix (6x6 = 36 elements)
|
||||
/// </summary>
|
||||
public const int CovarianceSize = 36;
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public PoseWithCovariance()
|
||||
{
|
||||
Pose = new Pose();
|
||||
Covariance = new double[CovarianceSize];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public PoseWithCovariance(Pose pose, double[] covariance)
|
||||
{
|
||||
Pose = pose;
|
||||
if (covariance == null || covariance.Length != CovarianceSize)
|
||||
{
|
||||
throw new ArgumentException($"Covariance array must have {CovarianceSize} elements", nameof(covariance));
|
||||
}
|
||||
Covariance = covariance;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
namespace RobotNet10.Shared.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// PoseWithCovarianceStamped message (geometry_msgs/PoseWithCovarianceStamped)
|
||||
/// A PoseWithCovariance with reference coordinate frame and timestamp
|
||||
/// </summary>
|
||||
public struct PoseWithCovarianceStamped
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Pose with covariance
|
||||
/// </summary>
|
||||
public PoseWithCovariance Pose { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public PoseWithCovarianceStamped()
|
||||
{
|
||||
Header = new Header();
|
||||
Pose = new PoseWithCovariance();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public PoseWithCovarianceStamped(Header header, PoseWithCovariance pose)
|
||||
{
|
||||
Header = header;
|
||||
Pose = pose;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
namespace RobotNet10.Shared.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Quaternion message (geometry_msgs/Quaternion)
|
||||
/// Represents a rotation in free space in quaternion form
|
||||
/// </summary>
|
||||
public struct Quaternion
|
||||
{
|
||||
/// <summary>
|
||||
/// X component
|
||||
/// </summary>
|
||||
public double X { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Y component
|
||||
/// </summary>
|
||||
public double Y { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Z component
|
||||
/// </summary>
|
||||
public double Z { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// W component (scalar part)
|
||||
/// </summary>
|
||||
public double W { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public Quaternion()
|
||||
{
|
||||
X = 0.0;
|
||||
Y = 0.0;
|
||||
Z = 0.0;
|
||||
W = 1.0; // Identity quaternion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public Quaternion(double x, double y, double z, double w)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Z = z;
|
||||
W = w;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
using RobotNet10.Shared.Numbers;
|
||||
|
||||
namespace RobotNet10.Shared.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// QuaternionStamped message (geometry_msgs/QuaternionStamped)
|
||||
/// A Quaternion with reference coordinate frame and timestamp
|
||||
/// </summary>
|
||||
public struct QuaternionStamped
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Quaternion
|
||||
/// </summary>
|
||||
public Quaternion Quaternion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public QuaternionStamped()
|
||||
{
|
||||
Header = new Header();
|
||||
Quaternion = new Quaternion();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public QuaternionStamped(Header header, Quaternion quaternion)
|
||||
{
|
||||
Header = header;
|
||||
Quaternion = quaternion;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
using RobotNet10.Shared.Numbers;
|
||||
|
||||
namespace RobotNet10.Shared.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Transform message (geometry_msgs/Transform)
|
||||
/// Represents a transform between two coordinate frames in free space
|
||||
/// </summary>
|
||||
public struct Transform
|
||||
{
|
||||
/// <summary>
|
||||
/// Translation (Vector3)
|
||||
/// </summary>
|
||||
public Vector3 Translation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Rotation (Quaternion)
|
||||
/// </summary>
|
||||
public Quaternion Rotation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public Transform()
|
||||
{
|
||||
Translation = new Vector3();
|
||||
Rotation = new Quaternion();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public Transform(Vector3 translation, Quaternion rotation)
|
||||
{
|
||||
Translation = translation;
|
||||
Rotation = rotation;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
namespace RobotNet10.Shared.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// TransformStamped message (geometry_msgs/TransformStamped)
|
||||
/// A Transform with reference coordinate frame and timestamp
|
||||
/// </summary>
|
||||
public struct TransformStamped
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID (child_frame_id is stored in frame_id)
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Child frame ID (the frame being transformed to)
|
||||
/// </summary>
|
||||
public string ChildFrameId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Transform
|
||||
/// </summary>
|
||||
public Transform Transform { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public TransformStamped()
|
||||
{
|
||||
Header = new Header();
|
||||
ChildFrameId = string.Empty;
|
||||
Transform = new Transform();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public TransformStamped(Header header, string childFrameId, Transform transform)
|
||||
{
|
||||
Header = header;
|
||||
ChildFrameId = childFrameId;
|
||||
Transform = transform;
|
||||
}
|
||||
}
|
||||
|
||||
39
srcs/RobotNet10/Shared/RobotNet10.Shared/Geometry/Twist.cs
Normal file
39
srcs/RobotNet10/Shared/RobotNet10.Shared/Geometry/Twist.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using RobotNet10.Shared.Numbers;
|
||||
|
||||
namespace RobotNet10.Shared.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Twist message (geometry_msgs/Twist)
|
||||
/// Expresses velocity in free space broken into its linear and angular parts
|
||||
/// </summary>
|
||||
public struct Twist
|
||||
{
|
||||
/// <summary>
|
||||
/// Linear velocity (Vector3)
|
||||
/// </summary>
|
||||
public Vector3 Linear { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Angular velocity (Vector3)
|
||||
/// </summary>
|
||||
public Vector3 Angular { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public Twist()
|
||||
{
|
||||
Linear = new Vector3();
|
||||
Angular = new Vector3();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public Twist(Vector3 linear, Vector3 angular)
|
||||
{
|
||||
Linear = linear;
|
||||
Angular = angular;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
namespace RobotNet10.Shared.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// TwistStamped message (geometry_msgs/TwistStamped)
|
||||
/// A Twist with reference coordinate frame and timestamp
|
||||
/// </summary>
|
||||
public struct TwistStamped
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Twist
|
||||
/// </summary>
|
||||
public Twist Twist { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public TwistStamped()
|
||||
{
|
||||
Header = new Header();
|
||||
Twist = new Twist();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public TwistStamped(Header header, Twist twist)
|
||||
{
|
||||
Header = header;
|
||||
Twist = twist;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
namespace RobotNet10.Shared.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// TwistWithCovariance message (geometry_msgs/TwistWithCovariance)
|
||||
/// A Twist with associated covariance matrix
|
||||
/// </summary>
|
||||
public struct TwistWithCovariance
|
||||
{
|
||||
/// <summary>
|
||||
/// Twist
|
||||
/// </summary>
|
||||
public Twist Twist { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Covariance matrix (row-major order)
|
||||
/// The orientation parameters use a fixed-axis representation.
|
||||
/// In order, the parameters are:
|
||||
/// (vx, vy, vz, wx, wy, wz)
|
||||
/// </summary>
|
||||
public double[] Covariance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of covariance matrix (6x6 = 36 elements)
|
||||
/// </summary>
|
||||
public const int CovarianceSize = 36;
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public TwistWithCovariance()
|
||||
{
|
||||
Twist = new Twist();
|
||||
Covariance = new double[CovarianceSize];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public TwistWithCovariance(Twist twist, double[] covariance)
|
||||
{
|
||||
Twist = twist;
|
||||
if (covariance == null || covariance.Length != CovarianceSize)
|
||||
{
|
||||
throw new ArgumentException($"Covariance array must have {CovarianceSize} elements", nameof(covariance));
|
||||
}
|
||||
Covariance = covariance;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
namespace RobotNet10.Shared.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// TwistWithCovarianceStamped message (geometry_msgs/TwistWithCovarianceStamped)
|
||||
/// A TwistWithCovariance with reference coordinate frame and timestamp
|
||||
/// </summary>
|
||||
public struct TwistWithCovarianceStamped
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Twist with covariance
|
||||
/// </summary>
|
||||
public TwistWithCovariance Twist { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public TwistWithCovarianceStamped()
|
||||
{
|
||||
Header = new Header();
|
||||
Twist = new TwistWithCovariance();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public TwistWithCovarianceStamped(Header header, TwistWithCovariance twist)
|
||||
{
|
||||
Header = header;
|
||||
Twist = twist;
|
||||
}
|
||||
}
|
||||
|
||||
44
srcs/RobotNet10/Shared/RobotNet10.Shared/Geometry/Vector3.cs
Normal file
44
srcs/RobotNet10/Shared/RobotNet10.Shared/Geometry/Vector3.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
namespace RobotNet10.Shared.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Vector3 message (geometry_msgs/Vector3)
|
||||
/// Represents a vector in free space
|
||||
/// </summary>
|
||||
public struct Vector3
|
||||
{
|
||||
/// <summary>
|
||||
/// X component
|
||||
/// </summary>
|
||||
public double X { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Y component
|
||||
/// </summary>
|
||||
public double Y { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Z component
|
||||
/// </summary>
|
||||
public double Z { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public Vector3()
|
||||
{
|
||||
X = 0.0;
|
||||
Y = 0.0;
|
||||
Z = 0.0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public Vector3(double x, double y, double z)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Z = z;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
using RobotNet10.Shared.Numbers;
|
||||
|
||||
namespace RobotNet10.Shared.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Vector3Stamped message (geometry_msgs/Vector3Stamped)
|
||||
/// A Vector3 with reference coordinate frame and timestamp
|
||||
/// </summary>
|
||||
public struct Vector3Stamped
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Vector3
|
||||
/// </summary>
|
||||
public Vector3 Vector { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public Vector3Stamped()
|
||||
{
|
||||
Header = new Header();
|
||||
Vector = new Vector3();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public Vector3Stamped(Header header, Vector3 vector)
|
||||
{
|
||||
Header = header;
|
||||
Vector = vector;
|
||||
}
|
||||
}
|
||||
|
||||
43
srcs/RobotNet10/Shared/RobotNet10.Shared/Header.cs
Normal file
43
srcs/RobotNet10/Shared/RobotNet10.Shared/Header.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
namespace RobotNet10.Shared;
|
||||
|
||||
/// <summary>
|
||||
/// Standard ROS Header message (similar to std_msgs/Header)
|
||||
/// </summary>
|
||||
public struct Header
|
||||
{
|
||||
/// <summary>
|
||||
/// Sequence number: consecutively increasing ID
|
||||
/// </summary>
|
||||
public uint Seq { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp: time when data was acquired
|
||||
/// </summary>
|
||||
public DateTime Stamp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Frame ID: frame this data is associated with
|
||||
/// </summary>
|
||||
public string FrameId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public Header()
|
||||
{
|
||||
Seq = 0;
|
||||
Stamp = DateTime.MinValue;
|
||||
FrameId = string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public Header(uint seq, DateTime stamp, string frameId)
|
||||
{
|
||||
Seq = seq;
|
||||
Stamp = stamp;
|
||||
FrameId = frameId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
using RobotNet10.Shared.Geometry;
|
||||
|
||||
namespace RobotNet10.Shared.Localization;
|
||||
|
||||
/// <summary>
|
||||
/// Occupancy grid for representing map as a 2D grid of cells
|
||||
/// Compatible with ROS navigation_msgs/OccupancyGrid
|
||||
/// </summary>
|
||||
public class OccupancyGrid
|
||||
{
|
||||
/// <summary>
|
||||
/// Resolution of the grid (meters per pixel)
|
||||
/// </summary>
|
||||
public double Resolution { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Width of the grid (number of cells)
|
||||
/// </summary>
|
||||
public int Width { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Height of the grid (number of cells)
|
||||
/// </summary>
|
||||
public int Height { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Origin of the grid in map frame (bottom-left corner)
|
||||
/// </summary>
|
||||
public Pose Origin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Grid data: -1 = Unknown, 0-100 = Probability of occupancy (0 = free, 100 = occupied)
|
||||
/// Stored in row-major order (index = y * width + x)
|
||||
/// </summary>
|
||||
public sbyte[] Data { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new empty occupancy grid
|
||||
/// </summary>
|
||||
public OccupancyGrid()
|
||||
{
|
||||
Resolution = 0.05;
|
||||
Width = 0;
|
||||
Height = 0;
|
||||
Origin = new Pose();
|
||||
Data = [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new occupancy grid with specified dimensions
|
||||
/// </summary>
|
||||
public OccupancyGrid(double resolution, int width, int height, Pose origin)
|
||||
{
|
||||
Resolution = resolution;
|
||||
Width = width;
|
||||
Height = height;
|
||||
Origin = origin;
|
||||
Data = new sbyte[width * height];
|
||||
|
||||
// Initialize all cells as unknown (-1)
|
||||
Array.Fill(Data, (sbyte)-1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the occupancy value at the specified cell coordinates
|
||||
/// </summary>
|
||||
/// <param name="x">X coordinate (0 to Width-1)</param>
|
||||
/// <param name="y">Y coordinate (0 to Height-1)</param>
|
||||
/// <returns>-1 = Unknown, 0-100 = Occupancy probability</returns>
|
||||
public sbyte GetCell(int x, int y)
|
||||
{
|
||||
if (x < 0 || x >= Width || y < 0 || y >= Height)
|
||||
{
|
||||
return -1; // Out of bounds = unknown
|
||||
}
|
||||
return Data[y * Width + x];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the occupancy value at the specified cell coordinates
|
||||
/// </summary>
|
||||
/// <param name="x">X coordinate (0 to Width-1)</param>
|
||||
/// <param name="y">Y coordinate (0 to Height-1)</param>
|
||||
/// <param name="value">-1 = Unknown, 0-100 = Occupancy probability</param>
|
||||
public void SetCell(int x, int y, sbyte value)
|
||||
{
|
||||
if (x < 0 || x >= Width || y < 0 || y >= Height)
|
||||
{
|
||||
return; // Out of bounds, ignore
|
||||
}
|
||||
Data[y * Width + x] = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts world coordinates (meters) to grid cell coordinates
|
||||
/// </summary>
|
||||
/// <param name="worldX">X coordinate in meters</param>
|
||||
/// <param name="worldY">Y coordinate in meters</param>
|
||||
/// <returns>Cell coordinates (x, y)</returns>
|
||||
public (int x, int y) WorldToGrid(double worldX, double worldY)
|
||||
{
|
||||
// Convert world coordinates relative to origin
|
||||
var relativeX = worldX - Origin.Position.X;
|
||||
var relativeY = worldY - Origin.Position.Y;
|
||||
|
||||
// Convert to grid coordinates
|
||||
var gridX = (int)Math.Floor(relativeX / Resolution);
|
||||
var gridY = (int)Math.Floor(relativeY / Resolution);
|
||||
|
||||
return (gridX, gridY);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts grid cell coordinates to world coordinates (meters)
|
||||
/// </summary>
|
||||
/// <param name="gridX">X coordinate in grid cells</param>
|
||||
/// <param name="gridY">Y coordinate in grid cells</param>
|
||||
/// <returns>World coordinates (x, y) in meters</returns>
|
||||
public (double x, double y) GridToWorld(int gridX, int gridY)
|
||||
{
|
||||
var worldX = Origin.Position.X + (gridX * Resolution);
|
||||
var worldY = Origin.Position.Y + (gridY * Resolution);
|
||||
return (worldX, worldY);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bounds of the grid in world coordinates
|
||||
/// </summary>
|
||||
public BoundingBox GetBounds()
|
||||
{
|
||||
var (minX, minY) = GridToWorld(0, 0);
|
||||
var (maxX, maxY) = GridToWorld(Width, Height);
|
||||
return new BoundingBox
|
||||
{
|
||||
MinX = Math.Min(minX, maxX),
|
||||
MinY = Math.Min(minY, maxY),
|
||||
MaxX = Math.Max(minX, maxX),
|
||||
MaxY = Math.Max(minY, maxY)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bounding box for representing map bounds
|
||||
/// </summary>
|
||||
public class BoundingBox
|
||||
{
|
||||
public double MinX { get; set; }
|
||||
public double MinY { get; set; }
|
||||
public double MaxX { get; set; }
|
||||
public double MaxY { get; set; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace RobotNet10.Shared;
|
||||
|
||||
public record MessageResult(bool IsSuccess, string Message = "");
|
||||
|
||||
public record MessageResult<T>(bool IsSuccess, T? Data = default, string Message = "");
|
||||
204
srcs/RobotNet10/Shared/RobotNet10.Shared/Numbers/Matrix3x2.cs
Normal file
204
srcs/RobotNet10/Shared/RobotNet10.Shared/Numbers/Matrix3x2.cs
Normal file
@@ -0,0 +1,204 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace RobotNet10.Shared.Numbers;
|
||||
|
||||
/// <summary>
|
||||
/// Custom 3x2 matrix struct for 2D affine transformations.
|
||||
/// Replacement for System.Numerics.Matrix3x2 which doesn't serialize properly.
|
||||
/// </summary>
|
||||
public struct Matrix3x2 : IEquatable<Matrix3x2>
|
||||
{
|
||||
/// <summary>
|
||||
/// Value at row 1, column 1
|
||||
/// </summary>
|
||||
public double M11 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Value at row 1, column 2
|
||||
/// </summary>
|
||||
public double M12 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Value at row 2, column 1
|
||||
/// </summary>
|
||||
public double M21 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Value at row 2, column 2
|
||||
/// </summary>
|
||||
public double M22 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Value at row 3, column 1 (translation X)
|
||||
/// </summary>
|
||||
public double M31 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Value at row 3, column 2 (translation Y)
|
||||
/// </summary>
|
||||
public double M32 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new Matrix3x2
|
||||
/// </summary>
|
||||
public Matrix3x2(double m11, double m12, double m21, double m22, double m31, double m32)
|
||||
{
|
||||
M11 = m11;
|
||||
M12 = m12;
|
||||
M21 = m21;
|
||||
M22 = m22;
|
||||
M31 = m31;
|
||||
M32 = m32;
|
||||
}
|
||||
|
||||
#region Static Properties
|
||||
|
||||
/// <summary>
|
||||
/// Returns the identity matrix
|
||||
/// </summary>
|
||||
public static Matrix3x2 Identity => new(1, 0, 0, 1, 0, 0);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Static Methods
|
||||
|
||||
/// <summary>
|
||||
/// Creates a rotation matrix
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Matrix3x2 CreateRotation(double radians)
|
||||
{
|
||||
double cos = Math.Cos(radians);
|
||||
double sin = Math.Sin(radians);
|
||||
return new Matrix3x2(cos, sin, -sin, cos, 0, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a translation matrix
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Matrix3x2 CreateTranslation(double x, double y)
|
||||
{
|
||||
return new Matrix3x2(1, 0, 0, 1, x, y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a translation matrix from a Vector2
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Matrix3x2 CreateTranslation(Vector2 position)
|
||||
{
|
||||
return new Matrix3x2(1, 0, 0, 1, position.X, position.Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a scale matrix
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Matrix3x2 CreateScale(double scale)
|
||||
{
|
||||
return new Matrix3x2(scale, 0, 0, scale, 0, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a scale matrix
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Matrix3x2 CreateScale(double scaleX, double scaleY)
|
||||
{
|
||||
return new Matrix3x2(scaleX, 0, 0, scaleY, 0, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Multiplies two matrices
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Matrix3x2 Multiply(Matrix3x2 value1, Matrix3x2 value2)
|
||||
{
|
||||
return value1 * value2;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Operators
|
||||
|
||||
/// <summary>
|
||||
/// Multiplies two matrices
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Matrix3x2 operator *(Matrix3x2 value1, Matrix3x2 value2)
|
||||
{
|
||||
return new Matrix3x2(
|
||||
value1.M11 * value2.M11 + value1.M12 * value2.M21,
|
||||
value1.M11 * value2.M12 + value1.M12 * value2.M22,
|
||||
value1.M21 * value2.M11 + value1.M22 * value2.M21,
|
||||
value1.M21 * value2.M12 + value1.M22 * value2.M22,
|
||||
value1.M31 * value2.M11 + value1.M32 * value2.M21 + value2.M31,
|
||||
value1.M31 * value2.M12 + value1.M32 * value2.M22 + value2.M32
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two matrices are equal
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator ==(Matrix3x2 left, Matrix3x2 right)
|
||||
{
|
||||
return left.M11 == right.M11 && left.M12 == right.M12 &&
|
||||
left.M21 == right.M21 && left.M22 == right.M22 &&
|
||||
left.M31 == right.M31 && left.M32 == right.M32;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two matrices are not equal
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator !=(Matrix3x2 left, Matrix3x2 right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Equality
|
||||
|
||||
/// <summary>
|
||||
/// Checks if this matrix equals another matrix
|
||||
/// </summary>
|
||||
public readonly bool Equals(Matrix3x2 other)
|
||||
{
|
||||
return M11 == other.M11 && M12 == other.M12 &&
|
||||
M21 == other.M21 && M22 == other.M22 &&
|
||||
M31 == other.M31 && M32 == other.M32;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if this matrix equals an object
|
||||
/// </summary>
|
||||
public override readonly bool Equals(object? obj)
|
||||
{
|
||||
return obj is Matrix3x2 matrix && Equals(matrix);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hash code for this matrix
|
||||
/// </summary>
|
||||
public override readonly int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(M11, M12, M21, M22, M31, M32);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region String
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string representation of this matrix
|
||||
/// </summary>
|
||||
public override readonly string ToString()
|
||||
{
|
||||
return $"{{ {{M11:{M11} M12:{M12}}} {{M21:{M21} M22:{M22}}} {{M31:{M31} M32:{M32}}} }}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
605
srcs/RobotNet10/Shared/RobotNet10.Shared/Numbers/Quaternion.cs
Normal file
605
srcs/RobotNet10/Shared/RobotNet10.Shared/Numbers/Quaternion.cs
Normal file
@@ -0,0 +1,605 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace RobotNet10.Shared.Numbers;
|
||||
|
||||
/// <summary>
|
||||
/// Custom quaternion struct that supports JSON serialization.
|
||||
/// Replacement for System.Numerics.Quaternion which doesn't serialize properly.
|
||||
/// Represents rotation in 3D space using the formula: q = w + xi + yj + zk
|
||||
/// </summary>
|
||||
public struct Quaternion : IEquatable<Quaternion>
|
||||
{
|
||||
/// <summary>
|
||||
/// X component of the vector part
|
||||
/// </summary>
|
||||
public double X { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Y component of the vector part
|
||||
/// </summary>
|
||||
public double Y { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Z component of the vector part
|
||||
/// </summary>
|
||||
public double Z { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// W component (scalar/real part)
|
||||
/// </summary>
|
||||
public double W { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new Quaternion
|
||||
/// </summary>
|
||||
public Quaternion(double x, double y, double z, double w)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Z = z;
|
||||
W = w;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a quaternion from a vector and scalar parts
|
||||
/// </summary>
|
||||
public Quaternion(Vector3 vectorPart, double scalarPart)
|
||||
{
|
||||
X = vectorPart.X;
|
||||
Y = vectorPart.Y;
|
||||
Z = vectorPart.Z;
|
||||
W = scalarPart;
|
||||
}
|
||||
|
||||
#region Static Properties
|
||||
|
||||
/// <summary>
|
||||
/// Returns the identity quaternion (no rotation)
|
||||
/// </summary>
|
||||
public static Quaternion Identity => new(0, 0, 0, 1);
|
||||
|
||||
public static Quaternion FromYawRadian(double yaw)
|
||||
{
|
||||
var halfYaw = yaw / 2.0;
|
||||
return new Quaternion(0, 0, Math.Sin(halfYaw), Math.Cos(halfYaw));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Returns the length (magnitude) of the quaternion
|
||||
/// </summary>
|
||||
public readonly double Length()
|
||||
{
|
||||
return Math.Sqrt(X * X + Y * Y + Z * Z + W * W);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the squared length of the quaternion (faster than Length)
|
||||
/// </summary>
|
||||
public readonly double LengthSquared()
|
||||
{
|
||||
return X * X + Y * Y + Z * Z + W * W;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this is a unit quaternion
|
||||
/// </summary>
|
||||
public readonly bool IsIdentity
|
||||
{
|
||||
get
|
||||
{
|
||||
return X == 0 && Y == 0 && Z == 0 && W == 1;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Returns a normalized copy of this quaternion (unit length)
|
||||
/// </summary>
|
||||
public readonly Quaternion Normalize()
|
||||
{
|
||||
double length = Length();
|
||||
if (length < double.Epsilon)
|
||||
return Identity;
|
||||
|
||||
double invLength = 1.0 / length;
|
||||
return new Quaternion(X * invLength, Y * invLength, Z * invLength, W * invLength);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Normalizes this quaternion in place
|
||||
/// </summary>
|
||||
public void NormalizeInPlace()
|
||||
{
|
||||
double length = Length();
|
||||
if (length < double.Epsilon)
|
||||
{
|
||||
X = Y = Z = 0;
|
||||
W = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
double invLength = 1.0 / length;
|
||||
X *= invLength;
|
||||
Y *= invLength;
|
||||
Z *= invLength;
|
||||
W *= invLength;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the conjugate of this quaternion (negated vector part)
|
||||
/// For unit quaternions, conjugate equals inverse
|
||||
/// </summary>
|
||||
public readonly Quaternion Conjugate()
|
||||
{
|
||||
return new Quaternion(-X, -Y, -Z, W);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the inverse of this quaternion
|
||||
/// </summary>
|
||||
public readonly Quaternion Inverse()
|
||||
{
|
||||
double lengthSq = LengthSquared();
|
||||
if (lengthSq < double.Epsilon)
|
||||
return Identity;
|
||||
|
||||
double invLengthSq = 1.0 / lengthSq;
|
||||
return new Quaternion(-X * invLengthSq, -Y * invLengthSq, -Z * invLengthSq, W * invLengthSq);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Static Methods
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the dot product of two quaternions
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static double Dot(Quaternion quaternion1, Quaternion quaternion2)
|
||||
{
|
||||
return quaternion1.X * quaternion2.X +
|
||||
quaternion1.Y * quaternion2.Y +
|
||||
quaternion1.Z * quaternion2.Z +
|
||||
quaternion1.W * quaternion2.W;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the conjugate of a quaternion (static version)
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Quaternion Conjugate(Quaternion value)
|
||||
{
|
||||
return value.Conjugate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the inverse of a quaternion (static version)
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Quaternion Inverse(Quaternion value)
|
||||
{
|
||||
return value.Inverse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a normalized copy of a quaternion (static version)
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Quaternion Normalize(Quaternion value)
|
||||
{
|
||||
return value.Normalize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Multiplies two quaternions (static version)
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Quaternion Multiply(Quaternion value1, Quaternion value2)
|
||||
{
|
||||
return value1 * value2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs spherical linear interpolation between two quaternions
|
||||
/// </summary>
|
||||
public static Quaternion Slerp(Quaternion quaternion1, Quaternion quaternion2, double amount)
|
||||
{
|
||||
double cosOmega = Dot(quaternion1, quaternion2);
|
||||
|
||||
bool flip = false;
|
||||
if (cosOmega < 0.0)
|
||||
{
|
||||
flip = true;
|
||||
cosOmega = -cosOmega;
|
||||
}
|
||||
|
||||
double s1, s2;
|
||||
|
||||
if (cosOmega > (1.0 - 1e-6))
|
||||
{
|
||||
// Too close, do straight linear interpolation
|
||||
s1 = 1.0 - amount;
|
||||
s2 = flip ? -amount : amount;
|
||||
}
|
||||
else
|
||||
{
|
||||
double omega = Math.Acos(cosOmega);
|
||||
double invSinOmega = 1.0 / Math.Sin(omega);
|
||||
|
||||
s1 = Math.Sin((1.0 - amount) * omega) * invSinOmega;
|
||||
s2 = flip
|
||||
? -Math.Sin(amount * omega) * invSinOmega
|
||||
: Math.Sin(amount * omega) * invSinOmega;
|
||||
}
|
||||
|
||||
return new Quaternion(
|
||||
s1 * quaternion1.X + s2 * quaternion2.X,
|
||||
s1 * quaternion1.Y + s2 * quaternion2.Y,
|
||||
s1 * quaternion1.Z + s2 * quaternion2.Z,
|
||||
s1 * quaternion1.W + s2 * quaternion2.W
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs linear interpolation between two quaternions
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Quaternion Lerp(Quaternion quaternion1, Quaternion quaternion2, double amount)
|
||||
{
|
||||
double t = amount;
|
||||
double t1 = 1.0 - t;
|
||||
|
||||
Quaternion result;
|
||||
|
||||
double dot = Dot(quaternion1, quaternion2);
|
||||
|
||||
if (dot >= 0.0)
|
||||
{
|
||||
result = new Quaternion(
|
||||
t1 * quaternion1.X + t * quaternion2.X,
|
||||
t1 * quaternion1.Y + t * quaternion2.Y,
|
||||
t1 * quaternion1.Z + t * quaternion2.Z,
|
||||
t1 * quaternion1.W + t * quaternion2.W
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = new Quaternion(
|
||||
t1 * quaternion1.X - t * quaternion2.X,
|
||||
t1 * quaternion1.Y - t * quaternion2.Y,
|
||||
t1 * quaternion1.Z - t * quaternion2.Z,
|
||||
t1 * quaternion1.W - t * quaternion2.W
|
||||
);
|
||||
}
|
||||
|
||||
return result.Normalize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Concatenates two quaternions (applies rotation1 followed by rotation2)
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Quaternion Concatenate(Quaternion value1, Quaternion value2)
|
||||
{
|
||||
// This is equivalent to value2 * value1
|
||||
double q1x = value2.X;
|
||||
double q1y = value2.Y;
|
||||
double q1z = value2.Z;
|
||||
double q1w = value2.W;
|
||||
|
||||
double q2x = value1.X;
|
||||
double q2y = value1.Y;
|
||||
double q2z = value1.Z;
|
||||
double q2w = value1.W;
|
||||
|
||||
// Cross product
|
||||
double cx = q1y * q2z - q1z * q2y;
|
||||
double cy = q1z * q2x - q1x * q2z;
|
||||
double cz = q1x * q2y - q1y * q2x;
|
||||
|
||||
double dot = q1x * q2x + q1y * q2y + q1z * q2z;
|
||||
|
||||
return new Quaternion(
|
||||
q1x * q2w + q2x * q1w + cx,
|
||||
q1y * q2w + q2y * q1w + cy,
|
||||
q1z * q2w + q2z * q1w + cz,
|
||||
q1w * q2w - dot
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a quaternion from an axis and angle
|
||||
/// </summary>
|
||||
public static Quaternion CreateFromAxisAngle(Vector3 axis, double angle)
|
||||
{
|
||||
double halfAngle = angle * 0.5;
|
||||
double s = Math.Sin(halfAngle);
|
||||
double c = Math.Cos(halfAngle);
|
||||
|
||||
return new Quaternion(
|
||||
axis.X * s,
|
||||
axis.Y * s,
|
||||
axis.Z * s,
|
||||
c
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a quaternion from yaw, pitch, and roll angles (in radians)
|
||||
/// </summary>
|
||||
public static Quaternion CreateFromYawPitchRoll(double yaw, double pitch, double roll)
|
||||
{
|
||||
double halfRoll = roll * 0.5;
|
||||
double halfPitch = pitch * 0.5;
|
||||
double halfYaw = yaw * 0.5;
|
||||
|
||||
double sinRoll = Math.Sin(halfRoll);
|
||||
double cosRoll = Math.Cos(halfRoll);
|
||||
double sinPitch = Math.Sin(halfPitch);
|
||||
double cosPitch = Math.Cos(halfPitch);
|
||||
double sinYaw = Math.Sin(halfYaw);
|
||||
double cosYaw = Math.Cos(halfYaw);
|
||||
|
||||
return new Quaternion(
|
||||
cosYaw * sinPitch * cosRoll + sinYaw * cosPitch * sinRoll,
|
||||
sinYaw * cosPitch * cosRoll - cosYaw * sinPitch * sinRoll,
|
||||
cosYaw * cosPitch * sinRoll - sinYaw * sinPitch * cosRoll,
|
||||
cosYaw * cosPitch * cosRoll + sinYaw * sinPitch * sinRoll
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a quaternion from a rotation matrix
|
||||
/// </summary>
|
||||
public static Quaternion CreateFromRotationMatrix(double[,] matrix)
|
||||
{
|
||||
if (matrix.GetLength(0) < 3 || matrix.GetLength(1) < 3)
|
||||
return Identity;
|
||||
|
||||
double trace = matrix[0, 0] + matrix[1, 1] + matrix[2, 2];
|
||||
|
||||
Quaternion q = default;
|
||||
|
||||
if (trace > 0.0)
|
||||
{
|
||||
double s = Math.Sqrt(trace + 1.0);
|
||||
q.W = s * 0.5;
|
||||
s = 0.5 / s;
|
||||
q.X = (matrix[2, 1] - matrix[1, 2]) * s;
|
||||
q.Y = (matrix[0, 2] - matrix[2, 0]) * s;
|
||||
q.Z = (matrix[1, 0] - matrix[0, 1]) * s;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (matrix[0, 0] >= matrix[1, 1] && matrix[0, 0] >= matrix[2, 2])
|
||||
{
|
||||
double s = Math.Sqrt(1.0 + matrix[0, 0] - matrix[1, 1] - matrix[2, 2]);
|
||||
double invS = 0.5 / s;
|
||||
q.X = 0.5 * s;
|
||||
q.Y = (matrix[1, 0] + matrix[0, 1]) * invS;
|
||||
q.Z = (matrix[2, 0] + matrix[0, 2]) * invS;
|
||||
q.W = (matrix[2, 1] - matrix[1, 2]) * invS;
|
||||
}
|
||||
else if (matrix[1, 1] > matrix[2, 2])
|
||||
{
|
||||
double s = Math.Sqrt(1.0 + matrix[1, 1] - matrix[0, 0] - matrix[2, 2]);
|
||||
double invS = 0.5 / s;
|
||||
q.X = (matrix[0, 1] + matrix[1, 0]) * invS;
|
||||
q.Y = 0.5 * s;
|
||||
q.Z = (matrix[1, 2] + matrix[2, 1]) * invS;
|
||||
q.W = (matrix[0, 2] - matrix[2, 0]) * invS;
|
||||
}
|
||||
else
|
||||
{
|
||||
double s = Math.Sqrt(1.0 + matrix[2, 2] - matrix[0, 0] - matrix[1, 1]);
|
||||
double invS = 0.5 / s;
|
||||
q.X = (matrix[0, 2] + matrix[2, 0]) * invS;
|
||||
q.Y = (matrix[1, 2] + matrix[2, 1]) * invS;
|
||||
q.Z = 0.5 * s;
|
||||
q.W = (matrix[1, 0] - matrix[0, 1]) * invS;
|
||||
}
|
||||
}
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Operators
|
||||
|
||||
/// <summary>
|
||||
/// Adds two quaternions component-wise (rarely used - prefer multiplication for combining rotations)
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Quaternion operator +(Quaternion value1, Quaternion value2)
|
||||
{
|
||||
return new Quaternion(
|
||||
value1.X + value2.X,
|
||||
value1.Y + value2.Y,
|
||||
value1.Z + value2.Z,
|
||||
value1.W + value2.W
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subtracts two quaternions component-wise (rarely used)
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Quaternion operator -(Quaternion value1, Quaternion value2)
|
||||
{
|
||||
return new Quaternion(
|
||||
value1.X - value2.X,
|
||||
value1.Y - value2.Y,
|
||||
value1.Z - value2.Z,
|
||||
value1.W - value2.W
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Negates a quaternion
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Quaternion operator -(Quaternion value)
|
||||
{
|
||||
return new Quaternion(-value.X, -value.Y, -value.Z, -value.W);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Multiplies two quaternions (combines rotations: first apply value2, then value1)
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Quaternion operator *(Quaternion value1, Quaternion value2)
|
||||
{
|
||||
double q1x = value1.X;
|
||||
double q1y = value1.Y;
|
||||
double q1z = value1.Z;
|
||||
double q1w = value1.W;
|
||||
|
||||
double q2x = value2.X;
|
||||
double q2y = value2.Y;
|
||||
double q2z = value2.Z;
|
||||
double q2w = value2.W;
|
||||
|
||||
// Cross product
|
||||
double cx = q1y * q2z - q1z * q2y;
|
||||
double cy = q1z * q2x - q1x * q2z;
|
||||
double cz = q1x * q2y - q1y * q2x;
|
||||
|
||||
double dot = q1x * q2x + q1y * q2y + q1z * q2z;
|
||||
|
||||
return new Quaternion(
|
||||
q1x * q2w + q2x * q1w + cx,
|
||||
q1y * q2w + q2y * q1w + cy,
|
||||
q1z * q2w + q2z * q1w + cz,
|
||||
q1w * q2w - dot
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Multiplies a quaternion by a scalar
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Quaternion operator *(Quaternion value1, double value2)
|
||||
{
|
||||
return new Quaternion(
|
||||
value1.X * value2,
|
||||
value1.Y * value2,
|
||||
value1.Z * value2,
|
||||
value1.W * value2
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Divides a quaternion by a scalar
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Quaternion operator /(Quaternion value1, double value2)
|
||||
{
|
||||
double invValue = 1.0 / value2;
|
||||
return new Quaternion(
|
||||
value1.X * invValue,
|
||||
value1.Y * invValue,
|
||||
value1.Z * invValue,
|
||||
value1.W * invValue
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two quaternions are equal
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator ==(Quaternion value1, Quaternion value2)
|
||||
{
|
||||
return value1.X == value2.X &&
|
||||
value1.Y == value2.Y &&
|
||||
value1.Z == value2.Z &&
|
||||
value1.W == value2.W;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two quaternions are not equal
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator !=(Quaternion value1, Quaternion value2)
|
||||
{
|
||||
return value1.X != value2.X ||
|
||||
value1.Y != value2.Y ||
|
||||
value1.Z != value2.Z ||
|
||||
value1.W != value2.W;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implicit conversion from System.Numerics.Quaternion
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static implicit operator Quaternion(System.Numerics.Quaternion value)
|
||||
{
|
||||
return new Quaternion(value.X, value.Y, value.Z, value.W);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implicit conversion to System.Numerics.Quaternion
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static implicit operator System.Numerics.Quaternion(Quaternion value)
|
||||
{
|
||||
return new Quaternion((float)value.X, (float)value.Y, (float)value.Z, (float)value.W);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Equality
|
||||
|
||||
/// <summary>
|
||||
/// Checks if this quaternion equals another quaternion
|
||||
/// </summary>
|
||||
public readonly bool Equals(Quaternion other)
|
||||
{
|
||||
return X == other.X && Y == other.Y && Z == other.Z && W == other.W;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if this quaternion equals an object
|
||||
/// </summary>
|
||||
public override readonly bool Equals(object? obj)
|
||||
{
|
||||
return obj is Quaternion quaternion && Equals(quaternion);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hash code for this quaternion
|
||||
/// </summary>
|
||||
public override readonly int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(X, Y, Z, W);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region String
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string representation of this quaternion
|
||||
/// </summary>
|
||||
public override readonly string ToString()
|
||||
{
|
||||
return $"{{X:{X} Y:{Y} Z:{Z} W:{W}}}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a formatted string representation of this quaternion
|
||||
/// </summary>
|
||||
public readonly string ToString(string format)
|
||||
{
|
||||
return $"{{X:{X.ToString(format)} Y:{Y.ToString(format)} Z:{Z.ToString(format)} W:{W.ToString(format)}}}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
384
srcs/RobotNet10/Shared/RobotNet10.Shared/Numbers/Vector2.cs
Normal file
384
srcs/RobotNet10/Shared/RobotNet10.Shared/Numbers/Vector2.cs
Normal file
@@ -0,0 +1,384 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace RobotNet10.Shared.Numbers;
|
||||
|
||||
/// <summary>
|
||||
/// Custom 2D vector struct that supports JSON serialization.
|
||||
/// Replacement for System.Numerics.Vector2 which doesn't serialize properly.
|
||||
/// </summary>
|
||||
public struct Vector2 : IEquatable<Vector2>
|
||||
{
|
||||
/// <summary>
|
||||
/// X component
|
||||
/// </summary>
|
||||
public double X { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Y component
|
||||
/// </summary>
|
||||
public double Y { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new Vector2
|
||||
/// </summary>
|
||||
public Vector2(double x, double y)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a Vector2 with both components set to the same value
|
||||
/// </summary>
|
||||
public Vector2(double value)
|
||||
{
|
||||
X = Y = value;
|
||||
}
|
||||
|
||||
#region Static Properties
|
||||
|
||||
/// <summary>
|
||||
/// Returns a Vector2 with both components set to zero
|
||||
/// </summary>
|
||||
public static Vector2 Zero => new(0, 0);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a Vector2 with both components set to one
|
||||
/// </summary>
|
||||
public static Vector2 One => new(1, 1);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the unit vector for the X axis (1, 0)
|
||||
/// </summary>
|
||||
public static Vector2 UnitX => new(1, 0);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the unit vector for the Y axis (0, 1)
|
||||
/// </summary>
|
||||
public static Vector2 UnitY => new(0, 1);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Returns the length (magnitude) of the vector
|
||||
/// </summary>
|
||||
public readonly double Length()
|
||||
{
|
||||
return Math.Sqrt(X * X + Y * Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the squared length of the vector (faster than Length)
|
||||
/// </summary>
|
||||
public readonly double LengthSquared()
|
||||
{
|
||||
return X * X + Y * Y;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Returns a normalized copy of this vector (unit length)
|
||||
/// </summary>
|
||||
public readonly Vector2 Normalize()
|
||||
{
|
||||
double length = Length();
|
||||
if (length < double.Epsilon)
|
||||
return Zero;
|
||||
|
||||
double invLength = 1.0 / length;
|
||||
return new Vector2(X * invLength, Y * invLength);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Normalizes this vector in place
|
||||
/// </summary>
|
||||
public void NormalizeInPlace()
|
||||
{
|
||||
double length = Length();
|
||||
if (length < double.Epsilon)
|
||||
{
|
||||
X = Y = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
double invLength = 1.0 / length;
|
||||
X *= invLength;
|
||||
Y *= invLength;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Static Methods
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the dot product of two vectors
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static double Dot(Vector2 left, Vector2 right)
|
||||
{
|
||||
return left.X * right.X + left.Y * right.Y;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a normalized copy of a vector (static version)
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector2 Normalize(Vector2 value)
|
||||
{
|
||||
return value.Normalize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the distance between two vectors
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static double Distance(Vector2 value1, Vector2 value2)
|
||||
{
|
||||
double dx = value1.X - value2.X;
|
||||
double dy = value1.Y - value2.Y;
|
||||
return Math.Sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the squared distance between two vectors (faster than Distance)
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static double DistanceSquared(Vector2 value1, Vector2 value2)
|
||||
{
|
||||
double dx = value1.X - value2.X;
|
||||
double dy = value1.Y - value2.Y;
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs linear interpolation between two vectors
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector2 Lerp(Vector2 value1, Vector2 value2, double amount)
|
||||
{
|
||||
return new Vector2(
|
||||
value1.X + (value2.X - value1.X) * amount,
|
||||
value1.Y + (value2.Y - value1.Y) * amount
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a vector with the minimum components of two vectors
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector2 Min(Vector2 value1, Vector2 value2)
|
||||
{
|
||||
return new Vector2(
|
||||
Math.Min(value1.X, value2.X),
|
||||
Math.Min(value1.Y, value2.Y)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a vector with the maximum components of two vectors
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector2 Max(Vector2 value1, Vector2 value2)
|
||||
{
|
||||
return new Vector2(
|
||||
Math.Max(value1.X, value2.X),
|
||||
Math.Max(value1.Y, value2.Y)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a vector whose components are the absolute values of the input vector
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector2 Abs(Vector2 value)
|
||||
{
|
||||
return new Vector2(
|
||||
Math.Abs(value.X),
|
||||
Math.Abs(value.Y)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clamps a vector to the specified minimum and maximum values
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector2 Clamp(Vector2 value, Vector2 min, Vector2 max)
|
||||
{
|
||||
return new Vector2(
|
||||
Math.Clamp(value.X, min.X, max.X),
|
||||
Math.Clamp(value.Y, min.Y, max.Y)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reflects a vector off a surface with the specified normal
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector2 Reflect(Vector2 vector, Vector2 normal)
|
||||
{
|
||||
double dot = Dot(vector, normal);
|
||||
return vector - 2.0 * dot * normal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transforms a Vector2 by a Matrix3x2
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector2 Transform(Vector2 position, Matrix3x2 matrix)
|
||||
{
|
||||
return new Vector2(
|
||||
position.X * matrix.M11 + position.Y * matrix.M21 + matrix.M31,
|
||||
position.X * matrix.M12 + position.Y * matrix.M22 + matrix.M32
|
||||
);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Operators
|
||||
|
||||
/// <summary>
|
||||
/// Adds two vectors
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector2 operator +(Vector2 left, Vector2 right)
|
||||
{
|
||||
return new Vector2(left.X + right.X, left.Y + right.Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subtracts two vectors
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector2 operator -(Vector2 left, Vector2 right)
|
||||
{
|
||||
return new Vector2(left.X - right.X, left.Y - right.Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Negates a vector
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector2 operator -(Vector2 value)
|
||||
{
|
||||
return new Vector2(-value.X, -value.Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Multiplies two vectors component-wise
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector2 operator *(Vector2 left, Vector2 right)
|
||||
{
|
||||
return new Vector2(left.X * right.X, left.Y * right.Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Multiplies a vector by a scalar
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector2 operator *(Vector2 left, double right)
|
||||
{
|
||||
return new Vector2(left.X * right, left.Y * right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Multiplies a scalar by a vector
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector2 operator *(double left, Vector2 right)
|
||||
{
|
||||
return new Vector2(left * right.X, left * right.Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Divides two vectors component-wise
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector2 operator /(Vector2 left, Vector2 right)
|
||||
{
|
||||
return new Vector2(left.X / right.X, left.Y / right.Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Divides a vector by a scalar
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector2 operator /(Vector2 left, double right)
|
||||
{
|
||||
double invRight = 1.0 / right;
|
||||
return new Vector2(left.X * invRight, left.Y * invRight);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two vectors are equal
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator ==(Vector2 left, Vector2 right)
|
||||
{
|
||||
return left.X == right.X && left.Y == right.Y;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two vectors are not equal
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator !=(Vector2 left, Vector2 right)
|
||||
{
|
||||
return left.X != right.X || left.Y != right.Y;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Equality
|
||||
|
||||
/// <summary>
|
||||
/// Checks if this vector equals another vector
|
||||
/// </summary>
|
||||
public readonly bool Equals(Vector2 other)
|
||||
{
|
||||
return X == other.X && Y == other.Y;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if this vector equals an object
|
||||
/// </summary>
|
||||
public override readonly bool Equals(object? obj)
|
||||
{
|
||||
return obj is Vector2 vector && Equals(vector);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hash code for this vector
|
||||
/// </summary>
|
||||
public override readonly int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(X, Y);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region String
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string representation of this vector
|
||||
/// </summary>
|
||||
public override readonly string ToString()
|
||||
{
|
||||
return $"<{X}, {Y}>";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a formatted string representation of this vector
|
||||
/// </summary>
|
||||
public readonly string ToString(string format)
|
||||
{
|
||||
return $"<{X.ToString(format)}, {Y.ToString(format)}>";
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
452
srcs/RobotNet10/Shared/RobotNet10.Shared/Numbers/Vector3.cs
Normal file
452
srcs/RobotNet10/Shared/RobotNet10.Shared/Numbers/Vector3.cs
Normal file
@@ -0,0 +1,452 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace RobotNet10.Shared.Numbers;
|
||||
|
||||
/// <summary>
|
||||
/// Custom 3D vector struct that supports JSON serialization.
|
||||
/// Replacement for System.Numerics.Vector3 which doesn't serialize properly.
|
||||
/// </summary>
|
||||
public struct Vector3 : IEquatable<Vector3>
|
||||
{
|
||||
/// <summary>
|
||||
/// X component
|
||||
/// </summary>
|
||||
public double X { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Y component
|
||||
/// </summary>
|
||||
public double Y { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Z component
|
||||
/// </summary>
|
||||
public double Z { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new Vector3
|
||||
/// </summary>
|
||||
public Vector3(double x, double y, double z)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Z = z;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a Vector3 with all components set to the same value
|
||||
/// </summary>
|
||||
public Vector3(double value)
|
||||
{
|
||||
X = Y = Z = value;
|
||||
}
|
||||
|
||||
#region Static Properties
|
||||
|
||||
/// <summary>
|
||||
/// Returns a Vector3 with all components set to zero
|
||||
/// </summary>
|
||||
public static Vector3 Zero => new(0, 0, 0);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a Vector3 with all components set to one
|
||||
/// </summary>
|
||||
public static Vector3 One => new(1, 1, 1);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the unit vector for the X axis (1, 0, 0)
|
||||
/// </summary>
|
||||
public static Vector3 UnitX => new(1, 0, 0);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the unit vector for the Y axis (0, 1, 0)
|
||||
/// </summary>
|
||||
public static Vector3 UnitY => new(0, 1, 0);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the unit vector for the Z axis (0, 0, 1)
|
||||
/// </summary>
|
||||
public static Vector3 UnitZ => new(0, 0, 1);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Returns the length (magnitude) of the vector
|
||||
/// </summary>
|
||||
public readonly double Length()
|
||||
{
|
||||
return Math.Sqrt(X * X + Y * Y + Z * Z);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the squared length of the vector (faster than Length)
|
||||
/// </summary>
|
||||
public readonly double LengthSquared()
|
||||
{
|
||||
return X * X + Y * Y + Z * Z;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Returns a normalized copy of this vector (unit length)
|
||||
/// </summary>
|
||||
public readonly Vector3 Normalize()
|
||||
{
|
||||
double length = Length();
|
||||
if (length < double.Epsilon)
|
||||
return Zero;
|
||||
|
||||
double invLength = 1.0 / length;
|
||||
return new Vector3(X * invLength, Y * invLength, Z * invLength);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Normalizes this vector in place
|
||||
/// </summary>
|
||||
public void NormalizeInPlace()
|
||||
{
|
||||
double length = Length();
|
||||
if (length < double.Epsilon)
|
||||
{
|
||||
X = Y = Z = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
double invLength = 1.0 / length;
|
||||
X *= invLength;
|
||||
Y *= invLength;
|
||||
Z *= invLength;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Static Methods
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the dot product of two vectors
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static double Dot(Vector3 left, Vector3 right)
|
||||
{
|
||||
return left.X * right.X + left.Y * right.Y + left.Z * right.Z;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the cross product of two vectors
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector3 Cross(Vector3 left, Vector3 right)
|
||||
{
|
||||
return new Vector3(
|
||||
left.Y * right.Z - left.Z * right.Y,
|
||||
left.Z * right.X - left.X * right.Z,
|
||||
left.X * right.Y - left.Y * right.X
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a normalized copy of a vector (static version)
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector3 Normalize(Vector3 value)
|
||||
{
|
||||
return value.Normalize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the distance between two vectors
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static double Distance(Vector3 value1, Vector3 value2)
|
||||
{
|
||||
double dx = value1.X - value2.X;
|
||||
double dy = value1.Y - value2.Y;
|
||||
double dz = value1.Z - value2.Z;
|
||||
return Math.Sqrt(dx * dx + dy * dy + dz * dz);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the squared distance between two vectors (faster than Distance)
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static double DistanceSquared(Vector3 value1, Vector3 value2)
|
||||
{
|
||||
double dx = value1.X - value2.X;
|
||||
double dy = value1.Y - value2.Y;
|
||||
double dz = value1.Z - value2.Z;
|
||||
return dx * dx + dy * dy + dz * dz;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs linear interpolation between two vectors
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector3 Lerp(Vector3 value1, Vector3 value2, double amount)
|
||||
{
|
||||
return new Vector3(
|
||||
value1.X + (value2.X - value1.X) * amount,
|
||||
value1.Y + (value2.Y - value1.Y) * amount,
|
||||
value1.Z + (value2.Z - value1.Z) * amount
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a vector with the minimum components of two vectors
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector3 Min(Vector3 value1, Vector3 value2)
|
||||
{
|
||||
return new Vector3(
|
||||
Math.Min(value1.X, value2.X),
|
||||
Math.Min(value1.Y, value2.Y),
|
||||
Math.Min(value1.Z, value2.Z)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a vector with the maximum components of two vectors
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector3 Max(Vector3 value1, Vector3 value2)
|
||||
{
|
||||
return new Vector3(
|
||||
Math.Max(value1.X, value2.X),
|
||||
Math.Max(value1.Y, value2.Y),
|
||||
Math.Max(value1.Z, value2.Z)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a vector whose components are the absolute values of the input vector
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector3 Abs(Vector3 value)
|
||||
{
|
||||
return new Vector3(
|
||||
Math.Abs(value.X),
|
||||
Math.Abs(value.Y),
|
||||
Math.Abs(value.Z)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clamps a vector to the specified minimum and maximum values
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector3 Clamp(Vector3 value, Vector3 min, Vector3 max)
|
||||
{
|
||||
return new Vector3(
|
||||
Math.Clamp(value.X, min.X, max.X),
|
||||
Math.Clamp(value.Y, min.Y, max.Y),
|
||||
Math.Clamp(value.Z, min.Z, max.Z)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reflects a vector off a surface with the specified normal
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector3 Reflect(Vector3 vector, Vector3 normal)
|
||||
{
|
||||
double dot = Dot(vector, normal);
|
||||
return vector - 2.0 * dot * normal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transforms a Vector3 by a Quaternion rotation
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector3 Transform(Vector3 value, Quaternion rotation)
|
||||
{
|
||||
// This is the formula: q * v * q^-1 where v is treated as a quaternion with w=0
|
||||
// Optimized version without creating intermediate quaternions
|
||||
|
||||
double x2 = rotation.X + rotation.X;
|
||||
double y2 = rotation.Y + rotation.Y;
|
||||
double z2 = rotation.Z + rotation.Z;
|
||||
|
||||
double wx2 = rotation.W * x2;
|
||||
double wy2 = rotation.W * y2;
|
||||
double wz2 = rotation.W * z2;
|
||||
double xx2 = rotation.X * x2;
|
||||
double xy2 = rotation.X * y2;
|
||||
double xz2 = rotation.X * z2;
|
||||
double yy2 = rotation.Y * y2;
|
||||
double yz2 = rotation.Y * z2;
|
||||
double zz2 = rotation.Z * z2;
|
||||
|
||||
return new Vector3(
|
||||
value.X * (1.0 - yy2 - zz2) + value.Y * (xy2 - wz2) + value.Z * (xz2 + wy2),
|
||||
value.X * (xy2 + wz2) + value.Y * (1.0 - xx2 - zz2) + value.Z * (yz2 - wx2),
|
||||
value.X * (xz2 - wy2) + value.Y * (yz2 + wx2) + value.Z * (1.0 - xx2 - yy2)
|
||||
);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Operators
|
||||
|
||||
/// <summary>
|
||||
/// Adds two vectors
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector3 operator +(Vector3 left, Vector3 right)
|
||||
{
|
||||
return new Vector3(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subtracts two vectors
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector3 operator -(Vector3 left, Vector3 right)
|
||||
{
|
||||
return new Vector3(left.X - right.X, left.Y - right.Y, left.Z - right.Z);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Negates a vector
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector3 operator -(Vector3 value)
|
||||
{
|
||||
return new Vector3(-value.X, -value.Y, -value.Z);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Multiplies two vectors component-wise
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector3 operator *(Vector3 left, Vector3 right)
|
||||
{
|
||||
return new Vector3(left.X * right.X, left.Y * right.Y, left.Z * right.Z);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Multiplies a vector by a scalar
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector3 operator *(Vector3 left, double right)
|
||||
{
|
||||
return new Vector3(left.X * right, left.Y * right, left.Z * right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Multiplies a scalar by a vector
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector3 operator *(double left, Vector3 right)
|
||||
{
|
||||
return new Vector3(left * right.X, left * right.Y, left * right.Z);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Divides two vectors component-wise
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector3 operator /(Vector3 left, Vector3 right)
|
||||
{
|
||||
return new Vector3(left.X / right.X, left.Y / right.Y, left.Z / right.Z);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Divides a vector by a scalar
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector3 operator /(Vector3 left, double right)
|
||||
{
|
||||
double invRight = 1.0 / right;
|
||||
return new Vector3(left.X * invRight, left.Y * invRight, left.Z * invRight);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two vectors are equal
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator ==(Vector3 left, Vector3 right)
|
||||
{
|
||||
return left.X == right.X && left.Y == right.Y && left.Z == right.Z;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two vectors are not equal
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator !=(Vector3 left, Vector3 right)
|
||||
{
|
||||
return left.X != right.X || left.Y != right.Y || left.Z != right.Z;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implicit conversion from System.Numerics.Vector3
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static implicit operator Vector3(System.Numerics.Vector3 value)
|
||||
{
|
||||
return new Vector3(value.X, value.Y, value.Z);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implicit conversion to System.Numerics.Vector3
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static implicit operator System.Numerics.Vector3(Vector3 value)
|
||||
{
|
||||
return new Vector3((float)value.X, (float)value.Y, (float)value.Z);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Equality
|
||||
|
||||
/// <summary>
|
||||
/// Checks if this vector equals another vector
|
||||
/// </summary>
|
||||
public readonly bool Equals(Vector3 other)
|
||||
{
|
||||
return X == other.X && Y == other.Y && Z == other.Z;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if this vector equals an object
|
||||
/// </summary>
|
||||
public override readonly bool Equals(object? obj)
|
||||
{
|
||||
return obj is Vector3 vector && Equals(vector);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hash code for this vector
|
||||
/// </summary>
|
||||
public override readonly int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(X, Y, Z);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region String
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string representation of this vector
|
||||
/// </summary>
|
||||
public override readonly string ToString()
|
||||
{
|
||||
return $"<{X}, {Y}, {Z}>";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a formatted string representation of this vector
|
||||
/// </summary>
|
||||
public readonly string ToString(string format)
|
||||
{
|
||||
return $"<{X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)}>";
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace RobotNet10.Shared;
|
||||
|
||||
public record SearchRequest(int Page, int Size, string TxtSearch);
|
||||
4
srcs/RobotNet10/Shared/RobotNet10.Shared/SearchResult.cs
Normal file
4
srcs/RobotNet10/Shared/RobotNet10.Shared/SearchResult.cs
Normal file
@@ -0,0 +1,4 @@
|
||||
namespace RobotNet10.Shared;
|
||||
|
||||
public record SearchResult<T>(int Total, int Page, int Size, T[] Items);
|
||||
|
||||
139
srcs/RobotNet10/Shared/RobotNet10.Shared/Sensor/BatteryState.cs
Normal file
139
srcs/RobotNet10/Shared/RobotNet10.Shared/Sensor/BatteryState.cs
Normal file
@@ -0,0 +1,139 @@
|
||||
namespace RobotNet10.Shared.Sensor;
|
||||
|
||||
/// <summary>
|
||||
/// BatteryState message (sensor_msgs/BatteryState)
|
||||
/// Describes the state of a battery
|
||||
/// </summary>
|
||||
public struct BatteryState
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Voltage in Volts (Mandatory)
|
||||
/// </summary>
|
||||
public double Voltage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Current in Amperes (If not available: NaN)
|
||||
/// </summary>
|
||||
public double Current { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Charge in Ah (If not available: NaN)
|
||||
/// </summary>
|
||||
public double Charge { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Capacity in Ah (last full capacity) (If not available: NaN)
|
||||
/// </summary>
|
||||
public double Capacity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Design capacity in Ah (If not available: NaN)
|
||||
/// </summary>
|
||||
public double DesignCapacity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Percentage (0-100) (If not available: NaN)
|
||||
/// </summary>
|
||||
public double Percentage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Power supply status constants
|
||||
/// </summary>
|
||||
public const byte PowerSupplyStatusUnknown = 0;
|
||||
public const byte PowerSupplyStatusCharging = 1;
|
||||
public const byte PowerSupplyStatusDischarging = 2;
|
||||
public const byte PowerSupplyStatusNotCharging = 3;
|
||||
public const byte PowerSupplyStatusFull = 4;
|
||||
|
||||
/// <summary>
|
||||
/// Power supply status (PowerSupplyStatus constants)
|
||||
/// </summary>
|
||||
public byte PowerSupplyStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Power supply health constants
|
||||
/// </summary>
|
||||
public const byte PowerSupplyHealthUnknown = 0;
|
||||
public const byte PowerSupplyHealthGood = 1;
|
||||
public const byte PowerSupplyHealthOverheat = 2;
|
||||
public const byte PowerSupplyHealthDead = 3;
|
||||
public const byte PowerSupplyHealthOvervoltage = 4;
|
||||
public const byte PowerSupplyHealthUnspecifiedFailure = 5;
|
||||
public const byte PowerSupplyHealthCold = 6;
|
||||
|
||||
/// <summary>
|
||||
/// Power supply health (PowerSupplyHealth constants)
|
||||
/// </summary>
|
||||
public byte PowerSupplyHealth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Power supply technology (chemistry) constants
|
||||
/// </summary>
|
||||
public const byte PowerSupplyTechnologyUnknown = 0;
|
||||
public const byte PowerSupplyTechnologyNiMh = 1;
|
||||
public const byte PowerSupplyTechnologyLion = 2;
|
||||
public const byte PowerSupplyTechnologyLipo = 3;
|
||||
public const byte PowerSupplyTechnologyLife = 4;
|
||||
public const byte PowerSupplyTechnologyNiCd = 5;
|
||||
public const byte PowerSupplyTechnologyLiMn = 6;
|
||||
|
||||
/// <summary>
|
||||
/// Power supply technology (PowerSupplyTechnology constants)
|
||||
/// </summary>
|
||||
public byte PowerSupplyTechnology { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if the battery is present
|
||||
/// </summary>
|
||||
public bool Present { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An array of individual cell voltages. Each individual cell voltage should be > 0.0.
|
||||
/// If not available: empty array
|
||||
/// </summary>
|
||||
public double[] CellVoltage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An array of individual cell temperatures. Each individual cell temperature should be > 0.0.
|
||||
/// If not available: empty array
|
||||
/// </summary>
|
||||
public double[] CellTemperature { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The location into which the battery is inserted. (slot number or plug)
|
||||
/// </summary>
|
||||
public string Location { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The serial number of the battery pack.
|
||||
/// </summary>
|
||||
public string SerialNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public BatteryState()
|
||||
{
|
||||
Header = new Header();
|
||||
Voltage = 0.0;
|
||||
Current = double.NaN;
|
||||
Charge = double.NaN;
|
||||
Capacity = double.NaN;
|
||||
DesignCapacity = double.NaN;
|
||||
Percentage = double.NaN;
|
||||
PowerSupplyStatus = PowerSupplyStatusUnknown;
|
||||
PowerSupplyHealth = PowerSupplyHealthUnknown;
|
||||
PowerSupplyTechnology = PowerSupplyTechnologyUnknown;
|
||||
Present = false;
|
||||
CellVoltage = [];
|
||||
CellTemperature = [];
|
||||
Location = string.Empty;
|
||||
SerialNumber = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
153
srcs/RobotNet10/Shared/RobotNet10.Shared/Sensor/CameraInfo.cs
Normal file
153
srcs/RobotNet10/Shared/RobotNet10.Shared/Sensor/CameraInfo.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
namespace RobotNet10.Shared.Sensor;
|
||||
|
||||
/// <summary>
|
||||
/// CameraInfo message (sensor_msgs/CameraInfo)
|
||||
/// This message defines meta information for a camera
|
||||
/// </summary>
|
||||
public struct CameraInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Image height (rows)
|
||||
/// </summary>
|
||||
public uint Height { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Image width (columns)
|
||||
/// </summary>
|
||||
public uint Width { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Distortion model constants
|
||||
/// </summary>
|
||||
public const string DistortionModelPlumbBob = "plumb_bob";
|
||||
public const string DistortionModelRationalPolynomial = "rational_polynomial";
|
||||
|
||||
/// <summary>
|
||||
/// The distortion model used
|
||||
/// </summary>
|
||||
public string DistortionModel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Intrinsic camera matrix for the raw (distorted) images.
|
||||
/// [fx 0 cx]
|
||||
/// K = [ 0 fy cy]
|
||||
/// [ 0 0 1]
|
||||
/// Projects 3D points in the camera coordinate frame to 2D pixel
|
||||
/// coordinates using the focal lengths (fx, fy) and principal point
|
||||
/// (cx, cy).
|
||||
/// </summary>
|
||||
public double[] K { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of intrinsic camera matrix (3x3 = 9 elements)
|
||||
/// </summary>
|
||||
public const int KSize = 9;
|
||||
|
||||
/// <summary>
|
||||
/// Rectification matrix (stereo cameras only)
|
||||
/// A rotation matrix aligning the camera coordinate system to the ideal
|
||||
/// stereo image plane so that epipolar lines in both stereo images are
|
||||
/// parallel.
|
||||
/// </summary>
|
||||
public double[] R { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of rectification matrix (3x3 = 9 elements)
|
||||
/// </summary>
|
||||
public const int RSize = 9;
|
||||
|
||||
/// <summary>
|
||||
/// Projection/camera matrix
|
||||
/// [fx' 0 cx' Tx]
|
||||
/// P = [ 0 fy' cy' Ty]
|
||||
/// [ 0 0 1 0]
|
||||
/// By convention, this matrix specifies the intrinsic (camera) matrix
|
||||
/// of the processed (rectified) image. That is, the left 3x3 portion
|
||||
/// is the normal camera intrinsic matrix for the rectified image.
|
||||
/// </summary>
|
||||
public double[] P { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of projection matrix (3x4 = 12 elements)
|
||||
/// </summary>
|
||||
public const int PSize = 12;
|
||||
|
||||
/// <summary>
|
||||
/// The distortion parameters, size depending on the distortion model.
|
||||
/// For "plumb_bob", the 5 parameters are: (k1, k2, t1, t2, k3).
|
||||
/// </summary>
|
||||
public double[] D { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Region of interest (subwindow of full camera resolution)
|
||||
/// </summary>
|
||||
public RegionOfInterest Roi { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public CameraInfo()
|
||||
{
|
||||
Header = new Header();
|
||||
Height = 0;
|
||||
Width = 0;
|
||||
DistortionModel = DistortionModelPlumbBob;
|
||||
K = new double[KSize];
|
||||
R = new double[RSize];
|
||||
P = new double[PSize];
|
||||
D = [];
|
||||
Roi = new RegionOfInterest();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RegionOfInterest message (sensor_msgs/RegionOfInterest)
|
||||
/// This message is used to specify a region of interest within an image
|
||||
/// </summary>
|
||||
public struct RegionOfInterest
|
||||
{
|
||||
/// <summary>
|
||||
/// Leftmost pixel of the ROI
|
||||
/// </summary>
|
||||
public uint XOffset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Topmost pixel of the ROI
|
||||
/// </summary>
|
||||
public uint YOffset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Height of ROI
|
||||
/// </summary>
|
||||
public uint Height { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Width of ROI
|
||||
/// </summary>
|
||||
public uint Width { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if a distinct rectified ROI should be calculated from the "raw"
|
||||
/// ROI in this message. Typically this should be False on the "raw" image
|
||||
/// and True on the "rectified" image.
|
||||
/// </summary>
|
||||
public bool DoRectify { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public RegionOfInterest()
|
||||
{
|
||||
XOffset = 0;
|
||||
YOffset = 0;
|
||||
Height = 0;
|
||||
Width = 0;
|
||||
DoRectify = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
namespace RobotNet10.Shared.Sensor;
|
||||
|
||||
/// <summary>
|
||||
/// CompressedImage message (sensor_msgs/CompressedImage)
|
||||
/// This message contains a compressed image
|
||||
/// </summary>
|
||||
public struct CompressedImage
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the format of the data
|
||||
/// Acceptable values: jpeg, png, tiff
|
||||
/// </summary>
|
||||
public string Format { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Compressed image buffer
|
||||
/// </summary>
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public CompressedImage()
|
||||
{
|
||||
Header = new Header();
|
||||
Format = string.Empty;
|
||||
Data = Array.Empty<byte>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
namespace RobotNet10.Shared.Sensor;
|
||||
|
||||
/// <summary>
|
||||
/// FluidPressure message (sensor_msgs/FluidPressure)
|
||||
/// Single pressure reading
|
||||
/// </summary>
|
||||
public struct FluidPressure
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Absolute pressure reading in Pascals
|
||||
/// </summary>
|
||||
public double FluidPressureValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Variance of the pressure reading
|
||||
/// </summary>
|
||||
public double Variance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public FluidPressure()
|
||||
{
|
||||
Header = new Header();
|
||||
FluidPressureValue = 0.0;
|
||||
Variance = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
namespace RobotNet10.Shared.Sensor;
|
||||
|
||||
/// <summary>
|
||||
/// Illuminance message (sensor_msgs/Illuminance)
|
||||
/// Single photometric illuminance measurement
|
||||
/// </summary>
|
||||
public struct Illuminance
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Illuminance reading in Lux
|
||||
/// </summary>
|
||||
public double IlluminanceValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Variance of the illuminance reading
|
||||
/// </summary>
|
||||
public double Variance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public Illuminance()
|
||||
{
|
||||
Header = new Header();
|
||||
IlluminanceValue = 0.0;
|
||||
Variance = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
58
srcs/RobotNet10/Shared/RobotNet10.Shared/Sensor/Image.cs
Normal file
58
srcs/RobotNet10/Shared/RobotNet10.Shared/Sensor/Image.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
namespace RobotNet10.Shared.Sensor;
|
||||
|
||||
/// <summary>
|
||||
/// Image message (sensor_msgs/Image)
|
||||
/// This message contains an uncompressed image
|
||||
/// </summary>
|
||||
public struct Image
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Image height (rows)
|
||||
/// </summary>
|
||||
public uint Height { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Image width (columns)
|
||||
/// </summary>
|
||||
public uint Width { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Encoding of pixels -- channel meaning, ordering, size
|
||||
/// </summary>
|
||||
public string Encoding { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is this data bigendian?
|
||||
/// </summary>
|
||||
public byte IsBigendian { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Full row length in bytes
|
||||
/// </summary>
|
||||
public uint Step { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Actual matrix data, size is (step * rows)
|
||||
/// </summary>
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public Image()
|
||||
{
|
||||
Header = new Header();
|
||||
Height = 0;
|
||||
Width = 0;
|
||||
Encoding = string.Empty;
|
||||
IsBigendian = 0;
|
||||
Step = 0;
|
||||
Data = [];
|
||||
}
|
||||
}
|
||||
|
||||
128
srcs/RobotNet10/Shared/RobotNet10.Shared/Sensor/Imu.cs
Normal file
128
srcs/RobotNet10/Shared/RobotNet10.Shared/Sensor/Imu.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
using RobotNet10.Shared.Geometry;
|
||||
|
||||
namespace RobotNet10.Shared.Sensor;
|
||||
|
||||
/// <summary>
|
||||
/// Imu message (sensor_msgs/Imu)
|
||||
/// Contains data from an IMU (Inertial Measurement Unit)
|
||||
///
|
||||
/// Accelerations should be in m/s^2 (not g's), and rotational velocity should be in rad/sec
|
||||
///
|
||||
/// If the covariance of the measurement is known, it should be filled in (if all you know is the
|
||||
/// variance of each measurement, e.g. from the datasheet, just put those along the diagonal)
|
||||
/// A covariance matrix of all zeros will be interpreted as "covariance unknown", and to use the
|
||||
/// data a covariance will have to be assumed or gotten from some other source
|
||||
///
|
||||
/// If you have no estimate for one of the data elements (e.g. your IMU doesn't produce an orientation
|
||||
/// estimate), please set element 0 of the associated covariance matrix to -1
|
||||
/// If you are interpreting this message, please check for a value of -1 in the first element of each
|
||||
/// covariance matrix, and ignore the associated estimate.
|
||||
/// </summary>
|
||||
public struct Imu
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Orientation quaternion (geometry_msgs/Quaternion)
|
||||
/// </summary>
|
||||
public Quaternion Orientation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Orientation covariance matrix (row-major about x, y, z axes)
|
||||
/// Size: 9 (3x3 matrix)
|
||||
/// </summary>
|
||||
public double[] OrientationCovariance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of orientation covariance matrix (3x3 = 9 elements)
|
||||
/// </summary>
|
||||
public const int OrientationCovarianceSize = 9;
|
||||
|
||||
/// <summary>
|
||||
/// Angular velocity (geometry_msgs/Vector3)
|
||||
/// </summary>
|
||||
public Vector3 AngularVelocity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Angular velocity covariance matrix (row-major about x, y, z axes)
|
||||
/// Size: 9 (3x3 matrix)
|
||||
/// </summary>
|
||||
public double[] AngularVelocityCovariance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of angular velocity covariance matrix (3x3 = 9 elements)
|
||||
/// </summary>
|
||||
public const int AngularVelocityCovarianceSize = 9;
|
||||
|
||||
/// <summary>
|
||||
/// Linear acceleration (geometry_msgs/Vector3)
|
||||
/// </summary>
|
||||
public Vector3 LinearAcceleration { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Linear acceleration covariance matrix (row-major about x, y, z axes)
|
||||
/// Size: 9 (3x3 matrix)
|
||||
/// </summary>
|
||||
public double[] LinearAccelerationCovariance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of linear acceleration covariance matrix (3x3 = 9 elements)
|
||||
/// </summary>
|
||||
public const int LinearAccelerationCovarianceSize = 9;
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public Imu()
|
||||
{
|
||||
Header = new Header();
|
||||
Orientation = new Quaternion();
|
||||
OrientationCovariance = new double[OrientationCovarianceSize];
|
||||
AngularVelocity = new Vector3();
|
||||
AngularVelocityCovariance = new double[AngularVelocityCovarianceSize];
|
||||
LinearAcceleration = new Vector3();
|
||||
LinearAccelerationCovariance = new double[LinearAccelerationCovarianceSize];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public Imu(
|
||||
Header header,
|
||||
Quaternion orientation,
|
||||
double[] orientationCovariance,
|
||||
Vector3 angularVelocity,
|
||||
double[] angularVelocityCovariance,
|
||||
Vector3 linearAcceleration,
|
||||
double[] linearAccelerationCovariance)
|
||||
{
|
||||
Header = header;
|
||||
Orientation = orientation;
|
||||
|
||||
if (orientationCovariance == null || orientationCovariance.Length != OrientationCovarianceSize)
|
||||
{
|
||||
throw new ArgumentException($"Orientation covariance array must have {OrientationCovarianceSize} elements", nameof(orientationCovariance));
|
||||
}
|
||||
OrientationCovariance = orientationCovariance;
|
||||
|
||||
AngularVelocity = angularVelocity;
|
||||
|
||||
if (angularVelocityCovariance == null || angularVelocityCovariance.Length != AngularVelocityCovarianceSize)
|
||||
{
|
||||
throw new ArgumentException($"Angular velocity covariance array must have {AngularVelocityCovarianceSize} elements", nameof(angularVelocityCovariance));
|
||||
}
|
||||
AngularVelocityCovariance = angularVelocityCovariance;
|
||||
|
||||
LinearAcceleration = linearAcceleration;
|
||||
|
||||
if (linearAccelerationCovariance == null || linearAccelerationCovariance.Length != LinearAccelerationCovarianceSize)
|
||||
{
|
||||
throw new ArgumentException($"Linear acceleration covariance array must have {LinearAccelerationCovarianceSize} elements", nameof(linearAccelerationCovariance));
|
||||
}
|
||||
LinearAccelerationCovariance = linearAccelerationCovariance;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
namespace RobotNet10.Shared.Sensor;
|
||||
|
||||
/// <summary>
|
||||
/// JointState message (sensor_msgs/JointState)
|
||||
/// This message holds data to describe the state of a set of torque controlled joints
|
||||
/// </summary>
|
||||
public struct JointState
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The joint names
|
||||
/// </summary>
|
||||
public string[] Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The joint positions (rad)
|
||||
/// </summary>
|
||||
public double[] Position { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The joint velocities (rad/s)
|
||||
/// </summary>
|
||||
public double[] Velocity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The joint efforts (Nm)
|
||||
/// </summary>
|
||||
public double[] Effort { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public JointState()
|
||||
{
|
||||
Header = new Header();
|
||||
Name = Array.Empty<string>();
|
||||
Position = Array.Empty<double>();
|
||||
Velocity = Array.Empty<double>();
|
||||
Effort = Array.Empty<double>();
|
||||
}
|
||||
}
|
||||
|
||||
95
srcs/RobotNet10/Shared/RobotNet10.Shared/Sensor/Joy.cs
Normal file
95
srcs/RobotNet10/Shared/RobotNet10.Shared/Sensor/Joy.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
namespace RobotNet10.Shared.Sensor;
|
||||
|
||||
/// <summary>
|
||||
/// Joy message (sensor_msgs/Joy)
|
||||
/// Reports the state of a joystick's axes and buttons
|
||||
/// </summary>
|
||||
public struct Joy
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The axes measurements from a joystick
|
||||
/// </summary>
|
||||
public double[] Axes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The buttons measurements from a joystick
|
||||
/// </summary>
|
||||
public int[] Buttons { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public Joy()
|
||||
{
|
||||
Header = new Header();
|
||||
Axes = [];
|
||||
Buttons = [];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JoyFeedback message (sensor_msgs/JoyFeedback)
|
||||
/// Reports the state of a joystick's axes and buttons
|
||||
/// </summary>
|
||||
public struct JoyFeedback
|
||||
{
|
||||
/// <summary>
|
||||
/// Type constants
|
||||
/// </summary>
|
||||
public const byte TypeLed = 0;
|
||||
public const byte TypeRumble = 1;
|
||||
public const byte TypeBuzzer = 2;
|
||||
|
||||
/// <summary>
|
||||
/// Type of feedback (Type constants)
|
||||
/// </summary>
|
||||
public byte Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This will hold an id number for each type of each feedback.
|
||||
/// Example, the first led would be id=0, the second would be id=1
|
||||
/// </summary>
|
||||
public byte Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Intensity of the feedback, from 0.0 to 1.0, inclusive. If device is
|
||||
/// actually binary, driver should treat 0<=x<0.5 as off, 0.5<=x<=1.0 as on.
|
||||
/// </summary>
|
||||
public double Intensity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public JoyFeedback()
|
||||
{
|
||||
Type = TypeLed;
|
||||
Id = 0;
|
||||
Intensity = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JoyFeedbackArray message (sensor_msgs/JoyFeedbackArray)
|
||||
/// Array of JoyFeedback
|
||||
/// </summary>
|
||||
public struct JoyFeedbackArray
|
||||
{
|
||||
/// <summary>
|
||||
/// Array of feedback
|
||||
/// </summary>
|
||||
public JoyFeedback[] Array { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public JoyFeedbackArray()
|
||||
{
|
||||
Array = System.Array.Empty<JoyFeedback>();
|
||||
}
|
||||
}
|
||||
|
||||
80
srcs/RobotNet10/Shared/RobotNet10.Shared/Sensor/LaserScan.cs
Normal file
80
srcs/RobotNet10/Shared/RobotNet10.Shared/Sensor/LaserScan.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
namespace RobotNet10.Shared.Sensor;
|
||||
|
||||
/// <summary>
|
||||
/// LaserScan message (sensor_msgs/LaserScan)
|
||||
/// Single scan from a planar laser range-finder
|
||||
/// </summary>
|
||||
public struct LaserScan
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Start angle of the scan (rad)
|
||||
/// </summary>
|
||||
public double AngleMin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// End angle of the scan (rad)
|
||||
/// </summary>
|
||||
public double AngleMax { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Angular distance between measurements (rad)
|
||||
/// </summary>
|
||||
public double AngleIncrement { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Time between measurements (seconds) - if your scanner
|
||||
/// is moving, this will be used in interpolating position
|
||||
/// of 3d points
|
||||
/// </summary>
|
||||
public double TimeIncrement { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Time between scans (seconds)
|
||||
/// </summary>
|
||||
public double ScanTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Minimum range value (m)
|
||||
/// </summary>
|
||||
public double RangeMin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum range value (m)
|
||||
/// </summary>
|
||||
public double RangeMax { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Range data (m)
|
||||
/// (Note: values < range_min or > range_max should be discarded)
|
||||
/// </summary>
|
||||
public double[] Ranges { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Intensity data (device-specific units)
|
||||
/// If your device does not provide intensities, please leave the array empty
|
||||
/// </summary>
|
||||
public double[] Intensities { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public LaserScan()
|
||||
{
|
||||
Header = new Header();
|
||||
AngleMin = 0.0;
|
||||
AngleMax = 0.0;
|
||||
AngleIncrement = 0.0;
|
||||
TimeIncrement = 0.0;
|
||||
ScanTime = 0.0;
|
||||
RangeMin = 0.0;
|
||||
RangeMax = 0.0;
|
||||
Ranges = [];
|
||||
Intensities = [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
using RobotNet10.Shared.Geometry;
|
||||
using RobotNet10.Shared.Numbers;
|
||||
|
||||
namespace RobotNet10.Shared.Sensor;
|
||||
|
||||
/// <summary>
|
||||
/// MagneticField message (sensor_msgs/MagneticField)
|
||||
/// Measurement of the Magnetic Field vector at a specific location
|
||||
/// </summary>
|
||||
public struct MagneticField
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Magnetic field vector in Tesla
|
||||
/// </summary>
|
||||
public RobotNet10.Shared.Numbers.Vector3 MagneticFieldVector { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Covariance matrix (row-major about x, y, z axes)
|
||||
/// Size: 9 (3x3 matrix)
|
||||
/// </summary>
|
||||
public double[] MagneticFieldCovariance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of magnetic field covariance matrix (3x3 = 9 elements)
|
||||
/// </summary>
|
||||
public const int MagneticFieldCovarianceSize = 9;
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public MagneticField()
|
||||
{
|
||||
Header = new Header();
|
||||
MagneticFieldVector = new RobotNet10.Shared.Numbers.Vector3();
|
||||
MagneticFieldCovariance = new double[MagneticFieldCovarianceSize];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public MagneticField(Header header, RobotNet10.Shared.Numbers.Vector3 magneticFieldVector, double[] magneticFieldCovariance)
|
||||
{
|
||||
Header = header;
|
||||
MagneticFieldVector = magneticFieldVector;
|
||||
|
||||
if (magneticFieldCovariance == null || magneticFieldCovariance.Length != MagneticFieldCovarianceSize)
|
||||
{
|
||||
throw new ArgumentException($"Magnetic field covariance array must have {MagneticFieldCovarianceSize} elements", nameof(magneticFieldCovariance));
|
||||
}
|
||||
MagneticFieldCovariance = magneticFieldCovariance;
|
||||
}
|
||||
}
|
||||
|
||||
136
srcs/RobotNet10/Shared/RobotNet10.Shared/Sensor/NavSatFix.cs
Normal file
136
srcs/RobotNet10/Shared/RobotNet10.Shared/Sensor/NavSatFix.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
namespace RobotNet10.Shared.Sensor;
|
||||
|
||||
/// <summary>
|
||||
/// NavSatFix message (sensor_msgs/NavSatFix)
|
||||
/// Navigation Satellite fix for any Global Navigation Satellite System
|
||||
/// </summary>
|
||||
public struct NavSatFix
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Navigation Satellite fix status constants
|
||||
/// </summary>
|
||||
public const short StatusNoFix = -1;
|
||||
public const short StatusFix = 0;
|
||||
public const short StatusSbasFix = 1;
|
||||
public const short StatusGbasFix = 2;
|
||||
|
||||
/// <summary>
|
||||
/// Navigation Satellite fix status (Status constants)
|
||||
/// </summary>
|
||||
public short Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Service constants
|
||||
/// </summary>
|
||||
public const ushort ServiceGps = 1;
|
||||
public const ushort ServiceGlonass = 2;
|
||||
public const ushort ServiceCompass = 4;
|
||||
public const ushort ServiceGalileo = 8;
|
||||
|
||||
/// <summary>
|
||||
/// Service which is being used (Service constants)
|
||||
/// </summary>
|
||||
public ushort Service { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Latitude in degrees
|
||||
/// </summary>
|
||||
public double Latitude { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Longitude in degrees
|
||||
/// </summary>
|
||||
public double Longitude { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Altitude in meters
|
||||
/// </summary>
|
||||
public double Altitude { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Position covariance matrix (row-major about x, y, z axes)
|
||||
/// Size: 9 (3x3 matrix)
|
||||
/// </summary>
|
||||
public double[] PositionCovariance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of position covariance matrix (3x3 = 9 elements)
|
||||
/// </summary>
|
||||
public const int PositionCovarianceSize = 9;
|
||||
|
||||
/// <summary>
|
||||
/// Position covariance type constants
|
||||
/// </summary>
|
||||
public const byte CovarianceTypeUnknown = 0;
|
||||
public const byte CovarianceTypeApproximated = 1;
|
||||
public const byte CovarianceTypeDiagonalKnown = 2;
|
||||
public const byte CovarianceTypeKnown = 3;
|
||||
|
||||
/// <summary>
|
||||
/// Position covariance type (CovarianceType constants)
|
||||
/// </summary>
|
||||
public byte PositionCovarianceType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public NavSatFix()
|
||||
{
|
||||
Header = new Header();
|
||||
Status = StatusNoFix;
|
||||
Service = 0;
|
||||
Latitude = 0.0;
|
||||
Longitude = 0.0;
|
||||
Altitude = 0.0;
|
||||
PositionCovariance = new double[PositionCovarianceSize];
|
||||
PositionCovarianceType = CovarianceTypeUnknown;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// NavSatStatus message (sensor_msgs/NavSatStatus)
|
||||
/// Navigation Satellite fix status for any Global Navigation Satellite System
|
||||
/// </summary>
|
||||
public struct NavSatStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// Status constants
|
||||
/// </summary>
|
||||
public const sbyte StatusNoFix = -1;
|
||||
public const sbyte StatusFix = 0;
|
||||
public const sbyte StatusSbasFix = 1;
|
||||
public const sbyte StatusGbasFix = 2;
|
||||
|
||||
/// <summary>
|
||||
/// Status (Status constants)
|
||||
/// </summary>
|
||||
public sbyte Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Service constants
|
||||
/// </summary>
|
||||
public const ushort ServiceGps = 1;
|
||||
public const ushort ServiceGlonass = 2;
|
||||
public const ushort ServiceCompass = 4;
|
||||
public const ushort ServiceGalileo = 8;
|
||||
|
||||
/// <summary>
|
||||
/// Service which is being used (Service constants)
|
||||
/// </summary>
|
||||
public ushort Service { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public NavSatStatus()
|
||||
{
|
||||
Status = StatusNoFix;
|
||||
Service = 0;
|
||||
}
|
||||
}
|
||||
|
||||
56
srcs/RobotNet10/Shared/RobotNet10.Shared/Sensor/Odometry.cs
Normal file
56
srcs/RobotNet10/Shared/RobotNet10.Shared/Sensor/Odometry.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using RobotNet10.Shared;
|
||||
using RobotNet10.Shared.Geometry;
|
||||
|
||||
namespace RobotNet10.Shared.Sensor;
|
||||
|
||||
/// <summary>
|
||||
/// Odometry message (nav_msgs/Odometry)
|
||||
/// This represents an estimate of a position and velocity in free space.
|
||||
/// The pose in this message should be specified in the coordinate frame given by header.frame_id.
|
||||
/// The twist in this message should be specified in the coordinate frame given by the child_frame_id.
|
||||
/// </summary>
|
||||
public struct Odometry
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID (parent frame, typically "odom")
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Child frame ID (typically "base_link" or "base_footprint")
|
||||
/// </summary>
|
||||
public string ChildFrameId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Pose with covariance (PoseWithCovariance)
|
||||
/// </summary>
|
||||
public PoseWithCovariance Pose { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Twist with covariance (TwistWithCovariance)
|
||||
/// </summary>
|
||||
public TwistWithCovariance Twist { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public Odometry()
|
||||
{
|
||||
Header = new Header();
|
||||
ChildFrameId = string.Empty;
|
||||
Pose = new PoseWithCovariance();
|
||||
Twist = new TwistWithCovariance();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with parameters
|
||||
/// </summary>
|
||||
public Odometry(Header header, string childFrameId, PoseWithCovariance pose, TwistWithCovariance twist)
|
||||
{
|
||||
Header = header;
|
||||
ChildFrameId = childFrameId;
|
||||
Pose = pose;
|
||||
Twist = twist;
|
||||
}
|
||||
}
|
||||
|
||||
132
srcs/RobotNet10/Shared/RobotNet10.Shared/Sensor/PointCloud2.cs
Normal file
132
srcs/RobotNet10/Shared/RobotNet10.Shared/Sensor/PointCloud2.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
namespace RobotNet10.Shared.Sensor;
|
||||
|
||||
/// <summary>
|
||||
/// PointCloud2 message (sensor_msgs/PointCloud2)
|
||||
/// This message holds a collection of N-dimensional points, which may
|
||||
/// contain additional information such as normals, intensity, etc. The
|
||||
/// point data is stored as a binary blob, its layout described by the
|
||||
/// contents of the "fields" array.
|
||||
/// </summary>
|
||||
public struct PointCloud2
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Height of the cloud
|
||||
/// </summary>
|
||||
public uint Height { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Width of the cloud
|
||||
/// </summary>
|
||||
public uint Width { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Describes the channels and their layout in the binary data blob
|
||||
/// </summary>
|
||||
public PointField[] Fields { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is this data bigendian?
|
||||
/// </summary>
|
||||
public bool IsBigendian { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of a point in bytes
|
||||
/// </summary>
|
||||
public uint PointStep { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of a row in bytes
|
||||
/// </summary>
|
||||
public uint RowStep { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Actual point data, size is (row_step*height)
|
||||
/// </summary>
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if there are no invalid points
|
||||
/// </summary>
|
||||
public bool IsDense { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public PointCloud2()
|
||||
{
|
||||
Header = new Header();
|
||||
Height = 0;
|
||||
Width = 0;
|
||||
Fields = Array.Empty<PointField>();
|
||||
IsBigendian = false;
|
||||
PointStep = 0;
|
||||
RowStep = 0;
|
||||
Data = Array.Empty<byte>();
|
||||
IsDense = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PointField message (sensor_msgs/PointField)
|
||||
/// This message holds the description of one point entry in the PointCloud2 message format
|
||||
/// </summary>
|
||||
public struct PointField
|
||||
{
|
||||
/// <summary>
|
||||
/// Point field name constants
|
||||
/// </summary>
|
||||
public const string NameX = "x";
|
||||
public const string NameY = "y";
|
||||
public const string NameZ = "z";
|
||||
public const string NameRgb = "rgb";
|
||||
public const string NameIntensity = "intensity";
|
||||
|
||||
/// <summary>
|
||||
/// Name of field
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Offset from start of point struct
|
||||
/// </summary>
|
||||
public uint Offset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Datatype enumeration constants
|
||||
/// </summary>
|
||||
public const byte Int8 = 1;
|
||||
public const byte Uint8 = 2;
|
||||
public const byte Int16 = 3;
|
||||
public const byte Uint16 = 4;
|
||||
public const byte Int32 = 5;
|
||||
public const byte Uint32 = 6;
|
||||
public const byte Float32 = 7;
|
||||
public const byte Float64 = 8;
|
||||
|
||||
/// <summary>
|
||||
/// Datatype enumeration (Datatype constants)
|
||||
/// </summary>
|
||||
public byte Datatype { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// How many elements in field
|
||||
/// </summary>
|
||||
public uint Count { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public PointField()
|
||||
{
|
||||
Name = string.Empty;
|
||||
Offset = 0;
|
||||
Datatype = 0;
|
||||
Count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
60
srcs/RobotNet10/Shared/RobotNet10.Shared/Sensor/Range.cs
Normal file
60
srcs/RobotNet10/Shared/RobotNet10.Shared/Sensor/Range.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
namespace RobotNet10.Shared.Sensor;
|
||||
|
||||
/// <summary>
|
||||
/// Range message (sensor_msgs/Range)
|
||||
/// Single range reading from an active ranger that emits energy and reports
|
||||
/// one range reading that is valid along an arc at the distance measured.
|
||||
/// </summary>
|
||||
public struct Range
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Radiation type constants
|
||||
/// </summary>
|
||||
public const byte RadiationTypeUltrasound = 0;
|
||||
public const byte RadiationTypeInfrared = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The type of radiation used by the sensor (RadiationType constants)
|
||||
/// </summary>
|
||||
public byte RadiationType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The size of the arc that the distance reading is valid for (rad)
|
||||
/// </summary>
|
||||
public double FieldOfView { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Minimum range value (m)
|
||||
/// </summary>
|
||||
public double MinRange { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum range value (m)
|
||||
/// </summary>
|
||||
public double MaxRange { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Range data (m)
|
||||
/// (Note: values < range_min or > range_max should be discarded)
|
||||
/// </summary>
|
||||
public double RangeValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public Range()
|
||||
{
|
||||
Header = new Header();
|
||||
RadiationType = RadiationTypeUltrasound;
|
||||
FieldOfView = 0.0;
|
||||
MinRange = 0.0;
|
||||
MaxRange = 0.0;
|
||||
RangeValue = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
namespace RobotNet10.Shared.Sensor;
|
||||
|
||||
/// <summary>
|
||||
/// RelativeHumidity message (sensor_msgs/RelativeHumidity)
|
||||
/// Single reading from a relative humidity sensor
|
||||
/// </summary>
|
||||
public struct RelativeHumidity
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Relative humidity reading (0-1)
|
||||
/// </summary>
|
||||
public double RelativeHumidityValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Variance of the relative humidity reading
|
||||
/// </summary>
|
||||
public double Variance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public RelativeHumidity()
|
||||
{
|
||||
Header = new Header();
|
||||
RelativeHumidityValue = 0.0;
|
||||
Variance = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
namespace RobotNet10.Shared.Sensor;
|
||||
|
||||
/// <summary>
|
||||
/// Temperature message (sensor_msgs/Temperature)
|
||||
/// Single temperature reading
|
||||
/// </summary>
|
||||
public struct Temperature
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Temperature reading in Celsius
|
||||
/// </summary>
|
||||
public double TemperatureValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Variance of the temperature reading
|
||||
/// </summary>
|
||||
public double Variance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public Temperature()
|
||||
{
|
||||
Header = new Header();
|
||||
TemperatureValue = 0.0;
|
||||
Variance = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
namespace RobotNet10.Shared.Sensor;
|
||||
|
||||
/// <summary>
|
||||
/// TimeReference message (sensor_msgs/TimeReference)
|
||||
/// Measurement from an external time source not actively synchronized with the system clock
|
||||
/// </summary>
|
||||
public struct TimeReference
|
||||
{
|
||||
/// <summary>
|
||||
/// Header with timestamp and frame ID
|
||||
/// </summary>
|
||||
public Header Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Measurement from an external time source not actively synchronized with the system clock
|
||||
/// </summary>
|
||||
public DateTime TimeRef { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The source of the time reference
|
||||
/// </summary>
|
||||
public string Source { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public TimeReference()
|
||||
{
|
||||
Header = new Header();
|
||||
TimeRef = DateTime.MinValue;
|
||||
Source = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user