C# 使用角度和 Trig 绘制多边形

发布于 2024-10-02 05:33:08 字数 877 浏览 3 评论 0原文

我试图通过有一个起点并计算每个顶点的其他点应该在哪里来创建简单的形状,六边形,五边形,三角形等。我不断创建直线或奇怪的重叠多边形。 我使用下面的方法尝试计算六边形的顶点,然后执行一个简单的 Graphics.DrawPolygon(pen, aptsVertices) 稍后绘制它。 任何帮助将不胜感激。

protected override void CalculateVertices()
{
    //member variables
    aptsVertices = new Point[6];
    deg = 120;
    rad = deg * (Math.PI / 180);

    double nSinDeg = Math.Sin(rad);
    double nCosDeg = Math.Cos(rad);

    aptsVertices[0] = ptFirstVertex;

    for(int i = 1; i < aptsVertices.Length; i++)
    {
        double x = aptsVertices[i - 1].X - nCosDeg * nSideLength;
        double y = aptsVertices[i - 1].Y - nSinDeg * nSideLength;
        aptsVertices[i] = new Point((int)x, (int)y);

        //recalculate the degree for the next vertex
        deg += 120;
        rad = deg * (Math.PI / 180);

        nSinDeg = Math.Sin(rad);
        nCosDeg = Math.Cos(rad);
    }
}

I'm trying to create simple shapes, Hexagon, Pentagon, Triangle, etc by having a starting Point and calculating where the other Points should be for each vertex. And i keep create straight lines or weird overlaping polygons.
I use the method below to try to calculate the vertices for a Hexagon, then do a simple graphics.DrawPolygon(pen, aptsVertices) to draw it later.
Any help would be appreciated.

protected override void CalculateVertices()
{
    //member variables
    aptsVertices = new Point[6];
    deg = 120;
    rad = deg * (Math.PI / 180);

    double nSinDeg = Math.Sin(rad);
    double nCosDeg = Math.Cos(rad);

    aptsVertices[0] = ptFirstVertex;

    for(int i = 1; i < aptsVertices.Length; i++)
    {
        double x = aptsVertices[i - 1].X - nCosDeg * nSideLength;
        double y = aptsVertices[i - 1].Y - nSinDeg * nSideLength;
        aptsVertices[i] = new Point((int)x, (int)y);

        //recalculate the degree for the next vertex
        deg += 120;
        rad = deg * (Math.PI / 180);

        nSinDeg = Math.Sin(rad);
        nCosDeg = Math.Cos(rad);
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

維他命╮ 2024-10-09 05:33:08

好的,问题出在您的 deg += 120 上。实际上,您需要将 deg 减小 step = 60°(或增加,具体取决于您想要的构造方向)*。

以下是通用边数的代码:

public static Point[] CalculateVertices(int nSides, int nSideLength, Point ptFirstVertex)
{
    if (nSides < 3)
        throw new ArgumentException("Polygons can't have less than 3 sides...");

    var aptsVertices = new Point[nSides];
    var deg = (180.0 * (nSides - 2)) / nSides;
    var step = 360.0 / nSides;
    var rad = deg * (Math.PI / 180);

    double nSinDeg = Math.Sin(rad);
    double nCosDeg = Math.Cos(rad);

    aptsVertices[0] = ptFirstVertex;

    for (int i = 1; i < aptsVertices.Length; i++)
    {
        double x = aptsVertices[i - 1].X - nCosDeg * nSideLength;
        double y = aptsVertices[i - 1].Y - nSinDeg * nSideLength;
        aptsVertices[i] = new Point((int)x, (int)y);


        //recalculate the degree for the next vertex
        deg -= step;
        rad = deg * (Math.PI / 180);

        nSinDeg = Math.Sin(rad);
        nCosDeg = Math.Cos(rad);

    }
    return aptsVertices;
}

*

减去步骤,您将构建一个逆时针添加边数的多边形。
添加步骤,您将构建一个按顺时针方向添加边的多边形。
如果您想更改第一条边的倾斜度,只需将初始deg偏移您想要的角度即可。

PS
我使用静态方法只是因为更方便我测试,但您仍然可以使用实例方法。

Ok, the problem is in your deg += 120. Actually you need to decrease deg by a step = 60° (or increase, depending on your desired construction direction) *.

Here's the code for generic number of sides:

public static Point[] CalculateVertices(int nSides, int nSideLength, Point ptFirstVertex)
{
    if (nSides < 3)
        throw new ArgumentException("Polygons can't have less than 3 sides...");

    var aptsVertices = new Point[nSides];
    var deg = (180.0 * (nSides - 2)) / nSides;
    var step = 360.0 / nSides;
    var rad = deg * (Math.PI / 180);

    double nSinDeg = Math.Sin(rad);
    double nCosDeg = Math.Cos(rad);

    aptsVertices[0] = ptFirstVertex;

    for (int i = 1; i < aptsVertices.Length; i++)
    {
        double x = aptsVertices[i - 1].X - nCosDeg * nSideLength;
        double y = aptsVertices[i - 1].Y - nSinDeg * nSideLength;
        aptsVertices[i] = new Point((int)x, (int)y);


        //recalculate the degree for the next vertex
        deg -= step;
        rad = deg * (Math.PI / 180);

        nSinDeg = Math.Sin(rad);
        nCosDeg = Math.Cos(rad);

    }
    return aptsVertices;
}

*

Subtracting the step, you will build a polygon adding sides counter-clockwise.
Adding the step, you will build a polygon adding sides clockwise.
If you want to change the inclination of your first side, just offset the initial deg by your desired angle.

P.S.
I did a static method just because was more convenient for me to test, but you can still use your instance method.

动听の歌 2024-10-09 05:33:08

虽然我没有想通你的算法;恕我直言,更好的方法是定义一个中心点;并让您的代码使用 point [i] = new Point (center.x + sideLength * cos ((Math.PI * i) / 6), center.计算其他点(如果是六边形,则为六个) y + sideLength * sin ((Math.PI * i) / 6));

While I did not think through your algorithm; IMHO, a better approach would be to define a central point; and have your code calculate the other points (six, in case of a hexagon) using point [i] = new Point (center.x + sideLength * cos ((Math.PI * i) / 6), center.y + sideLength * sin ((Math.PI * i) / 6));.

苏佲洛 2024-10-09 05:33:08

上面的静态函数是正确的,但是由于它将点计算为整数,因此舍入误差会逐渐增加。即使对于 5 边形,顶点计算也会偏差几个像素。

我替换了一个使用双精度数而不是整数的 Point 类来消除舍入误差。绘制顶点时,您可以四舍五入到最接近的整数。

否则,代码是完全相同的。

public static PointD[] CalculateVertices(int nSides, int nSideLength, PointD ptFirstVertex)
{
    //calculate the points for a polygon of N sides
    if (nSides < 3)
        throw new ArgumentException("Polygons can't have less than 3 sides...");

    var aptsVertices = new PointD[nSides];
    var deg = (180.0 * (nSides - 2)) / nSides;
    var step = 360.0 / nSides;
    var rad = deg * (Math.PI / 180);

    double nSinDeg = Math.Sin(rad);
    double nCosDeg = Math.Cos(rad);

    aptsVertices[0] = ptFirstVertex;

    for (int i = 1; i < aptsVertices.Length; i++)
    {
        double x = aptsVertices[i - 1].X - nCosDeg * nSideLength;
        double y = aptsVertices[i - 1].Y - nSinDeg * nSideLength;
        aptsVertices[i] = new PointD(x, y);

        //recalculate the degree for the next vertex
        deg -= step;
        rad = deg * (Math.PI / 180);

        nSinDeg = Math.Sin(rad);
        nCosDeg = Math.Cos(rad);

    }
    return aptsVertices;
}

这是新的点类。

public class PointD
{
    public double X, Y;
    public PointD(double _x, double _y)
    {
        X = _x;
        Y = _y;
    }
}

The static function above is correct, however since it calculates the points as integers, rounding errors creep in. Even for a 5-sided polygon, the vertex calculations will be off by a few pixels.

I substituted a Point class that uses doubles rather than integers to remove the rounding errors. You can just round to the nearest integer when you draw the vertices.

Otherwise, the code is exactly the same.

public static PointD[] CalculateVertices(int nSides, int nSideLength, PointD ptFirstVertex)
{
    //calculate the points for a polygon of N sides
    if (nSides < 3)
        throw new ArgumentException("Polygons can't have less than 3 sides...");

    var aptsVertices = new PointD[nSides];
    var deg = (180.0 * (nSides - 2)) / nSides;
    var step = 360.0 / nSides;
    var rad = deg * (Math.PI / 180);

    double nSinDeg = Math.Sin(rad);
    double nCosDeg = Math.Cos(rad);

    aptsVertices[0] = ptFirstVertex;

    for (int i = 1; i < aptsVertices.Length; i++)
    {
        double x = aptsVertices[i - 1].X - nCosDeg * nSideLength;
        double y = aptsVertices[i - 1].Y - nSinDeg * nSideLength;
        aptsVertices[i] = new PointD(x, y);

        //recalculate the degree for the next vertex
        deg -= step;
        rad = deg * (Math.PI / 180);

        nSinDeg = Math.Sin(rad);
        nCosDeg = Math.Cos(rad);

    }
    return aptsVertices;
}

This is the new point class.

public class PointD
{
    public double X, Y;
    public PointD(double _x, double _y)
    {
        X = _x;
        Y = _y;
    }
}
心房的律动 2024-10-09 05:33:08

我知道这是一个旧线程,但我最近使用了它,所以我想我添加了一些可能对某些人有帮助的修改。

我使用了上面的代码,但是通过使用中心点设置第一个顶点并偏移第一度,我能够围绕中心点创建一个多边形。我还添加了一种根据半径计算边长的方法。

以下是我的想法(Objective-C 中的代码):

-(NSArray *) calculateVertices:(int)numSides center:(CGPoint)ctr{
NSMutableArray *vertices = [[NSMutableArray alloc] init];

if (numSides < 3) {
    return vertices;
}

float deg = ((180.0 * (numSides-2) / numSides)-180)/2;

float step = 360.0 / numSides;
float rad = deg * (M_PI / 180);

double nSinDeg = sin(rad);
double nCosDeg = cos(rad);

int sl = [self calculateSideLength:numSides];

CGPoint firstPoint = CGPointMake(ctr.x, ctr.y-radius);    
[vertices addObject:[NSValue valueWithCGPoint:firstPoint]];

for (int i = 1; i < numSides; i++) {
    NSValue *vp = [vertices objectAtIndex:i-1];
    CGPoint pp =[vp CGPointValue];
    double x = pp.x - nCosDeg * sl;
    double y = pp.y - nSinDeg * sl;
    CGPoint np = CGPointMake(x, y);
    [vertices addObject:[NSValue valueWithCGPoint:np]];

    deg -= step;
    rad = deg * (M_PI / 180);

    nSinDeg = sin(rad);
    nCosDeg = cos(rad);

}

return vertices;

}

-(int) calculateSideLength:(int)numSides{
   int length = (2*radius)*sin(M_PI/numSides);
   return length;
}

注意:半径被设置为类属性,这就是为什么您在任何地方都看不到它被设置的原因。另外,我不希望它在边数小于 3 时抛出异常,因为我正在其他地方检查边数。

我只是有一个问题,将边长作为参数传递更好,还是像我一样,然后从我的方法中调用该方法?

I know this is an old thread, but I recently used it, so I thought I add some modifications I added that may help some people.

I used the code above, but by using a center point to set the first vertex, and offsetting the first degree, I was able to create a polygon around a center point. I also added a method to calculate the side length, based on the radius.

Here's what I came up with (the code it's in Objective-C):

-(NSArray *) calculateVertices:(int)numSides center:(CGPoint)ctr{
NSMutableArray *vertices = [[NSMutableArray alloc] init];

if (numSides < 3) {
    return vertices;
}

float deg = ((180.0 * (numSides-2) / numSides)-180)/2;

float step = 360.0 / numSides;
float rad = deg * (M_PI / 180);

double nSinDeg = sin(rad);
double nCosDeg = cos(rad);

int sl = [self calculateSideLength:numSides];

CGPoint firstPoint = CGPointMake(ctr.x, ctr.y-radius);    
[vertices addObject:[NSValue valueWithCGPoint:firstPoint]];

for (int i = 1; i < numSides; i++) {
    NSValue *vp = [vertices objectAtIndex:i-1];
    CGPoint pp =[vp CGPointValue];
    double x = pp.x - nCosDeg * sl;
    double y = pp.y - nSinDeg * sl;
    CGPoint np = CGPointMake(x, y);
    [vertices addObject:[NSValue valueWithCGPoint:np]];

    deg -= step;
    rad = deg * (M_PI / 180);

    nSinDeg = sin(rad);
    nCosDeg = cos(rad);

}

return vertices;

}

-(int) calculateSideLength:(int)numSides{
   int length = (2*radius)*sin(M_PI/numSides);
   return length;
}

NOTE: radius is set as a class property, that's why you don't see it being set anywhere. Also, I didn't want it throwing an exception if sides is less than 3, since I was checking for the number of sides elsewhere.

I just have a question, is it better to pass the side length as a parameter, or as I did, and call the method from within my method?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文