微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用角度计算多边形顶点会产生错误的形状大小

如何解决使用角度计算多边形顶点会产生错误的形状大小

当我用 startingAngle=0 调用我的函数时,它会产生一个大小合适的好形状。 示例:

var points = GetpolygonVertices(sides:4,radius:5,center:(5,5),startingAngle:0),produces:
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º 的旋转正方形。

为了解决这个问题,我添加一个开关/外壳来偏移 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}

我尝试使用地板和天花板而不是圆形,但它总是以丢失 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));


        // Fix rotation
        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) //go in a circle
        {
            if (i == sides) break; // Fix floating problem
            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;
    }

编辑:我更新了功能,以在未给出角度时摆脱人眼正确方向的开关条件和产品形状。它仍然遭受同样的“问题”

public static Point[] GetpolygonVertices(int sides,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;//calculate the rotation angle
    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;
}

编辑 2: 来自 Tim Roberts anwser 这里的函数从半径计算边长和从边长计算半径,这解决了我的问题。谢谢!

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));
}

解决方法

你的问题是一道数学题。您说“根据观察,边长为 10px”。它绝对不是 10px。从 (10,5) 到 (5,0) 的距离是 sqrt(5*5 + 5*5),即 7.07。这正是我们对内接在半径为 5 的圆中的正方形的期望:5 x sqrt(2)。

其他方格也是如此。

跟进

作为一个额外的好处,这里有一个函数,它返回外接一个长度为 L 的 N 条边的正多边形的圆的半径:

import math

def rad(length,nsides):
    theta = 360/nsides
    r = length / (2 * math.cos( (90-theta/2) * math.pi / 180))
    return r

for s in range(3,9):
    print(s,rad(10,s))

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。