Извините, ничего не найдено.

Не расстраивайся! Лучше выпей чайку!
Регистрация
Справка
Календарь

Вернуться   forum.boolean.name > Программирование в широком смысле слова > Алгоритмика

Алгоритмика Об алгоритмах вообще; методы, обсуждения способов решения

Ответ
 
Опции темы
Старый 20.06.2011, 00:06   #1
shybovycha
ПроЭктировщик
 
Аватар для shybovycha
 
Регистрация: 27.05.2007
Сообщений: 110
Написано 40 полезных сообщений
(для 33 пользователей)
Триангуляция простых полигонов

Добрый день, уважаемое комьюнити!

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

Суть моего алгоритма такова:

если в многоугольнике три вершины - заменяем его соотв. треугольником

если же нет - выбираем вершину v таким образом, чтобы выполнялись условия:

# пускай P2 - полигон, в котором вершина v заменена ребром e[ prev(v); next(v) ] *(prev - предыдущая вершина, next - следующая по порядку)

1. v находится вне P2
2. e не пересекает ни одно из существующих ребер, начало и конец которых не совпадает с prev(v) и next(v)

Если соответствующая вершина найдена - мы можем заменить существующий многоугольник комбинацией треугольника [prev(v), v, next(v)] и полигона Р без вершины v [P \ { v }]

На С++ мое решение выглядит примерно так:

typedef struct Point
{
  float x, y;
};

class MooPolygon
{
    private:
        vector<Point> points;

        int isVertexEar(int n, const vector<Point> &p)
        {
            return (isVertexInsideNewPoly(n, p) && !isEdgeIntersect(n, p));
        }

        int isEdgeIntersect(int n, const vector<Point> &p)
        {
            Point v = p[n];
            vector<Point> a;

            for (size_t i = 0; i < p.size(); i++)
                if (i != n)
                    a.push_back(p[i]);

            int c = 0, cnt = a.size(), prev = (cnt + (n - 1)) % cnt, next = n % cnt;

            Point v1 = a[prev], v2 = a[next];

            for (size_t i = 0, j = cnt - 1; i < cnt; j = i++)
            {
                if (prev == i || prev == j || next == i || next == j)
                    continue;

                Point v4 = a[j], v3 = a[i];

                float denominator = ((v4.y - v3.y) * (v2.x - v1.x)) - ((v4.x - v3.x) * (v2.y - v1.y));

                if (!denominator)
                    continue;

                float ua = (((v4.x - v3.x) * (v1.y - v3.y)) - ((v4.y - v3.y) * (v1.x - v3.x))) / denominator;
                float ub = (((v2.x - v1.x) * (v1.y - v3.y)) - ((v2.y - v1.y) * (v1.x - v3.x))) / denominator;

                //float x = v1.x + (ua * (v2.x - v1.x)), y = v1.y + (ua * (v2.y - v1.y));

                if (ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1)
                {
                    c = 1;
                    break;
                }
            }

            return c;
        }

        int isVertexInsideNewPoly(int n, const vector<Point> &p)
        {
            Point v = p[n];
            vector<Point> a;

            for (size_t i = 0; i < p.size(); i++)
                if (i != n)
                    a.push_back(p[i]);

            int c = 1;

            for (size_t i = 0, j = a.size() - 1; i < a.size(); j = i++) 
            {
                if ((((a[i].y <= v.y) && (v.y < a[j].y)) || ((a[j].y <= v.y) && (v.y < a[i].y))) && (v.x > (a[j].x - a[i].x) * (v.y - a[i].y) / (a[j].y - a[i].y) + a[i].x))
                    c = !c;
            }

            return c;
        }

        float dist(Point a, Point b)
        {
            return sqrt(  ((a.x - b.x) * (a.x - b.x)) + (((a.y - b.y) * (a.y - b.y)))  );
        }

    public:
        void push(const Point &p)
        {
            for (size_t i = 0; i < points.size(); i++)
            {
                if (dist(points[i], p) < 7.f)
                {
                    points.push_back(points[i]);

                    return;
                }
            }

            points.push_back(p);
        }

        void pop()
        {
            if (points.size() > 0)
                points.pop_back();
        }

        void clear()
        {
            points.clear();
        }

        Point v(int index)
        {
            return points[index];
        }

        size_t size()
        {
            return points.size();
        }

        void triangulate()
        {
            vector<Point> a;

            for (size_t i = 0; i < points.size(); i++)
            {
                a.push_back(points[i]);
            }

            points.clear();

            for (size_t t = a.size() - 1, i = 0, j = 1; i < a.size(); t = i++, j = (i + 1) % a.size())
            {
                if (a.size() == 3)
                {
                    points.push_back(a[0]);
                    points.push_back(a[1]);
                    points.push_back(a[2]);

                    break;
                }

                if (isVertexEar(i, a))
                {
                    points.push_back(a[t]);
                    points.push_back(a[i]);
                    points.push_back(a[j]);

                    a.erase(a.begin() + i, a.begin() + i + 1);

                    t = a.size() - 1;
                    i = 0;
                    j = 1;
                }
            }
        }
};
Я был бы очень рад, если бы кто-нибудь проверил работоспособность и/или прокомментировал данную затею - насколько она жизнеспособна и удобна ли в использовании.

Спасибо за внимание!

P.S.: На stackoverflow мне подсказали, что данный алгоритм является реализацией алгоритма "обрезания ушек" (англ. ear clipping).
(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
Randomize (21.06.2011)
Ответ


Опции темы

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


Часовой пояс GMT +4, время: 06:46.


vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot
Style crйe par Allan - vBulletin-Ressources.com