C # Рисование полигонов, используя угловые градусы и триг - PullRequest
1 голос
/ 11 ноября 2010

Я пытаюсь создать простые фигуры, шестиугольник, пятиугольник, треугольник и т. Д., Имея начальную точку и вычисляя, где остальные точки должны быть для каждой вершины.И я продолжаю создавать прямые или странные пересекающиеся многоугольники.Я использую метод ниже, чтобы попытаться вычислить вершины для шестиугольника, затем делаю простой 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);
    }
}

Ответы [ 4 ]

3 голосов
/ 11 ноября 2010

Хорошо, проблема в вашем 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 на желаемый угол.

приписка
Я сделал статический метод только потому, что мне было удобнее тестировать, но вы все равно можете использовать свой метод экземпляра.

0 голосов
/ 07 октября 2012

Я знаю, что это старая ветка, но недавно я ее использовал, поэтому подумал, что я добавил некоторые изменения, которые я добавил, которые могут помочь некоторым людям.

Я использовал приведенный выше код, но с помощью центральной точки для установки первой вершины и смещения первой степени я смог создать многоугольник вокруг центральной точки. Я также добавил метод для расчета длины стороны на основе радиуса.

Вот что я придумал (код в 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, поскольку я проверял количество сторон в другом месте.

У меня просто вопрос, лучше ли передать длину стороны в качестве параметра или, как я, и вызвать метод из моего метода?

0 голосов
/ 04 июля 2012

Статическая функция выше верна, однако, поскольку она вычисляет точки как целые числа, появляются ошибки округления. Даже для 5-стороннего многоугольника вычисления вершин будут отключены на несколько пикселей.

Iзаменил класс 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;
    }
}
0 голосов
/ 11 ноября 2010

Пока я не продумал ваш алгоритм; ИМХО, лучшим подходом было бы определить центральную точку; и попросите ваш код вычислить другие точки (шесть, в случае шестиугольника), используя point [i] = new Point (center.x + sideLength * cos ((Math.PI * i) / 6), center.y + sideLength * sin ((Math.PI * i) / 6));.

...