You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

计算带旋转角度的多边形顶点时出现尺寸偏差如何解决?

多边形顶点生成函数尺寸偏差问题与解决方案

当我调用函数时传入startingAngle=0参数,可以生成尺寸正确的正常形状,示例如下:

var points = GetPolygonVertices(sides:4, radius:5, center:(5, 5), startingAngle:0), 输出结果为:
points[0] = {X = 10 Y = 5}
points[1] = {X = 5 Y = 0}
points[2] = {X = 0 Y = 5}
points[3] = {X = 5 Y = 10}

可以看到边长为10px,符合预期,但从人眼视角看生成的正方形旋转了45度。

为解决这个问题,我添加了switch/case逻辑对startAngle进行偏移,通过旋转45度让正方形呈现人眼习惯的正置角度。旋转功能正常,但生成的形状不再是10x10px的正方形,边长会损失1到2px:

[0] = {X = 9 Y = 1}
[1] = {X = 1 Y = 1}
[2] = {X = 1 Y = 9}
[3] = {X = 9 Y = 9}

并且半径越大偏差越明显,例如radius=10时的输出为:

[0] = {X = 17 Y = 3}
[1] = {X = 3 Y = 3}
[2] = {X = 3 Y = 17}
[3] = {X = 17 Y = 17}

我尝试过用floor、ceil替代round取整,但始终会有1-2px的损失。有没有方法可以优化这个函数,使得无论边数和旋转角度是多少,都能保持形状尺寸一致?


初始函数代码

public static Point[] GetPolygonVertices(int sides, int radius, Point center, double startingAngle = 0)
{
    if (sides < 3)
        throw new ArgumentException("Polygons can't have less than 3 sides...", nameof(sides));

    // 修正旋转角度
    switch (sides)
    {
        case 3:
            startingAngle += 90;
            break;
        case 4:
            startingAngle += 45;
            break;
        case 5:
            startingAngle += 22.5;
            break;
    }

    var points = new Point[sides];
    var step = 360.0 / sides;
    int i = 0;
    for (var angle = startingAngle; angle < startingAngle + 360.0; angle += step) //沿圆周遍历
    {
        if (i == sides) break; // 修复浮点数精度问题
        double radians = angle * Math.PI / 180.0;
        points[i++] = new(
            (int) Math.Round(Math.Cos(radians) * radius + center.X),
            (int) Math.Round(Math.Sin(-radians) * radius + center.Y)
        );
    }
    return points;
}

第一次更新后的函数

更新了函数,移除了switch条件,未传入角度时可以生成符合人眼视角的正置形状,但仍然存在相同的“尺寸偏差”问题:

public static Point[] GetPolygonVertices(int sides, int radius, Point center, double startingAngle = 0, bool flipHorizontally = false, bool flipVertically = false)
{
    if (sides < 3)
        throw new ArgumentException("Polygons can't have less than 3 sides...", nameof(sides));

    var vertices = new Point[sides];

    double deg = 360.0 / sides;//计算旋转步长
    var rad = Math.PI / 180.0;

    var x0 = center.X + radius * Math.Cos(-(((180 - deg) / 2) + startingAngle) * rad);
    var y0 = center.Y - radius * Math.Sin(-(((180 - deg) / 2) + startingAngle) * rad);

    var x1 = center.X + radius * Math.Cos(-(((180 - deg) / 2) + deg + startingAngle) * rad);
    var y1 = center.Y - radius * Math.Sin(-(((180 - deg) / 2) + deg + startingAngle) * rad);

    vertices[0] = new(
        (int) Math.Round(x0),
        (int) Math.Round(y0)
        );

    vertices[1] = new(
        (int) Math.Round(x1),
        (int) Math.Round(y1)
        );

    for (int i = 0; i < sides - 2; i++)
    {
        double dsinrot = Math.Sin((deg * (i + 1)) * rad);
        double dcosrot = Math.Cos((deg * (i + 1)) * rad);

        vertices[i + 2] = new(
                (int)Math.Round(center.X + dcosrot * (x1 - center.X) - dsinrot * (y1 - center.Y)),
                (int)Math.Round(center.Y + dsinrot * (x1 - center.X) + dcosrot * (y1 - center.Y))
        );
    }

    if (flipHorizontally)
    {
        var startX = center.X - radius;
        var endX = center.X + radius;
        for (int i = 0; i < sides; i++)
        {
            vertices[i].X = endX - (vertices[i].X - startX);
        }
    }

    if (flipVertically)
    {
        var startY = center.Y - radius;
        var endY = center.Y + radius;
        for (int i = 0; i < sides; i++)
        {
            vertices[i].Y = endY - (vertices[i].Y - startY);
        }
    }

    return vertices;
}

最终解决方案

根据Tim Roberts的回答,补充了通过半径计算边长、通过边长计算半径的函数,已经解决了尺寸偏差问题:

public static double CalculatePolygonSideLengthFromRadius(double radius, int sides)
{
    return 2 * radius * Math.Sin(Math.PI / sides);
}

public static double CalculatePolygonVerticalLengthFromRadius(double radius, int sides)
{
    return radius * Math.Cos(Math.PI / sides);
}

public static double CalculatePolygonRadiusFromSideLength(double length, int sides)
{
    var theta = 360.0 / sides;
    return length / (2 * Math.Cos((90 - theta / 2) * Math.PI / 180.0));
}

内容的提问来源于stack exchange,提问作者Tiago Conceição

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.17 06:36:04