// 车体、运动、车队坐标系之间的转换
using System;
namespace MyParking.Shared
{
///
/// 提供二维刚体坐标系之间的点、向量、位姿和速度变换。
/// 坐标系采用X向前、Y向左、逆时针为正的右手系。
///
public static class FrameTransform2D
{
///
/// 将角度归一化到[-π, π)范围。
///
public static double NormalizeAngle(double angleRadians)
{
return AngleMath.NormalizeRadians(angleRadians);
}
///
/// 计算从current到target的最短角度差。
/// 返回正值表示逆时针旋转。
///
public static double ShortestAngleDifference(
double targetRadians,
double currentRadians)
{
return AngleMath.ShortestDifferenceRadians(
targetRadians,
currentRadians);
}
///
/// 将源坐标系中的点变换到目标坐标系。
/// sourcePoseInTarget表示源坐标系在目标坐标系中的位姿。
///
public static Point2D TransformPoint(
Pose2D sourcePoseInTarget,
Point2D pointInSource)
{
var cos = Math.Cos(sourcePoseInTarget.YawRadians);
var sin = Math.Sin(sourcePoseInTarget.YawRadians);
return new Point2D(
sourcePoseInTarget.XMeters +
cos * pointInSource.XMeters -
sin * pointInSource.YMeters,
sourcePoseInTarget.YMeters +
sin * pointInSource.XMeters +
cos * pointInSource.YMeters);
}
///
/// 将目标坐标系中的点反向变换到源坐标系。
///
public static Point2D InverseTransformPoint(
Pose2D sourcePoseInTarget,
Point2D pointInTarget)
{
var dx = pointInTarget.XMeters - sourcePoseInTarget.XMeters;
var dy = pointInTarget.YMeters - sourcePoseInTarget.YMeters;
var cos = Math.Cos(sourcePoseInTarget.YawRadians);
var sin = Math.Sin(sourcePoseInTarget.YawRadians);
return new Point2D(
cos * dx + sin * dy,
-sin * dx + cos * dy);
}
///
/// 将源坐标系中的向量旋转到目标坐标系。
/// 向量没有位置,因此不叠加平移量。
///
public static Point2D TransformVector(
Pose2D sourcePoseInTarget,
Point2D vectorInSource)
{
var cos = Math.Cos(sourcePoseInTarget.YawRadians);
var sin = Math.Sin(sourcePoseInTarget.YawRadians);
return new Point2D(
cos * vectorInSource.XMeters -
sin * vectorInSource.YMeters,
sin * vectorInSource.XMeters +
cos * vectorInSource.YMeters);
}
///
/// 组合两级坐标变换。
/// parentFromMiddle表示middle在parent中的位姿;
/// middleFromChild表示child在middle中的位姿;
/// 返回child在parent中的位姿。
///
public static Pose2D Compose(
Pose2D parentFromMiddle,
Pose2D middleFromChild)
{
var childPositionInParent = TransformPoint(
parentFromMiddle,
middleFromChild.Position);
return new Pose2D(
childPositionInParent.XMeters,
childPositionInParent.YMeters,
NormalizeAngle(
parentFromMiddle.YawRadians +
middleFromChild.YawRadians));
}
///
/// 对坐标变换求逆。
/// 输入child在parent中的位姿,返回parent在child中的位姿。
///
public static Pose2D Inverse(Pose2D childPoseInParent)
{
var cos = Math.Cos(childPoseInParent.YawRadians);
var sin = Math.Sin(childPoseInParent.YawRadians);
return new Pose2D(
-cos * childPoseInParent.XMeters -
sin * childPoseInParent.YMeters,
sin * childPoseInParent.XMeters -
cos * childPoseInParent.YMeters,
NormalizeAngle(
-childPoseInParent.YawRadians));
}
///
/// 将源坐标系中的位姿变换到目标坐标系。
///
public static Pose2D TransformPose(
Pose2D sourcePoseInTarget,
Pose2D poseInSource)
{
return Compose(sourcePoseInTarget, poseInSource);
}
///
/// 转换同一物理参考点处的速度表达坐标系。
/// 只旋转线速度,角速度保持不变。
///
public static Twist2D TransformTwistAtSamePoint(
Pose2D sourcePoseInTarget,
Twist2D twistInSource)
{
var linearVelocityInTarget = TransformVector(
sourcePoseInTarget,
new Point2D(
twistInSource.VxMetersPerSecond,
twistInSource.VyMetersPerSecond));
return new Twist2D(
linearVelocityInTarget.XMeters,
linearVelocityInTarget.YMeters,
twistInSource.OmegaRadiansPerSecond);
}
}
}