Ejemplo n.º 1
0
        static bool splitAndResume(vertex_info begin, FList <TriIdx> result)
        {
            vertex_info v1, v2;

            if (!findDiagonal(begin, out v1, out v2))
            {
                return(false);
            }

            vertex_info v1_copy = v1.Clone();
            vertex_info v2_copy = v2.Clone();

            v1.next = v2;
            v2.prev = v1;

            v1_copy.next.prev = v1_copy;
            v2_copy.prev.next = v2_copy;

            v1_copy.prev = v2_copy;
            v2_copy.next = v1_copy;

            bool r1 = doTriangulate(v1, result);
            bool r2 = doTriangulate(v1_copy, result);

            return(r1 && r2);
        }
Ejemplo n.º 2
0
        static int windingNumber(vertex_info begin, vector point)
        {
            int wn = 0;

            vertex_info v = begin;

            do
            {
                if (v.p.Y <= point.Y)
                {
                    if (v.next.p.Y > point.Y && orient2d(v.p, v.next.p, point) > 0)
                    {
                        ++wn;
                    }
                }
                else
                {
                    if (v.next.p.Y <= point.Y && orient2d(v.p, v.next.p, point) < 0)
                    {
                        --wn;
                    }
                }
                v = v.next;
            } while (v != begin);

            return(wn);
        }
Ejemplo n.º 3
0
            // 39% of execution time
            public void updateVertex(vertex_info v)
            {
                var spre = v.score;
                var qpre = v.isCandidate();

                v.recompute();
                var qpost = v.isCandidate();
                var spost = v.score;

                v.score = spre;

                if (qpre)
                {
                    if (qpost)
                    {
                        if (v.score != spre)
                        {
                            changeScore(v, spost);
                        }
                    }
                    else
                    {
                        remove(v);
                    }
                }
                else
                {
                    if (qpost)
                    {
                        push(v);
                    }
                }
            }
Ejemplo n.º 4
0
 static bool isLeft(vertex_info a, vertex_info b, vertex_info c)
 {
     if (a.idx < b.idx && b.idx < c.idx)
     {
         return(orient2d(a.p, b.p, c.p) > 0.0);
     }
     else if (a.idx < c.idx && c.idx < b.idx)
     {
         return(orient2d(a.p, c.p, b.p) < 0.0);
     }
     else if (b.idx < a.idx && a.idx < c.idx)
     {
         return(orient2d(b.p, a.p, c.p) < 0.0);
     }
     else if (b.idx < c.idx && c.idx < a.idx)
     {
         return(orient2d(b.p, c.p, a.p) > 0.0);
     }
     else if (c.idx < a.idx && a.idx < b.idx)
     {
         return(orient2d(c.p, a.p, b.p) > 0.0);
     }
     else
     {
         return(orient2d(c.p, b.p, a.p) < 0.0);
     }
 }
Ejemplo n.º 5
0
 public void changeScore(vertex_info v, element score)
 {
     if (v.score != score)
     {
         v.score = score;
         queue.UpdateHeap();
     }
 }
Ejemplo n.º 6
0
            public void remove(vertex_info v)
            {
                var score = v.score;

                if (v != queue.List[0])
                {
                    v.score = queue.List[0].score + 1;
                    queue.UpdateHeap();
                }
                queue.Pop();
                v.score = score;
            }
Ejemplo n.º 7
0
        public static void triangulate <T>(Project <T> project, FList <T> poly, FList <TriIdx> result)
        {
            var N = poly.Count;

            result.Clear();
            if (N < 3)
            {
                return;
            }

            result.Capacity = poly.Count - 2;

            if (N == 3)
            {
                result.Add(new TriIdx(0, 1, 2));
                return;
            }

            var vinfo = new vertex_info[N];

            vinfo[0] = new vertex_info(project(poly[0]), 0);
            for (int i = 1; i < N - 1; ++i)
            {
                vinfo[i]          = new vertex_info(project(poly[i]), i);
                vinfo[i].prev     = vinfo[i - 1];
                vinfo[i - 1].next = vinfo[i];
            }
            vinfo[N - 1]      = new vertex_info(project(poly[N - 1]), N - 1);
            vinfo[N - 1].prev = vinfo[N - 2];
            vinfo[N - 1].next = vinfo[0];
            vinfo[0].prev     = vinfo[N - 1];
            vinfo[N - 2].next = vinfo[N - 1];

            for (int i = 0; i < N; ++i)
            {
                vinfo[i].recompute();
            }

            var begin = vinfo[0];

            removeDegeneracies(ref begin, result);

            doTriangulate(begin, result);
        }
Ejemplo n.º 8
0
            public static element triScore(vertex_info p, vertex_info v, vertex_info n)
            {
                // range: 0 - 1
                element a, b, c;

                bool convex = isLeft(p, v, n);

                if (!convex)
                {
                    return(-1e-5f);
                }

                a = (n.p - v.p).Length;
                b = (p.p - n.p).Length;
                c = (v.p - p.p).Length;

                if (a < 1e-10 || b < 1e-10 || c < 1e-10)
                {
                    return(0);
                }

                return(Math.Max(Math.Min((a + b) / c, Math.Min((a + c) / b, (b + c) / a)) - 1, 0));
            }
Ejemplo n.º 9
0
            public bool isClipable()
            {
                for (vertex_info v_test = next.next; v_test != prev; v_test = v_test.next)
                {
                    if (v_test.convex)
                    {
                        continue;
                    }

                    if (v_test.p == prev.p ||
                        v_test.p == next.p)
                    {
                        continue;
                    }

                    if (v_test.p == p)
                    {
                        if (v_test.next.p == prev.p &&
                            v_test.prev.p == next.p)
                        {
                            return(false);
                        }
                        if (v_test.next.p == prev.p ||
                            v_test.prev.p == next.p)
                        {
                            continue;
                        }
                    }

                    if (pointInTriangle(prev, this, next, v_test))
                    {
                        return(false);
                    }
                }
                return(true);
            }
Ejemplo n.º 10
0
 static bool internalToAngle(vertex_info a, vertex_info b, vertex_info c, vector p)
 {
     return(internalToAngle(a.p, b.p, c.p, p));
 }
Ejemplo n.º 11
0
        static bool findDiagonal(vertex_info begin, out vertex_info v1, out vertex_info v2)
        {
            vertex_info t;
            var         heap = new FList <vertex_info>();

            v1 = begin;
            do
            {
                heap.Clear();

                for (v2 = v1.next.next; v2 != v1.prev; v2 = v2.next)
                {
                    if (!internalToAngle(v1.next, v1, v1.prev, v2.p) ||
                        !internalToAngle(v2.next, v2, v2.prev, v1.p))
                    {
                        continue;
                    }

                    PriorityQueue <vertex_info> .PushHeap(heap, v2, new vertex_info_l2norm_inc_ordering(v1));
                }

                while (heap.Count != 0)
                {
                    v2 = PriorityQueue <vertex_info> .PopHeap(heap, new vertex_info_l2norm_inc_ordering(v1));

                    // test whether v1-v2 is a valid diagonal.
                    var v_min_x = Math.Min(v1.p.X, v2.p.X);
                    var v_max_x = Math.Max(v1.p.X, v2.p.X);

                    bool intersected = false;

                    for (t = v1.next; !intersected && t != v1.prev; t = t.next)
                    {
                        vertex_info u = t.next;
                        if (t == v2 || u == v2)
                        {
                            continue;
                        }

                        var l1 = orient2d(v1.p, v2.p, t.p);
                        var l2 = orient2d(v1.p, v2.p, u.p);

                        if ((l1 > 0.0 && l2 > 0.0) || (l1 < 0.0 && l2 < 0.0))
                        {
                            // both on the same side; no intersection
                            continue;
                        }

                        var dx13 = v1.p.X - t.p.X;
                        var dy13 = v1.p.Y - t.p.Y;
                        var dx43 = u.p.X - t.p.X;
                        var dy43 = u.p.Y - t.p.Y;
                        var dx21 = v2.p.X - v1.p.X;
                        var dy21 = v2.p.Y - v1.p.Y;
                        var ua_n = dx43 * dy13 - dy43 * dx13;
                        var ub_n = dx21 * dy13 - dy21 * dx13;
                        var u_d  = dy43 * dx21 - dx43 * dy21;

                        if (Math.Abs(u_d) < element.Epsilon)
                        {
                            // parallel
                            if (Math.Abs(ua_n) < element.Epsilon)
                            {
                                // colinear
                                if (Math.Max(t.p.X, u.p.X) >= v_min_x && Math.Min(t.p.X, u.p.X) <= v_max_x)
                                {
                                    // colinear and intersecting
                                    intersected = true;
                                }
                            }
                        }
                        else
                        {
                            // not parallel
                            var ua = ua_n / u_d;
                            var ub = ub_n / u_d;

                            if (0 <= ua && ua <= 1 && 0 <= ub && ub <= 1)
                            {
                                intersected = true;
                            }
                        }
                    }

                    if (!intersected)
                    {
                        // test whether midpoint winding == 1

                        var mid = (v1.p + v2.p) / 2;
                        if (windingNumber(begin, mid) == 1)
                        {
                            // this diagonal is ok
                            return(true);
                        }
                    }
                }

                // couldn't find a diagonal from v1 that was ok.
                v1 = v1.next;
            } while (v1 != begin);
            return(false);
        }
Ejemplo n.º 12
0
        static int removeDegeneracies(ref vertex_info begin, FList <TriIdx> result)
        {
            vertex_info v;
            vertex_info n;
            int         count  = 0;
            int         remain = 0;

            v = begin;
            do
            {
                v = v.next;
                ++remain;
            } while (v != begin);

            v = begin;
            do
            {
                if (remain < 4)
                {
                    break;
                }

                bool remove = false;
                if (v.p == v.next.p)
                {
                    remove = true;
                }
                else if (v.p == v.next.next.p)
                {
                    if (v.next.p == v.next.next.next.p)
                    {
                        // a 'z' in the loop: z (a) b a b c . remove a-b-a . z (a) a b c . remove a-a-b (next loop) . z a b c
                        // z --(a)-- b
                        //         /
                        //        /
                        //      a -- b -- d
                        remove = true;
                    }
                    else
                    {
                        // a 'shard' in the loop: z (a) b a c d . remove a-b-a . z (a) a b c d . remove a-a-b (next loop) . z a b c d
                        // z --(a)-- b
                        //         /
                        //        /
                        //      a -- c -- d
                        // n.b. can only do this if the shard is pointing out of the polygon. i.e. b is outside z-a-c
                        remove = !internalToAngle(v.next.next.next, v, v.prev, v.next.p);
                    }
                }

                if (remove)
                {
                    result.Add(new TriIdx(v.idx, v.next.idx, v.next.next.idx));
                    n = v.next;
                    if (n == begin)
                    {
                        begin = n.next;
                    }
                    n.remove();
                    count++;
                    remain--;
                }
                else
                {
                    v = v.next;
                }
            } while (v != begin);

            return(count);
        }
Ejemplo n.º 13
0
 static bool pointInTriangle(vertex_info a, vertex_info b, vertex_info c, vertex_info d)
 {
     return(!isLeft(a, c, d) && !isLeft(b, a, d) && !isLeft(c, b, d));
 }
Ejemplo n.º 14
0
 public void push(vertex_info v)
 {
     queue.Push(v);
 }
Ejemplo n.º 15
0
        static bool doTriangulate(vertex_info begin, FList <TriIdx> result)
        {
            var vq = new EarQueue();

            var v      = begin;
            int remain = 0;

            do
            {
                if (v.isCandidate())
                {
                    vq.push(v);
                }
                v = v.next;
                remain++;
            } while (v != begin);

            while (remain > 3 && vq.size() != 0)
            {
                var v2 = vq.pop();
                if (!v2.isClipable())
                {
                    v2.failed = true;
                    continue;
                }

continue_clipping:
                var n = v2.next;
                var p = v2.prev;

                result.Add(new TriIdx(v2.prev.idx, v2.idx, v2.next.idx));

                v2.remove();
                if (v2 == begin)
                {
                    begin = v2.next;
                }

                if (--remain == 3)
                {
                    break;
                }

                vq.updateVertex(n);
                vq.updateVertex(p);

                if (n.score < p.score)
                {
                    var t = n;
                    n = p;
                    p = t;
                }

                if (n.score > 0.25 && n.isCandidate() && n.isClipable())
                {
                    vq.remove(n);
                    v2 = n;
                    goto continue_clipping;
                }

                if (p.score > 0.25 && p.isCandidate() && p.isClipable())
                {
                    vq.remove(p);
                    v2 = p;
                    goto continue_clipping;
                }
            }


            if (remain > 3)
            {
                remain -= removeDegeneracies(ref begin, result);

                if (remain > 3)
                {
                    return(splitAndResume(begin, result));
                }
            }

            if (remain == 3)
            {
                result.Add(new TriIdx(begin.idx, begin.next.idx, begin.next.next.idx));
            }

            var d = begin;

            do
            {
                var n = d.next;
                d = n;
            } while (d != begin);

            return(true);
        }