1.求旋转中心
public static Point CalculateRotateCenter(Point p1, Point p2, double angle)
{
double r = angle / 180.0 * Math.PI;
double x = 0.5 * ((p2.Y - p1.Y) * Math.Sin(r) + (p2.X + p1.X) * Math.Cos(r) - (p2.X + p1.X)) / (Math.Cos(r) - 1.0);
double y = 0.5 * ((p2.Y + p1.Y) * Math.Cos(r) - (p2.X - p1.X) * Math.Sin(r) - (p2.Y + p1.Y)) / (Math.Cos(r) - 1.0);
return new Point(x, y);
}
2、已知旋转中心求旋转点
public static Point CalculateRotateCenter(Point p1, Point p2, double angle)
{
double r = angle / 180.0 * Math.PI;
double x = 0.5 * ((p2.Y - p1.Y) * Math.Sin(r) + (p2.X + p1.X) * Math.Cos(r) - (p2.X + p1.X)) / (Math.Cos(r) - 1.0);
double y = 0.5 * ((p2.Y + p1.Y) * Math.Cos(r) - (p2.X - p1.X) * Math.Sin(r) - (p2.Y + p1.Y)) / (Math.Cos(r) - 1.0);
return new Point(x, y);
}
3、向量法求解
using System;
public class RotationCenterCalculator
{
public static (double X, double Y) CalculateRotationCenter(double p1x, double p1y, double p2x, double p2y)
{
// 计算P1和P2之间的中点
double midX = (p1x + p2x) / 2.0;
double midY = (p1y + p2y) / 2.0;
// 计算P1和P2之间的距离
double distance = Math.Sqrt(Math.Pow(p2x - p1x, 2) + Math.Pow(p2y - p1y, 2));
// 旋转半径等于P1和P2之间距离除以根号2
double radius = distance / Math.Sqrt(2);
// 旋转中心位于P1和P2连线的垂直平分线上,且距离中点radius远
// 由于是顺时针旋转90度,旋转中心位于P1和P2连线的垂直平分线的下方(或左侧,取决于坐标系的方向)
// 但由于我们不知道具体是在哪个方向上(上方或下方,左侧或右侧),我们需要考虑两种情况
// 然而,在这个特定情况下,由于旋转是90度,我们只需要考虑一个确定的方向
// 旋转中心位于中点向下(或向左,取决于你如何定义旋转的方向)偏移radius的位置
// 但实际上,由于旋转中心位于垂直平分线上,且距离两点等远,我们只需要考虑中点和半径即可确定位置
// 这里我们假设坐标系是标准的,即x轴向右,y轴向上,因此旋转中心位于中点的左下方(对于顺时针旋转)
// 但由于旋转中心实际上位于中垂线上且与两点的连线垂直,我们可以通过中点和向量旋转来确定其位置
// 不过,为了简化,我们可以直接使用中点和半径以及旋转方向来“猜测”旋转中心的位置
// 在这个例子中,我们知道旋转中心位于P1和P2连线的中垂线上,且距离它们radius远
// 我们可以使用中点和P1到P2的向量来计算出旋转中心的坐标
// 向量P1P2
double dx = p2x - p1x;
double dy = p2y - p1y;
// 旋转中心坐标(使用中点和旋转半径以及旋转方向来确定)
// 由于是顺时针旋转90度,我们可以将向量P1P2旋转-90度(即逆时针旋转90度的相反方向)来找到从中点到旋转中心的向量
// 然后将这个向量加到中点上即可得到旋转中心的坐标
// 旋转-90度的向量是(dy, -dx)除以向量的长度(但在这里我们不需要除以长度,因为我们已经知道半径)
double centerX = midX - dy * (radius / distance); // 注意:这里乘以radius/distance实际上是多余的,因为dy已经是单位向量的一部分了,但为了保持一致性,可以保留
double centerY = midY + dx * (radius / distance); // 同上
// 但由于我们已经知道distance = radius * sqrt(2),所以上面的计算可以简化为:
centerX = midX - dy / Math.Sqrt(2);
centerY = midY + dx / Math.Sqrt(2);
// 或者更简单地,由于我们只需要确定旋转中心位于中垂线上且与P1和P2等远,我们可以直接使用中点和半径来计算:
// centerX = midX - (p2y - p1y) / 2(这是错误的,因为上面的旋转逻辑不适用,这里只是为了说明直接计算的方法不可行)
// centerY = midY + (p2x - p1x) / 2(这同样是错误的)
// 正确的做法是使用上面的旋转向量方法或者下面的简化方法(考虑到旋转角度是90度的特殊情况)
// 正确的简化方法(考虑到旋转角度是90度,且旋转中心位于中垂线上):
// 由于旋转中心位于中垂线上,我们可以直接使用中点和P1到P2的单位向量的垂直分量来确定位置
// 单位向量P1P2是(dx/distance, dy/distance),其垂直向量是(-dy/distance, dx/distance)
// 但由于我们只需要找到旋转中心,且知道旋转半径,我们可以直接使用中点和这个垂直向量乘以半径来确定位置
// 不过,为了与上面的计算保持一致(尽管有些步骤是多余的),我们可以使用下面的方法:
// 最终简化的正确计算:
centerX = midX - dy * (1 / Math.Sqrt(2)); // 乘以1/sqrt(2)是因为我们要得到单位向量的一部分,但在这里乘以radius(即distance/sqrt(2))已经是单位向量的倍数了,所以直接乘以1/sqrt(2)即可
centerY = midY + dx * (1 / Math.Sqrt(2)); // 同上
// 但由于我们之前已经计算了radius,并且知道distance = radius * sqrt(2),所以上面的乘以1/sqrt(2)实际上是直接使用radius来计算:
// centerX = midX - (p2y - p1y) * (1 / (2 * radius / distance)) = midX - (p2y - p1y) * (sqrt(2) / 2 * 1/sqrt(2)) = midX - (p2y - p1y) / 2 * (但这里我们不需要再除以2,因为radius已经是distance的一半的sqrt(2)倍了)
// centerY = midY + (p2x - p1x) * (1 / (2 * radius / distance)) = 同上(但注意这里的计算过程是为了说明,实际上我们应该直接使用上面的简化方法)
// 所以,最终的正确计算就是:
centerX = midX - dy / Math.Sqrt(2); // 这与上面的正确简化方法中的第一个等式相同(但注意这里的dy已经是P1和P2的y坐标差)
centerY = midY + dx / Math.Sqrt(2); // 这与上面的正确简化方法中的第二个等式相同(但注意这里的dx已经是P1和P2的x坐标差)
// 注意:上面的解释中有些步骤是冗余的,目的是为了说明计算过程。实际的正确计算就是最后给出的两个等式。
return (centerX, centerY);
}
public static void Main()
{
double p1x = 0, p1y = 0; // 点P1的坐标
double p2x = 1, p2y = 1; // 点P2的坐标(假设P1顺时针旋转90度后到达P2的位置)
var rotationCenter = CalculateRotationCenter(p1x, p1y, p2x, p2y);
Console.WriteLine($"Rotation center: X = {rotationCenter.X}, Y = {rotationCenter.Y}");
}
}
public class RotationCenterCalculator
{
/// <summary>
/// 计算旋转中心
/// </summary>
/// <param name="p1">初始点</param>
/// <param name="p2">旋转后的点</param>
/// <param name="angleDegrees">旋转角度(度)</param>
/// <returns>旋转中心</returns>
public static Point CalculateRotationCenter(Point p1, Point p2, double angleDegrees)
{
// 将角度转换为弧度
double angleRadians = angleDegrees * Math.PI / 180;
// 计算 P1 和 P2 的中点
double midX = (p1.X + p2.X) / 2;
double midY = (p1.Y + p2.Y) / 2;
// 计算 P1 到 P2 的向量
double dx = p2.X - p1.X;
double dy = p2.Y - p1.Y;
// 计算 P1 和 P2 之间的距离
double distance = Math.Sqrt(dx * dx + dy * dy);
// 计算旋转半径
double radius = distance / (2 * Math.Sin(angleRadians / 2));
// 计算垂直平分线的斜率
double slopePerpendicular = -dx / dy;
// 计算旋转中心
double centerX = midX - (dy / distance) * radius * Math.Cos(angleRadians / 2);
double centerY = midY + (dx / distance) * radius * Math.Cos(angleRadians / 2);
return new Point(centerX, centerY);
}
}
旋转半径公式:
旋转半径 R与两点距离 d 和旋转角度θ 的关系为:
R= d/2sin(θ/2)
旋转中心坐标:
旋转中心位于垂直平分线上,且距离中点的长度为 Rcos(θ/2)。
旋转中心的坐标为:
centerX=midX− dy/d ⋅R⋅cos(θ/2)
centerY= midY+ dx/d R⋅cos(θ/2)