2
votes

I've decided to create a simple demo, dividing a polygon into triangle set. Here what i've got so far:

A sequential vertex list is given (P1) forming polygon edges (polygon is not convex in most cases); a triangle set is needed

Loop through all the vertices within the polygon P1 and find the one (v), which will satisfy next clauses:

  1. remove v from polygon and save the new one to P2 previous vertex to v connected to its next one form a line which do not cross any of P2 edges

  2. v is not inside P2

If these are satisfied, we can replace P1 with (P2 + triangle( prev(v), v, next(v)) ) and repeat this action until P1 contains more than 3 vertices.

So, the questions are: is this algorithm correct and how it could be implemented using C / C++ using the most obvious and simple way?

3
Any constraint on the polygon (such as concave/convex) or do you want the general case ?Vincent Mimoun-Prat
oh, i am sorry. totally forgot to mention that fact... just general case - for both convex and concave ones. excluding holes, of courseshybovycha

3 Answers

5
votes

I think you're describing the ear clipping method. There's code for that method at http://cs.smith.edu/~orourke/books/ftp.html ; it's the code described in the book Computational Geometry in C.

1
votes

Seems that i'm done with this algorithm implementation. Please, verify it someone. Thanks!

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;
                }
            }
        }
};
0
votes

The code has an error on the line below. The line is in the for loop in the push() function of your class:

points.push_back(points[i]);

You are not passing the pushed Point, but an empty element of the vector itself. I changed the line to

points.push_back(p);

and it worked.