--- /dev/null
+/*
+ * File: cutils.h
+ * Author: user
+ *
+ * Created on 28 מאי 2011, 02:24
+ */
+
+#ifndef CUTILS_H
+#define CUTILS_H
+
+#include <glib.h>
+#include "poly2tri-private.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define DEBUG FALSE
+
+ typedef GPtrArray* P2tEdgePtrArray;
+#define edge_index(array,index_) ((P2tEdge*)g_ptr_array_index(array,index_))
+ typedef GPtrArray* P2tPointPtrArray;
+#define point_index(array,index_) ((P2tPoint*)g_ptr_array_index(array,index_))
+ typedef GPtrArray* P2tTrianglePtrArray;
+#define triangle_index(array,index_) ((P2tTriangle*)g_ptr_array_index(array,index_))
+ typedef GPtrArray* P2tNodePtrArray;
+#define node_index(array,index_) ((P2tNode*)g_ptr_array_index(array,index_))
+ typedef GList* P2tTrianglePtrList;
+#define triangle_val(list) ((P2tTriangle*)((list)->data))
+
+#define g_ptr_array_index_cyclic(array,index_) g_ptr_array_index(array,(index_)%((array)->len))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CUTILS_H */
+
--- /dev/null
+/*
+ * File: poly2tri-private.h
+ * Author: user
+ *
+ * Created on 4 יוני 2011, 13:22
+ */
+
+#ifndef POLY2TRI_PRIVATE_H
+#define POLY2TRI_PRIVATE_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef struct _P2tNode P2tNode;
+typedef struct AdvancingFront_ P2tAdvancingFront;
+typedef struct CDT_ P2tCDT;
+typedef struct _P2tEdge P2tEdge;
+typedef struct _P2tPoint P2tPoint;
+typedef struct _P2tTriangle P2tTriangle;
+typedef struct SweepContext_ P2tSweepContext;
+typedef struct Sweep_ P2tSweep;
+
+typedef struct P2tSweepContextBasin_ P2tSweepContextBasin;
+typedef struct P2tSweepContextEdgeEvent_ P2tSweepContextEdgeEvent;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* POLY2TRI_PRIVATE_H */
+
--- /dev/null
+/*
+ * This file is a part of Poly2Tri-C - The C port of the Poly2Tri library
+ * Porting to C done by (c) Barak Itkin <lightningismyname@gmail.com>
+ * http://code.google.com/p/poly2tri-c/
+ *
+ * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
+ * http://code.google.com/p/poly2tri/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Poly2Tri nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "shapes.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+/// Default constructor does nothing (for performance).
+
+void
+p2t_point_init (P2tPoint* THIS)
+{
+ THIS->x = 0;
+ THIS->y = 0;
+ THIS->edge_list = g_ptr_array_new ();
+}
+
+P2tPoint*
+p2t_point_new ()
+{
+ P2tPoint* THIS = g_slice_new (P2tPoint);
+ p2t_point_init (THIS);
+ return THIS;
+}
+
+/// Construct using coordinates.
+
+void
+p2t_point_init_dd (P2tPoint* THIS, double x, double y)
+{
+ THIS->x = x;
+ THIS->y = y;
+ THIS->edge_list = g_ptr_array_new ();
+}
+
+P2tPoint*
+p2t_point_new_dd (double x, double y)
+{
+ P2tPoint* THIS = g_slice_new (P2tPoint);
+ p2t_point_init_dd (THIS, x, y);
+ return THIS;
+}
+
+void
+p2t_point_destroy (P2tPoint* THIS)
+{
+ g_ptr_array_free (THIS->edge_list, TRUE);
+}
+
+void
+p2t_point_free (P2tPoint* THIS)
+{
+ p2t_point_destroy (THIS);
+ g_slice_free (P2tPoint, THIS);
+}
+
+/// Constructor
+
+void
+p2t_edge_init (P2tEdge* THIS, P2tPoint* p1, P2tPoint* p2)
+{
+ THIS->p = p1;
+ THIS->q = p2;
+ if (p1->y > p2->y)
+ {
+ THIS->q = p1;
+ THIS->p = p2;
+ }
+ else if (p1->y == p2->y)
+ {
+ if (p1->x > p2->x)
+ {
+ THIS->q = p1;
+ THIS->p = p2;
+ }
+ else if (p1->x == p2->x)
+ {
+ // Repeat points
+ assert (FALSE);
+ }
+ }
+
+ g_ptr_array_add (THIS->q->edge_list, THIS);
+}
+
+P2tEdge*
+p2t_edge_new (P2tPoint* p1, P2tPoint* p2)
+{
+ P2tEdge* THIS = g_slice_new (P2tEdge);
+ p2t_edge_init (THIS, p1, p2);
+ return THIS;
+}
+
+void
+p2t_edge_destroy (P2tEdge* THIS) { }
+
+void
+p2t_edge_free (P2tEdge* THIS)
+{
+ p2t_edge_destroy (THIS);
+ g_slice_free (P2tEdge, THIS);
+}
+
+P2tTriangle*
+p2t_triangle_new (P2tPoint* a, P2tPoint* b, P2tPoint* c)
+{
+ P2tTriangle *tr = g_new (P2tTriangle, 1);
+ p2t_triangle_init (tr, a, b, c);
+ return tr;
+}
+
+void
+p2t_triangle_init (P2tTriangle* THIS, P2tPoint* a, P2tPoint* b, P2tPoint* c)
+{
+ THIS->points_[0] = a;
+ THIS->points_[1] = b;
+ THIS->points_[2] = c;
+ THIS->neighbors_[0] = NULL;
+ THIS->neighbors_[1] = NULL;
+ THIS->neighbors_[2] = NULL;
+ THIS->constrained_edge[0] = THIS->constrained_edge[1] = THIS->constrained_edge[2] = FALSE;
+ THIS->delaunay_edge[0] = THIS->delaunay_edge[1] = THIS->delaunay_edge[2] = FALSE;
+ THIS->interior_ = FALSE;
+
+}
+// Update neighbor pointers
+
+void
+p2t_triangle_mark_neighbor_pt_pt_tr (P2tTriangle* THIS, P2tPoint* p1, P2tPoint* p2, P2tTriangle* t)
+{
+ if ((p1 == THIS->points_[2] && p2 == THIS->points_[1]) || (p1 == THIS->points_[1] && p2 == THIS->points_[2]))
+ THIS->neighbors_[0] = t;
+ else if ((p1 == THIS->points_[0] && p2 == THIS->points_[2]) || (p1 == THIS->points_[2] && p2 == THIS->points_[0]))
+ THIS->neighbors_[1] = t;
+ else if ((p1 == THIS->points_[0] && p2 == THIS->points_[1]) || (p1 == THIS->points_[1] && p2 == THIS->points_[0]))
+ THIS->neighbors_[2] = t;
+ else
+ assert (0);
+}
+
+// Exhaustive search to update neighbor pointers
+
+void
+p2t_triangle_mark_neighbor_tr (P2tTriangle* THIS, P2tTriangle *t)
+{
+ if (p2t_triangle_contains_pt_pt (t, THIS->points_[1], THIS->points_[2]))
+ {
+ THIS->neighbors_[0] = t;
+ p2t_triangle_mark_neighbor_pt_pt_tr (t, THIS->points_[1], THIS->points_[2], THIS);
+ }
+ else if (p2t_triangle_contains_pt_pt (t, THIS->points_[0], THIS->points_[2]))
+ {
+ THIS->neighbors_[1] = t;
+ p2t_triangle_mark_neighbor_pt_pt_tr (t, THIS->points_[0], THIS->points_[2], THIS);
+ }
+ else if (p2t_triangle_contains_pt_pt (t, THIS->points_[0], THIS->points_[1]))
+ {
+ THIS->neighbors_[2] = t;
+ p2t_triangle_mark_neighbor_pt_pt_tr (t, THIS->points_[0], THIS->points_[1], THIS);
+ }
+}
+
+/**
+ * Clears all references to all other triangles and points
+ */
+void
+p2t_triangle_clear (P2tTriangle* THIS)
+{
+ int i;
+ P2tTriangle *t;
+ for (i = 0; i < 3; i++)
+ {
+ t = THIS->neighbors_[i];
+ if (t != NULL)
+ {
+ p2t_triangle_clear_neighbor_tr (t, THIS);
+ }
+ }
+ p2t_triangle_clear_neighbors (THIS);
+ THIS->points_[0] = THIS->points_[1] = THIS->points_[2] = NULL;
+}
+
+void
+p2t_triangle_clear_neighbor_tr (P2tTriangle* THIS, P2tTriangle *triangle)
+{
+ if (THIS->neighbors_[0] == triangle)
+ {
+ THIS->neighbors_[0] = NULL;
+ }
+ else if (THIS->neighbors_[1] == triangle)
+ {
+ THIS->neighbors_[1] = NULL;
+ }
+ else
+ {
+ THIS->neighbors_[2] = NULL;
+ }
+}
+
+void
+p2t_triangle_clear_neighbors (P2tTriangle* THIS)
+{
+ THIS->neighbors_[0] = NULL;
+ THIS->neighbors_[1] = NULL;
+ THIS->neighbors_[2] = NULL;
+}
+
+void
+p2t_triangle_clear_delunay_edges (P2tTriangle* THIS)
+{
+ THIS->delaunay_edge[0] = THIS->delaunay_edge[1] = THIS->delaunay_edge[2] = FALSE;
+}
+
+P2tPoint*
+p2t_triangle_opposite_point (P2tTriangle* THIS, P2tTriangle* t, P2tPoint* p)
+{
+ P2tPoint *cw = p2t_triangle_point_cw (t, p);
+ double x = cw->x;
+ double y = cw->y;
+ x = p->x;
+ y = p->y;
+ P2tPoint* ham = p2t_triangle_point_cw (THIS, cw);
+ return p2t_triangle_point_cw (THIS, cw);
+}
+
+// Legalized triangle by rotating clockwise around point(0)
+
+void
+p2t_triangle_legalize_pt (P2tTriangle* THIS, P2tPoint *point)
+{
+ THIS->points_[1] = THIS->points_[0];
+ THIS->points_[0] = THIS->points_[2];
+ THIS->points_[2] = point;
+}
+
+// Legalize triagnle by rotating clockwise around oPoint
+
+void
+p2t_triangle_legalize_pt_pt (P2tTriangle* THIS, P2tPoint *opoint, P2tPoint *npoint)
+{
+ if (opoint == THIS->points_[0])
+ {
+ THIS->points_[1] = THIS->points_[0];
+ THIS->points_[0] = THIS->points_[2];
+ THIS->points_[2] = npoint;
+ }
+ else if (opoint == THIS->points_[1])
+ {
+ THIS->points_[2] = THIS->points_[1];
+ THIS->points_[1] = THIS->points_[0];
+ THIS->points_[0] = npoint;
+ }
+ else if (opoint == THIS->points_[2])
+ {
+ THIS->points_[0] = THIS->points_[2];
+ THIS->points_[2] = THIS->points_[1];
+ THIS->points_[1] = npoint;
+ }
+ else
+ {
+ assert (0);
+ }
+}
+
+int
+p2t_triangle_index (P2tTriangle* THIS, const P2tPoint* p)
+{
+ if (p == THIS->points_[0])
+ {
+ return 0;
+ }
+ else if (p == THIS->points_[1])
+ {
+ return 1;
+ }
+ else if (p == THIS->points_[2])
+ {
+ return 2;
+ }
+ assert (0);
+}
+
+int
+p2t_triangle_edge_index (P2tTriangle* THIS, const P2tPoint* p1, const P2tPoint* p2)
+{
+ if (THIS->points_[0] == p1)
+ {
+ if (THIS->points_[1] == p2)
+ {
+ return 2;
+ }
+ else if (THIS->points_[2] == p2)
+ {
+ return 1;
+ }
+ }
+ else if (THIS->points_[1] == p1)
+ {
+ if (THIS->points_[2] == p2)
+ {
+ return 0;
+ }
+ else if (THIS->points_[0] == p2)
+ {
+ return 2;
+ }
+ }
+ else if (THIS->points_[2] == p1)
+ {
+ if (THIS->points_[0] == p2)
+ {
+ return 1;
+ }
+ else if (THIS->points_[1] == p2)
+ {
+ return 0;
+ }
+ }
+ return -1;
+}
+
+void
+p2t_triangle_mark_constrained_edge_i (P2tTriangle* THIS, const int index)
+{
+ THIS->constrained_edge[index] = TRUE;
+}
+
+void
+p2t_triangle_mark_constrained_edge_ed (P2tTriangle* THIS, P2tEdge* edge)
+{
+ p2t_triangle_mark_constrained_edge_pt_pt (THIS, edge->p, edge->q);
+}
+
+// Mark edge as constrained
+
+void
+p2t_triangle_mark_constrained_edge_pt_pt (P2tTriangle* THIS, P2tPoint* p, P2tPoint* q)
+{
+ if ((q == THIS->points_[0] && p == THIS->points_[1]) || (q == THIS->points_[1] && p == THIS->points_[0]))
+ {
+ THIS->constrained_edge[2] = TRUE;
+ }
+ else if ((q == THIS->points_[0] && p == THIS->points_[2]) || (q == THIS->points_[2] && p == THIS->points_[0]))
+ {
+ THIS->constrained_edge[1] = TRUE;
+ }
+ else if ((q == THIS->points_[1] && p == THIS->points_[2]) || (q == THIS->points_[2] && p == THIS->points_[1]))
+ {
+ THIS->constrained_edge[0] = TRUE;
+ }
+}
+
+// The point counter-clockwise to given point
+
+P2tPoint*
+p2t_triangle_point_cw (P2tTriangle* THIS, P2tPoint* point)
+{
+ if (point == THIS->points_[0])
+ {
+ return THIS->points_[2];
+ }
+ else if (point == THIS->points_[1])
+ {
+ return THIS->points_[0];
+ }
+ else if (point == THIS->points_[2])
+ {
+ return THIS->points_[1];
+ }
+ assert (0);
+}
+
+// The point counter-clockwise to given point
+
+P2tPoint*
+p2t_triangle_point_ccw (P2tTriangle* THIS, P2tPoint* point)
+{
+ if (point == THIS->points_[0])
+ {
+ return THIS->points_[1];
+ }
+ else if (point == THIS->points_[1])
+ {
+ return THIS->points_[2];
+ }
+ else if (point == THIS->points_[2])
+ {
+ return THIS->points_[0];
+ }
+ assert (0);
+}
+
+// The neighbor clockwise to given point
+
+P2tTriangle*
+p2t_triangle_neighbor_cw (P2tTriangle* THIS, P2tPoint* point)
+{
+ if (point == THIS->points_[0])
+ {
+ return THIS->neighbors_[1];
+ }
+ else if (point == THIS->points_[1])
+ {
+ return THIS->neighbors_[2];
+ }
+ return THIS->neighbors_[0];
+}
+
+// The neighbor counter-clockwise to given point
+
+P2tTriangle*
+p2t_triangle_neighbor_ccw (P2tTriangle* THIS, P2tPoint* point)
+{
+ if (point == THIS->points_[0])
+ {
+ return THIS->neighbors_[2];
+ }
+ else if (point == THIS->points_[1])
+ {
+ return THIS->neighbors_[0];
+ }
+ return THIS->neighbors_[1];
+}
+
+gboolean
+p2t_triangle_get_constrained_edge_ccw (P2tTriangle* THIS, P2tPoint* p)
+{
+ if (p == THIS->points_[0])
+ {
+ return THIS->constrained_edge[2];
+ }
+ else if (p == THIS->points_[1])
+ {
+ return THIS->constrained_edge[0];
+ }
+ return THIS->constrained_edge[1];
+}
+
+gboolean
+p2t_triangle_get_constrained_edge_cw (P2tTriangle* THIS, P2tPoint* p)
+{
+ if (p == THIS->points_[0])
+ {
+ return THIS->constrained_edge[1];
+ }
+ else if (p == THIS->points_[1])
+ {
+ return THIS->constrained_edge[2];
+ }
+ return THIS->constrained_edge[0];
+}
+
+void
+p2t_triangle_set_constrained_edge_ccw (P2tTriangle* THIS, P2tPoint* p, gboolean ce)
+{
+ if (p == THIS->points_[0])
+ {
+ THIS->constrained_edge[2] = ce;
+ }
+ else if (p == THIS->points_[1])
+ {
+ THIS->constrained_edge[0] = ce;
+ }
+ else
+ {
+ THIS->constrained_edge[1] = ce;
+ }
+}
+
+void
+p2t_triangle_set_constrained_edge_cw (P2tTriangle* THIS, P2tPoint* p, gboolean ce)
+{
+ if (p == THIS->points_[0])
+ {
+ THIS->constrained_edge[1] = ce;
+ }
+ else if (p == THIS->points_[1])
+ {
+ THIS->constrained_edge[2] = ce;
+ }
+ else
+ {
+ THIS->constrained_edge[0] = ce;
+ }
+}
+
+gboolean
+p2t_triangle_get_delunay_edge_ccw (P2tTriangle* THIS, P2tPoint* p)
+{
+ if (p == THIS->points_[0])
+ {
+ return THIS->delaunay_edge[2];
+ }
+ else if (p == THIS->points_[1])
+ {
+ return THIS->delaunay_edge[0];
+ }
+ return THIS->delaunay_edge[1];
+}
+
+gboolean
+p2t_triangle_get_delunay_edge_cw (P2tTriangle* THIS, P2tPoint* p)
+{
+ if (p == THIS->points_[0])
+ {
+ return THIS->delaunay_edge[1];
+ }
+ else if (p == THIS->points_[1])
+ {
+ return THIS->delaunay_edge[2];
+ }
+ return THIS->delaunay_edge[0];
+}
+
+void
+p2t_triangle_set_delunay_edge_ccw (P2tTriangle* THIS, P2tPoint* p, gboolean e)
+{
+ if (p == THIS->points_[0])
+ {
+ THIS->delaunay_edge[2] = e;
+ }
+ else if (p == THIS->points_[1])
+ {
+ THIS->delaunay_edge[0] = e;
+ }
+ else
+ {
+ THIS->delaunay_edge[1] = e;
+ }
+}
+
+void
+p2t_triangle_set_delunay_edge_cw (P2tTriangle* THIS, P2tPoint* p, gboolean e)
+{
+ if (p == THIS->points_[0])
+ {
+ THIS->delaunay_edge[1] = e;
+ }
+ else if (p == THIS->points_[1])
+ {
+ THIS->delaunay_edge[2] = e;
+ }
+ else
+ {
+ THIS->delaunay_edge[0] = e;
+ }
+}
+
+// The neighbor across to given point
+
+P2tTriangle*
+p2t_triangle_neighbor_across (P2tTriangle* THIS, P2tPoint* opoint)
+{
+ if (opoint == THIS->points_[0])
+ {
+ return THIS->neighbors_[0];
+ }
+ else if (opoint == THIS->points_[1])
+ {
+ return THIS->neighbors_[1];
+ }
+ return THIS->neighbors_[2];
+}
+
+void
+p2t_triangle_debug_print (P2tTriangle* THIS)
+{
+ printf ("%f,%f ", THIS->points_[0]->x, THIS->points_[0]->y);
+ printf ("%f,%f ", THIS->points_[1]->x, THIS->points_[1]->y);
+ printf ("%f,%f\n", THIS->points_[2]->x, THIS->points_[2]->y);
+}
+
+// WARNING! the function for sorting a g_ptr_array expects to recieve
+// pointers to the pointers (double indirection)!
+
+gint
+p2t_point_cmp (gconstpointer a, gconstpointer b)
+{
+ P2tPoint *ap = *((P2tPoint**) a), *bp = *((P2tPoint**) b);
+ if (ap->y < bp->y)
+ {
+ return -1;
+ }
+ else if (ap->y == bp->y)
+ {
+ // Make sure q is point with greater x value
+ if (ap->x < bp->x)
+ {
+ return -1;
+ }
+ else if (ap->x == bp->x)
+ return 0;
+ }
+ return 1;
+}
+
+// /// Add two points_ component-wise.
+//
+// Point operator + (const Point& a, const Point& b)
+// {
+// return Point (a.x + b.x, a.y + b.y);
+// }
+//
+// /// Subtract two points_ component-wise.
+//
+// Point operator - (const Point& a, const Point& b)
+// {
+// return Point (a.x - b.x, a.y - b.y);
+// }
+//
+// /// Multiply point by scalar
+//
+// Point operator * (double s, const Point& a)
+// {
+// return Point (s * a.x, s * a.y);
+// }
+
+// gboolean operator == (const Point& a, const Point& b)
+
+gboolean
+p2t_point_equals (const P2tPoint* a, const P2tPoint* b)
+{
+ return a->x == b->x && a->y == b->y;
+}
+//
+// gboolean operator != (const Point& a, const Point& b)
+// {
+// return a.x != b.x && a.y != b.y;
+// }
+
+// /// Peform the dot product on two vectors.
+//
+// double
+// Dot (const Point& a, const Point& b)
+// {
+// return a.x * b.x + a.y * b.y;
+// }
+//
+// /// Perform the cross product on two vectors. In 2D this produces a scalar.
+//
+// double
+// Cross (const Point& a, const Point& b)
+// {
+// return a.x * b.y - a.y * b.x;
+// }
+//
+// /// Perform the cross product on a point and a scalar. In 2D this produces
+// /// a point.
+//
+// Point
+// Cross (const Point& a, double s)
+// {
+// return Point (s * a.y, -s * a.x);
+// }
+//
+// /// Perform the cross product on a scalar and a point. In 2D this produces
+// /// a point.
+//
+// Point
+// Cross (const double s, const Point& a)
+// {
+// return Point (-s * a.y, s * a.x);
+// }
+
+P2tPoint*
+p2t_triangle_get_point (P2tTriangle* THIS, const int index)
+{
+ return THIS->points_[index];
+}
+
+P2tTriangle*
+p2t_triangle_get_neighbor (P2tTriangle* THIS, const int index)
+{
+ return THIS->neighbors_[index];
+}
+
+gboolean
+p2t_triangle_contains_pt (P2tTriangle* THIS, P2tPoint* p)
+{
+ return p == THIS->points_[0] || p == THIS->points_[1] || p == THIS->points_[2];
+}
+
+gboolean
+p2t_triangle_contains_ed (P2tTriangle* THIS, const P2tEdge* e)
+{
+ return p2t_triangle_contains_pt (THIS, e->p) && p2t_triangle_contains_pt (THIS, e->q);
+}
+
+gboolean
+p2t_triangle_contains_pt_pt (P2tTriangle* THIS, P2tPoint* p, P2tPoint* q)
+{
+ return p2t_triangle_contains_pt (THIS, p) && p2t_triangle_contains_pt (THIS, q);
+}
+
+gboolean
+p2t_triangle_is_interior (P2tTriangle* THIS)
+{
+ return THIS->interior_;
+}
+
+void
+p2t_triangle_is_interior_b (P2tTriangle* THIS, gboolean b)
+{
+ THIS->interior_ = b;
+}
--- /dev/null
+/*
+ * This file is a part of Poly2Tri-C - The C port of the Poly2Tri library
+ * Porting to C done by (c) Barak Itkin <lightningismyname@gmail.com>
+ * http://code.google.com/p/poly2tri-c/
+ *
+ * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
+ * http://code.google.com/p/poly2tri/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Poly2Tri nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SHAPES_H__
+#define __SHAPES_H__
+
+#include <stddef.h>
+#include <assert.h>
+#include <math.h>
+#include "poly2tri-private.h"
+#include "cutils.h"
+
+/**
+ * P2tPoint:
+ * @x: The x coordinate of the point
+ * @y: The y coordinate of the point
+ * @edge_list: The edges this point constitutes an upper ending point
+ *
+ * A struct to represent 2D points with double precision, and to keep track
+ * of the edges this point constitutes an upper ending point
+ */
+struct _P2tPoint
+{
+ /*< public >*/
+ P2tEdgePtrArray edge_list;
+ double x, y;
+};
+
+/**
+ * p2t_point_init_dd:
+ * @THIS: The #P2tPoint to initialize
+ * @x: The desired x coordinate of the point
+ * @y: The desired y coordinate of the point
+ *
+ * A function to initialize a #P2tPoint struct with the given coordinates. The
+ * struct must later be finalized by a call to #p2t_point_destroy
+ */
+void p2t_point_init_dd (P2tPoint* THIS, double x, double y);
+
+/**
+ * p2t_point_new_dd:
+ * @x: The desired x coordinate of the point
+ * @y: The desired y coordinate of the point
+ *
+ * A utility function to alloacte and initialize a #P2tPoint.
+ * See #p2t_point_init_dd. Note that when finished using the point, it must be
+ * freed by a call to #p2t_point_free and can not be freed like regular memory.
+ *
+ * Returns: The allocated and initialized point
+ */
+P2tPoint* p2t_point_new_dd (double x, double y);
+
+/**
+ * p2t_point_init:
+ * @THIS: The #P2tPoint to initialize
+ *
+ * A function to initialize a #P2tPoint struct to (0,0). The struct must later
+ * be finalized by a call to #p2t_point_destroy
+ */
+void p2t_point_init (P2tPoint* THIS);
+
+/**
+ * p2t_point_new:
+ *
+ * A utility function to alloacte and initialize a #P2tPoint.
+ * See #p2t_point_init. Note that when finished using the point, it must be
+ * freed by a call to #p2t_point_free and can not be freed like regular memory.
+ */
+P2tPoint* p2t_point_new ();
+
+/**
+ * p2t_point_destroy:
+ * @THIS: The #P2tPoint whose resources should be freed
+ *
+ * This function will free all the resources allocated by a #P2tPoint, without
+ * freeing the #P2tPoint pointed by @THIS
+ */
+void p2t_point_destroy (P2tPoint* THIS);
+
+/**
+ * p2t_point_free:
+ * @THIS: The #P2tPoint to free
+ *
+ * This function will free all the resources allocated by a #P2tPoint, and will
+ * also free the #P2tPoint pointed by @THIS
+ */
+void p2t_point_free (P2tPoint* THIS);
+
+/**
+ * P2tEdge:
+ * @p: The top right point of the edge
+ * @q: The bottom left point of the edge
+ *
+ * Represents a simple polygon's edge
+ */
+struct _P2tEdge
+{
+ P2tPoint *p, *q;
+};
+
+/**
+ * p2t_edge_init:
+ * @THIS: The #P2tEdge to initialize
+ * @p1: One of the two points that form the edge
+ * @p2: The other point of the two points that form the edge
+ *
+ * A function to initialize a #P2tEdge struct from the given points. The
+ * struct must later be finalized by a call to #p2t_point_destroy.
+ *
+ * Warning: The points must be geometrically not-equal! This means that they
+ * must differ by at least one of their coordinates. Otherwise, a runtime error
+ * would be raised!
+ */
+void p2t_edge_init (P2tEdge* THIS, P2tPoint* p1, P2tPoint* p2);
+
+/**
+ * p2t_edge_new:
+ *
+ * A utility function to alloacte and initialize a #P2tEdge.
+ * See #p2t_edge_init. Note that when finished using the point, it must be freed
+ * by a call to #p2t_point_free and can not be freed like regular memory.
+ *
+ * Returns: The allocated and initialized edge
+ */
+P2tEdge* p2t_edge_new (P2tPoint* p1, P2tPoint* p2);
+
+/**
+ * p2t_edge_destroy:
+ * @THIS: The #P2tEdge whose resources should be freed
+ *
+ * This function will free all the resources allocated by a #P2tEdge, without
+ * freeing the #P2tPoint pointed by @THIS
+ */
+void p2t_edge_destroy (P2tEdge* THIS);
+
+/**
+ * p2t_edge_free:
+ * @THIS: The #P2tEdge to free
+ *
+ * This function will free all the resources allocated by a #P2tEdge, and will
+ * also free the #P2tEdge pointed by @THIS
+ */
+void p2t_edge_free (P2tEdge* THIS);
+
+
+/* Triangle-based data structures are know to have better performance than quad-edge structures
+ * See: J. Shewchuk, "Triangle: Engineering a 2D Quality Mesh Generator and Delaunay Triangulator"
+ * "Triangulations in CGAL"
+ */
+
+/**
+ * P2tTriangle:
+ * @constrained_edge: Flags to determine if an edge is a Constrained edge
+ * @delaunay_edg: Flags to determine if an edge is a Delauney edge
+ * @points_: Triangle points
+ * @neighbors_: Neighbor list
+ * @interior_: Has this triangle been marked as an interior triangle?
+ *
+ * A data structure for representing a triangle, while keeping information about
+ * neighbor triangles, etc.
+ */
+struct _P2tTriangle
+{
+ /*< public >*/
+ gboolean constrained_edge[3];
+ gboolean delaunay_edge[3];
+
+ /*< private >*/
+ P2tPoint * points_[3];
+ struct _P2tTriangle * neighbors_[3];
+ gboolean interior_;
+};
+
+P2tTriangle* p2t_triangle_new (P2tPoint* a, P2tPoint* b, P2tPoint* c);
+void p2t_triangle_init (P2tTriangle* THIS, P2tPoint* a, P2tPoint* b, P2tPoint* c);
+P2tPoint* p2t_triangle_get_point (P2tTriangle* THIS, const int index);
+P2tPoint* p2t_triangle_point_cw (P2tTriangle* THIS, P2tPoint* point);
+P2tPoint* p2t_triangle_point_ccw (P2tTriangle* THIS, P2tPoint* point);
+P2tPoint* p2t_triangle_opposite_point (P2tTriangle* THIS, P2tTriangle* t, P2tPoint* p);
+
+P2tTriangle* p2t_triangle_get_neighbor (P2tTriangle* THIS, const int index);
+void p2t_triangle_mark_neighbor_pt_pt_tr (P2tTriangle* THIS, P2tPoint* p1, P2tPoint* p2, P2tTriangle* t);
+void p2t_triangle_mark_neighbor_tr (P2tTriangle* THIS, P2tTriangle *t);
+
+void p2t_triangle_mark_constrained_edge_i (P2tTriangle* THIS, const int index);
+void p2t_triangle_mark_constrained_edge_ed (P2tTriangle* THIS, P2tEdge* edge);
+void p2t_triangle_mark_constrained_edge_pt_pt (P2tTriangle* THIS, P2tPoint* p, P2tPoint* q);
+
+int p2t_triangle_index (P2tTriangle* THIS, const P2tPoint* p);
+int p2t_triangle_edge_index (P2tTriangle* THIS, const P2tPoint* p1, const P2tPoint* p2);
+
+P2tTriangle* p2t_triangle_neighbor_cw (P2tTriangle* THIS, P2tPoint* point);
+P2tTriangle* p2t_triangle_neighbor_ccw (P2tTriangle* THIS, P2tPoint* point);
+gboolean p2t_triangle_get_constrained_edge_ccw (P2tTriangle* THIS, P2tPoint* p);
+gboolean p2t_triangle_get_constrained_edge_cw (P2tTriangle* THIS, P2tPoint* p);
+void p2t_triangle_set_constrained_edge_ccw (P2tTriangle* THIS, P2tPoint* p, gboolean ce);
+void p2t_triangle_set_constrained_edge_cw (P2tTriangle* THIS, P2tPoint* p, gboolean ce);
+gboolean p2t_triangle_get_delunay_edge_ccw (P2tTriangle* THIS, P2tPoint* p);
+gboolean p2t_triangle_get_delunay_edge_cw (P2tTriangle* THIS, P2tPoint* p);
+void p2t_triangle_set_delunay_edge_ccw (P2tTriangle* THIS, P2tPoint* p, gboolean e);
+void p2t_triangle_set_delunay_edge_cw (P2tTriangle* THIS, P2tPoint* p, gboolean e);
+
+gboolean p2t_triangle_contains_pt (P2tTriangle* THIS, P2tPoint* p);
+gboolean p2t_triangle_contains_ed (P2tTriangle* THIS, const P2tEdge* e);
+gboolean p2t_triangle_contains_pt_pt (P2tTriangle* THIS, P2tPoint* p, P2tPoint* q);
+void p2t_triangle_legalize_pt (P2tTriangle* THIS, P2tPoint* point);
+void p2t_triangle_legalize_pt_pt (P2tTriangle* THIS, P2tPoint* opoint, P2tPoint* npoint);
+/**
+ * Clears all references to all other triangles and points
+ */
+void p2t_triangle_clear (P2tTriangle* THIS);
+void p2t_triangle_clear_neighbor_tr (P2tTriangle* THIS, P2tTriangle *triangle);
+void p2t_triangle_clear_neighbors (P2tTriangle* THIS);
+void p2t_triangle_clear_delunay_edges (P2tTriangle* THIS);
+
+gboolean p2t_triangle_is_interior (P2tTriangle* THIS);
+void p2t_triangle_is_interior_b (P2tTriangle* THIS, gboolean b);
+
+P2tTriangle* p2t_triangle_neighbor_across (P2tTriangle* THIS, P2tPoint* opoint);
+
+void p2t_triangle_debug_print (P2tTriangle* THIS);
+
+gint p2t_point_cmp (gconstpointer a, gconstpointer b);
+
+// gboolean operator == (const Point& a, const Point& b);
+gboolean p2t_point_equals (const P2tPoint* a, const P2tPoint* b);
+
+#endif
+
+
--- /dev/null
+
+/*
+ * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
+ * http://code.google.com/p/poly2tri/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Poly2Tri nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <math.h>
+#include "utils.h"
+
+/**
+ * Forumla to calculate signed area<br>
+ * Positive if CCW<br>
+ * Negative if CW<br>
+ * 0 if collinear<br>
+ * <pre>
+ * A[P1,P2,P3] = (x1*y2 - y1*x2) + (x2*y3 - y2*x3) + (x3*y1 - y3*x1)
+ * = (x1-x3)*(y2-y3) - (y1-y3)*(x2-x3)
+ * </pre>
+ */
+P2tOrientation
+p2t_orient2d (P2tPoint* pa, P2tPoint* pb, P2tPoint* pc)
+{
+ double detleft = (pa->x - pc->x) * (pb->y - pc->y);
+ double detright = (pa->y - pc->y) * (pb->x - pc->x);
+ double val = detleft - detright;
+ if (val > -EPSILON && val < EPSILON)
+ {
+ return COLLINEAR;
+ }
+ else if (val > 0)
+ {
+ return CCW;
+ }
+ return CW;
+}
+
+gboolean
+p2t_utils_in_scan_area (P2tPoint* pa, P2tPoint* pb, P2tPoint* pc, P2tPoint* pd)
+{
+ double pdx = pd->x;
+ double pdy = pd->y;
+ double adx = pa->x - pdx;
+ double ady = pa->y - pdy;
+ double bdx = pb->x - pdx;
+ double bdy = pb->y - pdy;
+
+ double adxbdy = adx * bdy;
+ double bdxady = bdx * ady;
+ double oabd = adxbdy - bdxady;
+
+ if (oabd <= EPSILON)
+ {
+ return FALSE;
+ }
+
+ double cdx = pc->x - pdx;
+ double cdy = pc->y - pdy;
+
+ double cdxady = cdx * ady;
+ double adxcdy = adx * cdy;
+ double ocad = cdxady - adxcdy;
+
+ if (ocad <= EPSILON)
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
--- /dev/null
+/* \r
+ * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors\r
+ * http://code.google.com/p/poly2tri/\r
+ *\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * * Redistributions of source code must retain the above copyright notice,\r
+ * this list of conditions and the following disclaimer.\r
+ * * Redistributions in binary form must reproduce the above copyright notice,\r
+ * this list of conditions and the following disclaimer in the documentation\r
+ * and/or other materials provided with the distribution.\r
+ * * Neither the name of Poly2Tri nor the names of its contributors may be\r
+ * used to endorse or promote products derived from this software without specific\r
+ * prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\r
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\r
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\r
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+\r
+#ifndef UTILS_H\r
+#define UTILS_H\r
+\r
+#include <glib.h>\r
+#include "poly2tri-private.h"\r
+#include "cutils.h"\r
+#include "shapes.h"\r
+\r
+#define PI_3div4 (3 * M_PI / 4)\r
+#define EPSILON (1e-6)\r
+\r
+typedef enum\r
+{\r
+ CW, CCW, COLLINEAR\r
+} P2tOrientation;\r
+\r
+/**\r
+ * Forumla to calculate signed area<br>\r
+ * Positive if CCW<br>\r
+ * Negative if CW<br>\r
+ * 0 if collinear<br>\r
+ * <pre>\r
+ * A[P1,P2,P3] = (x1*y2 - y1*x2) + (x2*y3 - y2*x3) + (x3*y1 - y3*x1)\r
+ * = (x1-x3)*(y2-y3) - (y1-y3)*(x2-x3)\r
+ * </pre>\r
+ */\r
+P2tOrientation p2t_orient2d (P2tPoint* pa, P2tPoint* pb, P2tPoint* pc);\r
+\r
+gboolean p2t_utils_in_scan_area (P2tPoint* pa, P2tPoint* pb, P2tPoint* pc, P2tPoint* pd);\r
+\r
+#endif\r
+\r
--- /dev/null
+/*
+ * Poly2Tri Copyright (c) 2009-2011, Poly2Tri Contributors
+ * http://code.google.com/p/poly2tri/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Poly2Tri nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <glib.h>
+
+#include "poly2tri.h"
+
+#include "refine/triangulation.h"
+#include "render/svg-plot.h"
+#include "refine/refine.h"
+
+#include "render/mesh-render.h"
+
+#include <string.h>
+
+
+static gint refine_max_steps = 1000;
+static gboolean debug_print = TRUE;
+static gboolean verbose = TRUE;
+static gchar *input_file = NULL;
+static gchar *output_file = NULL;
+
+static GOptionEntry entries[] =
+{
+ { "refine-max-steps", 'r', 0, G_OPTION_ARG_INT, &refine_max_steps, "Set maximal refinement steps to N", "N" },
+ { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Print output?", NULL },
+ { "debug", 'd', 0, G_OPTION_ARG_NONE, &debug_print, "Enable debug printing", NULL },
+ { "input", 'i', 0, G_OPTION_ARG_FILENAME, &input_file, "Use input file at FILE_IN", "FILE_IN" },
+ { "output", 'o', 0, G_OPTION_ARG_FILENAME, &output_file, "Use output file at FILE_OUT", "FILE_OUT" },
+ { NULL }
+};
+
+typedef gfloat Color3f[3];
+typedef gfloat Point2f[2];
+
+/**
+ * read_points_file:
+ * @path: The path to the points & colors file
+ * @points: An pointer to an array of pointers to #P2RrPoint will be returned
+ * here. NULL can be passed.
+ * @colors: An pointer to an array of colors will be returned here. NULL can be
+ * passed.
+ *
+ *
+ */
+void
+read_points_file (const gchar *path,
+ GPtrArray **points,
+ GArray **colors)
+{
+ FILE *f = fopen (path, "r");
+ gint countPts = 0, countCls = 0;
+
+ if (f == NULL)
+ {
+ g_print ("Error! Could not read input file!");
+ exit (1);
+ }
+
+ if (verbose)
+ g_print ("Now parsing \"%s\"\n", path);
+
+ if (points != NULL) *points = g_ptr_array_new ();
+ if (colors != NULL) *colors = g_array_new (FALSE, FALSE, sizeof (Color3f));
+
+ if (debug_print && points == NULL) g_print ("Points will not be kept\n");
+ if (debug_print && colors == NULL) g_print ("Colors will not be kept\n");
+
+ while (! feof (f))
+ {
+ Color3f col = { 0, 0, 0 };
+ Point2f ptc = { 0, 0 };
+ gboolean foundCol = FALSE, foundPt = FALSE;
+
+ /* Read only while we have valid points */
+ gint readSize = fscanf (f, "@ %f %f ", &ptc[0], &ptc[1]);
+
+ if (readSize > 0)
+ {
+ if (readSize != 2)
+ {
+ g_error ("Error! %d is an unexpected number of floats after point '@' declaration!\n", readSize);
+ exit (1);
+ }
+
+ foundPt = TRUE;
+
+ if (points != NULL)
+ {
+ g_ptr_array_add (*points, p2tr_point_new (ptc[0], ptc[1]));
+ countPts++;
+ }
+ }
+
+ readSize = fscanf (f, "# %f %f %f ", &col[0], &col[1], &col[2]);
+
+ if (readSize > 0)
+ {
+ if (readSize != 1 && readSize != 3)
+ {
+ g_error ("Error! %d is an unexpected number of floats after color '#' declaration!\n", readSize);
+ exit (1);
+ }
+
+ foundCol = TRUE;
+
+ /* Did we read Gray color information? */
+ if (readSize == 1)
+ col[1] = col[2] = col[0];
+
+ if (colors != NULL)
+ {
+ g_array_append_val (*colors, ptc);
+ countCls++;
+ }
+ }
+
+ if (!foundCol && !foundPt)
+ break;
+ }
+
+ fclose (f);
+
+ if (verbose)
+ g_print ("Read %d points and %d colors\n", countPts, countCls);
+}
+
+/* In order to find the maximal length of a filename path, most
+ * platforms have either the macro MAX_PATH, or PATH_MAX. This is a
+ * guess which tries them both */
+
+#ifdef MAX_PATH
+#define P2TC_MAX_PATH MAX_PATH
+#else
+#define P2TC_MAX_PATH PATH_MAX
+#endif
+
+gint main (int argc, char *argv[])
+{
+ FILE *out;
+ GError *error = NULL;
+ GOptionContext *context;
+
+ GPtrArray *pts;
+ GArray *colors;
+
+ P2tRTriangulation *T;
+
+ gint i;
+ gchar buf[P2TC_MAX_PATH+1];
+ gfloat *im;
+
+ context = g_option_context_new ("- Create a fine mesh from a given PSLG");
+ g_option_context_add_main_entries (context, entries, NULL);
+
+// g_option_context_add_group (context, gtk_get_option_group (TRUE));
+
+ if (!g_option_context_parse (context, &argc, &argv, &error))
+ {
+ g_print ("option parsing failed: %s\n", error->message);
+ exit (1);
+ }
+
+ if (input_file == NULL)
+ {
+ g_print ("No input file given. Stop.");
+ exit (1);
+ }
+
+ if (! g_file_test (input_file, G_FILE_TEST_EXISTS))
+ {
+ g_print ("Input file does not exist. Stop.");
+ exit (1);
+ }
+
+ if (output_file == NULL)
+ {
+ g_print ("No output file given. Stop.");
+ exit (1);
+ }
+
+ if ((out = fopen (output_file, "w")) == NULL)
+ {
+ g_print ("Can't open the output file. Stop.");
+ exit (1);
+ }
+
+ read_points_file (input_file, &pts, &colors);
+
+ T = p2tr_triangulate_and_refine (pts, refine_max_steps);
+
+ p2tr_plot_svg (T,out);
+
+ fclose (out);
+
+ sprintf (buf, "%s.ppm", output_file);
+
+ if ((out = fopen (buf, "w")) == NULL)
+ {
+ g_print ("Can't open the output ppm file. Stop.");
+ exit (1);
+ }
+
+ P2tRImageConfig imc;
+
+ imc.cpp = 4;
+ imc.min_x = imc.min_y = 0;
+ imc.step_x = imc.step_y = 0.2;
+ imc.x_samples = imc.y_samples = 500;
+
+ im = g_new (gfloat, imc.cpp * imc.x_samples * imc.y_samples);
+
+ p2tr_mesh_render_scanline (T, im, &imc, p2tr_test_point_to_color, NULL);
+
+ p2tr_write_ppm (out, im, &imc);
+ fclose (out);
+
+ g_free (im);
+
+ p2tr_triangulation_free (T);
+
+ for (i = 0; i < pts->len; i++)
+ {
+ p2tr_point_unref ((P2tRPoint*) g_ptr_array_index (pts, i));
+ }
+
+ g_ptr_array_free (pts, TRUE);
+ g_array_free (colors, TRUE);
+
+}
--- /dev/null
+/*
+ * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
+ * http://code.google.com/p/poly2tri/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Poly2Tri nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef POLY2TRI_H
+#define POLY2TRI_H
+
+#include "common/shapes.h"
+#include "sweep/cdt.h"
+
+#endif
+
--- /dev/null
+#include <stdlib.h>
+
+#include "triangulation.h"
+
+/* Place holder function. In the future, this should be replaced by some search
+ * tree, such as a quad tree.
+ */
+P2tRTriangle *
+p2tr_triangulation_locate_point (P2tRTriangulation *T, P2tRPoint *X)
+{
+ P2trHashSetIter iter;
+ P2tRTriangle *result;
+
+ p2tr_hash_set_iter_init (&iter, T->tris);
+
+ while (p2tr_hash_set_iter_next(&iter, (gpointer*)&result))
+ {
+ if (p2tr_triangle_contains_pt (result, X))
+ return result;
+ }
+
+ return NULL;
+}
+
+gboolean
+p2tr_points_are_same (P2tRPoint *pt1, P2tRPoint *pt2)
+{
+ return p2tr_math_edge_len_sq (pt1->x, pt1->y, pt2->x, pt2->y) < EPSILON2;
+}
+
+/* As the algorithm paper states, an edge can only be encroached by the
+ * point opposite to it in one of the triangles it's a part of.
+ * We can deduce from that that a point may only encroach upon edges that form
+ * the triangle in/on which it is located.
+ * which are opposite to it in some triangle, and that it may encroach free
+ * points (points which are not a part of any triangles)
+ * We can find the list of triangles in which a point it a part, by iterating
+ * over the .tri property of the out going edges.
+ * NOTE: If there is a triangle formed by edges, but without a real triangle
+ * there, then we are dealing with the edges of the domain which have to
+ * be constrained! Therefore, we can ignore these edges and not return them
+ */
+P2tRHashSet *
+p2tr_triangulation_get_encroaches_upon (P2tRPoint *pt, P2tRTriangulation *T)
+{
+ GList *iter;
+ P2tRTriangle *Tri = p2tr_triangulation_locate_point (T, pt);
+ P2tRPoint *p;
+ P2tRHashSet *E = p2tr_hash_set_set_new (g_direct_hash, g_direct_equal, NULL);
+ gint i;
+
+ if (Tri == NULL)
+ return E;
+
+ for (i = 0; i < 3; i++)
+ {
+ /* If the point is the same as any of the points of the triangle, then it
+ * is inside the diametral circle of all the edges that connect to that
+ * point. In that case, add all the edges of the point to the list of
+ * encroahced edges.
+ * TODO: check if you can break after finding one in this case
+ */
+ if (p2tr_points_are_same (pt, p = p2tr_edge_get_end (Tri->edges[i])))
+ foreach (iter, p->edges)
+ p2tr_hash_set_insert (E, (P2tREdge*) iter->data);
+
+ /* Now, check if any of the edges contains the point inside it's diametral
+ * circle */
+ if (p2tr_edge_diametral_circle_contains (Tri->edges[i], pt))
+ p2tr_hash_set_insert (E, Tri->edges[i]);
+
+ /* TODO: add a check for the case where the point is actually on one of the
+ * edges */
+ }
+
+ return E;
+}
+
+
+/**
+ * Split an edge at a given point. If the point is at the same location as one
+ * of the sides, the edge will not be split in order to avoid zero lengthed edges.
+ *
+ * @param e the edge to split
+ * @param pt the point to add
+ * @param T the triangulation to maintain
+ * @param patchHoles Whethe the holes created by removing the original edge
+ * should be patched
+ * @param dest An array where the results of the split are to be stored. The
+ * array should be of size 2, and it will contain one edge if no split
+ * occured or two edges if a split did in fact occur.
+ *
+ * @return The amount of edges resulting from the split - 1 if no split, 2 if a
+ * split occured
+ */
+gint
+p2tr_split_edge (P2tREdge *e,
+ P2tRPoint *pt,
+ P2tRTriangulation *T,
+ gboolean patchHoles,
+ P2tREdge *dest[2],
+ gboolean flipFix)
+{
+ /* A
+ * / \
+ * / | \
+ * / \
+ * / | \
+ * / \
+ * S---- pt----E ===> This is edge e, and pt is the point we insert
+ * \ | /
+ * \ /
+ * \ | /
+ * \ /
+ * \ | /
+ * \ /
+ * B
+ *
+ * Each of these edges may need flip fixing!
+ */
+ P2tRPoint *S = p2tr_edge_get_start (e);
+ P2tRPoint *E = p2tr_edge_get_end (e);
+ P2tRPoint *A = NULL, *B = NULL;
+
+ P2tRTriangle *SptA = NULL, *ptEA = NULL, *SptB = NULL, *ptEB = NULL;
+
+ gboolean constrained = e->constrained;
+ /* TODO: T remove me */
+ p2tr_validate_edge (e);
+
+ P2tREdge *Spt, *ptE;
+
+ p2tr_debug ("Checking if can split\n");
+
+ if (p2tr_points_are_same (pt, S) || p2tr_points_are_same (pt, E))
+ {
+ dest[0] = e;
+ dest[1] = NULL;
+ return 1;
+ }
+
+ p2tr_debug ("Splitting!\nAdding (%f,%f) between (%f,%f) and (%f,%f)\n", pt->x,pt->y,S->x,S->y,E->x,E->y);
+
+ if (patchHoles)
+ {
+ if (e->tri != NULL)
+ A = p2tr_triangle_opposite_point (e->tri, e);
+
+ if (e->mirror->tri != NULL)
+ B = p2tr_triangle_opposite_point (e->mirror->tri, e);
+ }
+
+ p2tr_edge_remove (e, T);
+
+ Spt = p2tr_edge_new (S, pt);
+ ptE = p2tr_edge_new (pt,E);
+
+ p2tr_edge_set_constrained (Spt, constrained);
+ p2tr_edge_set_constrained (ptE, constrained);
+
+ if (patchHoles)
+ {
+ if (A != NULL)
+ {
+ P2tREdge *ptA = p2tr_point_edge_to (pt, A);
+ P2tRTriangle *SptA = p2tr_triangle_new (Spt, ptA, p2tr_point_edge_to (A, S), T);
+ P2tRTriangle *ptEA = p2tr_triangle_new (ptE, p2tr_point_edge_to (E, A), ptA->mirror,T);
+ }
+
+ if (B != NULL)
+ {
+ P2tREdge* ptB = p2tr_point_edge_to (pt, B);
+ P2tRTriangle *SptB = p2tr_triangle_new (Spt, ptB, p2tr_point_edge_to (B, S), T);
+ P2tRTriangle *ptEB = p2tr_triangle_new (ptE, p2tr_point_edge_to (E, B), ptB->mirror,T);
+ }
+ }
+
+ if (flipFix)
+ {
+ P2tREdge *temp;
+
+ /* We do not want the edges resulting from the split to be flipped! */
+ p2tr_edge_set_delaunay (Spt, TRUE);
+ p2tr_edge_set_delaunay (ptE, TRUE);
+
+ if (A != NULL)
+ {
+ p2tr_triangulation_legalize (T, SptA);
+ p2tr_triangulation_legalize (T, ptEA);
+ }
+ if (B != NULL)
+ {
+ p2tr_triangulation_legalize (T, SptB);
+ p2tr_triangulation_legalize (T, ptEB);
+ }
+
+ p2tr_edge_set_delaunay (Spt, FALSE);
+ p2tr_edge_set_delaunay (ptE, FALSE);
+ }
+
+ // Error - if the triangles were remove, unreffing them would cause problems
+ // So for now, I'm commenting these out
+ // TODO: FIXME!
+// p2tr_triangle_unref (SptA);
+// p2tr_triangle_unref (ptEA);
+
+// p2tr_triangle_unref (SptB);
+// p2tr_triangle_unref (ptEB);
+
+ if (dest != NULL)
+ {
+ /* We shouldn't decrese the reference to Spt and ptE, since it's 1
+ * right now, and we pass the reference to them back to the caller through
+ * dest */
+ dest[0] = Spt;
+ dest[1] = ptE;
+ }
+ else
+ {
+ p2tr_edge_unref (Spt);
+ p2tr_edge_unref (ptE);
+ }
+ return 2;
+}
+
+/**
+ * Insert a point into a triangulation. If it's outside of the triangulation or
+ * if it merges with an existing point it will not be inserted. If it's on an
+ * existing edge, the edge will be split and then there will be a flipfix to
+ * make the triangulation CDT again. If it's inside a triangle, the triangle
+ * will be subdivided and flipfixing will be applied to maintain the CDT
+ * property.
+ *
+ * @param pt the point to insert
+ * @param T the triangulation to insert into
+ *
+ * @return TRUE if the point was inserted, FALSE otherwise
+ */
+gboolean
+p2tr_triangulation_insert_pt (P2tRPoint *pt, P2tRTriangulation *T)
+{
+ p2tr_debug ("@insertPt\n");
+ P2tRTriangle *Tri = p2tr_triangulation_locate_point (T, pt);
+
+ gint i;
+ P2tREdge *temp;
+
+ p2tr_validate_triangulation (T);
+ if (Tri == NULL)
+ {
+ p2tr_debug ("Warning - tried to insert point outside of domain\n");
+ return FALSE;
+ }
+
+ P2tREdge *ab = Tri->edges[0];
+ P2tREdge *bc = Tri->edges[1];
+ P2tREdge *ca = Tri->edges[2];
+
+ P2tRPoint *a = p2tr_edge_get_end (ca);
+ P2tRPoint *b = p2tr_edge_get_end (ab);
+ P2tRPoint *c = p2tr_edge_get_end (bc);
+
+ if (p2tr_points_are_same (pt, a)
+ || p2tr_points_are_same (pt, b)
+ || p2tr_points_are_same (pt, c))
+ {
+ p2tr_debug ("Not inserting point on existing point!\n");
+ return FALSE;
+ }
+
+ p2tr_validate_triangulation (T);
+ /* Check if the point is on any of the edges */
+ for (i = 0; i < 3; i++)
+ {
+ P2tRPoint *S = p2tr_edge_get_start (Tri->edges[i]);
+ P2tRPoint *E = p2tr_edge_get_end (Tri->edges[i]);
+
+ /* Is the point on the edge? */
+ if (p2tr_math_orient2d (pt,S,E) == COLLINEAR)
+ {
+ gint j;
+ gint splitCount;
+ P2tREdge *splits[2];
+
+ /* If so, flip the edge */
+ p2tr_validate_triangulation (T);
+ splitCount = p2tr_split_edge (Tri->edges[i], pt, T, TRUE, splits, TRUE);
+ p2tr_validate_triangulation (T);
+ /* Then, flipfix each of the resulting edges */
+ for (j = 0; j < splitCount; j++)
+ {
+ p2tr_triangulation_flip_fix (splits[j], T);
+ /* We don't use the edge after this point, so unref */
+ p2tr_edge_unref (splits[j]);
+ }
+
+ /* If the point is on one edge then it's not on any other edge (unless
+ * it is in fact one of the triangle vertices but we already fixed
+ * that case earlier). So by splitting the edge and flipfixing the
+ * result, we are in fact done. */
+ return TRUE;
+ }
+ }
+
+ /* If reached here, then the point was not on any of the edges. So just
+ * insert it into the triangle */
+
+ p2tr_validate_triangulation (T);
+ p2tr_triangle_subdivide (Tri, pt, T, NULL);
+ p2tr_validate_triangulation (T);
+
+ /* IMPORTANT: YOU CAN NOT FLIP AB/BC/CA BECAUSE THEY MAY NOT EXIST!
+ * Even if there is an edge from a to b for example, it may not be ab we got
+ * earlier! It can be there as a result of different flip fixing which
+ * deleted and then created it! So, take the edge returned from has_edge_to
+ * (which is the updated one) and flip-fix if it exists.
+ */
+ if ((temp = p2tr_point_has_edge_to (a,b)) != NULL)
+ p2tr_triangulation_flip_fix (temp, T);
+ p2tr_validate_triangulation (T);
+
+ if ((temp = p2tr_point_has_edge_to (b,c)) != NULL)
+ p2tr_triangulation_flip_fix (temp, T);
+ p2tr_validate_triangulation (T);
+
+ if ((temp = p2tr_point_has_edge_to (c,a)) != NULL)
+ p2tr_triangulation_flip_fix (temp, T);
+ p2tr_validate_triangulation (T);
+
+ return TRUE;
+}
+
+typedef gboolean (*deltafunc) (P2tRTriangle *);
+
+
+/*
+ * This function returns negative if triangle a is uglier than b, 0 if same, and
+ * 1 if b is uglier
+ */
+gint
+ugliness_comparision (gconstpointer a,
+ gconstpointer b,
+ gpointer ignored)
+{
+ if (a == b)
+ return 0; // Fast path exit
+
+ gdouble shortestA = p2tr_triangle_shortest_edge_len ((P2tRTriangle*)a);
+ gdouble shortestB = p2tr_triangle_shortest_edge_len ((P2tRTriangle*)b);
+
+ gdouble longestA = p2tr_triangle_longest_edge_len ((P2tRTriangle*)a);
+ gdouble longestB = p2tr_triangle_longest_edge_len ((P2tRTriangle*)b);
+
+ gdouble smallestA = p2tr_triangle_smallest_non_seperating_angle ((P2tRTriangle*)a);
+ gdouble smallestB = p2tr_triangle_smallest_non_seperating_angle ((P2tRTriangle*)b);
+
+// Bad
+// return (gint) ((smallestA - smallestB) / M_PI) ;//+ (longestA - longestB) / MAX (longestA, longestB);
+
+// Seems Good
+ return (gint) (1 - longestA/longestB + ((smallestA - smallestB) / M_PI));
+
+// Not sure?
+// return (gint) (longestB/shortestB - longestA/shortestA);
+
+// Trivial, reasonable
+// return (gint) (smallestA - smallestB);
+}
+
+
+void
+NewVertex (P2tRPoint *v, gdouble theta, deltafunc delta,
+ GQueue *Qs, GSequence *Qt)
+{
+ GList *iter;
+
+ p2tr_debug ("NewVertex: After inserting ");
+ p2tr_debug_point (v, TRUE);
+
+ foreach (iter, v->edges)
+ {
+ P2tREdge *ed = (P2tREdge*) iter->data;
+ P2tRTriangle *t = ed->tri;
+
+ if (t != NULL)
+ {
+ p2tr_debug ("NewVertex: Checking tri ");
+ p2tr_debug_tri (t, TRUE);
+
+ P2tREdge *e = p2tr_triangle_opposite_edge (t, v);
+ if (e->mirror->tri == NULL && p2tr_edge_is_encroached_by (e, v))
+ g_queue_push_tail (Qs, e);
+ else if (delta (t) || p2tr_triangle_smallest_non_seperating_angle (t) < theta)
+ g_sequence_insert_sorted (Qt, t, ugliness_comparision, NULL);
+ }
+ }
+}
+
+void
+SplitEncroachedSubsegments (gdouble theta,
+ deltafunc delta,
+ P2tRTriangulation *T,
+ GQueue *Qs,
+ GSequence *Qt)
+{
+ while (! g_queue_is_empty (Qs))
+ {
+ p2tr_debug ("Handling edge\n");
+ P2tREdge *s = g_queue_pop_head (Qs);
+ gboolean isin = FALSE;
+
+ P2trHashSetIter iter;
+ P2tRTriangle *t;
+ p2tr_hash_set_iter_init (&iter, T->tris);
+
+ while (p2tr_hash_set_iter_next (&iter, (gpointer*)&t))
+ {
+ if (t->edges[0] == s || t->edges[1] == s || t->edges[2] == s)
+ {
+ isin = TRUE;
+ break;
+ }
+ }
+
+ if (isin)
+ {
+ if (p2tr_edge_len_sq (s) >= 1)
+ {
+ P2tRPoint *v = p2tr_edge_concentric_center (s);
+ P2tREdge *splits[2];
+ gint splitCount = p2tr_split_edge (s, v, T, TRUE, splits, TRUE), i;
+
+ for (i = 0; i < splitCount; i++)
+ {
+ p2tr_triangulation_flip_fix (splits[i], T);
+ }
+
+ NewVertex (v, theta, delta, Qs, Qt);
+ for (i = 0; i < splitCount; i++)
+ {
+ if (p2tr_edge_is_encroached (splits[i]))
+ g_queue_push_tail (Qs, splits[i]);
+ }
+ }
+ }
+ }
+}
+
+
+gboolean
+p2tr_false_delta (P2tRTriangle *t)
+{
+ return FALSE;
+}
+
+const gdouble POW2_EPS = 0;
+const gdouble LENGTHSQ_EPS = 0;
+
+gboolean
+SplitPermitted (P2tREdge *s, gdouble d)
+{
+ p2tr_debug ("@SplitPermitted\n");
+ if (! (p2tr_point_is_in_cluster (p2tr_edge_get_start(s), s) ^ p2tr_point_is_in_cluster (p2tr_edge_get_end(s), s->mirror)))
+ {
+ p2tr_debug ("Criteria 1\n");
+ return TRUE;
+ }
+ gdouble l = p2tr_edge_len_sq (s);
+ gdouble temp = log2 (l) / 2;
+ if (ABS (round (temp) - temp) < POW2_EPS)
+ {
+ p2tr_debug ("Criteria 2\n");
+ return TRUE;
+ }
+
+ gdouble phi_min;
+ GList *S = p2tr_point_get_cluster (p2tr_edge_get_start (s), s, &phi_min);
+ GList *s1;
+
+ foreach(s1, S)
+ {
+ if (p2tr_edge_len_sq ((P2tREdge*)s1->data) < 1 * (1 + LENGTHSQ_EPS))
+ {
+ p2tr_debug ("Criteria 3\n");
+ return TRUE;
+ }
+ }
+
+ gdouble r_min = sqrt(l) * sin (phi_min / 2);
+
+ if (r_min >= d)
+ {
+ p2tr_debug ("Criteria 4\n");
+ return TRUE;
+ }
+
+ p2tr_debug ("Split not permitted\n");
+ return FALSE;
+}
+
+#define MIN_MAX_EDGE_LEN 0
+
+void
+DelaunayTerminator (P2tRTriangulation *T,
+ GList *XEs,
+ gdouble theta,
+ deltafunc delta,
+ int max_refine_steps)
+{
+ const gint STEPS = max_refine_steps;
+ GSequence *Qt;
+ GQueue Qs;
+
+ GList *Liter, Liter2;
+ P2trHashSetIter Hiter;
+
+ p2tr_debug("Max refine point count is %d\n", max_refine_steps);
+
+ p2tr_validate_triangulation (T);
+
+ P2tRTriangle *t;
+
+ g_queue_init (&Qs);
+ Qt = g_sequence_new (NULL);
+
+ if (STEPS == 0)
+ return;
+
+ foreach (Liter, XEs)
+ {
+ P2tREdge *s = (P2tREdge*) (Liter->data);
+ if (p2tr_edge_is_encroached (s))
+ {
+ g_queue_push_tail (&Qs, s);
+ }
+ }
+
+ SplitEncroachedSubsegments(0, p2tr_false_delta,T,&Qs,Qt);
+
+ p2tr_validate_triangulation (T);
+
+ p2tr_hash_set_iter_init (&Hiter, T->tris);
+ while (p2tr_hash_set_iter_next (&Hiter, (gpointer*)&t))
+ if (delta (t) || p2tr_triangle_smallest_non_seperating_angle (t) < theta)
+ g_sequence_insert_sorted (Qt, t, ugliness_comparision, NULL);
+
+ gint STOP = STEPS - 1; /* The above split was a step */
+
+ while (g_sequence_get_length (Qt) > 0 && STOP > 0)
+ {
+ p2tr_validate_triangulation (T);
+ p2tr_debug ("Restarting main loop\n");
+ STOP--;
+
+ do
+ {
+ GSequenceIter *siter = g_sequence_get_begin_iter (Qt);
+ t = g_sequence_get (siter);
+ g_sequence_remove (siter);
+ if (g_sequence_get_length (Qt) == 0) break;
+ }
+ while (! p2tr_hash_set_contains (T->tris, t));
+ if (g_sequence_get_length (Qt) == 0) break;
+
+ if (p2tr_triangle_longest_edge_len (t) < MIN_MAX_EDGE_LEN)
+ {
+ continue;
+ }
+
+ /* Possibly make more efficient by adding an "erased" field */
+ if (p2tr_hash_set_contains (T->tris, t))
+ {
+ P2tRCircle cc;
+ P2tRPoint *c;
+ P2tRHashSet *E;
+
+ p2tr_debug ("Found a triangle that still needs fixing\n");
+
+ p2tr_triangle_circumcircle (t, &cc);
+ c = p2tr_point_new (cc.x,cc.y);
+
+ E = p2tr_triangulation_get_encroaches_upon (c, T);
+ p2tr_validate_triangulation (T);
+
+ if (g_hash_table_size (E) == 0)
+ {
+ p2tr_debug ("It's circumcircle encraoches upon nothing!\n");
+ /* Check if the point is in the domain and inserted OK */
+ if (p2tr_triangulation_insert_pt (c, T))
+ {
+ p2tr_validate_triangulation (T);
+ NewVertex (c,theta,delta,&Qs,Qt);
+ p2tr_validate_triangulation (T);
+ }
+ else
+ {
+ int k;
+ /* In the other cases, split the edge crossing the
+ * line to the point
+ */
+ g_assert (! p2tr_triangle_contains_pt (t, c));
+ P2tRPoint *M = p2tr_triangle_median_pt (t);
+ P2tREdge *MC = p2tr_point_edge_to (M, c);
+ p2tr_validate_triangulation (T);
+ for (k = 0; k < 3; k++)
+ {
+ P2tREdge *e = t->edges[k];
+ if (p2tr_edges_intersect (e, MC))
+ {
+ P2tREdge *splits[2];
+ P2tRPoint *splitPoint = p2tr_edge_concentric_center (e);
+ gint count = p2tr_split_edge (e, splitPoint, T, TRUE, splits, TRUE);
+ p2tr_validate_triangulation (T);
+ gint j;
+
+ for (j = 0; j < count; j++)
+ {
+ p2tr_triangulation_flip_fix (splits[j], T);
+ p2tr_validate_triangulation (T);
+ }
+
+ p2tr_point_unref (splitPoint);
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ P2tREdge *s;
+ p2tr_debug ("It's circumcircle encraoches %d edges\n", g_hash_table_size (E));
+ gdouble d = p2tr_triangle_shortest_edge_len (t);
+
+ p2tr_hash_set_iter_init (&Hiter, E);
+ while (p2tr_hash_set_iter_next (&Hiter, (gpointer*)&s))
+ {
+ if (delta (t) || SplitPermitted(s,d))
+ {
+ p2tr_debug ("Appending an edge for splitting\n");
+ g_queue_push_tail (&Qs, s);
+ }
+ }
+ if (! g_queue_is_empty (&Qs))
+ {
+ g_sequence_insert_sorted (Qt, t, ugliness_comparision, NULL);
+ p2tr_debug ("Will now try splitting\n");
+ SplitEncroachedSubsegments(theta,delta,T,&Qs,Qt);
+ }
+ }
+
+ p2tr_point_unref (c);
+ }
+
+ // Why not to legalize here:
+ // 1. Because it should have no effect if we did maintain the CDT
+ // 2. Because if it does have an effect, since legalizations checks only
+ // vialoations with adjacent neighbours, it may simply violate the CDT
+ // property with remote ones!
+
+ // Flip fixing actually adds more triangles that may have to be fixed.
+ // Untill we do it preoperly, add them here:
+ /*
+ P2trHashSetIter triter;
+ P2tRTriangle *trit;
+
+ p2tr_hash_set_iter_init (&triter,T->tris);
+ while (p2tr_hash_set_iter_next (&triter, (gpointer*)&trit))
+ {
+ if (p2tr_triangle_smallest_non_seperating_angle (trit) < theta)
+ g_sequence_insert_sorted (Qt, t, ugliness_comparision, NULL);
+ }
+ */
+ }
+}
+
+/*
+ * Input must be a GPtrArray of P2tRPoint*
+ */
+P2tRTriangulation*
+p2tr_triangulate_and_refine (GPtrArray *pts, int max_refine_steps)
+{
+ gint i, N = pts->len;
+ GList *XEs = NULL, *iter;
+ P2tRTriangulation *T;
+
+ for (i = 0; i < pts->len; i++)
+ {
+ P2tREdge *E = p2tr_point_edge_to ((P2tRPoint*)g_ptr_array_index_cyclic (pts, i),
+ (P2tRPoint*)g_ptr_array_index_cyclic (pts, i+1));
+ p2tr_edge_set_constrained (E, TRUE);
+ XEs = g_list_prepend (XEs, E);
+ }
+
+ T = p2tr_triangulateA ((P2tRPoint**)pts->pdata ,pts->len);
+ DelaunayTerminator (T,XEs,M_PI/6,p2tr_false_delta, max_refine_steps);
+
+ foreach (iter, XEs)
+ {
+ P2tREdge *E = (P2tREdge*) iter->data;
+ p2tr_edge_unref (E);
+ }
+
+ g_list_free (XEs);
+
+ return T;
+}
--- /dev/null
+/*
+ * File: refine.h
+ * Author: Barak
+ *
+ * Created on 29 יולי 2011, 04:52
+ */
+
+#ifndef REFINE_H
+#define REFINE_H
+
+#include <glib.h>
+#include "triangulation.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+P2tRTriangulation*
+p2tr_triangulate_and_refine (GPtrArray *pts, int max_refine_steps);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* REFINE_H */
+
--- /dev/null
+#include <math.h>
+
+#include "../common/utils.h"
+#include "triangulation.h"
+#include "../poly2tri.h"
+
+static void p2tr_edge_init (P2tREdge *self, P2tRPoint *start, P2tRPoint *end);
+
+static void p2tr_edge_init_private (P2tREdge *self, P2tRPoint *start, P2tRPoint *end, gboolean mirror);
+
+static void p2tr_edge_remove_private (P2tREdge *self, P2tRTriangulation *T);
+
+static void p2tr_point_init (P2tRPoint *self, gdouble x, gdouble y);
+
+static void p2tr_point_add_edge (P2tRPoint *self, P2tREdge *edge);
+
+
+/* ########################################################################## */
+/* Common math */
+/* ########################################################################## */
+gdouble
+p2tr_math_normalize_angle (gdouble angle)
+{
+ while (angle < -M_PI)
+ angle += 2 * M_PI_2;
+ while (angle > M_PI)
+ angle -= 2 * M_PI;
+ return angle;
+}
+
+/* NOTE: exact copy of p2t_orient2d, with different EPSILON2
+ * TODO: merge somehow
+ */
+P2tROrientation
+p2tr_math_orient2d (P2tRPoint* pa,
+ P2tRPoint* pb,
+ P2tRPoint* pc)
+{
+ double detleft = (pa->x - pc->x) * (pb->y - pc->y);
+ double detright = (pa->y - pc->y) * (pb->x - pc->x);
+ double val = detleft - detright;
+// p2tr_debug ("orient2d val is %f\n",val);
+ if (val > -EPSILON2 && val < EPSILON2)
+ {
+// p2tr_debug ("COLLINEAR!\n");
+ return COLLINEAR;
+ }
+ else if (val > 0)
+ {
+// p2tr_debug ("CCW!\n");
+ return CCW;
+ }
+// p2tr_debug ("CW!\n");
+ return CW;
+}
+
+/* TODO: check relation with p2t_utils_in_scan_area */
+/* This function is based on an article by Jonathan Richard Shewchuk
+ * "Robust Adaptive Floating-Point Geometric Predicates"
+ *
+ * | ax-dx ay-dy (ax-dx)^2+(ay-dy)^2 |
+ * | bx-dx by-dy (bx-dx)^2+(by-dy)^2 |
+ * | cx-dx cy-dy (cx-dx)^2+(cy-dy)^2 |
+ *
+ * A, B AND C MUST BE IN CCW ORDER!
+ */
+P2tRInCircle
+p2tr_math_incircle (P2tRPoint* a,
+ P2tRPoint* b,
+ P2tRPoint* c,
+ P2tRPoint* d)
+{
+ gdouble ad_dx = a->x - d->x;
+ gdouble ad_dy = a->y - d->y;
+ gdouble ad_dsq = ad_dx * ad_dx + ad_dy * ad_dy;
+
+ gdouble bd_dx = b->x - d->x;
+ gdouble bd_dy = b->y - d->y;
+ gdouble bd_dsq = bd_dx * bd_dx + bd_dy * bd_dy;
+
+ gdouble cd_dx = c->x - d->x;
+ gdouble cd_dy = c->y - d->y;
+ gdouble cd_dsq = cd_dx * cd_dx + cd_dy * cd_dy;
+
+ gdouble calc = + ad_dx * (bd_dy * cd_dsq - cd_dy * bd_dsq)
+ - ad_dy * (bd_dx * cd_dsq - cd_dx * bd_dsq)
+ + ad_dsq * (bd_dx * cd_dy - cd_dx * bd_dy);
+
+ if (calc > EPSILON2)
+ return INCIRCLE_INSIDE;
+ else if (calc < EPSILON2)
+ return INCIRCLE_OUTSIDE;
+ else
+ return INCIRCLE_ON;
+}
+
+gdouble
+p2tr_math_edge_len_sq (gdouble x1, gdouble y1, gdouble x2, gdouble y2)
+{
+ gdouble dx = x2 - x1;
+ gdouble dy = y2 - y1;
+ return dx * dx + dy * dy;
+}
+
+/* ########################################################################## */
+/* Triangulation struct */
+/* ########################################################################## */
+
+void
+p2tr_triangulation_remove_pt (P2tRTriangulation *self, P2tRPoint *pt)
+{
+ if (p2tr_hash_set_remove (self->pts, pt))
+ p2tr_point_unref (pt);
+}
+
+void
+p2tr_triangulation_remove_ed (P2tRTriangulation *self, P2tREdge *ed)
+{
+ if (p2tr_hash_set_remove (self->edges, ed))
+ p2tr_edge_unref (ed);
+}
+
+void
+p2tr_triangulation_remove_tr (P2tRTriangulation *self, P2tRTriangle *tr)
+{
+ if (p2tr_hash_set_remove (self->tris, tr))
+ p2tr_triangle_unref (tr);
+}
+
+void
+p2tr_triangulation_add_pt (P2tRTriangulation *self, P2tRPoint *pt)
+{
+ if (p2tr_hash_set_contains (self->pts, pt))
+ return;
+
+ p2tr_hash_set_insert (self->pts, pt);
+ p2tr_point_ref (pt);
+}
+void
+p2tr_triangulation_add_ed (P2tRTriangulation *self, P2tREdge *ed)
+{
+ if (p2tr_hash_set_contains (self->edges, ed))
+ return;
+
+ p2tr_hash_set_insert (self->edges, ed);
+ p2tr_edge_ref (ed);
+}
+void
+p2tr_triangulation_add_tr (P2tRTriangulation *self, P2tRTriangle *tr)
+{
+ if (p2tr_hash_set_contains (self->tris, tr))
+ return;
+
+ p2tr_hash_set_insert (self->tris, tr);
+ p2tr_triangle_ref (tr);
+}
+
+void
+p2tr_triangulation_get_points (P2tRTriangulation *self, GPtrArray *dest)
+{
+ P2trHashSetIter iter;
+ P2tRTriangle *tr;
+ P2tRHashSet *pts = p2tr_hash_set_set_new (g_direct_hash, g_direct_equal, NULL);
+ gint i;
+
+ p2tr_hash_set_iter_init (&iter, self->tris);
+ while (p2tr_hash_set_iter_next (&iter, (gpointer*)&tr))
+ {
+ for (i = 0; i < 3; i++)
+ {
+ P2tRPoint *pt = p2tr_edge_get_end (tr->edges[i]);
+ if (! p2tr_hash_set_contains (pts, pt))
+ {
+ p2tr_point_ref (pt);
+ g_ptr_array_add (dest, pt);
+ p2tr_hash_set_insert (pts, pt);
+ }
+ }
+ }
+
+ g_hash_table_destroy (pts);
+}
+/* ########################################################################## */
+/* Point struct */
+/* ########################################################################## */
+
+static void
+p2tr_point_init (P2tRPoint *self,
+ gdouble x,
+ gdouble y)
+{
+ self->x = x;
+ self->y = y;
+ self->edges = NULL;
+ self->_refcount = 1;
+}
+
+P2tRPoint*
+p2tr_point_new (gdouble x,
+ gdouble y)
+{
+ P2tRPoint *self = g_slice_new (P2tRPoint);
+ p2tr_point_init (self, x, y);
+ return self;
+}
+
+static void
+p2tr_point_destroy (P2tRPoint *self)
+{
+ GList *iter;
+
+ g_assert (self->_refcount == 0);
+
+ foreach (iter, self->edges)
+ {
+ P2tREdge *e = (P2tREdge*) iter->data;
+ p2tr_edge_unref (e);
+ }
+
+ g_list_free (self->edges);
+}
+
+void
+p2tr_point_free (P2tRPoint *self)
+{
+ p2tr_point_destroy (self);
+ g_slice_free (P2tRPoint, self);
+}
+/* DBG: Differs from original
+ *
+ * THIS FUNCTION SHOULD NOT BE USED DIRECTLY! IT IS JUST A CONVINIENCE FUNCTION
+ * USED BY THE CONSTRUCTOR OF THE EDGE OBJECT TO ACTUALLY REFERENCE THE EDGE
+ * FROM THE POINT!
+ */
+static void
+p2tr_point_add_edge (P2tRPoint *self,
+ P2tREdge *edge)
+{
+ GList *iter = self->edges;
+ for (iter = self->edges; iter != NULL; iter = iter->next)
+ {
+ if (!(P2TR_EDGE(iter->data)->angle < edge->angle))
+ break;
+ }
+
+ /* Inserting before NULL will insert at the end of the list */
+ self->edges = g_list_insert_before (self->edges, iter, edge);
+
+ /* We now hold a reference to the edge! */
+ p2tr_edge_ref (edge);
+}
+
+void
+p2tr_point_remove_edge (P2tRPoint *self,
+ P2tREdge *edge)
+{
+ p2tr_assert_and_explain (g_list_find (self->edges, edge) != NULL, "can't remove non existing edge");
+ self->edges = g_list_remove (self->edges, edge);
+ p2tr_edge_unref (edge);
+}
+
+void
+p2tr_point_remove (P2tRPoint *self,
+ P2tRTriangulation *T)
+{
+ GList *iter = self->edges;
+ for (iter = self->edges; iter != NULL; iter = iter->next)
+ {
+ p2tr_edge_remove (P2TR_EDGE(iter->data), T);
+ }
+ p2tr_triangulation_remove_pt (T, self);
+}
+
+/* This function will return an edge from the current
+ * point to a given other point. If no such edge exists,
+ * it will be created
+ */
+P2tREdge*
+p2tr_point_edge_to (P2tRPoint *self, P2tRPoint *end)
+{
+ GList *iter = self->edges;
+
+ for (iter = self->edges; iter != NULL; iter = iter->next)
+ if (P2TR_EDGE(iter->data)->end == end)
+ {
+ p2tr_edge_ref (P2TR_EDGE(iter->data));
+ return P2TR_EDGE (iter->data);
+ }
+
+ /* Don't decrease reference - this is returned to someone else */
+ return p2tr_edge_new (self, end);
+}
+
+P2tREdge*
+p2tr_point_has_edge_to (P2tRPoint *self, P2tRPoint *end)
+{
+ GList *iter = self->edges;
+
+ for (iter = self->edges; iter != NULL; iter = iter->next)
+ if (P2TR_EDGE(iter->data)->end == end)
+ return P2TR_EDGE(iter->data);
+
+ return NULL;
+}
+
+P2tREdge*
+p2tr_point_edgeccw (P2tRPoint *self, P2tREdge *edge)
+{
+ GList *index = g_list_find (self->edges, edge);
+ return p2tr_edgelist_ccw (self->edges, index);
+}
+
+P2tREdge*
+p2tr_point_edgecw (P2tRPoint *self, P2tREdge *edge)
+{
+ GList *index = g_list_find (self->edges, edge);
+ return p2tr_edgelist_cw (self->edges, index);
+}
+
+/*
+ * ^ e1 = CCW Neighbor of e
+ * /
+ * / e1.tri
+ * /
+ * P *------> e
+ * \
+ * \ e.tri
+ * \
+ * v e2 = CW Neighbor of e
+ *
+ * e is in a cluster defined by P, if any of the
+ * following conditions hold:
+ * - The angle between e and e2 is less than 60 degrees,
+ * and the triangle of e1 is not None (i.e. the area
+ * between the edges is in the triangulation domain)
+ * - Same with e and e1
+ */
+gboolean
+p2tr_point_is_in_cluster (P2tRPoint *self, P2tREdge *e)
+{
+ /* TODO: make more efficient instead of two searches */
+ GList *eL = g_list_find (self->edges, e);
+ P2tREdge *e1 = p2tr_edgelist_ccw (self->edges, eL);
+ P2tREdge *e2 = p2tr_edgelist_cw (self->edges, eL);
+
+ gdouble Ae1e = p2tr_math_normalize_angle (e1->angle - e->angle);
+ gdouble Aee2 = p2tr_math_normalize_angle (e->angle - e2->angle);
+
+ return (e1->tri != NULL && ABS (Ae1e) <= M_PI/3)
+ || (e->tri != NULL && ABS (Aee2) <= M_PI/3);
+}
+
+/*
+ * DBG: different from original
+ */
+GList*
+p2tr_point_get_cluster (P2tRPoint *self, P2tREdge *e, gdouble *angle)
+{
+ gdouble A = M_PI, a;
+ GList *eI = g_list_find (self->edges, e);
+ GList *temp;
+
+ GList *S = g_list_append (NULL, e);
+
+ GList *ePrev = g_list_cyclic_prev (self->edges,eI);
+ GList *eNext = g_list_cyclic_next (self->edges,eI);
+
+ a = p2tr_math_normalize_angle (e->angle - P2TR_EDGE (ePrev->data)->angle);
+ while (a <= M_PI / 3 && ePrev != eI)
+ {
+ A = MIN(a, A);
+ S = g_list_prepend (S, P2TR_EDGE (ePrev->data));
+ temp = ePrev;
+ ePrev = g_list_cyclic_prev (self->edges, ePrev);
+ a = p2tr_math_normalize_angle (P2TR_EDGE (temp->data)->angle - P2TR_EDGE (ePrev->data)->angle);
+ }
+
+ a = p2tr_math_normalize_angle (P2TR_EDGE (eNext->data)->angle - e->angle);
+ while (a <= M_PI / 3 && eNext->data != S->data)
+ {
+ A = MIN(a, A);
+ S = g_list_append (S, P2TR_EDGE (eNext->data));
+ temp = eNext;
+ eNext = g_list_cyclic_next (self->edges, eNext);
+ a = p2tr_math_normalize_angle (P2TR_EDGE (eNext->data)->angle - P2TR_EDGE (temp->data)->angle);
+ }
+
+ if (angle != NULL)
+ *angle = A;
+
+ return S;
+}
+
+gboolean
+p2tr_point_is_fully_in_domain (P2tRPoint *self)
+{
+ GList *iter = self->edges;
+
+ for (iter = self->edges; iter != NULL; iter = iter->next)
+ if (P2TR_EDGE(iter->data)->end == NULL)
+ return FALSE;
+
+ return TRUE;
+}
+
+/* ########################################################################## */
+/* Edge struct */
+/* ########################################################################## */
+
+P2tREdge*
+p2tr_edge_new (P2tRPoint *start, P2tRPoint *end)
+{
+ return p2tr_edge_new_private (start, end, FALSE);
+}
+
+P2tREdge*
+p2tr_edge_new_private (P2tRPoint *start, P2tRPoint *end, gboolean mirror)
+{
+ P2tREdge *self = g_slice_new (P2tREdge);
+ p2tr_edge_init_private (self, start, end, mirror);
+ return self;
+}
+
+static void
+p2tr_edge_init (P2tREdge *self, P2tRPoint *start, P2tRPoint *end)
+{
+ p2tr_edge_init_private (self, start, end, FALSE);
+}
+
+static void
+p2tr_edge_init_private (P2tREdge *self, P2tRPoint *start, P2tRPoint *end, gboolean mirror)
+{
+ self->_refcount = 0;
+ self->removed = FALSE;
+ self->end = end;
+ self->tri = NULL;
+
+ self->angle = atan2 (end->y - start->y, end->x - start->x);
+
+ self->delaunay = FALSE;
+ self->constrained = FALSE;
+
+ /* Important! Add the edge only once we have an angle!
+ * This function also adds a reference to the edge, since the point now points
+ * at the edge. */
+ p2tr_point_add_edge (start, self);
+
+ if (!mirror)
+ {
+ self->mirror = p2tr_edge_new_private (end, start, TRUE);
+ self->mirror->mirror = self;
+ }
+
+ /* The edge that was created should have it's reference count increased by 1,
+ * since it will be returned (so mark the person who gets it holds a ref).
+ * Note that we don't count the reference loop between two mirror edges */
+ if (!mirror)
+ p2tr_edge_ref (self);
+
+ /* Finally, the edge now references it's end point */
+ p2tr_point_ref (self->end);
+
+ p2tr_assert_and_explain (p2tr_point_has_edge_to (start, end), "edge connectivity");
+ p2tr_assert_and_explain (p2tr_point_has_edge_to (end, start), "edge connectivity");
+}
+
+/* Note that you can't really free one edge - since the edge and it's mirror are
+ * tightly coupled. By freeing one of them, you will also free the other - so
+ * beware of double freeing!
+ *
+ * The best way is not to free directly, but to use the unref function.
+ *
+ * TODO: Merge some logic and fill in missing part with the edge_remove function
+ */
+void
+p2tr_edge_free (P2tREdge *self)
+{
+ g_assert (self->_refcount == 0);
+
+ if (self->mirror->_refcount != 0)
+ return;
+
+ self->removed = self->mirror->removed = TRUE;
+
+ p2tr_point_unref (self->mirror->end);
+ p2tr_point_unref (self->end);
+
+ p2tr_triangle_unref (self->mirror->tri);
+ p2tr_triangle_unref (self->tri);
+
+ g_slice_free (P2tREdge, self->mirror);
+ g_slice_free (P2tREdge, self);
+}
+
+/* You can't remove just one edge from a triangulation. When you remove an edge,
+ * it's mirror is also removed! Calling this will also remove the edge from the
+ * points that form the edge.
+ *
+ * TODO: Merge some logic and fill in missing part with the edge_free function
+ */
+void
+p2tr_edge_remove (P2tREdge *self, P2tRTriangulation *T)
+{
+ p2tr_edge_remove_private (self, T);
+ p2tr_validate_triangulation (T);
+}
+
+static void
+p2tr_edge_remove_private (P2tREdge *self, P2tRTriangulation *T)
+{
+ P2tREdge *mir = self->mirror;
+
+ if (self->removed)
+ return;
+
+ if (self->tri != NULL)
+ p2tr_triangle_remove (self->tri, T);
+ p2tr_validate_triangulation (T);
+
+ if (mir->tri != NULL)
+ p2tr_triangle_remove (mir->tri, T);
+ p2tr_validate_triangulation (T);
+
+ self->removed = mir->removed = TRUE;
+
+ p2tr_validate_triangulation (T);
+ p2tr_point_remove_edge (p2tr_edge_get_start (self), self);
+ p2tr_validate_triangulation (T);
+ p2tr_point_remove_edge (p2tr_edge_get_start (mir), mir);
+ p2tr_validate_triangulation (T);
+
+ p2tr_triangulation_remove_ed (T, self);
+ p2tr_triangulation_remove_ed (T, mir);
+}
+
+/*
+ * DBG: different from source
+ */
+gboolean
+p2tr_edge_is_encroached_by (P2tREdge *self, P2tRPoint *other)
+{
+ if (p2tr_edge_diametral_circle_contains (self, other))
+ {
+ p2tr_debug ("The point ");
+ p2tr_debug_point (other, FALSE);
+ p2tr_debug (" encroaches ");
+ p2tr_debug_edge (self, TRUE);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * DBG: different from source
+ */
+gboolean
+p2tr_edge_is_encroached (P2tREdge *self)
+{
+ if (self->tri != NULL)
+ {
+ P2tRPoint *w = p2tr_triangle_opposite_point (self->tri, self);
+ if (p2tr_edge_is_encroached_by (self, w))
+ return TRUE;
+ }
+
+ if (self->mirror->tri != NULL)
+ {
+ P2tRPoint *w = p2tr_triangle_opposite_point (self->mirror->tri, self);
+ if (p2tr_edge_is_encroached_by (self, w))
+ return TRUE;
+ }
+
+ p2tr_debug ("The edge ");
+ p2tr_debug_edge (self, FALSE);
+ p2tr_debug (" is not encroached!\n");
+
+ return FALSE;
+}
+
+gboolean
+p2tr_edge_diametral_circle_contains (P2tREdge *self, P2tRPoint *pt)
+{
+ /* a-----O-----b
+ * /
+ * /
+ * pt
+ *
+ * pt is in the diametral circle only if it's distance from O (the center of
+ * a and b) is equal/less than a's distance from O (that's the radius).
+ */
+ P2tRPoint *a = p2tr_edge_get_start (self);
+ P2tRPoint *b = p2tr_edge_get_end (self);
+
+ gdouble Ox = (a->x + b->x) / 2;
+ gdouble Oy = (a->y + b->y) / 2;
+
+ return (Ox - a->x) * (Ox - a->x) + (Oy - a->y) * (Oy - a->y)
+ >= (Ox - pt->x) * (Ox - pt->x) + (Oy - pt->y) * (Oy - pt->y);
+ /*
+ return (pt->y - a->y) * (pt->x - a->x)
+ * (pt->y - b->y) * (pt->x - b->x) <= 0;
+ */
+}
+
+gboolean
+p2tr_edge_diametral_lens_contains (P2tREdge *self, P2tRPoint *W)
+{
+ /*
+ * W
+ * /|\
+ * / | \
+ * /60|60\
+ * / | \
+ * /30 | 30\
+ * X-----O-----Y
+ * L L
+ *
+ * Non-Efficient: Calculate XW, and XO=YO
+ *
+ * |XO| ===> |XO| sqrt(3) ===> |XO|^2 3
+ * Make sure asin (----) >= 60° ===> ---- >= ------- ===> ------ >= -
+ * |XW| ===> |XW| 2 ===> |XW|^2 4
+ *
+ * |YO| ===> |YO| sqrt(3) ===> |YO|^2 3
+ * Make sure asin (----) >= 60° ===> ---- >= ------- ===> ------ >= -
+ * |YW| ===> |YW| 2 ===> |YW|^2 4
+ */
+
+ P2tRPoint *X = p2tr_edge_get_start (self);
+ P2tRPoint *Y = p2tr_edge_get_end (self);
+
+ gdouble XO2 = p2tr_edge_len_sq (self) / 4, YO2 = XO2;
+
+ gdouble XW2 = p2tr_math_edge_len_sq (X->x, X->y, W->x, W->y);
+ gdouble YW2 = p2tr_math_edge_len_sq (Y->x, Y->y, W->x, W->y);
+
+ return (XO2 / XW2 >= 0.75) && (YO2 / YW2 >= 0.75);
+}
+
+gdouble
+p2tr_edge_len_sq (P2tREdge *self)
+{
+ P2tRPoint *S = p2tr_edge_get_start (self);
+ P2tRPoint *E = p2tr_edge_get_end (self);
+ return p2tr_math_edge_len_sq (S->x,S->y,E->x,E->y);
+}
+
+void
+p2tr_edge_set_constrained (P2tREdge *self, gboolean b)
+{
+ self->constrained = self->mirror->constrained = b;
+}
+
+void
+p2tr_edge_set_delaunay (P2tREdge *self, gboolean b)
+{
+ self->delaunay = self->mirror->delaunay = b;
+}
+
+/* a = abs(E1.angle)
+ * b = abs(E2.angle)
+ *
+ * A is the angle we wish to find. Note the fact that we want
+ * to find the angle so that the edges go CLOCKWISE around it.
+ *
+ * Case 1: Signs of E1.angle and | Case 2: Signs of E1.angle and
+ * E2.angle agree | E2.angle disagree
+ * |
+ * A=a'+b=180-a+b | A=180-a-b
+ *
+ * ^^ |
+ * E2 // | *
+ * // | ^^ \\
+ * // \ | // A \\
+ * * A| | E1 // \_/ \\ E2
+ * /^^ / | // \\
+ * / || | //a vv
+ * / || E1 | ------------------
+ * / || | \b
+ * /b a'||a | \
+ * -------------- | \
+ * PRECONDITION: e1.getEnd() == e2.getStart()
+ */
+gdouble
+p2tr_angle_between (P2tREdge *e1, P2tREdge *e2)
+{
+ gdouble RET;
+
+ g_assert (p2tr_edge_get_end (e1) == p2tr_edge_get_start (e2));
+
+ if (e1->angle < 0)
+ {
+ if (e2->angle > 0)
+ return ABS (e1->angle) + ABS (e2->angle) - M_PI;
+ else
+ return ABS (e1->angle) - (ABS (e2->angle) - M_PI);
+ }
+ else
+ {
+ if (e2->angle > 0)
+ return M_PI - ABS (e1->angle) + ABS (e2->angle);
+ else
+ return M_PI - ABS (e1->angle) - ABS (e2->angle);
+ }
+
+ /* g_assert (RET + EPSILON2 >= 0 && RET <= M_PI + EPSILON2); */
+
+ return RET;
+}
+
+void
+p2tr_triangle_init (P2tRTriangle *self, P2tREdge *e1, P2tREdge *e2, P2tREdge *e3, P2tRTriangulation *T)
+{
+ P2tRPoint *A = p2tr_edge_get_end (e1);
+ P2tRPoint *B = p2tr_edge_get_end (e2);
+ P2tRPoint *C = p2tr_edge_get_end (e3);
+
+ /* Assert that edges do form a loop! */
+ p2tr_assert_and_explain (A == p2tr_edge_get_start (e2)
+ && B == p2tr_edge_get_start (e3)
+ && C == p2tr_edge_get_start (e1), "Edges form a loop!");
+
+ P2tROrientation o = p2tr_math_orient2d (A, B, C);
+
+ /*
+ * ^
+ * | \ | ^ \
+ * a | \ c ==> | a' | \ c'
+ * v \ | | \
+ * -----> | <--- v
+ * b | b'
+ *
+ * When found a CCW triangle with edges a-b-c, change it to
+ * a'-c'-b' and not a'-b'-c' !!!
+ */
+
+ p2tr_assert_and_explain (o != COLLINEAR, "No support for collinear points!");
+
+ if (o == CCW)
+ {
+ self->edges[0] = e1->mirror;
+ self->edges[1] = e3->mirror;
+ self->edges[2] = e2->mirror;
+ }
+ else
+ {
+ self->edges[0] = e1;
+ self->edges[1] = e2;
+ self->edges[2] = e3;
+ }
+
+ /* The triangle is now referenced by the person who requested it, and also by
+ * 3 edges. Also, the 3 edges are now referenced by the triangle.
+ */
+ self->edges[0]->tri = self->edges[1]->tri = self->edges[2]->tri = self;
+ self->_refcount = 4;
+ p2tr_edge_ref (self->edges[0]);
+ p2tr_edge_ref (self->edges[1]);
+ p2tr_edge_ref (self->edges[2]);
+
+ if (T != NULL)
+ {
+ p2tr_triangulation_add_tr (T, self);
+ }
+}
+
+P2tRTriangle*
+p2tr_triangle_new (P2tREdge *e1, P2tREdge *e2, P2tREdge *e3, P2tRTriangulation *T)
+{
+ P2tRTriangle *self = g_slice_new (P2tRTriangle);
+ p2tr_triangle_init (self, e1, e2, e3, T);
+ return self;
+}
+
+/* TODO: merge logic with the remove function */
+void
+p2tr_triangle_free (P2tRTriangle *self)
+{
+ g_assert (self->_refcount == 0);
+
+ p2tr_edge_unref (self->edges[0]);
+ p2tr_edge_unref (self->edges[1]);
+ p2tr_edge_unref (self->edges[2]);
+
+ g_slice_free (P2tRTriangle, self);
+}
+
+/*
+ * e0.end
+ * ^
+ * | \
+ * | \ e0 <=> e1.end
+ * e0 | \ e1 e1 <=> e2.end
+ * | \ e2 <=> e0.end
+ * <---- v
+ * e2.end e2 e1.end
+ */
+P2tRPoint*
+p2tr_triangle_opposite_point (P2tRTriangle *self, P2tREdge *e)
+{
+ if (self->edges[0] == e || self->edges[0] == e->mirror)
+ return p2tr_edge_get_end (self->edges[1]);
+ else if (self->edges[1] == e || self->edges[1] == e->mirror)
+ return p2tr_edge_get_end (self->edges[2]);
+ else if (self->edges[2] == e || self->edges[2] == e->mirror)
+ return p2tr_edge_get_end (self->edges[0]);
+
+ p2tr_assert_and_explain (FALSE, "Edge not in in triangle!");
+}
+
+P2tREdge*
+p2tr_triangle_opposite_edge (P2tRTriangle *self, P2tRPoint *pt)
+{
+ if (p2tr_edge_get_end (self->edges[0]) == pt)
+ return self->edges[2];
+ else if (p2tr_edge_get_end (self->edges[1]) == pt)
+ return self->edges[0];
+ else if (p2tr_edge_get_end (self->edges[2]) == pt)
+ return self->edges[1];
+
+ p2tr_assert_and_explain (FALSE, "Point not in in triangle!");
+}
+
+/* Return the smallest angle not seperating two input segments (Input segments
+ * can not be disconnected, so we can't fix a small angle between them)
+ */
+gdouble
+p2tr_triangle_smallest_non_seperating_angle (P2tRTriangle *self)
+{
+ gdouble minA = M_PI;
+
+ P2tREdge *e0 = self->edges[0];
+ P2tREdge *e1 = self->edges[1];
+ P2tREdge *e2 = self->edges[2];
+
+ if (! e0->mirror->constrained && ! e1->mirror->constrained)
+ minA = MIN (minA, p2tr_angle_between(self->edges[0], self->edges[1]));
+
+ if (! e1->mirror->constrained && ! e2->mirror->constrained)
+ minA = MIN (minA, p2tr_angle_between(self->edges[1], self->edges[2]));
+
+ if (! e2->mirror->constrained && ! e0->mirror->constrained)
+ minA = MIN (minA, p2tr_angle_between(self->edges[2], self->edges[0]));
+
+ return minA;
+}
+
+gdouble
+p2tr_triangle_shortest_edge_len (P2tRTriangle *self)
+{
+ gdouble l0 = p2tr_edge_len_sq (self->edges[0]);
+ gdouble l1 = p2tr_edge_len_sq (self->edges[1]);
+ gdouble l2 = p2tr_edge_len_sq (self->edges[2]);
+
+ return sqrt (MIN (l0, MIN (l1, l2)));
+}
+
+gdouble
+p2tr_triangle_longest_edge_len (P2tRTriangle *self)
+{
+ gdouble l0 = p2tr_edge_len_sq (self->edges[0]);
+ gdouble l1 = p2tr_edge_len_sq (self->edges[1]);
+ gdouble l2 = p2tr_edge_len_sq (self->edges[2]);
+
+ return sqrt (MAX (l0, MAX (l1, l2)));
+}
+
+void
+p2tr_triangle_angles (P2tRTriangle *self, gdouble dest[3])
+{
+ dest[0] = p2tr_angle_between(self->edges[0], self->edges[1]);
+ dest[1] = p2tr_angle_between(self->edges[1], self->edges[2]);
+ dest[2] = p2tr_angle_between(self->edges[2], self->edges[0]);
+}
+
+gdouble
+p2tr_triangle_get_angle_at (P2tRTriangle *self, P2tRPoint* pt)
+{
+ if (pt == self->edges[0]->end)
+ return p2tr_angle_between(self->edges[0], self->edges[1]);
+ else if (pt == self->edges[1]->end)
+ return p2tr_angle_between(self->edges[1], self->edges[2]);
+ else if (pt == self->edges[2]->end)
+ return p2tr_angle_between(self->edges[2], self->edges[0]);
+ else
+ p2tr_assert_and_explain (FALSE, "Trying to get the angle at a point not in the tri!\n");
+}
+
+/*
+ * TODO: merge logic with the free function
+ */
+void
+p2tr_triangle_remove (P2tRTriangle *self, P2tRTriangulation *T)
+{
+ p2tr_debug ("Removing a triangle\n");
+
+ if (T != NULL)
+ p2tr_triangulation_remove_tr (T, self);
+
+ self->edges[0]->tri = NULL;
+ p2tr_triangle_unref (self);
+
+ self->edges[1]->tri = NULL;
+ p2tr_triangle_unref (self);
+
+ self->edges[2]->tri = NULL;
+ p2tr_triangle_unref (self);
+
+}
+
+void
+p2tr_triangle_circumcircle (P2tRTriangle *self, P2tRCircle *dest)
+{
+ P2tRPoint *A = p2tr_edge_get_end (self->edges[2]);
+ P2tRPoint *B = p2tr_edge_get_end (self->edges[0]);
+ P2tRPoint *C = p2tr_edge_get_end (self->edges[1]);
+
+ gdouble Anorm = A->x * A->x + A->y * A->y;
+ gdouble Bnorm = B->x * B->x + B->y * B->y;
+ gdouble Cnorm = C->x * C->x + C->y * C->y;
+
+ gdouble D = 2*(A->x * (B->y - C->y) + B->x * (C->y - A->y) + C->x * (A->y - B->y));
+
+ dest->x = (Anorm * (B->y - C->y) + Bnorm * (C->y - A->y) + Cnorm * (A->y - B->y)) / D;
+ dest->y = -(Anorm * (B->x - C->x) + Bnorm * (C->x - A->x) + Cnorm * (A->x - B->x)) / D;
+
+ dest->radius = sqrt (p2tr_math_edge_len_sq (A->x, A->y, dest->x, dest->y));
+}
+
+gboolean
+p2tr_triangle_is_circumcenter_inside (P2tRTriangle *self)
+{
+ gdouble angles[3];
+
+ p2tr_triangle_angles (self, angles);
+
+ return MAX (angles[0], MAX (angles[1], angles[2])) < M_PI / 2;
+}
+
+
+/*
+ * P0
+ * ^ \
+ * / \
+ * e2/ \e0
+ * / *C \
+ * / v
+ * P2 <------- P1
+ * e1
+ *
+ * DBG: different from source
+ */
+void
+p2tr_triangle_subdivide (P2tRTriangle *self, P2tRPoint *C, P2tRTriangulation *T, P2tRTriangle *dest_new[3])
+{
+ P2tREdge *e0 = self->edges[0];
+ P2tREdge *e1 = self->edges[1];
+ P2tREdge *e2 = self->edges[2];
+
+ P2tREdge *CP0, *CP1, *CP2;
+
+ P2tRPoint *P0 = p2tr_edge_get_end (e2);
+ P2tRPoint *P1 = p2tr_edge_get_end (e0);
+ P2tRPoint *P2 = p2tr_edge_get_end (e1);
+
+ P2tRTriangle *t0, *t1, *t2;
+
+ if (C == NULL)
+ {
+ P2tRCircle cc;
+ p2tr_triangle_circumcircle (self, &cc);
+ C = p2tr_point_new (cc.x, cc.y);
+ }
+
+ g_assert (p2tr_triangle_contains_pt (self, C));
+
+ p2tr_validate_triangulation (T);
+ p2tr_triangle_remove (self, T);
+ p2tr_validate_triangulation (T);
+
+ CP0 = p2tr_point_edge_to (C, P0);
+ CP1 = p2tr_point_edge_to (C, P1);
+ CP2 = p2tr_point_edge_to (C, P2);
+
+ t0 = p2tr_triangle_new (CP0, e0, CP1->mirror, T);
+ p2tr_validate_triangulation (T);
+ t1 = p2tr_triangle_new (CP1, e1, CP2->mirror, T);
+ p2tr_validate_triangulation (T);
+ t2 = p2tr_triangle_new (CP2, e2, CP0->mirror, T);
+ p2tr_validate_triangulation (T);
+
+ if (dest_new != NULL)
+ {
+ dest_new[0] = t0;
+ dest_new[1] = t1;
+ dest_new[2] = t2;
+ }
+ else
+ {
+ p2tr_triangle_unref (t0);
+ p2tr_triangle_unref (t1);
+ p2tr_triangle_unref (t2);
+ }
+}
+
+/* Based on http://www.blackpawn.com/texts/pointinpoly/default.html */
+gboolean
+p2tr_triangle_contains_pt (P2tRTriangle *self, P2tRPoint *P)
+{
+ P2tRPoint *A = p2tr_edge_get_end (self->edges[2]);
+ P2tRPoint *B = p2tr_edge_get_end (self->edges[0]);
+ P2tRPoint *C = p2tr_edge_get_end (self->edges[1]);
+
+ gdouble v0x = C->x - A->x;
+ gdouble v0y = C->y - A->y;
+ gdouble v1x = B->x - A->x;
+ gdouble v1y = B->y - A->y;
+ gdouble v2x = P->x - A->x;
+ gdouble v2y = P->y - A->y;
+
+ /* Compute dot products */
+ gdouble dot00 = v0x * v0x + v0y * v0y;
+ gdouble dot01 = v0x * v1x + v0y * v1y;
+ gdouble dot02 = v0x * v2x + v0y * v2y;
+ gdouble dot11 = v1x * v1x + v1y * v1y;
+ gdouble dot12 = v1x * v2x + v1y * v2y;
+
+ /* Compute barycentric coordinates */
+ gdouble invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
+ gdouble u = (dot11 * dot02 - dot01 * dot12) * invDenom;
+ gdouble v = (dot00 * dot12 - dot01 * dot02) * invDenom;
+
+ /* Check if point is in triangle */
+ return (u > -EPSILON2) && (v > -EPSILON2) && (u + v < 1 + EPSILON2);
+}
+
+
+gboolean
+p2tr_triangulation_legalize (P2tRTriangulation *T,
+ P2tRTriangle *tr)
+{
+ /* Remember! Edges in each triangle are ordered counter clockwise!
+ * q
+ * *-----------*a shared_tr = p->q = tr->edges[i]
+ * |\ / shared_ot = q->p = tr->edges[i]->mirror
+ * | \ / ot = shared_ot->tri
+ * | \ tr /
+ * | \ /
+ * | ot \ /
+ * *-----*
+ * b p
+ *
+ * Also note that we can not flip in cases of concave quads! We must check
+ * that the angles at p and at q are both smaller than 180°.
+ */
+ gint i;
+
+ /* First, make sure this triangle still exists */
+ if (! p2tr_hash_set_contains (T->tris, tr))
+ return FALSE;
+
+ /* To legalize a triangle we start by finding if any of the three edges
+ * violate the Delaunay condition
+ */
+ for (i = 0; i < 3; i++)
+ {
+ P2tREdge *shared_tr = tr->edges[i];
+ P2tREdge *shared_ot = shared_tr->mirror;
+ P2tRTriangle* ot = shared_ot->tri;
+
+ // If this is a Constrained Edge or a Delaunay Edge (only during
+ // recursive legalization) then we should not try to legalize
+ if (shared_tr->delaunay || shared_tr->constrained)
+ continue;
+
+ if (ot)
+ {
+ P2tRPoint* p = p2tr_edge_get_end (shared_ot);
+ P2tRPoint* q = p2tr_edge_get_end (shared_tr);
+ P2tRPoint* a = p2tr_triangle_opposite_point (tr, shared_tr);
+ P2tRPoint* b = p2tr_triangle_opposite_point (ot, shared_ot);
+ // We already checked if it's constrained or delaunay for the case of
+ // skipping this tri
+
+ // Check for concave quads
+ if (p2tr_triangle_get_angle_at (tr, p) + p2tr_triangle_get_angle_at (ot, p) >= M_PI
+ || p2tr_triangle_get_angle_at (tr, q) + p2tr_triangle_get_angle_at (ot, q) >= M_PI)
+ continue;
+
+ gboolean inside = p2tr_math_incircle (p, a, q, b);
+
+ if (inside)
+ {
+ P2tREdge *ab;
+ P2tREdge *bq, *qa, *pb, *ap;
+ P2tRTriangle *abq, *pba;
+
+ // First of all, remove the edge
+ p2tr_edge_remove (shared_tr, T);
+
+ // Create a new matching rotated edge
+ ab = p2tr_edge_new (a, b);
+
+ // Mark it as Delaunay
+ p2tr_edge_set_delaunay (ab, TRUE);
+
+ // Create the triangles
+ bq = p2tr_point_edge_to (b,q);
+ qa = p2tr_point_edge_to (q,a);
+ abq = p2tr_triangle_new (ab, bq, qa, T);
+
+ pb = p2tr_point_edge_to (p,b);
+ ap = p2tr_point_edge_to (a,p);
+ pba = p2tr_triangle_new (pb, ab->mirror, ap, T);
+
+ // Unref stuff
+ p2tr_edge_unref (bq);
+ p2tr_edge_unref (qa);
+
+ p2tr_edge_unref (pb);
+ p2tr_edge_unref (ap);
+
+ // Now, legalize these two triangles:
+ p2tr_triangulation_legalize (T, abq);
+ p2tr_triangle_unref (abq);
+
+ // Legalization may have killed the other triangle, but that's OK
+ // since legalization makes sure the triangle exists
+ p2tr_triangulation_legalize (T, pba);
+ p2tr_triangle_unref (pba);
+
+ // Reset the Delaunay edges, since they only are valid Delaunay edges
+ // until we add a new triangle or point.
+ // XXX: need to think about this. Can these edges be tried after we
+ // return to previous recursive level?
+ p2tr_edge_set_delaunay (ab, FALSE);
+
+ // If triangle have been legalized no need to check the other edges since
+ // the recursive legalization will handles those so we can end here.
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/* * A2
+ * / \
+ * / \
+ * / T2 \
+ * B *------>* C e = B->C
+ * ^ T1 /
+ * \ /
+ * \ v
+ * * A1
+ */
+void
+p2tr_triangulation_flip_fix (P2tREdge *e, P2tRTriangulation *T)
+{
+ P2tRTriangle *T1 = e->tri;
+ P2tRTriangle *T2 = e->mirror->tri;
+
+ /* Removed edges do not need fixing, constrained edges can not be flipped, and
+ * edges that were already flipped should not be flipped again.
+ *
+ * Finally, edges must have a triangle on both sides of them (such a situation
+ * can occur during the execution of the algorithms, without the edge being
+ * constrained) in order to be flipped
+ */
+ if (e->removed || e->constrained || e->delaunay || T1 == NULL || T2 == NULL)
+ return;
+
+ P2tRPoint *A1 = p2tr_triangle_opposite_point (T1, e);
+ P2tRPoint *A2 = p2tr_triangle_opposite_point (T2, e);
+ P2tRPoint *B = p2tr_edge_get_start (e);
+ P2tRPoint *C = p2tr_edge_get_end (e);
+
+ /* We can't do a flip fix in cases where the two triangles form together a
+ * concave quad!
+ *
+ * To check this, see if the sum of the two angles at any of the edges is
+ * larger than 180 degress.
+ */
+ P2tREdge *BC = p2tr_point_edge_to (B, C);
+
+ p2tr_validate_triangulation (T);
+ P2tREdge *CA2 = p2tr_point_edge_to (C, A2);
+ p2tr_validate_triangulation (T);
+ P2tREdge *CA1 = p2tr_point_edge_to (C, A1);
+ p2tr_validate_triangulation (T);
+
+ P2tREdge *BA2 = p2tr_point_edge_to (B, A2);
+ p2tr_validate_triangulation (T);
+ P2tREdge *BA1 = p2tr_point_edge_to (B, A1);
+ p2tr_validate_triangulation (T);
+
+ gdouble BCA2 = p2tr_angle_between (CA2->mirror,BC->mirror);
+ gdouble BCA1 = p2tr_angle_between (BC,CA1);
+
+ gdouble CBA2 = p2tr_angle_between (BC->mirror,BA2);
+ gdouble CBA1 = p2tr_angle_between (BA1->mirror,BC);
+
+ if (BCA2 + BCA1 > M_PI - EPSILON2 || CBA2 + CBA1 > M_PI - EPSILON2)
+ {
+ p2tr_debug ("Won't fix concave quads!\n");
+
+ /* In the case of concave quads, mark the edge as non flip-able */
+ p2tr_edge_set_delaunay (BC, TRUE);
+
+ /* Now fix the other edges */
+ p2tr_triangulation_flip_fix (BA2,T);
+ p2tr_triangulation_flip_fix (BA1,T);
+ p2tr_triangulation_flip_fix (CA2,T);
+ p2tr_triangulation_flip_fix (CA1,T);
+
+ /* Restore */
+ p2tr_edge_set_delaunay (BC, FALSE);
+ }
+
+ /* Check if empty circle property does not hold */
+ else if (p2tr_math_incircle (A1,C,B,A2) != INCIRCLE_OUTSIDE
+ || p2tr_math_incircle (A2,B,C,A1) != INCIRCLE_OUTSIDE)
+ {
+ P2tREdge *A2A1;
+ P2tRTriangle *Tn1, *Tn2;
+
+ p2tr_validate_triangulation (T);
+ p2tr_edge_remove (e, T);
+ p2tr_validate_triangulation (T);
+
+ A2A1 = p2tr_point_edge_to (A2, A1);
+ p2tr_validate_triangulation (T);
+
+ Tn1 = p2tr_triangle_new (A2A1, BA1->mirror, BA2, T);
+ p2tr_validate_triangulation (T);
+ Tn2 = p2tr_triangle_new (A2A1, CA1->mirror, CA2, T);
+ p2tr_validate_triangulation (T);
+
+ p2tr_edge_set_delaunay (A2A1, TRUE);
+
+ p2tr_triangulation_flip_fix (BA2,T);
+ p2tr_triangulation_flip_fix (CA2,T);
+
+ p2tr_triangulation_flip_fix (BA1->mirror,T);
+ p2tr_triangulation_flip_fix (CA1->mirror,T);
+
+ p2tr_edge_set_delaunay (A2A1, FALSE);
+ }
+}
+
+/* TODO: UNEFFICIENT LIKE HELL! */
+gboolean
+p2tr_edges_intersect (P2tREdge *e1, P2tREdge *e2)
+{
+ P2tRPoint *e1S = p2tr_edge_get_start (e1);
+ P2tRPoint *e1E = p2tr_edge_get_end (e1);
+ P2tRPoint *e2S = p2tr_edge_get_start (e1);
+ P2tRPoint *e2E = p2tr_edge_get_end (e1);
+
+ return p2tr_math_orient2d (e1S,e1E,e2S) != p2tr_math_orient2d (e1S,e1E,e2E)
+ && p2tr_math_orient2d (e2S,e2E,e1S) != p2tr_math_orient2d (e2S,e2E,e1E);
+}
+
+P2tRPoint *
+p2tr_triangle_median_pt (P2tRTriangle *self)
+{
+ P2tRPoint *A = p2tr_edge_get_end (self->edges[2]);
+ P2tRPoint *B = p2tr_edge_get_end (self->edges[0]);
+ P2tRPoint *C = p2tr_edge_get_end (self->edges[1]);
+
+ return p2tr_point_new ((A->x+B->x+C->x)/3,(A->y+B->y+C->y)/3);
+}
+
+/* TODO: this computation can be much optimized using math rules! */
+P2tRPoint *
+p2tr_edge_concentric_center (P2tREdge *e)
+{
+ gdouble x0 = p2tr_edge_get_start(e)->x, y0 = p2tr_edge_get_start(e)->y;
+ gdouble x1 = p2tr_edge_get_end(e)->x, y1 = p2tr_edge_get_end(e)->y;
+ gdouble fraction;
+
+ gdouble l = sqrt (p2tr_edge_len_sq (e));
+ /* Note that in the braces below, it's L and not 1 */
+ gdouble lPart = pow (2, round (log2 (l/2)));
+
+ while (lPart >= l)
+ lPart /= 2
+ ;
+ fraction = lPart / l;
+
+ return p2tr_point_new (x0 + fraction * (x1 - x0), y0 + fraction * (y1 - y0));
+}
+
+P2tRTriangulation*
+p2tr_triangulate (GList *p2trpoints)
+{
+ P2tPointPtrArray D = g_ptr_array_new ();
+ GList *iter;
+
+ P2tRTriangulation *T = p2tr_triangulation_new ();
+
+ GHashTable *map = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
+
+ foreach (iter, p2trpoints)
+ {
+ P2tRPoint *pt = (P2tRPoint*) iter->data;
+ P2tPoint *opt = p2t_point_new_dd (pt->x, pt->y);
+
+ g_hash_table_insert (map, opt, pt);
+ g_ptr_array_add (D, opt);
+ }
+
+ P2tCDT *cdt = p2t_cdt_new (D);
+ p2t_cdt_triangulate (cdt);
+
+ P2tTrianglePtrArray pt = p2t_cdt_get_triangles (cdt);
+ int i;
+ for (i = 0; i < pt->len; i++)
+ {
+ P2tTriangle *t = triangle_index (pt,i);
+ P2tRPoint *p0 = g_hash_table_lookup (map, p2t_triangle_get_point (t, 0));
+ P2tRPoint *p1 = g_hash_table_lookup (map, p2t_triangle_get_point (t, 1));
+ P2tRPoint *p2 = g_hash_table_lookup (map, p2t_triangle_get_point (t, 2));
+ p2tr_triangle_new (p2tr_point_edge_to (p0, p1),
+ p2tr_point_edge_to (p1, p2),
+ p2tr_point_edge_to (p2, p0), T);
+ }
+
+ p2t_cdt_free (cdt);
+
+ for (i = 0; i < D->len; i++)
+ p2t_point_free (point_index (D, i));
+
+ g_ptr_array_free (D, TRUE);
+
+ g_hash_table_destroy (map);
+
+ return T;
+
+}
+
+P2tRTriangulation *
+p2tr_triangulation_new ()
+{
+ P2tRTriangulation *self = g_slice_new (P2tRTriangulation);
+ self->tris = p2tr_hash_set_set_new (g_direct_hash, g_direct_equal, NULL);
+ self->pts = p2tr_hash_set_set_new (g_direct_hash, g_direct_equal, NULL);
+ self->edges = p2tr_hash_set_set_new (g_direct_hash, g_direct_equal, NULL);
+ return self;
+}
+
+P2tRTriangulation*
+p2tr_triangulation_free (P2tRTriangulation *self)
+{
+ P2trHashSetIter siter;
+
+ P2tRTriangle *tr;
+ P2tREdge *ed;
+ P2tRPoint *pt;
+
+ p2tr_hash_set_iter_init (&siter, self->tris);
+ while (p2tr_hash_set_iter_next (&siter, (gpointer*) &tr))
+ {
+ p2tr_triangle_unref (tr);
+ }
+
+ p2tr_hash_set_iter_init (&siter, self->edges);
+ while (p2tr_hash_set_iter_next (&siter, (gpointer*) &ed))
+ {
+ p2tr_edge_unref (ed);
+ }
+
+ p2tr_hash_set_iter_init (&siter, self->pts);
+ while (p2tr_hash_set_iter_next (&siter, (gpointer*) &pt))
+ {
+ p2tr_point_unref (pt);
+ }
+
+ g_hash_table_destroy (self->tris);
+ g_hash_table_destroy (self->edges);
+ g_hash_table_destroy (self->pts);
+
+ g_slice_free (P2tRTriangulation, self);
+}
+
+P2tRTriangulation*
+p2tr_triangulateA (P2tRPoint **p2trpoints, gint count)
+{
+ GList *A = NULL;
+ P2tRTriangulation *T;
+ int i;
+ for (i = 0; i < count; i++)
+ {
+ A = g_list_prepend (A, p2trpoints[count-i-1]);
+ }
+
+ T = p2tr_triangulate (A);
+
+ g_list_free (A);
+
+ return T;
+
+}
+
+#define DEBUG FALSE
+gboolean
+p2tr_validate_triangulation (P2tRTriangulation* T)
+{
+#if DEBUG
+ P2trHashSetIter iter;
+ GList *L;
+ P2tRTriangle *t;
+
+ p2tr_hash_set_iter_init (&iter, T->tris);
+
+ while (p2tr_hash_set_iter_next (&iter, (gpointer*)&t))
+ {
+ int i;
+ for (i = 0; i < 3; i++)
+ {
+ P2tRPoint *S = p2tr_edge_get_start (t->edges[i]);
+ P2tRPoint *E = p2tr_edge_get_end (t->edges[i]);
+
+ p2tr_assert_and_explain (p2tr_point_has_edge_to (S, E), "edge connectivity");
+ p2tr_assert_and_explain (p2tr_point_has_edge_to (E, S), "edge connectivity");
+ p2tr_assert_and_explain (t->edges[i]->tri == t, "triangle <-> edge");
+ }
+ }
+#endif
+ return TRUE;
+
+}
+
+gboolean
+p2tr_validate_edge (P2tREdge* e)
+{
+ if (e->constrained != e->mirror->constrained)
+ {
+ G_BREAKPOINT();
+ g_assert (FALSE);
+ }
+ if (e->tri == NULL && ! e->constrained)
+ {
+ G_BREAKPOINT();
+ g_assert (FALSE);
+ }
+
+ if (e->mirror->constrained != e->mirror->mirror->constrained)
+ {
+ G_BREAKPOINT();
+ g_assert (FALSE);
+ }
+ if (e->mirror->tri == NULL && ! e->mirror->constrained)
+ {
+ G_BREAKPOINT();
+ g_assert (FALSE);
+ }
+
+ return TRUE;
+
+}
+
+
+void
+p2tr_debug_point (P2tRPoint* pt, gboolean newline)
+{
+ p2tr_debug ("@PT(%g,%g)", pt->x, pt->y);
+ if (newline) p2tr_debug ("\n");
+}
+
+void
+p2tr_debug_edge (P2tREdge* ed, gboolean newline)
+{
+ p2tr_debug ("@ED(");
+ p2tr_debug_point (p2tr_edge_get_start (ed), FALSE);
+ p2tr_debug ("->");
+ p2tr_debug_point (p2tr_edge_get_end (ed), FALSE);
+ p2tr_debug (")");
+ if (newline) p2tr_debug ("\n");
+}
+
+void
+p2tr_debug_tri (P2tRTriangle* tr, gboolean newline)
+{
+ p2tr_debug ("@TR(");
+ p2tr_debug_edge (tr->edges[0], FALSE);
+ p2tr_debug ("~");
+ p2tr_debug_edge (tr->edges[1], FALSE);
+ p2tr_debug ("~");
+ p2tr_debug_edge (tr->edges[2], FALSE);
+ p2tr_debug (")");
+ if (newline) p2tr_debug ("\n");
+}
+
--- /dev/null
+/*
+ * This file is a part of Poly2Tri-C - The C port of the Poly2Tri library
+ * Porting to C done by (c) Barak Itkin <lightningismyname@gmail.com>
+ * http://code.google.com/p/poly2tri-c/
+ *
+ * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
+ * http://code.google.com/p/poly2tri/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Poly2Tri nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __POLY2TRI_C_REFINE_TRIANGULATION_H__
+#define __POLY2TRI_C_REFINE_TRIANGULATION_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <glib.h>
+#include "../common/utils.h"
+#include "utils.h"
+#include <stdio.h>
+
+#define EPSILON2 (1e-6)
+
+#define p2tr_debug //g_printerr
+
+#define p2tr_assert_and_explain(expr,err) \
+do { \
+ if (!(expr)) \
+ { \
+ g_warning (err); \
+ g_assert (FALSE); \
+ } \
+} while (FALSE)
+
+
+typedef struct P2tRTriangle_ P2tRTriangle;
+typedef struct P2tREdge_ P2tREdge;
+typedef struct P2tRPoint_ P2tRPoint;
+typedef struct P2tRTriangulation_ P2tRTriangulation;
+typedef struct P2tRCircle_ P2tRCircle;
+
+/* ########################################################################## */
+/* Common math */
+/* ########################################################################## */
+
+gdouble p2tr_math_normalize_angle (gdouble angle);
+
+/* TODO: try to somehow merge with the matching functions in utils.c */
+typedef P2tOrientation P2tROrientation;
+
+typedef enum
+{
+ INCIRCLE_ON,
+ INCIRCLE_INSIDE,
+ INCIRCLE_OUTSIDE
+} P2tRInCircle;
+
+P2tROrientation p2tr_math_orient2d (P2tRPoint* pa, P2tRPoint* pb, P2tRPoint* pc);
+
+P2tRInCircle p2tr_math_incircle (P2tRPoint* a, P2tRPoint* b, P2tRPoint* c, P2tRPoint* d);
+
+gdouble p2tr_math_edge_len_sq (gdouble x1, gdouble y1, gdouble x2, gdouble y2);
+
+/* ########################################################################## */
+/* Triangulation struct */
+/* ########################################################################## */
+
+struct P2tRTriangulation_
+{
+ P2tRHashSet *pts;
+ P2tRHashSet *edges;
+ P2tRHashSet *tris;
+};
+
+void p2tr_triangulation_remove_pt (P2tRTriangulation *self, P2tRPoint *pt);
+void p2tr_triangulation_remove_ed (P2tRTriangulation *self, P2tREdge *ed);
+void p2tr_triangulation_remove_tr (P2tRTriangulation *self, P2tRTriangle *tr);
+
+void p2tr_triangulation_add_pt (P2tRTriangulation *self, P2tRPoint *pt);
+void p2tr_triangulation_add_ed (P2tRTriangulation *self, P2tREdge *ed);
+void p2tr_triangulation_add_tr (P2tRTriangulation *self, P2tRTriangle *tr);
+
+void p2tr_triangulation_get_points (P2tRTriangulation *self, GPtrArray *dest);
+
+
+/* ########################################################################## */
+/* Point struct */
+/* ########################################################################## */
+
+struct P2tRPoint_
+{
+ gdouble x;
+ gdouble y;
+ GList *edges;
+ guint _refcount;
+};
+
+P2tRPoint* p2tr_point_new (gdouble x, gdouble y);
+
+void p2tr_point_remove_edge (P2tRPoint *self, P2tREdge *edge);
+
+void p2tr_point_remove (P2tRPoint *self, P2tRTriangulation *T);
+
+P2tREdge* p2tr_point_edge_to (P2tRPoint *self, P2tRPoint *end);
+
+P2tREdge* p2tr_point_has_edge_to (P2tRPoint *self, P2tRPoint *end);
+
+P2tREdge* p2tr_point_edgeccw (P2tRPoint *self, P2tREdge *edge);
+
+P2tREdge* p2tr_point_edgecw (P2tRPoint *self, P2tREdge *edge);
+
+gboolean p2tr_point_is_in_cluster (P2tRPoint *self, P2tREdge *e);
+
+GList* p2tr_point_get_cluster (P2tRPoint *self, P2tREdge *e, gdouble *angle);
+
+gboolean p2tr_point_is_fully_in_domain (P2tRPoint *self);
+
+void p2tr_point_free (P2tRPoint *self);
+
+#define p2tr_point_ref(pt) ((pt)->_refcount++)
+
+#define p2tr_point_unref(pt) \
+do { \
+ if ((--(pt)->_refcount) == 0) \
+ { \
+ p2tr_point_free ((pt)); \
+ } \
+} while (FALSE)
+
+
+/* ########################################################################## */
+/* Edge struct */
+/* ########################################################################## */
+
+#define P2TR_EDGE(e) ((P2tREdge*)(e))
+
+struct P2tREdge_
+{
+ P2tRPoint *end;
+ gdouble angle;
+
+ P2tREdge *mirror;
+ P2tRTriangle *tri;
+
+ gboolean delaunay;
+ gboolean constrained;
+
+ gboolean removed;
+
+ /* Note that this count does not include the pointing from the mirror edge */
+ guint _refcount;
+};
+
+P2tREdge* p2tr_edge_new (P2tRPoint *start, P2tRPoint *end);
+
+P2tREdge* p2tr_edge_new_private (P2tRPoint *start, P2tRPoint *end, gboolean mirror);
+
+void p2tr_edge_remove (P2tREdge *self, P2tRTriangulation *T);
+
+gboolean p2tr_edge_is_encroached_by (P2tREdge *self, P2tRPoint *other);
+
+gboolean p2tr_edge_is_encroached (P2tREdge *self);
+
+gboolean p2tr_edge_diametral_lens_contains (P2tREdge *self, P2tRPoint *W);
+
+gboolean p2tr_edge_diametral_circle_contains (P2tREdge *self, P2tRPoint *pt);
+
+gdouble p2tr_edge_len_sq (P2tREdge *self);
+
+void p2tr_edge_set_constrained (P2tREdge *self, gboolean b);
+
+void p2tr_edge_set_delaunay (P2tREdge *self, gboolean b);
+
+/* Note that you can't really free one edge; Freeing will happen when both
+ * have no references to
+ */
+void p2tr_edge_free (P2tREdge *self);
+
+#define p2tr_edge_ref(ed) ((ed)->_refcount++)
+
+#define p2tr_edge_unref(ed) \
+do { \
+ if ((--(ed)->_refcount) == 0) \
+ { \
+ p2tr_edge_free ((ed)); \
+ } \
+} while (FALSE)
+
+#define p2tr_edgelist_ccw(elist,e) P2TR_EDGE(g_list_cyclic_next((elist),(e))->data)
+#define p2tr_edgelist_cw(elist,e) P2TR_EDGE(g_list_cyclic_prev((elist),(e))->data)
+
+#define p2tr_edge_get_start(e) ((e)->mirror->end)
+#define p2tr_edge_get_end(e) ((e)->end)
+
+/* ########################################################################## */
+/* Triangle struct */
+/* ########################################################################## */
+
+struct P2tRTriangle_
+{
+ P2tREdge *edges[3];
+ guint _refcount;
+};
+
+struct P2tRCircle_
+{
+ gdouble x;
+ gdouble y;
+
+ gdouble radius;
+};
+
+gdouble p2tr_angle_between (P2tREdge *e1, P2tREdge *e2);
+
+void p2tr_triangle_init (P2tRTriangle *self, P2tREdge *e1, P2tREdge *e2, P2tREdge *e3, P2tRTriangulation *T);
+
+P2tRTriangle* p2tr_triangle_new (P2tREdge *e1, P2tREdge *e2, P2tREdge *e3, P2tRTriangulation *T);
+
+void p2tr_triangle_free (P2tRTriangle *self);
+
+P2tRPoint* p2tr_triangle_opposite_point (P2tRTriangle *self, P2tREdge *e);
+
+P2tREdge* p2tr_triangle_opposite_edge (P2tRTriangle *self, P2tRPoint *pt);
+
+gdouble p2tr_triangle_smallest_non_seperating_angle (P2tRTriangle *self);
+
+gdouble p2tr_triangle_shortest_edge_len (P2tRTriangle *self);
+
+gdouble p2tr_triangle_longest_edge_len (P2tRTriangle *self);
+
+void p2tr_triangle_angles (P2tRTriangle *self, gdouble dest[3]);
+
+gdouble p2tr_triangle_get_angle_at (P2tRTriangle *self, P2tRPoint* pt);
+
+void p2tr_triangle_remove (P2tRTriangle *self, P2tRTriangulation *T);
+
+void p2tr_triangle_circumcircle (P2tRTriangle *self, P2tRCircle *dest);
+
+gboolean p2tr_triangle_is_circumcenter_inside (P2tRTriangle *self);
+
+void p2tr_triangle_subdivide (P2tRTriangle *self, P2tRPoint *C, P2tRTriangulation *T, P2tRTriangle *dest_new[3]);
+
+gboolean p2tr_triangle_contains_pt (P2tRTriangle *self, P2tRPoint *P);
+
+void p2tr_triangulation_flip_fix (P2tREdge *e, P2tRTriangulation *T);
+
+gboolean p2tr_edges_intersect (P2tREdge *e1, P2tREdge *e2);
+
+P2tRPoint *p2tr_triangle_median_pt (P2tRTriangle *self);
+
+P2tRPoint *p2tr_edge_concentric_center (P2tREdge *e);
+
+P2tRTriangulation* p2tr_triangulate (GList *p2trpoints);
+
+P2tRTriangulation* p2tr_triangulateA (P2tRPoint **p2trpoints, gint count);
+
+gboolean p2tr_validate_triangulation (P2tRTriangulation* T);
+
+gboolean p2tr_validate_edge (P2tREdge* e);
+
+gboolean p2tr_false_delta (P2tRTriangle *t);
+
+#define p2tr_triangle_ref(tr) ((tr)->_refcount++)
+
+#define p2tr_triangle_unref(tr) \
+do { \
+ if ((--(tr)->_refcount) == 0) \
+ { \
+ p2tr_triangle_free ((tr)); \
+ } \
+} while (FALSE)
+
+
+
+
+
+P2tRTriangulation*
+p2tr_triangulation_free (P2tRTriangulation *self);
+
+P2tRTriangulation*
+p2tr_triangulation_new ();
+
+
+
+
+void p2tr_debug_point (P2tRPoint* pt, gboolean newline);
+
+void p2tr_debug_edge (P2tREdge* ed, gboolean newline);
+
+void p2tr_debug_tri (P2tRTriangle* tr, gboolean newline);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TRIANGULATION_H */
--- /dev/null
+/*
+ * This file is a part of Poly2Tri-C - The C port of the Poly2Tri library
+ * Porting to C done by (c) Barak Itkin <lightningismyname@gmail.com>
+ * http://code.google.com/p/poly2tri-c/
+ *
+ * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
+ * http://code.google.com/p/poly2tri/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Poly2Tri nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __POLY2TRI_C_REFINE_UTILS_H__
+#define __POLY2TRI_C_REFINE_UTILS_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <glib.h>
+
+ /* The code for the Hash Set is partially based on the example given at
+ * http://developer.gnome.org/glib/2.29/glib-Hash-Tables.html
+ */
+
+ typedef GHashTable P2tRHashSet;
+ typedef GHashTableIter P2trHashSetIter;
+
+#define p2tr_hash_set_set_new(hash_func, equal_func, destroy) g_hash_table_new_full ((hash_func), (equal_func), (destroy),NULL)
+#define p2tr_hash_set_insert(set,element) g_hash_table_insert ((set), (element), (element))
+#define p2tr_hash_set_contains(set,element) g_hash_table_lookup_extended ((set), (element), NULL, NULL)
+#define p2tr_hash_set_remove(set,element) g_hash_table_remove ((set), (element))
+
+#define p2tr_hash_set_iter_init(iter,hash_set) g_hash_table_iter_init ((iter),(hash_set))
+#define p2tr_hash_set_iter_next(iter,val) g_hash_table_iter_next ((iter),(val),NULL)
+#define p2tr_hash_set_iter_remove(iter) g_hash_table_iter_remove ((iter))
+
+#define g_list_cyclic_prev(list,elem) (((elem)->prev != NULL) ? (elem)->prev : g_list_last ((elem)))
+#define g_list_cyclic_next(list,elem) (((elem)->next != NULL) ? (elem)->next : g_list_first ((elem)))
+
+#define foreach(iter,list) for ((iter) = (list); (iter) != NULL; (iter) = (iter)->next)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UTILS_H */
--- /dev/null
+#include <glib.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "../refine/triangulation.h"
+#include "mesh-render.h"
+
+/* Most computations using the Barycentric Coordinates are Based on
+ * http://www.blackpawn.com/texts/pointinpoly/default.html */
+
+/* This function is simply to make sure the code is consitant */
+void
+p2tr_triangle_barycentric_get_points (P2tRTriangle *self,
+ P2tRPoint **A,
+ P2tRPoint **B,
+ P2tRPoint **C)
+{
+ *A = p2tr_edge_get_end (self->edges[2]);
+ *B = p2tr_edge_get_end (self->edges[0]);
+ *C = p2tr_edge_get_end (self->edges[1]);
+}
+
+#define USE_BARYCENTRIC(u,v,A,B,C) ((A) + (v)*((B)-(A)) + (u)*((C)-(A)))
+
+gboolean
+p2tr_triangle_compute_barycentric_coords (P2tRTriangle *tr,
+ gdouble Px,
+ gdouble Py,
+ gdouble *u_out,
+ gdouble *v_out)
+{
+ P2tRPoint *A, *B, *C;
+
+ gdouble u, v;
+ gdouble v0x, v0y, v1x, v1y, v2x, v2y;
+ gdouble dot00, dot01, dot02, dot11, dot12;
+ gdouble invDenom;
+
+ p2tr_triangle_barycentric_get_points (tr, &A, &B, &C);
+
+ /* v0 = C-A */
+ v0x = C->x - A->x;
+ v0y = C->y - A->y;
+ /* v1 = B-A */
+ v1x = B->x - A->x;
+ v1y = B->y - A->y;
+ /* v2 = P-A */
+ v2x = Px - A->x;
+ v2y = Py - A->y;
+
+ /* Compute dot products */
+ dot00 = v0x * v0x + v0y * v0y;
+ dot01 = v0x * v1x + v0y * v1y;
+ dot02 = v0x * v2x + v0y * v2y;
+ dot11 = v1x * v1x + v1y * v1y;
+ dot12 = v1x * v2x + v1y * v2y;
+
+ /* Compute barycentric coordinates */
+ invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
+
+ /* P = A + v*(B-A) + u*(C-A) */
+ *u_out = u = (dot11 * dot02 - dot01 * dot12) * invDenom;
+ *v_out = v = (dot00 * dot12 - dot01 * dot02) * invDenom;
+
+ /* Check if point is in triangle */
+ return (u > -EPSILON2) && (v > -EPSILON2) && (u + v < 1 + EPSILON2);
+
+}
+
+/* This function implements box logic to see if a point is contained in a
+ * triangles bounding box. This is very useful for cases where there are many
+ * triangles to test against a single point, and most of them aren't even near
+ * it.
+ *
+ * Instead of finding the Xmin, Xmax, Ymin, Ymax and checking if the the point
+ * is outside, just check if the point is on the SAME SIDE compared to all the
+ * points of the triangle.
+ * See http://lightningismyname.blogspot.com/2011/08/quickboxa-quick-point-in-triangle-test.html
+ */
+gboolean
+p2tr_triangule_quick_box_test (P2tRTriangle *self,
+ gdouble Px,
+ gdouble Py)
+{
+ P2tRPoint *A = p2tr_edge_get_end (self->edges[2]);
+ P2tRPoint *B = p2tr_edge_get_end (self->edges[0]);
+ P2tRPoint *C = p2tr_edge_get_end (self->edges[1]);
+
+ register gboolean xPBorder = B->x <= Px;
+ register gboolean yPBorder = B->y <= Py;
+
+ return (((A->x <= Px) == xPBorder) && (xPBorder == (C->x <= Px)))
+ || (((A->y <= Py) == yPBorder) && (yPBorder == (C->y <= Py)));
+}
+/**
+ * p2tr_triangulation_locate_point2:
+ * @T: A triangulation object
+ * @X: The point to locate
+ * @guess: Some triangle near the point, or NULL if not known.
+ * WARNING! The triangle must be inside the same continuos region as the
+ * point! If not, this function may return wrong values!
+ *
+ * Returns: A triangle containing the point, or NULL if the point is outside the
+ * triangulation domain.
+ */
+P2tRTriangle*
+p2tr_triangulation_locate_point2 (P2tRTriangulation *T,
+ gdouble Px,
+ gdouble Py,
+ P2tRTriangle *guess,
+ gdouble *u,
+ gdouble *v)
+{
+ if (guess == NULL || ! p2tr_hash_set_contains (T->tris, guess))
+ {
+ /* If we have nothing, check all the triangles.
+ * TODO: This can probably be improved by sampling several triangles at
+ * random, picking the closest and using it as a guess.*/
+ P2tRTriangle *tr = NULL;
+ P2trHashSetIter iter;
+ p2tr_hash_set_iter_init (&iter, T->tris);
+ while (p2tr_hash_set_iter_next (&iter, (gpointer*)&tr))
+ {
+ if (p2tr_triangule_quick_box_test (tr, Px, Py))
+ continue;
+ else if (p2tr_triangle_compute_barycentric_coords (tr, Px, Py, u, v))
+ return tr;
+ }
+ return NULL;
+ }
+ else
+ {
+ /* Maintain a set of checked triangles, and a queue of ones to check.
+ * For each triangle in the queue, check if it has the point, and if not
+ * then add it's neighbors at the end of the queue. This also gaurantess
+ * to some level a search that starts local around the triangles and only
+ * goes farther if needed. */
+ P2tRHashSet *checked = p2tr_hash_set_set_new (g_direct_hash, g_direct_equal, NULL);
+ P2tRTriangle *result = NULL, *current = NULL;
+ GQueue tris;
+ gint i;
+
+ g_queue_init (&tris);
+ g_queue_push_tail (&tris, guess);
+
+ while (! g_queue_is_empty (&tris))
+ {
+ current = (P2tRTriangle*) g_queue_pop_head (&tris);
+ if (p2tr_triangle_compute_barycentric_coords (current, Px, Py, u, v))
+ {
+ result = current;
+ break;
+ }
+ else for (i = 0; i < 3; i++)
+ {
+ P2tRTriangle *neighbor = current->edges[i]->mirror->tri;
+ if (neighbor != NULL && ! p2tr_hash_set_contains (checked, neighbor))
+ g_queue_push_tail (&tris, current->edges[i]->mirror->tri);
+ }
+
+ p2tr_hash_set_insert (checked, current);
+ }
+
+ /* If the queue is empty, then we have nothing to free. It's struct is
+ * allocated directly on the stack and it has nothing dynamic in it. */
+
+ g_hash_table_destroy (checked);
+
+ return result;
+ }
+}
+
+void p2tr_test_point_to_color (P2tRPoint* point, gfloat *dest, gpointer user_data)
+{
+/*
+ GRand* sr = g_rand_new_with_seed ((*((guchar*)&point->x)) ^ (*((guchar*)&point->y)));
+ gfloat temp;
+
+ temp = (gfloat) g_rand_double (sr);
+ dest[0] = ABS (temp);
+
+ temp = (gfloat) g_rand_double (sr);
+ dest[1] = ABS (temp);
+
+ temp = (gfloat) g_rand_double (sr);
+ dest[2] = ABS (temp);
+
+ dest[3] = 1;
+*/
+ dest[0] = 0;
+ dest[1] = 0.5;
+ dest[2] = 1;
+}
+
+#define uvt3_u(ptr) (((ptr)+0)->u)
+#define uvt3_v(ptr) (((ptr)+1)->v)
+#define uvt3_t(ptr) (((ptr)+2)->tri)
+
+void
+p2tr_mesh_render_cache_uvt (P2tRTriangulation *T,
+ P2tRuvt *dest,
+ P2tRImageConfig *config)
+{
+ p2tr_mesh_render_cache_uvt_exact (T, dest, config->x_samples * config->y_samples, config);
+}
+
+void
+p2tr_mesh_render_cache_uvt_exact (P2tRTriangulation *T,
+ P2tRuvt *dest,
+ gint dest_len,
+ P2tRImageConfig *config)
+{
+ gint x, y, n = dest_len;
+ P2tRuvt *uvt = dest;
+ P2tRTriangle *tr_prev = NULL;
+
+ uvt3_t(uvt) = p2tr_triangulation_locate_point2 (T, config->min_x, config->min_y, NULL, &uvt3_u(uvt), &uvt3_v(uvt));
+ tr_prev = uvt3_t(uvt);
+
+ for (y = 0; y < config->y_samples; y++)
+ for (x = 0; x < config->x_samples; x++)
+ {
+ if (n-- == 0) return;
+ gdouble Px = config->min_x + x * config->step_x;
+ gdouble Py = config->min_y + y * config->step_y;
+ uvt3_t(uvt) = p2tr_triangulation_locate_point2 (T, Px, Py, tr_prev, &uvt3_u(uvt), &uvt3_v(uvt));
+ tr_prev = uvt3_t(uvt);
+ uvt += 3;
+ }
+}
+
+
+void
+p2tr_mesh_render_scanline (P2tRTriangulation *T,
+ gfloat *dest,
+ P2tRImageConfig *config,
+ P2tRPointToColorFunc pt2col,
+ gpointer pt2col_user_data)
+{
+ P2tRuvt *uvt_cache = g_new (P2tRuvt, 3 * config->x_samples * config->y_samples);
+ GTimer *timer = g_timer_new ();
+
+ g_timer_start (timer);
+ p2tr_mesh_render_cache_uvt (T, uvt_cache, config);
+ g_timer_stop (timer);
+ g_debug ("Mesh preprocessing took %f seconds\n", g_timer_elapsed (timer, NULL));
+
+ g_timer_start (timer);
+ p2tr_mesh_render_scanline2 (uvt_cache, dest, config, pt2col, pt2col_user_data);
+ g_timer_stop (timer);
+ g_debug ("Mesh rendering took %f seconds\n", g_timer_elapsed (timer, NULL));
+
+ g_timer_destroy (timer);
+ g_free (uvt_cache);
+
+}
+
+
+void
+p2tr_mesh_render_scanline2 (P2tRuvt *uvt_cache,
+ gfloat *dest,
+ P2tRImageConfig *config,
+ P2tRPointToColorFunc pt2col,
+ gpointer pt2col_user_data)
+{
+ P2tRuvt *uvt_p = uvt_cache;
+
+ gdouble u, v;
+ P2tRTriangle *tr_prev = NULL, *tr_now;
+
+ gint x, y;
+
+ P2tRPoint *A = NULL, *B = NULL, *C = NULL;
+
+ gfloat *col = g_new (gfloat, config->cpp);
+ gfloat *colA = g_new (gfloat, config->cpp);
+ gfloat *colB = g_new (gfloat, config->cpp);
+ gfloat *colC = g_new (gfloat, config->cpp);
+
+ gfloat *pixel = dest;
+
+ for (y = 0; y < config->y_samples; y++)
+ for (x = 0; x < config->x_samples; x++)
+ {
+ u = uvt3_u (uvt_p);
+ v = uvt3_v (uvt_p);
+ tr_now = uvt3_t (uvt_p);
+
+ uvt_p += 3;
+
+ /* If we are outside of the triangulation, set alpha to zero and
+ * continue */
+ if (tr_now == NULL)
+ {
+ pixel[3] = 0;
+ pixel += 4;
+ }
+ else
+ {
+ /* If the triangle hasn't changed since the previous pixel,
+ * then don't sample the color at the vertices again, since
+ * that is an expensive process! */
+ if (tr_now != tr_prev)
+ {
+ /* Get the points of the triangle in some fixed order,
+ * just to make sure that the computation goes the same
+ * everywhere */
+ p2tr_triangle_barycentric_get_points (tr_now, &A, &B, &C);
+ /* At each point X sample the color into colX */
+ pt2col (A, colA, pt2col_user_data);
+ pt2col (B, colB, pt2col_user_data);
+ pt2col (C, colC, pt2col_user_data);
+ /* Set the current triangle */
+ tr_now = tr_prev;
+ }
+
+ /* Interpolate the color using barycentric coodinates */
+ *pixel++ = USE_BARYCENTRIC (u,v,colA[0],colB[0],colC[0]);
+ *pixel++ = USE_BARYCENTRIC (u,v,colA[1],colB[1],colC[1]);
+ *pixel++ = USE_BARYCENTRIC (u,v,colA[2],colB[2],colC[2]);
+ /* Finally, set as opaque since we are inside the mesh */
+ *pixel++ = 1;
+ }
+ }
+}
+
+void
+p2tr_write_ppm (FILE *f,
+ gfloat *dest,
+ P2tRImageConfig *config)
+{
+ gint x, y;
+ fprintf (f, "P3\n");
+ fprintf (f, "%d %d\n", config->x_samples, config->y_samples);
+ fprintf (f, "255\n");
+
+ gfloat *pixel = dest;
+
+ for (y = 0; y < config->y_samples; y++)
+ {
+ for (x = 0; x < config->x_samples; x++)
+ {
+ if (pixel[3] <= 0.5)
+ fprintf (f, " 0 0 0");
+ else
+ fprintf (f, "%3d %3d %3d", (guchar)(pixel[0] * 255), (guchar)(pixel[1] * 255), (guchar)(pixel[2] * 255));
+
+ if (x != config->x_samples - 1)
+ fprintf (f, " ");
+
+ pixel += 4;
+ }
+ fprintf (f, "\n");
+ }
+}
--- /dev/null
+/*
+ * File: mesh-render.h
+ * Author: Barak
+ *
+ * Created on 1 אוגוסט 2011, 15:37
+ */
+
+#ifndef MESH_RENDER_H
+#define MESH_RENDER_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef struct {
+ /* Minimal X and Y coordinates to start sampling at */
+ gdouble min_x, min_y;
+ /* Size of a step in each axis */
+ gdouble step_x, step_y;
+ /* The amount of samples desired in each axis */
+ guint x_samples, y_samples;
+ /* The amount of channels per pixel, both in destination buffer and in the
+ * colors returned from the matching point-to-color function */
+ guint cpp;
+} P2tRImageConfig;
+
+typedef void (*P2tRPointToColorFunc) (P2tRPoint* point, gfloat *dest, gpointer user_data);
+
+typedef union {
+ P2tRTriangle *tri;
+ gdouble u;
+ gdouble v;
+} P2tRuvt;
+
+void p2tr_test_point_to_color (P2tRPoint* point, gfloat *dest, gpointer user_data);
+
+void
+p2tr_mesh_render_cache_uvt (P2tRTriangulation *T,
+ P2tRuvt *dest,
+ P2tRImageConfig *config);
+
+/* Like the regular version, but cache only the specified amount of
+ * pixels */
+void
+p2tr_mesh_render_cache_uvt_exact (P2tRTriangulation *T,
+ P2tRuvt *dest,
+ gint dest_len,
+ P2tRImageConfig *config);
+
+void
+p2tr_mesh_render_scanline (P2tRTriangulation *T,
+ gfloat *dest,
+ P2tRImageConfig *config,
+ P2tRPointToColorFunc pt2col,
+ gpointer pt2col_user_data);
+
+void
+p2tr_mesh_render_scanline2 (P2tRuvt *uvt_cache,
+ gfloat *dest,
+ P2tRImageConfig *config,
+ P2tRPointToColorFunc pt2col,
+ gpointer pt2col_user_data);
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MESH_RENDER_H */
+
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <glib.h>
+
+#include "../refine/triangulation.h"
+
+#include "svg-plot.h"
+
+void
+p2tr_plot_svg_plot_group_start (const gchar *Name, FILE *outfile)
+{
+ if (Name == NULL)
+ fprintf (outfile, "<g>" "\n");
+ else
+ fprintf (outfile, "<g name=\"%s\">" "\n", Name);
+}
+
+void
+p2tr_plot_svg_plot_group_end (FILE *outfile)
+{
+ fprintf (outfile, "</g>" "\n");
+}
+
+void
+p2tr_plot_svg_plot_line (gdouble x1, gdouble y1, gdouble x2, gdouble y2, const gchar *color, FILE *outfile)
+{
+ fprintf (outfile, "<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\"" "\n", x1, y1, x2, y2);
+ fprintf (outfile, "style=\"stroke: %s; stroke-width: %f\" />" "\n", color, PLOT_LINE_WIDTH);
+ fprintf (outfile, "" "\n");
+}
+
+void
+p2tr_plot_svg_plot_arrow (gdouble x1, gdouble y1, gdouble x2, gdouble y2, const gchar* color, FILE *outfile)
+{
+ p2tr_plot_svg_plot_line (x1, y1, x2, y2, color, outfile);
+
+ gdouble dy = y2 - y1;
+ gdouble dx = x2 - x1;
+ gdouble angle = atan2 (dy, dx);
+
+ gdouble temp = angle - ARROW_SIDE_ANGLE;
+ p2tr_plot_svg_plot_line (x2, y2, x2 - ARROW_HEAD_SIZE * cos (temp), y2 - ARROW_HEAD_SIZE * sin (temp), color, outfile);
+
+ temp = angle + ARROW_SIDE_ANGLE;
+ p2tr_plot_svg_plot_line (x2, y2, x2 - ARROW_HEAD_SIZE * cos (temp), y2 - ARROW_HEAD_SIZE * sin (temp), color, outfile);
+}
+
+void
+p2tr_plot_svg_fill_triangle (gdouble x1, gdouble y1, gdouble x2, gdouble y2, gdouble x3, gdouble y3, const gchar *color, FILE *outfile)
+{
+ fprintf (outfile, "<polyline points=\"%f,%f %f,%f %f,%f\"" "\n", x1, y1, x2, y2, x3, y3);
+ fprintf (outfile, "style=\"fill: %s\" />" "\n", color);
+ fprintf (outfile, "" "\n");
+}
+
+void
+p2tr_plot_svg_fill_point (gdouble x1, gdouble y1, const gchar* color, FILE *outfile)
+{
+ fprintf (outfile, "<circle cx=\"%f\" cy=\"%f\" r=\"%f\"" "\n", x1, y1, MAX (1, PLOT_LINE_WIDTH));
+ fprintf (outfile, "style=\"fill: %s; stroke: none\" />" "\n", color);
+ fprintf (outfile, "" "\n");
+}
+
+void
+p2tr_plot_svg_plot_circle (gdouble xc, gdouble yc, gdouble R, const gchar* color, FILE *outfile)
+{
+ fprintf (outfile, "<circle cx=\"%f\" cy=\"%f\" r=\"%f\"" "\n", xc, yc, R);
+ fprintf (outfile, "style=\"stroke: %s; stroke-width: %f; fill: none\" />" "\n", color, PLOT_LINE_WIDTH);
+ fprintf (outfile, "" "\n");
+}
+
+void
+p2tr_plot_svg_plot_end (FILE *outfile)
+{
+ fprintf (outfile, "</g>" "\n");
+ fprintf (outfile, "</svg>" "\n");
+}
+
+void
+p2tr_plot_svg_plot_init (FILE *outfile)
+{
+ fprintf (outfile, "<?xml version=\"1.0\" standalone=\"no\"?>" "\n");
+ fprintf (outfile, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"" "\n");
+ fprintf (outfile, "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">" "\n");
+ fprintf (outfile, "<svg width=\"100%%\" height=\"100%%\" version=\"1.1\"" "\n");
+ fprintf (outfile, "xmlns=\"http://www.w3.org/2000/svg\">" "\n");
+ fprintf (outfile, "" "\n");
+ fprintf (outfile, "<defs>" "\n");
+ fprintf (outfile, " <marker id=\"arrow\" viewBox=\"0 0 10 10\" refX=\"10\" refY=\"5\"" "\n");
+ fprintf (outfile, " markerUnits=\"strokeWidth\" orient=\"auto\"" "\n");
+ fprintf (outfile, " markerWidth=\"12\" markerHeight=\"9\">" "\n");
+ fprintf (outfile, "" "\n");
+ fprintf (outfile, " <polyline points=\"0,0 10,5 0,10\" fill=\"none\" stroke-width=\"2px\" stroke=\"inherit\" />" "\n");
+ fprintf (outfile, " </marker>" "\n");
+ fprintf (outfile, "</defs>" "\n");
+ fprintf (outfile, "" "\n");
+ fprintf (outfile, "<g transform=\"translate(%f,%f) scale(%f,-%f)\">" "\n", X_TRANSLATE, Y_TRANSLATE, X_SCALE, Y_SCALE);
+
+ p2tr_plot_svg_plot_arrow (-20, 0, 100, 0, "black", outfile);
+ p2tr_plot_svg_plot_arrow (0, -20, 0, 100, "black", outfile);
+}
+
+void
+p2tr_plot_svg_plot_edge (P2tREdge *self, const gchar* color, FILE* outfile)
+{
+ gdouble x1 = p2tr_edge_get_start (self)->x;
+ gdouble y1 = p2tr_edge_get_start (self)->y;
+ gdouble x2 = p2tr_edge_get_end (self)->x;
+ gdouble y2 = p2tr_edge_get_end (self)->y;
+ gdouble R = sqrt ((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)) / 2;
+
+ p2tr_plot_svg_plot_line (x1, y1, x2, y2, color, outfile);
+
+
+// if (p2tr_edge_is_encroached (self))
+// p2tr_plot_svg_plot_circle ((x1 + x2) / 2, (y1 + y2) / 2, R, "red", outfile);
+}
+
+void
+p2tr_plot_svg_plot_triangle (P2tRTriangle *self, const gchar* color, FILE* outfile)
+{
+ P2tRCircle c;
+ p2tr_triangle_circumcircle (self, &c);
+ p2tr_plot_svg_plot_edge (self->edges[0], color, outfile);
+ p2tr_plot_svg_plot_edge (self->edges[1], color, outfile);
+ p2tr_plot_svg_plot_edge (self->edges[2], color, outfile);
+ p2tr_plot_svg_plot_circle (c.x, c.y, c.radius, "green", outfile);
+ p2tr_plot_svg_fill_point (self->edges[0]->end->x, self->edges[0]->end->y, "blue", outfile);
+ p2tr_plot_svg_fill_point (self->edges[1]->end->x, self->edges[1]->end->y, "blue", outfile);
+ p2tr_plot_svg_fill_point (self->edges[2]->end->x, self->edges[2]->end->y, "blue", outfile);
+}
+
+void
+CCWTest (FILE* outfile)
+{
+ P2tRPoint *A = p2tr_point_new (50, 50);
+ gdouble C[8][2] = {
+ {0, 0},
+ {50, 0},
+ {100, 0},
+ {100, 50},
+ {100, 100},
+ {50, 100},
+ {0, 100},
+ {0, 50}
+ };
+
+ gint lenC = sizeof (C) / (2 * sizeof (gdouble));
+
+ gint j;
+ for (j = 0; j < lenC; j++)
+ {
+ gint k;
+ do
+ {
+ k = rand () % lenC;
+ }
+ while (C[k][0] == INFINITY && C[k][1] == INFINITY);
+
+ gdouble *h = C[k];
+
+ p2tr_point_edge_to (A, p2tr_point_new (h[0], h[1]));
+
+ h[0] = h[1] = INFINITY;
+ }
+
+ gint i = 0;
+ GList *iter;
+
+ foreach (iter, A->edges)
+ {
+ gchar color[18];
+ P2tREdge *e = (P2tREdge*) iter->data;
+ gint val = i * 255 / lenC;
+
+ sprintf (color, "#%02x%02x%02x", val, val, val);
+ p2tr_plot_svg_plot_edge (e, color, outfile);
+ i++;
+ }
+}
+
+void
+TriangleClockwiseTest (FILE* outfile)
+{
+
+ const gchar * ecolors[3] = {"#ff0000", "#00ff00", "#0000ff"};
+ const gchar * mecolors[3] = {"#770000", "#007700", "#000077"};
+ const gchar * ptcolors[3] = {"#ff00ff", "#ffff00", "#00ffff"};
+
+ const gchar * names[3] = {"A", "B", "C"};
+
+ P2tRPoint * pts[3];
+ int i;
+ for (i = 0; i < 3; i++)
+ {
+ pts[i] = p2tr_point_new (r (), r ());
+ }
+
+ P2tREdge * edges[3];
+ for (i = 0; i < 3; i++)
+ {
+ edges[i] = p2tr_edge_new (pts[i], pts[(i + 1) % 3]);
+ }
+
+ P2tRTriangle *tri = p2tr_triangle_new (edges[0], edges[1], edges[2], NULL);
+
+ for (i = 0; i < 3; i++)
+ {
+ p2tr_plot_svg_plot_edge (tri->edges[i]->mirror, mecolors[i], outfile);
+ }
+
+ for (i = 0; i < 3; i++)
+ {
+ p2tr_plot_svg_plot_edge (tri->edges[i], ecolors[i], outfile);
+ }
+
+ for (i = 0; i < 3; i++)
+ {
+ P2tRPoint *P = p2tr_edge_get_start (tri->edges[i]);
+ p2tr_plot_svg_fill_point (P->x, P->y, ptcolors[i], outfile);
+ }
+}
+
+void
+refineTest(FILE* outfile)
+{
+ /*
+ gdouble RAW[5][2] = {{10,10},{50,50},{55,130},{0,100},{30,50}};
+ P2tRPoint *X[5];
+ gint N = 5;
+ */
+ gdouble RAW[10][2] = {{10,10},{30,30},{50,50},{52.5,90},{55,130},{27.5,115},{0,100},{15,75},{30,50},{20,30}};
+ P2tRPoint *X[10];
+ gint N = 10;
+
+ GList *XEs = NULL;
+ int i;
+
+ for (i = 0; i < N; i++)
+ {
+ X[i] = p2tr_point_new (RAW[i][0], RAW[i][1]);
+ p2tr_plot_svg_fill_point (RAW[i][0], RAW[i][1], "blue", outfile);
+ }
+
+ fprintf (stderr, "Preparing to work on %d points\n", N);
+ for (i = 0; i < N; i++)
+ {
+ P2tREdge *E = p2tr_edge_new (X[N-i-1], X[N-1-((i+1)%N)]);
+ XEs = g_list_prepend (XEs, E);
+ p2tr_edge_set_constrained (E, TRUE);
+ }
+
+ P2tRTriangulation *T = p2tr_triangulateA (X,N);
+
+ {
+ GList *liter;
+ foreach (liter, XEs)
+ p2tr_validate_edge ((P2tREdge*)liter->data);
+ }
+
+ DelaunayTerminator (T,XEs,M_PI/6,p2tr_false_delta);
+
+ {
+ P2trHashSetIter iter;
+ P2tRTriangle *t;
+ p2tr_hash_set_iter_init (&iter, T->tris);
+ while (p2tr_hash_set_iter_next (&iter, (gpointer*)&t))
+ {
+ p2tr_assert_and_explain (t != NULL, "NULL triangle found!\n");
+ p2tr_assert_and_explain (t->edges[0] != NULL && t->edges[1] != NULL && t->edges[2] != NULL,
+ "Removed triangle found!\n");
+ p2tr_plot_svg_plot_triangle (t, "black", outfile);
+
+ p2tr_validate_edge (t->edges[0]);
+ p2tr_validate_edge (t->edges[1]);
+ p2tr_validate_edge (t->edges[2]);
+
+ }
+ }
+
+#if FALSE
+ GPtrArray* points = mvc_findEdgePoints (T);
+ //PlotPoints (points);
+
+ P2tRPoint *testX = p2tr_point_new (40, 45);
+ p2tr_plot_svg_fill_point (testX->x, testX->y, "red");
+ /* Give special care for the part after the last point - it may have less
+ * points than other parts */
+ gint div = points->len / 16;
+ P2tRHashSet *allPts = p2tr_hash_set_set_new (g_direct_hash, g_direct_equal, NULL);
+ for (i = 0; i < 16; i++)
+ {
+ gint index1 = i * div;
+ gint index2 = MIN ((i + 1) * div, points->len); /* In the last iteration, take the last */
+ mvc_makePtList (testX, points, index1, index2, allPts);
+ }
+
+ {
+ gint count = 0;
+ P2trHashSetIter iter;
+ P2tRPoint *pt;
+ p2tr_hash_set_iter_init (&iter, allPts);
+ while (p2tr_hash_set_iter_next (&iter, (gpointer*)&pt))
+ {
+ p2tr_plot_svg_fill_point (pt->x, pt->y, "orange");
+ count++;
+ }
+ fprintf (stderr, "In total, had %d sample points\n", count);
+ }
+#endif
+}
+
+
+void
+p2tr_plot_svg (P2tRTriangulation *T, FILE *outfile)
+{
+ P2trHashSetIter siter;
+ P2tRTriangle *tr;
+
+ p2tr_debug ("Starting to write SVG output\n");
+ p2tr_plot_svg_plot_init (outfile);
+
+ p2tr_hash_set_iter_init (&siter, T->tris);
+ while (p2tr_hash_set_iter_next (&siter, (gpointer*)&tr))
+ p2tr_plot_svg_plot_triangle (tr, "black", outfile);
+
+ p2tr_plot_svg_plot_end (outfile);
+ p2tr_debug ("Finished writing SVG output\n");
+}
\ No newline at end of file
--- /dev/null
+/*
+ * This file is a part of Poly2Tri-C - The C port of the Poly2Tri library
+ * Porting to C done by (c) Barak Itkin <lightningismyname@gmail.com>
+ * http://code.google.com/p/poly2tri-c/
+ *
+ * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
+ * http://code.google.com/p/poly2tri/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Poly2Tri nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SVG_PLOT_H
+#define SVG_PLOT_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "../refine/refine.h"
+
+#define PLOT_LINE_WIDTH 0.40
+#define ARROW_SIDE_ANGLE (M_PI / 180 * 30)
+#define ARROW_HEAD_SIZE 2.0
+
+#define X_SCALE 3.
+#define Y_SCALE 3.
+#define X_TRANSLATE 500.
+#define Y_TRANSLATE 500.
+
+void
+p2tr_plot_svg_plot_group_start (const gchar *Name, FILE* outfile);
+
+void
+p2tr_plot_svg_plot_group_end (FILE* outfile);
+
+void
+p2tr_plot_svg_plot_line (gdouble x1, gdouble y1, gdouble x2, gdouble y2, const gchar *color, FILE* outfile);
+
+void
+p2tr_plot_svg_plot_arrow (gdouble x1, gdouble y1, gdouble x2, gdouble y2, const gchar* color, FILE* outfile);
+
+void
+p2tr_plot_svg_fill_triangle (gdouble x1, gdouble y1, gdouble x2, gdouble y2, gdouble x3, gdouble y3, const gchar *color, FILE* outfile);
+
+void
+p2tr_plot_svg_fill_point (gdouble x1, gdouble y1, const gchar* color, FILE* outfile);
+
+void
+p2tr_plot_svg_plot_circle (gdouble xc, gdouble yc, gdouble R, const gchar* color, FILE* outfile);
+
+void
+p2tr_plot_svg_plot_end (FILE* outfile);
+
+void
+p2tr_plot_svg_plot_init (FILE* outfile);
+
+void
+p2tr_plot_svg_plot_edge (P2tREdge *self, const gchar* color, FILE* outfile);
+
+void
+p2tr_plot_svg_plot_triangle (P2tRTriangle *self, const gchar* color, FILE* outfile);
+
+#define r() (10+(rand () % 91))
+
+void
+p2tr_plot_svg (P2tRTriangulation *T, FILE* outfile);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SVG_PLOT_H */
+
--- /dev/null
+/*
+ * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
+ * http://code.google.com/p/poly2tri/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Poly2Tri nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "advancing_front.h"
+
+void
+p2t_node_init_pt (P2tNode* THIS, P2tPoint* p)
+{
+ THIS->point = p;
+ THIS->triangle = NULL;
+ THIS->value = p->x;
+ THIS->next = NULL;
+ THIS->prev = NULL;
+}
+
+P2tNode*
+p2t_node_new_pt (P2tPoint* p)
+{
+ P2tNode* THIS = g_slice_new (P2tNode);
+ p2t_node_init_pt (THIS, p);
+ return THIS;
+}
+
+void
+p2t_node_init_pt_tr (P2tNode* THIS, P2tPoint* p, P2tTriangle* t)
+{
+ THIS->point = p;
+ THIS->triangle = t;
+ THIS->value = p->x;
+ THIS->next = NULL;
+ THIS->prev = NULL;
+}
+
+P2tNode*
+p2t_node_new_pt_tr (P2tPoint* p, P2tTriangle* t)
+{
+ P2tNode* THIS = g_slice_new (P2tNode);
+ p2t_node_init_pt_tr (THIS, p, t);
+ return THIS;
+}
+
+void p2t_node_destroy (P2tNode* THIS)
+{
+}
+void p2t_node_free (P2tNode* THIS)
+{
+ p2t_node_destroy (THIS);
+ g_slice_free (P2tNode, THIS);
+}
+
+void
+p2t_advancingfront_init (P2tAdvancingFront* THIS, P2tNode* head, P2tNode* tail)
+{
+ THIS->head_ = head;
+ THIS->tail_ = tail;
+ THIS->search_node_ = head;
+}
+
+P2tAdvancingFront*
+p2t_advancingfront_new (P2tNode* head, P2tNode* tail)
+{
+ P2tAdvancingFront* THIS = g_slice_new (P2tAdvancingFront);
+ p2t_advancingfront_init (THIS, head, tail);
+ return THIS;
+}
+
+void
+p2t_advancingfront_destroy (P2tAdvancingFront* THIS) { }
+
+void
+p2t_advancingfront_free (P2tAdvancingFront* THIS)
+{
+ p2t_advancingfront_destroy (THIS);
+ g_slice_free (P2tAdvancingFront, THIS);
+}
+
+P2tNode*
+p2t_advancingfront_locate_node (P2tAdvancingFront *THIS, const double x)
+{
+ P2tNode* node = THIS->search_node_;
+
+ if (x < node->value)
+ {
+ while ((node = node->prev) != NULL)
+ {
+ if (x >= node->value)
+ {
+ THIS->search_node_ = node;
+ return node;
+ }
+ }
+ }
+ else
+ {
+ while ((node = node->next) != NULL)
+ {
+ if (x < node->value)
+ {
+ THIS->search_node_ = node->prev;
+ return node->prev;
+ }
+ }
+ }
+ return NULL;
+}
+
+P2tNode*
+p2t_advancingfront_find_search_node (P2tAdvancingFront *THIS, const double x)
+{
+ // TODO: implement BST index
+ return THIS->search_node_;
+}
+
+P2tNode*
+p2t_advancingfront_locate_point (P2tAdvancingFront *THIS, const P2tPoint* point)
+{
+ const double px = point->x;
+ P2tNode* node = p2t_advancingfront_find_search_node (THIS, px);
+ const double nx = node->point->x;
+
+ if (px == nx)
+ {
+ if (point != node->point)
+ {
+ // We might have two nodes with same x value for a short time
+ if (point == node->prev->point)
+ {
+ node = node->prev;
+ }
+ else if (point == node->next->point)
+ {
+ node = node->next;
+ }
+ else
+ {
+ assert (0);
+ }
+ }
+ }
+ else if (px < nx)
+ {
+ while ((node = node->prev) != NULL)
+ {
+ if (point == node->point)
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ while ((node = node->next) != NULL)
+ {
+ if (point == node->point)
+ break;
+ }
+ }
+ if (node) THIS->search_node_ = node;
+ return node;
+}
+
+P2tNode*
+p2t_advancingfront_head (P2tAdvancingFront *THIS)
+{
+ return THIS->head_;
+}
+
+void
+AdvancingFront_set_head (P2tAdvancingFront *THIS, P2tNode* node)
+{
+ THIS->head_ = node;
+}
+
+P2tNode*
+p2t_advancingfront_tail (P2tAdvancingFront *THIS)
+{
+ return THIS->tail_;
+}
+
+void
+p2t_advancingfront_set_tail (P2tAdvancingFront *THIS, P2tNode* node)
+{
+ THIS->tail_ = node;
+}
+
+P2tNode*
+p2t_advancingfront_search (P2tAdvancingFront *THIS)
+{
+ return THIS->search_node_;
+}
+
+void
+p2t_advancingfront_set_search (P2tAdvancingFront *THIS, P2tNode* node)
+{
+ THIS->search_node_ = node;
+}
+
--- /dev/null
+/*
+ * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
+ * http://code.google.com/p/poly2tri/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Poly2Tri nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ADVANCED_FRONT_H
+#define ADVANCED_FRONT_H
+
+#include "../common/poly2tri-private.h"
+#include "../common/shapes.h"
+
+// Advancing front node
+
+struct _P2tNode
+{
+ P2tPoint* point;
+ P2tTriangle* triangle;
+
+ struct _P2tNode* next;
+ struct _P2tNode* prev;
+
+ double value;
+};
+
+void p2t_node_init_pt (P2tNode* THIS, P2tPoint* p);
+P2tNode* p2t_node_new_pt (P2tPoint* p);
+void p2t_node_init_pt_tr (P2tNode* THIS, P2tPoint* p, P2tTriangle* t);
+P2tNode* p2t_node_new_pt_tr (P2tPoint* p, P2tTriangle* t);
+void p2t_node_destroy (P2tNode* THIS);
+void p2t_node_free (P2tNode* THIS);
+
+// Advancing front
+
+struct AdvancingFront_
+{
+ //private:
+
+ P2tNode* head_, *tail_, *search_node_;
+
+};
+
+void p2t_advancingfront_init (P2tAdvancingFront* THIS, P2tNode* head, P2tNode* tail);
+P2tAdvancingFront* p2t_advancingfront_new (P2tNode* head, P2tNode* tail);
+
+void p2t_advancingfront_destroy (P2tAdvancingFront* THIS);
+void p2t_advancingfront_free (P2tAdvancingFront* THIS);
+
+P2tNode* p2t_advancingfront_head (P2tAdvancingFront *THIS);
+void AdvancingFront_set_head (P2tAdvancingFront *THIS, P2tNode* node);
+P2tNode* p2t_advancingfront_tail (P2tAdvancingFront *THIS);
+void p2t_advancingfront_set_tail (P2tAdvancingFront *THIS, P2tNode* node);
+P2tNode* p2t_advancingfront_search (P2tAdvancingFront *THIS);
+void p2t_advancingfront_set_search (P2tAdvancingFront *THIS, P2tNode* node);
+
+/// Locate insertion point along advancing front
+P2tNode* p2t_advancingfront_locate_node (P2tAdvancingFront *THIS, const double x);
+
+P2tNode* p2t_advancingfront_locate_point (P2tAdvancingFront *THIS, const P2tPoint* point);
+
+P2tNode* p2t_advancingfront_find_search_node (P2tAdvancingFront *THIS, const double x);
+
+#endif
--- /dev/null
+/* \r
+ * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors\r
+ * http://code.google.com/p/poly2tri/\r
+ *\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * * Redistributions of source code must retain the above copyright notice,\r
+ * this list of conditions and the following disclaimer.\r
+ * * Redistributions in binary form must reproduce the above copyright notice,\r
+ * this list of conditions and the following disclaimer in the documentation\r
+ * and/or other materials provided with the distribution.\r
+ * * Neither the name of Poly2Tri nor the names of its contributors may be\r
+ * used to endorse or promote products derived from this software without specific\r
+ * prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\r
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\r
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\r
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+#include "cdt.h"\r
+\r
+void\r
+p2t_cdt_init (P2tCDT* THIS, P2tPointPtrArray polyline)\r
+{\r
+ THIS->sweep_context_ = p2t_sweepcontext_new (polyline);\r
+ THIS->sweep_ = p2t_sweep_new ();\r
+}\r
+\r
+P2tCDT*\r
+p2t_cdt_new (P2tPointPtrArray polyline)\r
+{\r
+ P2tCDT* THIS = g_slice_new (P2tCDT);\r
+ p2t_cdt_init (THIS, polyline);\r
+ return THIS;\r
+}\r
+\r
+void\r
+p2t_cdt_destroy (P2tCDT* THIS)\r
+{\r
+ p2t_sweepcontext_delete (THIS->sweep_context_);\r
+ p2t_sweep_free (THIS->sweep_);\r
+}\r
+\r
+void\r
+p2t_cdt_free (P2tCDT* THIS)\r
+{\r
+ p2t_cdt_destroy (THIS);\r
+ g_slice_free (P2tCDT, THIS);\r
+}\r
+\r
+void\r
+p2t_cdt_add_hole (P2tCDT *THIS, P2tPointPtrArray polyline)\r
+{\r
+ p2t_sweepcontext_add_hole (THIS->sweep_context_, polyline);\r
+}\r
+\r
+void\r
+p2t_cdt_add_point (P2tCDT *THIS, P2tPoint* point)\r
+{\r
+ p2t_sweepcontext_add_point (THIS->sweep_context_, point);\r
+}\r
+\r
+void\r
+p2t_cdt_triangulate (P2tCDT *THIS)\r
+{\r
+ p2t_sweep_triangulate (THIS->sweep_, THIS->sweep_context_);\r
+}\r
+\r
+P2tTrianglePtrArray\r
+p2t_cdt_get_triangles (P2tCDT *THIS)\r
+{\r
+ return p2t_sweepcontext_get_triangles (THIS->sweep_context_);\r
+}\r
+\r
+P2tTrianglePtrList\r
+p2t_cdt_get_map (P2tCDT *THIS)\r
+{\r
+ return p2t_sweepcontext_get_map (THIS->sweep_context_);\r
+}\r
--- /dev/null
+/* \r
+ * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors\r
+ * http://code.google.com/p/poly2tri/\r
+ *\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * * Redistributions of source code must retain the above copyright notice,\r
+ * this list of conditions and the following disclaimer.\r
+ * * Redistributions in binary form must reproduce the above copyright notice,\r
+ * this list of conditions and the following disclaimer in the documentation\r
+ * and/or other materials provided with the distribution.\r
+ * * Neither the name of Poly2Tri nor the names of its contributors may be\r
+ * used to endorse or promote products derived from this software without specific\r
+ * prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\r
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\r
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\r
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+\r
+#ifndef CDT_H\r
+#define CDT_H\r
+\r
+#include "../common/poly2tri-private.h"\r
+#include "advancing_front.h"\r
+#include "sweep_context.h"\r
+#include "sweep.h"\r
+\r
+/**\r
+ * \r
+ * @author Mason Green <mason.green@gmail.com>\r
+ *\r
+ */\r
+\r
+struct CDT_\r
+{\r
+ //private:\r
+\r
+ /**\r
+ * Internals\r
+ */\r
+\r
+ P2tSweepContext* sweep_context_;\r
+ P2tSweep* sweep_;\r
+\r
+};\r
+/**\r
+ * Constructor - add polyline with non repeating points\r
+ *\r
+ * @param polyline\r
+ */\r
+void p2t_cdt_init (P2tCDT* THIS, P2tPointPtrArray polyline);\r
+P2tCDT* p2t_cdt_new (P2tPointPtrArray polyline);\r
+\r
+/**\r
+ * Destructor - clean up memory\r
+ */\r
+void p2t_cdt_destroy (P2tCDT* THIS);\r
+void p2t_cdt_free (P2tCDT* THIS);\r
+\r
+/**\r
+ * Add a hole\r
+ *\r
+ * @param polyline\r
+ */\r
+void p2t_cdt_add_hole (P2tCDT *THIS, P2tPointPtrArray polyline);\r
+\r
+/**\r
+ * Add a steiner point\r
+ *\r
+ * @param point\r
+ */\r
+void p2t_cdt_add_point (P2tCDT *THIS, P2tPoint* point);\r
+\r
+/**\r
+ * Triangulate - do this AFTER you've added the polyline, holes, and Steiner points\r
+ */\r
+void p2t_cdt_triangulate (P2tCDT *THIS);\r
+\r
+/**\r
+ * Get CDT triangles\r
+ */\r
+P2tTrianglePtrArray p2t_cdt_get_triangles (P2tCDT *THIS);\r
+\r
+/**\r
+ * Get triangle map\r
+ */\r
+P2tTrianglePtrList p2t_cdt_get_map (P2tCDT *THIS);\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors\r
+ * http://code.google.com/p/poly2tri/\r
+ * \r
+ *\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * * Redistributions of source code must retain the above copyright notice,\r
+ * this list of conditions and the following disclaimer.\r
+ * * Redistributions in binary form must reproduce the above copyright notice,\r
+ * this list of conditions and the following disclaimer in the documentation\r
+ * and/or other materials provided with the distribution.\r
+ * * Neither the name of Poly2Tri nor the names of its contributors may be\r
+ * used to endorse or promote products derived from this software without specific\r
+ * prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\r
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\r
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\r
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+#include "sweep.h"\r
+#include "sweep_context.h"\r
+#include "advancing_front.h"\r
+#include "../common/utils.h"\r
+#include "../common/shapes.h"\r
+\r
+void\r
+p2t_sweep_init (P2tSweep* THIS)\r
+{\r
+ THIS->nodes_ = g_ptr_array_new ();\r
+}\r
+\r
+P2tSweep*\r
+p2t_sweep_new ()\r
+{\r
+ P2tSweep* THIS = g_new (P2tSweep, 1);\r
+ p2t_sweep_init (THIS);\r
+ return THIS;\r
+}\r
+\r
+/**\r
+ * Destructor - clean up memory\r
+ */\r
+void\r
+p2t_sweep_destroy (P2tSweep* THIS)\r
+{\r
+ int i;\r
+ // Clean up memory\r
+ for (i = 0; i < THIS->nodes_->len; i++)\r
+ {\r
+ p2t_node_free (node_index (THIS->nodes_, i));\r
+ }\r
+\r
+ g_ptr_array_free (THIS->nodes_, TRUE);\r
+}\r
+\r
+void\r
+p2t_sweep_free (P2tSweep* THIS)\r
+{\r
+ p2t_sweep_destroy (THIS);\r
+ g_free (THIS);\r
+}\r
+\r
+// Triangulate simple polygon with holes\r
+\r
+void\r
+p2t_sweep_triangulate (P2tSweep *THIS, P2tSweepContext *tcx)\r
+{\r
+ p2t_sweepcontext_init_triangulation (tcx);\r
+ p2t_sweepcontext_create_advancingfront (tcx, THIS->nodes_);\r
+ // Sweep points; build mesh\r
+ p2t_sweep_sweep_points (THIS, tcx);\r
+ // Clean up\r
+ p2t_sweep_finalization_polygon (THIS, tcx);\r
+}\r
+\r
+void\r
+p2t_sweep_sweep_points (P2tSweep *THIS, P2tSweepContext *tcx)\r
+{\r
+ int i, j;\r
+ for (i = 1; i < p2t_sweepcontext_point_count (tcx); i++)\r
+ {\r
+ P2tPoint* point = p2t_sweepcontext_get_point (tcx, i);\r
+ P2tNode* node = p2t_sweep_point_event (THIS, tcx, point);\r
+ for (j = 0; j < point->edge_list->len; j++)\r
+ {\r
+ p2t_sweep_edge_event_ed_n (THIS, tcx, edge_index (point->edge_list, j), node);\r
+ }\r
+ }\r
+}\r
+\r
+void\r
+p2t_sweep_finalization_polygon (P2tSweep *THIS, P2tSweepContext *tcx)\r
+{\r
+ // Get an Internal triangle to start with\r
+ P2tTriangle* t = p2t_advancingfront_head (p2t_sweepcontext_front (tcx))->next->triangle;\r
+ P2tPoint* p = p2t_advancingfront_head (p2t_sweepcontext_front (tcx))->next->point;\r
+ while (!p2t_triangle_get_constrained_edge_cw (t, p))\r
+ {\r
+ t = p2t_triangle_neighbor_ccw (t, p);\r
+ }\r
+\r
+ // Collect interior triangles constrained by edges\r
+ p2t_sweepcontext_mesh_clean (tcx, t);\r
+}\r
+\r
+P2tNode*\r
+p2t_sweep_point_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tPoint* point)\r
+{\r
+ P2tNode* node = p2t_sweepcontext_locate_node (tcx, point);\r
+ P2tNode* new_node = p2t_sweep_new_front_triangle (THIS, tcx, point, node);\r
+\r
+ // Only need to check +epsilon since point never have smaller\r
+ // x value than node due to how we fetch nodes from the front\r
+ if (point->x <= node->point->x + EPSILON)\r
+ {\r
+ p2t_sweep_fill (THIS, tcx, node);\r
+ }\r
+\r
+ //tcx.AddNode(new_node);\r
+\r
+ p2t_sweep_fill_advancingfront (THIS, tcx, new_node);\r
+ return new_node;\r
+}\r
+\r
+void\r
+p2t_sweep_edge_event_ed_n (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node)\r
+{\r
+ tcx->edge_event.constrained_edge = edge;\r
+ tcx->edge_event.right = (edge->p->x > edge->q->x);\r
+\r
+ if (p2t_sweep_is_edge_side_of_triangle (THIS, node->triangle, edge->p, edge->q))\r
+ {\r
+ return;\r
+ }\r
+\r
+ // For now we will do all needed filling\r
+ // TODO: integrate with flip process might give some better performance\r
+ // but for now this avoid the issue with cases that needs both flips and fills\r
+ p2t_sweep_fill_edge_event (THIS, tcx, edge, node);\r
+ p2t_sweep_edge_event_pt_pt_tr_pt (THIS, tcx, edge->p, edge->q, node->triangle, edge->q);\r
+}\r
+\r
+void\r
+p2t_sweep_edge_event_pt_pt_tr_pt (P2tSweep *THIS, P2tSweepContext *tcx, P2tPoint* ep, P2tPoint* eq, P2tTriangle* triangle, P2tPoint* point)\r
+{\r
+ if (p2t_sweep_is_edge_side_of_triangle (THIS, triangle, ep, eq))\r
+ {\r
+ return;\r
+ }\r
+\r
+ P2tPoint* p1 = p2t_triangle_point_ccw (triangle, point);\r
+ P2tOrientation o1 = p2t_orient2d (eq, p1, ep);\r
+ if (o1 == COLLINEAR)\r
+ {\r
+ if (p2t_triangle_contains_pt_pt (triangle, eq, p1))\r
+ {\r
+ p2t_triangle_mark_constrained_edge_pt_pt (triangle, eq, p1);\r
+ // We are modifying the constraint maybe it would be better to\r
+ // not change the given constraint and just keep a variable for the new constraint\r
+ tcx->edge_event.constrained_edge->q = p1;\r
+ triangle = p2t_triangle_neighbor_across (triangle, point);\r
+ p2t_sweep_edge_event_pt_pt_tr_pt (THIS, tcx, ep, p1, triangle, p1);\r
+ }\r
+ else\r
+ {\r
+ g_error ("EdgeEvent - collinear points not supported");\r
+ }\r
+ return;\r
+ }\r
+\r
+ P2tPoint* p2 = p2t_triangle_point_cw (triangle, point);\r
+ P2tOrientation o2 = p2t_orient2d (eq, p2, ep);\r
+ if (o2 == COLLINEAR)\r
+ {\r
+ if (p2t_triangle_contains_pt_pt (triangle, eq, p2))\r
+ {\r
+ p2t_triangle_mark_constrained_edge_pt_pt (triangle, eq, p2);\r
+ // We are modifying the constraint maybe it would be better to\r
+ // not change the given constraint and just keep a variable for the new constraint\r
+ tcx->edge_event.constrained_edge->q = p2;\r
+ triangle = p2t_triangle_neighbor_across (triangle, point);\r
+ p2t_sweep_edge_event_pt_pt_tr_pt (THIS, tcx, ep, p2, triangle, p2);\r
+ }\r
+ else\r
+ {\r
+ g_error ("EdgeEvent - collinear points not supported");\r
+ }\r
+ return;\r
+ }\r
+\r
+ if (o1 == o2)\r
+ {\r
+ // Need to decide if we are rotating CW or CCW to get to a triangle\r
+ // that will cross edge\r
+ if (o1 == CW)\r
+ {\r
+ triangle = p2t_triangle_neighbor_ccw (triangle, point);\r
+ }\r
+ else\r
+ {\r
+ triangle = p2t_triangle_neighbor_cw (triangle, point);\r
+ }\r
+ p2t_sweep_edge_event_pt_pt_tr_pt (THIS, tcx, ep, eq, triangle, point);\r
+ }\r
+ else\r
+ {\r
+ // This triangle crosses constraint so lets flippin start!\r
+ p2t_sweep_flip_edge_event (THIS, tcx, ep, eq, triangle, point);\r
+ }\r
+}\r
+\r
+gboolean\r
+p2t_sweep_is_edge_side_of_triangle (P2tSweep *THIS, P2tTriangle *triangle, P2tPoint* ep, P2tPoint* eq)\r
+{\r
+ int index = p2t_triangle_edge_index (triangle, ep, eq);\r
+\r
+ if (index != -1)\r
+ {\r
+ p2t_triangle_mark_constrained_edge_i (triangle, index);\r
+ P2tTriangle* t = p2t_triangle_get_neighbor (triangle, index);\r
+ if (t)\r
+ {\r
+ p2t_triangle_mark_constrained_edge_pt_pt (t, ep, eq);\r
+ }\r
+ return TRUE;\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+P2tNode*\r
+p2t_sweep_new_front_triangle (P2tSweep *THIS, P2tSweepContext *tcx, P2tPoint* point, P2tNode *node)\r
+{\r
+ P2tTriangle* triangle = p2t_triangle_new (point, node->point, node->next->point);\r
+\r
+ p2t_triangle_mark_neighbor_tr (triangle, node->triangle);\r
+ p2t_sweepcontext_add_to_map (tcx, triangle);\r
+\r
+ P2tNode* new_node = p2t_node_new_pt (point);\r
+ g_ptr_array_add (THIS->nodes_, new_node);\r
+\r
+ new_node->next = node->next;\r
+ new_node->prev = node;\r
+ node->next->prev = new_node;\r
+ node->next = new_node;\r
+\r
+ if (!p2t_sweep_legalize (THIS, tcx, triangle))\r
+ {\r
+ p2t_sweepcontext_map_triangle_to_nodes (tcx, triangle);\r
+ }\r
+\r
+ return new_node;\r
+}\r
+\r
+void\r
+p2t_sweep_fill (P2tSweep *THIS, P2tSweepContext *tcx, P2tNode* node)\r
+{\r
+ P2tTriangle* triangle = p2t_triangle_new (node->prev->point, node->point, node->next->point);\r
+\r
+ // TODO: should copy the constrained_edge value from neighbor triangles\r
+ // for now constrained_edge values are copied during the legalize\r
+ p2t_triangle_mark_neighbor_tr (triangle, node->prev->triangle);\r
+ p2t_triangle_mark_neighbor_tr (triangle, node->triangle);\r
+\r
+ p2t_sweepcontext_add_to_map (tcx, triangle);\r
+\r
+ // Update the advancing front\r
+ node->prev->next = node->next;\r
+ node->next->prev = node->prev;\r
+\r
+ // If it was legalized the triangle has already been mapped\r
+ if (!p2t_sweep_legalize (THIS, tcx, triangle))\r
+ {\r
+ p2t_sweepcontext_map_triangle_to_nodes (tcx, triangle);\r
+ }\r
+\r
+}\r
+\r
+void\r
+p2t_sweep_fill_advancingfront (P2tSweep *THIS, P2tSweepContext *tcx, P2tNode* n)\r
+{\r
+\r
+ // Fill right holes\r
+ P2tNode* node = n->next;\r
+\r
+ while (node->next)\r
+ {\r
+ double angle = p2t_sweep_hole_angle (THIS, node);\r
+ if (angle > M_PI_2 || angle < -M_PI_2) break;\r
+ p2t_sweep_fill (THIS, tcx, node);\r
+ node = node->next;\r
+ }\r
+\r
+ // Fill left holes\r
+ node = n->prev;\r
+\r
+ while (node->prev)\r
+ {\r
+ double angle = p2t_sweep_hole_angle (THIS, node);\r
+ if (angle > M_PI_2 || angle < -M_PI_2) break;\r
+ p2t_sweep_fill (THIS, tcx, node);\r
+ node = node->prev;\r
+ }\r
+\r
+ // Fill right basins\r
+ if (n->next && n->next->next)\r
+ {\r
+ double angle = p2t_sweep_basin_angle (THIS, n);\r
+ if (angle < PI_3div4)\r
+ {\r
+ p2t_sweep_fill_basin (THIS, tcx, n);\r
+ }\r
+ }\r
+}\r
+\r
+double\r
+p2t_sweep_basin_angle (P2tSweep *THIS, P2tNode* node)\r
+{\r
+ double ax = node->point->x - node->next->next->point->x;\r
+ double ay = node->point->y - node->next->next->point->y;\r
+ return atan2 (ay, ax);\r
+}\r
+\r
+double\r
+p2t_sweep_hole_angle (P2tSweep *THIS, P2tNode* node)\r
+{\r
+ /* Complex plane\r
+ * ab = cosA +i*sinA\r
+ * ab = (ax + ay*i)(bx + by*i) = (ax*bx + ay*by) + i(ax*by-ay*bx)\r
+ * atan2(y,x) computes the principal value of the argument function\r
+ * applied to the complex number x+iy\r
+ * Where x = ax*bx + ay*by\r
+ * y = ax*by - ay*bx\r
+ */\r
+ double ax = node->next->point->x - node->point->x;\r
+ double ay = node->next->point->y - node->point->y;\r
+ double bx = node->prev->point->x - node->point->x;\r
+ double by = node->prev->point->y - node->point->y;\r
+ return atan2 (ax * by - ay * bx, ax * bx + ay * by);\r
+}\r
+\r
+gboolean\r
+p2t_sweep_legalize (P2tSweep *THIS, P2tSweepContext *tcx, P2tTriangle *t)\r
+{\r
+ int i;\r
+ // To legalize a triangle we start by finding if any of the three edges\r
+ // violate the Delaunay condition\r
+ for (i = 0; i < 3; i++)\r
+ {\r
+ if (t->delaunay_edge[i])\r
+ continue;\r
+\r
+ P2tTriangle* ot = p2t_triangle_get_neighbor (t, i);\r
+\r
+ if (ot)\r
+ {\r
+ P2tPoint* p = p2t_triangle_get_point (t, i);\r
+ P2tPoint* op = p2t_triangle_opposite_point (ot, t, p);\r
+ int oi = p2t_triangle_index (ot, op);\r
+\r
+ // If this is a Constrained Edge or a Delaunay Edge(only during recursive legalization)\r
+ // then we should not try to legalize\r
+ if (ot->constrained_edge[oi] || ot->delaunay_edge[oi])\r
+ {\r
+ t->constrained_edge[i] = ot->constrained_edge[oi];\r
+ continue;\r
+ }\r
+\r
+ gboolean inside = p2t_sweep_incircle (THIS, p, p2t_triangle_point_ccw (t, p), p2t_triangle_point_cw (t, p), op);\r
+\r
+ if (inside)\r
+ {\r
+ // Lets mark this shared edge as Delaunay\r
+ t->delaunay_edge[i] = TRUE;\r
+ ot->delaunay_edge[oi] = TRUE;\r
+\r
+ // Lets rotate shared edge one vertex CW to legalize it\r
+ p2t_sweep_rotate_triangle_pair (THIS, t, p, ot, op);\r
+\r
+ // We now got one valid Delaunay Edge shared by two triangles\r
+ // This gives us 4 new edges to check for Delaunay\r
+\r
+ // Make sure that triangle to node mapping is done only one time for a specific triangle\r
+ gboolean not_legalized = !p2t_sweep_legalize (THIS, tcx, t);\r
+ if (not_legalized)\r
+ {\r
+ p2t_sweepcontext_map_triangle_to_nodes (tcx, t);\r
+ }\r
+\r
+ not_legalized = !p2t_sweep_legalize (THIS, tcx, ot);\r
+ if (not_legalized)\r
+ p2t_sweepcontext_map_triangle_to_nodes (tcx, ot);\r
+\r
+ // Reset the Delaunay edges, since they only are valid Delaunay edges\r
+ // until we add a new triangle or point.\r
+ // XXX: need to think about this. Can these edges be tried after we\r
+ // return to previous recursive level?\r
+ t->delaunay_edge[i] = FALSE;\r
+ ot->delaunay_edge[oi] = FALSE;\r
+\r
+ // If triangle have been legalized no need to check the other edges since\r
+ // the recursive legalization will handles those so we can end here.\r
+ return TRUE;\r
+ }\r
+ }\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+gboolean\r
+p2t_sweep_incircle (P2tSweep *THIS, P2tPoint* pa, P2tPoint* pb, P2tPoint* pc, P2tPoint* pd)\r
+{\r
+ double adx = pa->x - pd->x;\r
+ double ady = pa->y - pd->y;\r
+ double bdx = pb->x - pd->x;\r
+ double bdy = pb->y - pd->y;\r
+\r
+ double adxbdy = adx * bdy;\r
+ double bdxady = bdx * ady;\r
+ double oabd = adxbdy - bdxady;\r
+\r
+ if (oabd <= 0)\r
+ return FALSE;\r
+\r
+ double cdx = pc->x - pd->x;\r
+ double cdy = pc->y - pd->y;\r
+\r
+ double cdxady = cdx * ady;\r
+ double adxcdy = adx * cdy;\r
+ double ocad = cdxady - adxcdy;\r
+\r
+ if (ocad <= 0)\r
+ return FALSE;\r
+\r
+ double bdxcdy = bdx * cdy;\r
+ double cdxbdy = cdx * bdy;\r
+\r
+ double alift = adx * adx + ady * ady;\r
+ double blift = bdx * bdx + bdy * bdy;\r
+ double clift = cdx * cdx + cdy * cdy;\r
+\r
+ double det = alift * (bdxcdy - cdxbdy) + blift * ocad + clift * oabd;\r
+\r
+ return det > 0;\r
+}\r
+\r
+void\r
+p2t_sweep_rotate_triangle_pair (P2tSweep *THIS, P2tTriangle *t, P2tPoint* p, P2tTriangle *ot, P2tPoint* op)\r
+{\r
+ P2tTriangle* n1, *n2, *n3, *n4;\r
+ n1 = p2t_triangle_neighbor_ccw (t, p);\r
+ n2 = p2t_triangle_neighbor_cw (t, p);\r
+ n3 = p2t_triangle_neighbor_ccw (ot, op);\r
+ n4 = p2t_triangle_neighbor_cw (ot, op);\r
+\r
+ gboolean ce1, ce2, ce3, ce4;\r
+ ce1 = p2t_triangle_get_constrained_edge_ccw (t, p);\r
+ ce2 = p2t_triangle_get_constrained_edge_cw (t, p);\r
+ ce3 = p2t_triangle_get_constrained_edge_ccw (ot, op);\r
+ ce4 = p2t_triangle_get_constrained_edge_cw (ot, op);\r
+\r
+ gboolean de1, de2, de3, de4;\r
+ de1 = p2t_triangle_get_delunay_edge_ccw (t, p);\r
+ de2 = p2t_triangle_get_delunay_edge_cw (t, p);\r
+ de3 = p2t_triangle_get_delunay_edge_ccw (ot, op);\r
+ de4 = p2t_triangle_get_delunay_edge_cw (ot, op);\r
+\r
+ p2t_triangle_legalize_pt_pt (t, p, op);\r
+ p2t_triangle_legalize_pt_pt (ot, op, p);\r
+\r
+ // Remap delaunay_edge\r
+ p2t_triangle_set_delunay_edge_ccw (ot, p, de1);\r
+ p2t_triangle_set_delunay_edge_cw (t, p, de2);\r
+ p2t_triangle_set_delunay_edge_ccw (t, op, de3);\r
+ p2t_triangle_set_delunay_edge_cw (ot, op, de4);\r
+\r
+ // Remap constrained_edge\r
+ p2t_triangle_set_constrained_edge_ccw (ot, p, ce1);\r
+ p2t_triangle_set_constrained_edge_cw (t, p, ce2);\r
+ p2t_triangle_set_constrained_edge_ccw (t, op, ce3);\r
+ p2t_triangle_set_constrained_edge_cw (ot, op, ce4);\r
+\r
+ // Remap neighbors\r
+ // XXX: might optimize the markNeighbor by keeping track of\r
+ // what side should be assigned to what neighbor after the\r
+ // rotation. Now mark neighbor does lots of testing to find\r
+ // the right side.\r
+ p2t_triangle_clear_neighbors (t);\r
+ p2t_triangle_clear_neighbors (ot);\r
+ if (n1) p2t_triangle_mark_neighbor_tr (ot, n1);\r
+ if (n2) p2t_triangle_mark_neighbor_tr (t, n2);\r
+ if (n3) p2t_triangle_mark_neighbor_tr (t, n3);\r
+ if (n4) p2t_triangle_mark_neighbor_tr (ot, n4);\r
+ p2t_triangle_mark_neighbor_tr (t, ot);\r
+}\r
+\r
+void\r
+p2t_sweep_fill_basin (P2tSweep *THIS, P2tSweepContext *tcx, P2tNode* node)\r
+{\r
+ if (p2t_orient2d (node->point, node->next->point, node->next->next->point) == CCW)\r
+ {\r
+ tcx->basin.left_node = node->next->next;\r
+ }\r
+ else\r
+ {\r
+ tcx->basin.left_node = node->next;\r
+ }\r
+\r
+ // Find the bottom and right node\r
+ tcx->basin.bottom_node = tcx->basin.left_node;\r
+ while (tcx->basin.bottom_node->next\r
+ && tcx->basin.bottom_node->point->y >= tcx->basin.bottom_node->next->point->y)\r
+ {\r
+ tcx->basin.bottom_node = tcx->basin.bottom_node->next;\r
+ }\r
+ if (tcx->basin.bottom_node == tcx->basin.left_node)\r
+ {\r
+ // No valid basin\r
+ return;\r
+ }\r
+\r
+ tcx->basin.right_node = tcx->basin.bottom_node;\r
+ while (tcx->basin.right_node->next\r
+ && tcx->basin.right_node->point->y < tcx->basin.right_node->next->point->y)\r
+ {\r
+ tcx->basin.right_node = tcx->basin.right_node->next;\r
+ }\r
+ if (tcx->basin.right_node == tcx->basin.bottom_node)\r
+ {\r
+ // No valid basins\r
+ return;\r
+ }\r
+\r
+ tcx->basin.width = tcx->basin.right_node->point->x - tcx->basin.left_node->point->x;\r
+ tcx->basin.left_highest = tcx->basin.left_node->point->y > tcx->basin.right_node->point->y;\r
+\r
+ p2t_sweep_fill_basin_req (THIS, tcx, tcx->basin.bottom_node);\r
+}\r
+\r
+void\r
+p2t_sweep_fill_basin_req (P2tSweep *THIS, P2tSweepContext *tcx, P2tNode* node)\r
+{\r
+ // if shallow stop filling\r
+ if (p2t_sweep_is_shallow (THIS, tcx, node))\r
+ {\r
+ return;\r
+ }\r
+\r
+ p2t_sweep_fill (THIS, tcx, node);\r
+\r
+ if (node->prev == tcx->basin.left_node && node->next == tcx->basin.right_node)\r
+ {\r
+ return;\r
+ }\r
+ else if (node->prev == tcx->basin.left_node)\r
+ {\r
+ P2tOrientation o = p2t_orient2d (node->point, node->next->point, node->next->next->point);\r
+ if (o == CW)\r
+ {\r
+ return;\r
+ }\r
+ node = node->next;\r
+ }\r
+ else if (node->next == tcx->basin.right_node)\r
+ {\r
+ P2tOrientation o = p2t_orient2d (node->point, node->prev->point, node->prev->prev->point);\r
+ if (o == CCW)\r
+ {\r
+ return;\r
+ }\r
+ node = node->prev;\r
+ }\r
+ else\r
+ {\r
+ // Continue with the neighbor node with lowest Y value\r
+ if (node->prev->point->y < node->next->point->y)\r
+ {\r
+ node = node->prev;\r
+ }\r
+ else\r
+ {\r
+ node = node->next;\r
+ }\r
+ }\r
+\r
+ p2t_sweep_fill_basin_req (THIS, tcx, node);\r
+}\r
+\r
+gboolean\r
+p2t_sweep_is_shallow (P2tSweep *THIS, P2tSweepContext *tcx, P2tNode* node)\r
+{\r
+ double height;\r
+\r
+ if (tcx->basin.left_highest)\r
+ {\r
+ height = tcx->basin.left_node->point->y - node->point->y;\r
+ }\r
+ else\r
+ {\r
+ height = tcx->basin.right_node->point->y - node->point->y;\r
+ }\r
+\r
+ // if shallow stop filling\r
+ if (tcx->basin.width > height)\r
+ {\r
+ return TRUE;\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+void\r
+p2t_sweep_fill_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node)\r
+{\r
+ if (tcx->edge_event.right)\r
+ {\r
+ p2t_sweep_fill_right_above_edge_event (THIS, tcx, edge, node);\r
+ }\r
+ else\r
+ {\r
+ p2t_sweep_fill_left_above_edge_event (THIS, tcx, edge, node);\r
+ }\r
+}\r
+\r
+void\r
+p2t_sweep_fill_right_above_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node)\r
+{\r
+ while (node->next->point->x < edge->p->x)\r
+ {\r
+ // Check if next node is below the edge\r
+ if (p2t_orient2d (edge->q, node->next->point, edge->p) == CCW)\r
+ {\r
+ p2t_sweep_fill_right_below_edge_event (THIS, tcx, edge, node);\r
+ }\r
+ else\r
+ {\r
+ node = node->next;\r
+ }\r
+ }\r
+}\r
+\r
+void\r
+p2t_sweep_fill_right_below_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node)\r
+{\r
+ if (node->point->x < edge->p->x)\r
+ {\r
+ if (p2t_orient2d (node->point, node->next->point, node->next->next->point) == CCW)\r
+ {\r
+ // Concave\r
+ p2t_sweep_fill_right_concave_edge_event (THIS, tcx, edge, node);\r
+ }\r
+ else\r
+ {\r
+ // Convex\r
+ p2t_sweep_fill_right_convex_edge_event (THIS, tcx, edge, node);\r
+ // Retry this one\r
+ p2t_sweep_fill_right_below_edge_event (THIS, tcx, edge, node);\r
+ }\r
+ }\r
+}\r
+\r
+void\r
+p2t_sweep_fill_right_concave_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node)\r
+{\r
+ p2t_sweep_fill (THIS, tcx, node->next);\r
+ if (node->next->point != edge->p)\r
+ {\r
+ // Next above or below edge?\r
+ if (p2t_orient2d (edge->q, node->next->point, edge->p) == CCW)\r
+ {\r
+ // Below\r
+ if (p2t_orient2d (node->point, node->next->point, node->next->next->point) == CCW)\r
+ {\r
+ // Next is concave\r
+ p2t_sweep_fill_right_concave_edge_event (THIS, tcx, edge, node);\r
+ }\r
+ else\r
+ {\r
+ // Next is convex\r
+ }\r
+ }\r
+ }\r
+\r
+}\r
+\r
+void\r
+p2t_sweep_fill_right_convex_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node)\r
+{\r
+ // Next concave or convex?\r
+ if (p2t_orient2d (node->next->point, node->next->next->point, node->next->next->next->point) == CCW)\r
+ {\r
+ // Concave\r
+ p2t_sweep_fill_right_concave_edge_event (THIS, tcx, edge, node->next);\r
+ }\r
+ else\r
+ {\r
+ // Convex\r
+ // Next above or below edge?\r
+ if (p2t_orient2d (edge->q, node->next->next->point, edge->p) == CCW)\r
+ {\r
+ // Below\r
+ p2t_sweep_fill_right_convex_edge_event (THIS, tcx, edge, node->next);\r
+ }\r
+ else\r
+ {\r
+ // Above\r
+ }\r
+ }\r
+}\r
+\r
+void\r
+p2t_sweep_fill_left_above_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node)\r
+{\r
+ while (node->prev->point->x > edge->p->x)\r
+ {\r
+ // Check if next node is below the edge\r
+ if (p2t_orient2d (edge->q, node->prev->point, edge->p) == CW)\r
+ {\r
+ p2t_sweep_fill_left_below_edge_event (THIS, tcx, edge, node);\r
+ }\r
+ else\r
+ {\r
+ node = node->prev;\r
+ }\r
+ }\r
+}\r
+\r
+void\r
+p2t_sweep_fill_left_below_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node)\r
+{\r
+ if (node->point->x > edge->p->x)\r
+ {\r
+ if (p2t_orient2d (node->point, node->prev->point, node->prev->prev->point) == CW)\r
+ {\r
+ // Concave\r
+ p2t_sweep_fill_left_concave_edge_event (THIS, tcx, edge, node);\r
+ }\r
+ else\r
+ {\r
+ // Convex\r
+ p2t_sweep_fill_left_convex_edge_event (THIS, tcx, edge, node);\r
+ // Retry this one\r
+ p2t_sweep_fill_left_below_edge_event (THIS, tcx, edge, node);\r
+ }\r
+ }\r
+}\r
+\r
+void\r
+p2t_sweep_fill_left_convex_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node)\r
+{\r
+ // Next concave or convex?\r
+ if (p2t_orient2d (node->prev->point, node->prev->prev->point, node->prev->prev->prev->point) == CW)\r
+ {\r
+ // Concave\r
+ p2t_sweep_fill_left_concave_edge_event (THIS, tcx, edge, node->prev);\r
+ }\r
+ else\r
+ {\r
+ // Convex\r
+ // Next above or below edge?\r
+ if (p2t_orient2d (edge->q, node->prev->prev->point, edge->p) == CW)\r
+ {\r
+ // Below\r
+ p2t_sweep_fill_left_convex_edge_event (THIS, tcx, edge, node->prev);\r
+ }\r
+ else\r
+ {\r
+ // Above\r
+ }\r
+ }\r
+}\r
+\r
+void\r
+p2t_sweep_fill_left_concave_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node)\r
+{\r
+ p2t_sweep_fill (THIS, tcx, node->prev);\r
+ if (node->prev->point != edge->p)\r
+ {\r
+ // Next above or below edge?\r
+ if (p2t_orient2d (edge->q, node->prev->point, edge->p) == CW)\r
+ {\r
+ // Below\r
+ if (p2t_orient2d (node->point, node->prev->point, node->prev->prev->point) == CW)\r
+ {\r
+ // Next is concave\r
+ p2t_sweep_fill_left_concave_edge_event (THIS, tcx, edge, node);\r
+ }\r
+ else\r
+ {\r
+ // Next is convex\r
+ }\r
+ }\r
+ }\r
+\r
+}\r
+\r
+void\r
+p2t_sweep_flip_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tPoint* ep, P2tPoint* eq, P2tTriangle* t, P2tPoint* p)\r
+{\r
+ P2tTriangle* ot = p2t_triangle_neighbor_across (t, p);\r
+ P2tPoint* op = p2t_triangle_opposite_point (ot, t, p);\r
+\r
+ if (ot == NULL)\r
+ {\r
+ // If we want to integrate the fillEdgeEvent do it here\r
+ // With current implementation we should never get here\r
+ //throw new RuntimeException( "[BUG:FIXME] FLIP failed due to missing triangle");\r
+ assert (0);\r
+ }\r
+\r
+ if (p2t_utils_in_scan_area (p, p2t_triangle_point_ccw (t, p), p2t_triangle_point_cw (t, p), op))\r
+ {\r
+ // Lets rotate shared edge one vertex CW\r
+ p2t_sweep_rotate_triangle_pair (THIS, t, p, ot, op);\r
+ p2t_sweepcontext_map_triangle_to_nodes (tcx, t);\r
+ p2t_sweepcontext_map_triangle_to_nodes (tcx, ot);\r
+\r
+ if (p == eq && op == ep)\r
+ {\r
+ if (p2t_point_equals (eq, tcx->edge_event.constrained_edge->q) && p2t_point_equals (ep, tcx->edge_event.constrained_edge->p))\r
+ {\r
+ p2t_triangle_mark_constrained_edge_pt_pt (t, ep, eq);\r
+ p2t_triangle_mark_constrained_edge_pt_pt (ot, ep, eq);\r
+ p2t_sweep_legalize (THIS, tcx, t);\r
+ p2t_sweep_legalize (THIS, tcx, ot);\r
+ }\r
+ else\r
+ {\r
+ // XXX: I think one of the triangles should be legalized here?\r
+ }\r
+ }\r
+ else\r
+ {\r
+ P2tOrientation o = p2t_orient2d (eq, op, ep);\r
+ t = p2t_sweep_next_flip_triangle (THIS, tcx, (int) o, t, ot, p, op);\r
+ p2t_sweep_flip_edge_event (THIS, tcx, ep, eq, t, p);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ P2tPoint* newP = p2t_sweep_next_flip_point (THIS, ep, eq, ot, op);\r
+ p2t_sweep_flip_scan_edge_event (THIS, tcx, ep, eq, t, ot, newP);\r
+ p2t_sweep_edge_event_pt_pt_tr_pt (THIS, tcx, ep, eq, t, p);\r
+ }\r
+}\r
+\r
+P2tTriangle*\r
+p2t_sweep_next_flip_triangle (P2tSweep *THIS, P2tSweepContext *tcx, int o, P2tTriangle *t, P2tTriangle *ot, P2tPoint* p, P2tPoint* op)\r
+{\r
+ if (o == CCW)\r
+ {\r
+ // ot is not crossing edge after flip\r
+ int edge_index = p2t_triangle_edge_index (ot, p, op);\r
+ ot->delaunay_edge[edge_index] = TRUE;\r
+ p2t_sweep_legalize (THIS, tcx, ot);\r
+ p2t_triangle_clear_delunay_edges (ot);\r
+ return t;\r
+ }\r
+\r
+ // t is not crossing edge after flip\r
+ int edge_index = p2t_triangle_edge_index (t, p, op);\r
+\r
+ t->delaunay_edge[edge_index] = TRUE;\r
+ p2t_sweep_legalize (THIS, tcx, t);\r
+ p2t_triangle_clear_delunay_edges (t);\r
+ return ot;\r
+}\r
+\r
+P2tPoint*\r
+p2t_sweep_next_flip_point (P2tSweep *THIS, P2tPoint* ep, P2tPoint* eq, P2tTriangle *ot, P2tPoint* op)\r
+{\r
+ P2tOrientation o2d = p2t_orient2d (eq, op, ep);\r
+ if (o2d == CW)\r
+ {\r
+ // Right\r
+ return p2t_triangle_point_ccw (ot, op);\r
+ }\r
+ else if (o2d == CCW)\r
+ {\r
+ // Left\r
+ return p2t_triangle_point_cw (ot, op);\r
+ }\r
+ else\r
+ {\r
+ //throw new RuntimeException("[Unsupported] Opposing point on constrained edge");\r
+ assert (0);\r
+ }\r
+}\r
+\r
+void\r
+p2t_sweep_flip_scan_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tPoint* ep, P2tPoint* eq, P2tTriangle *flip_triangle,\r
+ P2tTriangle *t, P2tPoint* p)\r
+{\r
+ P2tTriangle* ot = p2t_triangle_neighbor_across (t, p);\r
+ P2tPoint* op = p2t_triangle_opposite_point (ot, t, p);\r
+\r
+ if (p2t_triangle_neighbor_across (t, p) == NULL)\r
+ {\r
+ // If we want to integrate the fillEdgeEvent do it here\r
+ // With current implementation we should never get here\r
+ //throw new RuntimeException( "[BUG:FIXME] FLIP failed due to missing triangle");\r
+ assert (0);\r
+ }\r
+\r
+ if (p2t_utils_in_scan_area (eq, p2t_triangle_point_ccw (flip_triangle, eq), p2t_triangle_point_cw (flip_triangle, eq), op))\r
+ {\r
+ // flip with new edge op->eq\r
+ p2t_sweep_flip_edge_event (THIS, tcx, eq, op, ot, op);\r
+ // TODO: Actually I just figured out that it should be possible to\r
+ // improve this by getting the next ot and op before the the above\r
+ // flip and continue the flipScanEdgeEvent here\r
+ // set new ot and op here and loop back to inScanArea test\r
+ // also need to set a new flip_triangle first\r
+ // Turns out at first glance that this is somewhat complicated\r
+ // so it will have to wait.\r
+ }\r
+ else\r
+ {\r
+ P2tPoint* newP = p2t_sweep_next_flip_point (THIS, ep, eq, ot, op);\r
+ p2t_sweep_flip_scan_edge_event (THIS, tcx, ep, eq, flip_triangle, ot, newP);\r
+ }\r
+}\r
--- /dev/null
+/*
+ * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
+ * http://code.google.com/p/poly2tri/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Poly2Tri nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * Sweep-line, Constrained Delauney Triangulation (CDT) See: Domiter, V. and
+ * Zalik, B.(2008)'Sweep-line algorithm for constrained Delaunay triangulation',
+ * International Journal of Geographical Information Science
+ *
+ * "FlipScan" Constrained Edge Algorithm invented by Thomas �hl�n, thahlen@gmail.com
+ */
+
+#ifndef SWEEP_H
+#define SWEEP_H
+
+#include "../common/poly2tri-private.h"
+#include "../common/shapes.h"
+
+struct Sweep_
+{
+//private:
+P2tNodePtrArray nodes_;
+
+};
+
+void p2t_sweep_init (P2tSweep* THIS);
+P2tSweep* p2t_sweep_new ();
+
+/**
+ * Destructor - clean up memory
+ */
+void p2t_sweep_destroy (P2tSweep* THIS);
+void p2t_sweep_free (P2tSweep* THIS);
+
+/**
+ * Triangulate
+ *
+ * @param tcx
+ */
+void p2t_sweep_triangulate (P2tSweep *THIS, P2tSweepContext *tcx);
+
+/**
+ * Start sweeping the Y-sorted point set from bottom to top
+ *
+ * @param tcx
+ */
+void p2t_sweep_sweep_points (P2tSweep *THIS, P2tSweepContext *tcx);
+
+/**
+ * Find closes node to the left of the new point and
+ * create a new triangle. If needed new holes and basins
+ * will be filled to.
+ *
+ * @param tcx
+ * @param point
+ * @return
+ */
+P2tNode* p2t_sweep_point_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tPoint* point);
+
+/**
+ *
+ *
+ * @param tcx
+ * @param edge
+ * @param node
+ */
+void p2t_sweep_edge_event_ed_n (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node);
+
+void p2t_sweep_edge_event_pt_pt_tr_pt (P2tSweep *THIS, P2tSweepContext *tcx, P2tPoint* ep, P2tPoint* eq, P2tTriangle* triangle, P2tPoint* point);
+
+/**
+ * Creates a new front triangle and legalize it
+ *
+ * @param tcx
+ * @param point
+ * @param node
+ * @return
+ */
+P2tNode* p2t_sweep_new_front_triangle (P2tSweep *THIS, P2tSweepContext *tcx, P2tPoint* point, P2tNode* node);
+
+/**
+ * Adds a triangle to the advancing front to fill a hole.
+ * @param tcx
+ * @param node - middle node, that is the bottom of the hole
+ */
+void p2t_sweep_fill (P2tSweep *THIS, P2tSweepContext *tcx, P2tNode* node);
+
+/**
+ * Returns true if triangle was legalized
+ */
+gboolean p2t_sweep_legalize (P2tSweep *THIS, P2tSweepContext *tcx, P2tTriangle *t);
+
+/**
+ * <b>Requirement</b>:<br>
+ * 1. a,b and c form a triangle.<br>
+ * 2. a and d is know to be on opposite side of bc<br>
+ * <pre>
+ * a
+ * +
+ * / \
+ * / \
+ * b/ \c
+ * +-------+
+ * / d \
+ * / \
+ * </pre>
+ * <b>Fact</b>: d has to be in area B to have a chance to be inside the circle formed by
+ * a,b and c<br>
+ * d is outside B if orient2d(a,b,d) or orient2d(c,a,d) is CW<br>
+ * This preknowledge gives us a way to optimize the incircle test
+ * @param a - triangle point, opposite d
+ * @param b - triangle point
+ * @param c - triangle point
+ * @param d - point opposite a
+ * @return true if d is inside circle, false if on circle edge
+ */
+gboolean p2t_sweep_incircle (P2tSweep *THIS, P2tPoint* pa, P2tPoint* pb, P2tPoint* pc, P2tPoint* pd);
+
+/**
+ * Rotates a triangle pair one vertex CW
+ *<pre>
+ * n2 n2
+ * P +-----+ P +-----+
+ * | t /| |\ t |
+ * | / | | \ |
+ * n1| / |n3 n1| \ |n3
+ * | / | after CW | \ |
+ * |/ oT | | oT \|
+ * +-----+ oP +-----+
+ * n4 n4
+ * </pre>
+ */
+void p2t_sweep_rotate_triangle_pair (P2tSweep *THIS, P2tTriangle *t, P2tPoint* p, P2tTriangle *ot, P2tPoint* op);
+
+/**
+ * Fills holes in the Advancing Front
+ *
+ *
+ * @param tcx
+ * @param n
+ */
+void p2t_sweep_fill_advancingfront (P2tSweep *THIS, P2tSweepContext *tcx, P2tNode* n);
+
+/**
+ *
+ * @param node - middle node
+ * @return the angle between 3 front nodes
+ */
+double p2t_sweep_hole_angle (P2tSweep *THIS, P2tNode* node);
+
+/**
+ * The basin angle is decided against the horizontal line [1,0]
+ */
+double p2t_sweep_basin_angle (P2tSweep *THIS, P2tNode* node);
+
+/**
+ * Fills a basin that has formed on the Advancing Front to the right
+ * of given node.<br>
+ * First we decide a left,bottom and right node that forms the
+ * boundaries of the basin. Then we do a reqursive fill.
+ *
+ * @param tcx
+ * @param node - starting node, this or next node will be left node
+ */
+void p2t_sweep_fill_basin (P2tSweep *THIS, P2tSweepContext *tcx, P2tNode* node);
+
+/**
+ * Recursive algorithm to fill a Basin with triangles
+ *
+ * @param tcx
+ * @param node - bottom_node
+ * @param cnt - counter used to alternate on even and odd numbers
+ */
+void p2t_sweep_fill_basin_req (P2tSweep *THIS, P2tSweepContext *tcx, P2tNode* node);
+
+gboolean p2t_sweep_is_shallow (P2tSweep *THIS, P2tSweepContext *tcx, P2tNode* node);
+
+gboolean p2t_sweep_is_edge_side_of_triangle (P2tSweep *THIS, P2tTriangle *triangle, P2tPoint* ep, P2tPoint* eq);
+
+void p2t_sweep_fill_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node);
+
+void p2t_sweep_fill_right_above_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node);
+
+void p2t_sweep_fill_right_below_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node);
+
+void p2t_sweep_fill_right_concave_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node);
+
+void p2t_sweep_fill_right_convex_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node);
+
+void p2t_sweep_fill_left_above_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node);
+
+void p2t_sweep_fill_left_below_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node);
+
+void p2t_sweep_fill_left_concave_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node);
+
+void p2t_sweep_fill_left_convex_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node);
+
+void p2t_sweep_flip_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tPoint* ep, P2tPoint* eq, P2tTriangle* t, P2tPoint* p);
+
+/**
+ * After a flip we have two triangles and know that only one will still be
+ * intersecting the edge. So decide which to contiune with and legalize the other
+ *
+ * @param tcx
+ * @param o - should be the result of an orient2d( eq, op, ep )
+ * @param t - triangle 1
+ * @param ot - triangle 2
+ * @param p - a point shared by both triangles
+ * @param op - another point shared by both triangles
+ * @return returns the triangle still intersecting the edge
+ */
+P2tTriangle* p2t_sweep_next_flip_triangle (P2tSweep *THIS, P2tSweepContext *tcx, int o, P2tTriangle *t, P2tTriangle *ot, P2tPoint* p, P2tPoint* op);
+
+/**
+ * When we need to traverse from one triangle to the next we need
+ * the point in current triangle that is the opposite point to the next
+ * triangle.
+ *
+ * @param ep
+ * @param eq
+ * @param ot
+ * @param op
+ * @return
+ */
+P2tPoint* p2t_sweep_next_flip_point (P2tSweep *THIS, P2tPoint* ep, P2tPoint* eq, P2tTriangle *ot, P2tPoint* op);
+
+/**
+ * Scan part of the FlipScan algorithm<br>
+ * When a triangle pair isn't flippable we will scan for the next
+ * point that is inside the flip triangle scan area. When found
+ * we generate a new flipEdgeEvent
+ *
+ * @param tcx
+ * @param ep - last point on the edge we are traversing
+ * @param eq - first point on the edge we are traversing
+ * @param flipTriangle - the current triangle sharing the point eq with edge
+ * @param t
+ * @param p
+ */
+void p2t_sweep_flip_scan_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tPoint* ep, P2tPoint* eq, P2tTriangle *flip_triangle, P2tTriangle *t, P2tPoint* p);
+
+void p2t_sweep_finalization_polygon (P2tSweep *THIS, P2tSweepContext *tcx);
+
+#endif
--- /dev/null
+/*
+ * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
+ * http://code.google.com/p/poly2tri/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Poly2Tri nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "sweep_context.h"
+#include "advancing_front.h"
+
+void
+p2t_sweepcontext_basin_init (P2tSweepContextBasin* THIS)
+{
+ p2t_sweepcontext_basin_clear (THIS);
+}
+
+void
+p2t_sweepcontext_basin_clear (P2tSweepContextBasin* THIS)
+{
+ THIS->left_node = NULL;
+ THIS->bottom_node = NULL;
+ THIS->right_node = NULL;
+ THIS->width = 0.0;
+ THIS->left_highest = FALSE;
+}
+
+void
+p2t_sweepcontext_edgeevent_init (P2tSweepContextEdgeEvent* THIS)
+{
+ THIS->constrained_edge = NULL;
+ THIS->right = FALSE;
+}
+
+void
+p2t_sweepcontext_init (P2tSweepContext* THIS, P2tPointPtrArray polyline)
+{
+ int i;
+ THIS->edge_list = g_ptr_array_new ();
+ THIS->triangles_ = g_ptr_array_new ();
+ THIS->map_ = NULL;
+
+ p2t_sweepcontext_basin_init (&THIS->basin);
+ p2t_sweepcontext_edgeevent_init (&THIS->edge_event);
+
+ THIS->points_ = g_ptr_array_sized_new (polyline->len);
+ for (i = 0; i < polyline->len; i++)
+ g_ptr_array_add (THIS->points_, point_index (polyline, i));
+
+ p2t_sweepcontext_init_edges (THIS, THIS->points_);
+}
+
+P2tSweepContext*
+p2t_sweepcontext_new (P2tPointPtrArray polyline)
+{
+ P2tSweepContext* THIS = g_new (P2tSweepContext, 1);
+ p2t_sweepcontext_init (THIS, polyline);
+ return THIS;
+}
+
+void
+p2t_sweepcontext_destroy (P2tSweepContext* THIS)
+{
+ GList* iter;
+ int i;
+ // Clean up memory
+
+ p2t_point_free (THIS->head_);
+ p2t_point_free (THIS->tail_);
+ p2t_advancingfront_free (THIS->front_);
+ p2t_node_free (THIS->af_head_);
+ p2t_node_free (THIS->af_middle_);
+ p2t_node_free (THIS->af_tail_);
+
+ g_ptr_array_free (THIS->triangles_, TRUE);
+
+ for (iter = g_list_first (THIS->map_); iter != NULL; iter = g_list_next (iter))
+ {
+ P2tTriangle* ptr = triangle_val (iter);
+ g_free (ptr);
+ }
+
+ g_list_free (THIS->map_);
+
+ for (i = 0; i < THIS->edge_list->len; i++)
+ {
+ p2t_edge_free (edge_index (THIS->edge_list, i));
+ }
+
+ g_ptr_array_free (THIS->edge_list, TRUE);
+
+}
+
+void
+p2t_sweepcontext_delete (P2tSweepContext* THIS)
+{
+ p2t_sweepcontext_destroy (THIS);
+ g_free(THIS);
+}
+
+void
+p2t_sweepcontext_add_hole (P2tSweepContext *THIS, P2tPointPtrArray polyline)
+{
+ int i;
+ p2t_sweepcontext_init_edges (THIS, polyline);
+ for (i = 0; i < polyline->len; i++)
+ {
+ g_ptr_array_add (THIS->points_, point_index (polyline, i));
+ }
+}
+
+void
+p2t_sweepcontext_add_point (P2tSweepContext *THIS, P2tPoint* point)
+{
+ g_ptr_array_add (THIS->points_, point);
+}
+
+P2tTrianglePtrArray
+p2t_sweepcontext_get_triangles (P2tSweepContext *THIS)
+{
+ return THIS->triangles_;
+}
+
+P2tTrianglePtrList
+p2t_sweepcontext_get_map (P2tSweepContext *THIS)
+{
+ return THIS->map_;
+}
+
+void
+p2t_sweepcontext_init_triangulation (P2tSweepContext *THIS)
+{
+ int i;
+ double xmax = point_index (THIS->points_, 0)->x, xmin = point_index (THIS->points_, 0)->x;
+ double ymax = point_index (THIS->points_, 0)->y, ymin = point_index (THIS->points_, 0)->y;
+
+ // Calculate bounds.
+ for (i = 0; i < THIS->points_->len; i++)
+ {
+ P2tPoint* p = point_index (THIS->points_, i);
+ if (p->x > xmax)
+ xmax = p->x;
+ if (p->x < xmin)
+ xmin = p->x;
+ if (p->y > ymax)
+ ymax = p->y;
+ if (p->y < ymin)
+ ymin = p->y;
+ }
+
+ double dx = kAlpha * (xmax - xmin);
+ double dy = kAlpha * (ymax - ymin);
+ THIS->head_ = p2t_point_new_dd (xmax + dx, ymin - dy);
+ THIS->tail_ = p2t_point_new_dd (xmin - dx, ymin - dy);
+
+ // Sort points along y-axis
+ g_ptr_array_sort (THIS->points_, p2t_point_cmp);
+}
+
+void
+p2t_sweepcontext_init_edges (P2tSweepContext *THIS, P2tPointPtrArray polyline)
+{
+ int i;
+ int num_points = polyline->len;
+ g_ptr_array_set_size (THIS->edge_list, THIS->edge_list->len + num_points); // C-OPTIMIZATION
+ for (i = 0; i < num_points; i++)
+ {
+ int j = i < num_points - 1 ? i + 1 : 0;
+ g_ptr_array_add (THIS->edge_list, p2t_edge_new (point_index (polyline, i), point_index (polyline, j)));
+ }
+}
+
+P2tPoint*
+p2t_sweepcontext_get_point (P2tSweepContext *THIS, const int index)
+{
+ return point_index (THIS->points_, index);
+}
+
+void
+p2t_sweepcontext_add_to_map (P2tSweepContext *THIS, P2tTriangle* triangle)
+{
+ THIS->map_ = g_list_append (THIS->map_, triangle);
+}
+
+P2tNode*
+p2t_sweepcontext_locate_node (P2tSweepContext *THIS, P2tPoint* point)
+{
+ // TODO implement search tree
+ return p2t_advancingfront_locate_node (THIS->front_, point->x);
+}
+
+void
+p2t_sweepcontext_create_advancingfront (P2tSweepContext *THIS, P2tNodePtrArray nodes)
+{
+
+ // Initial triangle
+ P2tTriangle* triangle = p2t_triangle_new (point_index (THIS->points_, 0), THIS->tail_, THIS->head_);
+
+ THIS->map_ = g_list_append (THIS->map_, triangle);
+
+ THIS->af_head_ = p2t_node_new_pt_tr (p2t_triangle_get_point (triangle, 1), triangle);
+ THIS->af_middle_ = p2t_node_new_pt_tr (p2t_triangle_get_point (triangle, 0), triangle);
+ THIS->af_tail_ = p2t_node_new_pt (p2t_triangle_get_point (triangle, 2));
+ THIS->front_ = p2t_advancingfront_new (THIS->af_head_, THIS->af_tail_);
+
+ // TODO: More intuitive if head is middles next and not previous?
+ // so swap head and tail
+ THIS->af_head_->next = THIS->af_middle_;
+ THIS->af_middle_->next = THIS->af_tail_;
+ THIS->af_middle_->prev = THIS->af_head_;
+ THIS->af_tail_->prev = THIS->af_middle_;
+}
+
+void
+p2t_sweepcontext_remove_node (P2tSweepContext *THIS, P2tNode* node)
+{
+ g_free (node);
+}
+
+void
+p2t_sweepcontext_map_triangle_to_nodes (P2tSweepContext *THIS, P2tTriangle* t)
+{
+ int i;
+ for (i = 0; i < 3; i++)
+ {
+ if (!p2t_triangle_get_neighbor (t, i))
+ {
+ P2tNode* n = p2t_advancingfront_locate_point (THIS->front_, p2t_triangle_point_cw (t, p2t_triangle_get_point (t, i)));
+ if (n)
+ n->triangle = t;
+ }
+ }
+}
+
+void
+p2t_sweepcontext_remove_from_map (P2tSweepContext *THIS, P2tTriangle* triangle)
+{
+ THIS->map_ = g_list_remove (THIS->map_, triangle);
+}
+
+void
+p2t_sweepcontext_mesh_clean (P2tSweepContext *THIS, P2tTriangle* triangle)
+{
+ int i;
+ if (triangle != NULL && !p2t_triangle_is_interior (triangle))
+ {
+ p2t_triangle_is_interior_b (triangle, TRUE);
+ g_ptr_array_add (THIS->triangles_, triangle);
+ for (i = 0; i < 3; i++)
+ {
+ if (!triangle->constrained_edge[i])
+ p2t_sweepcontext_mesh_clean (THIS, p2t_triangle_get_neighbor (triangle, i));
+ }
+ }
+}
+
+P2tAdvancingFront*
+p2t_sweepcontext_front (P2tSweepContext *THIS)
+{
+ return THIS->front_;
+}
+
+int
+p2t_sweepcontext_point_count (P2tSweepContext *THIS)
+{
+ return THIS->points_->len;
+}
+
+void
+p2t_sweepcontext_set_head (P2tSweepContext *THIS, P2tPoint* p1)
+{
+ THIS->head_ = p1;
+}
+
+P2tPoint*
+p2t_sweepcontext_head (P2tSweepContext *THIS)
+{
+ return THIS->head_;
+}
+
+void
+p2t_sweepcontext_set_tail (P2tSweepContext *THIS, P2tPoint* p1)
+{
+ THIS->tail_ = p1;
+}
+
+P2tPoint*
+p2t_sweepcontext_tail (P2tSweepContext *THIS)
+{
+ return THIS->tail_;
+}
--- /dev/null
+/*\r
+ * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors\r
+ * http://code.google.com/p/poly2tri/\r
+ *\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * * Redistributions of source code must retain the above copyright notice,\r
+ * this list of conditions and the following disclaimer.\r
+ * * Redistributions in binary form must reproduce the above copyright notice,\r
+ * this list of conditions and the following disclaimer in the documentation\r
+ * and/or other materials provided with the distribution.\r
+ * * Neither the name of Poly2Tri nor the names of its contributors may be\r
+ * used to endorse or promote products derived from this software without specific\r
+ * prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\r
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\r
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\r
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+\r
+#ifndef SWEEP_CONTEXT_H\r
+#define SWEEP_CONTEXT_H\r
+\r
+#include "../common/poly2tri-private.h"\r
+#include "../common/shapes.h"\r
+#include "advancing_front.h"\r
+\r
+// Inital triangle factor, seed triangle will extend 30% of\r
+// PointSet width to both left and right.\r
+#define kAlpha 0.3\r
+\r
+struct P2tSweepContextBasin_\r
+{\r
+ P2tNode* left_node;\r
+ P2tNode* bottom_node;\r
+ P2tNode* right_node;\r
+ double width;\r
+ gboolean left_highest;\r
+};\r
+\r
+void p2t_sweepcontext_basin_init (P2tSweepContextBasin* THIS);\r
+void p2t_sweepcontext_basin_clear (P2tSweepContextBasin* THIS);\r
+\r
+struct P2tSweepContextEdgeEvent_\r
+{\r
+ P2tEdge* constrained_edge;\r
+ gboolean right;\r
+};\r
+\r
+void p2t_sweepcontext_edgeevent_init (P2tSweepContextEdgeEvent* THIS);\r
+\r
+struct SweepContext_\r
+{\r
+ P2tEdgePtrArray edge_list;\r
+\r
+ P2tSweepContextBasin basin;\r
+ P2tSweepContextEdgeEvent edge_event;\r
+\r
+ P2tTrianglePtrArray triangles_;\r
+ P2tTrianglePtrList map_;\r
+ P2tPointPtrArray points_;\r
+\r
+ // Advancing front\r
+ P2tAdvancingFront* front_;\r
+ // head point used with advancing front\r
+ P2tPoint* head_;\r
+ // tail point used with advancing front\r
+ P2tPoint* tail_;\r
+\r
+ P2tNode *af_head_, *af_middle_, *af_tail_;\r
+};\r
+\r
+/// Constructor\r
+void p2t_sweepcontext_init (P2tSweepContext* THIS, P2tPointPtrArray polyline);\r
+P2tSweepContext* p2t_sweepcontext_new (P2tPointPtrArray polyline);\r
+\r
+/// Destructor\r
+void p2t_sweepcontext_destroy (P2tSweepContext* THIS);\r
+void p2t_sweepcontext_delete (P2tSweepContext* THIS);\r
+\r
+void p2t_sweepcontext_set_head (P2tSweepContext *THIS, P2tPoint* p1);\r
+\r
+P2tPoint* p2t_sweepcontext_head (P2tSweepContext *THIS);\r
+\r
+void p2t_sweepcontext_set_tail (P2tSweepContext *THIS, P2tPoint* p1);\r
+\r
+P2tPoint* p2t_sweepcontext_tail (P2tSweepContext *THIS);\r
+\r
+int p2t_sweepcontext_point_count (P2tSweepContext *THIS);\r
+\r
+P2tNode* p2t_sweepcontext_locate_node (P2tSweepContext *THIS, P2tPoint* point);\r
+\r
+void p2t_sweepcontext_remove_node (P2tSweepContext *THIS, P2tNode* node);\r
+\r
+void p2t_sweepcontext_create_advancingfront (P2tSweepContext *THIS, P2tNodePtrArray nodes);\r
+\r
+/// Try to map a node to all sides of this triangle that don't have a neighbor\r
+void p2t_sweepcontext_map_triangle_to_nodes (P2tSweepContext *THIS, P2tTriangle* t);\r
+\r
+void p2t_sweepcontext_add_to_map (P2tSweepContext *THIS, P2tTriangle* triangle);\r
+\r
+P2tPoint* p2t_sweepcontext_get_point (P2tSweepContext *THIS, const int index);\r
+\r
+P2tPoint* SweepContext_GetPoints (P2tSweepContext *THIS);\r
+\r
+void p2t_sweepcontext_remove_from_map (P2tSweepContext *THIS, P2tTriangle* triangle);\r
+\r
+void p2t_sweepcontext_add_hole (P2tSweepContext *THIS, P2tPointPtrArray polyline);\r
+\r
+void p2t_sweepcontext_add_point (P2tSweepContext *THIS, P2tPoint* point);\r
+\r
+P2tAdvancingFront* p2t_sweepcontext_front (P2tSweepContext *THIS);\r
+\r
+void p2t_sweepcontext_mesh_clean (P2tSweepContext *THIS, P2tTriangle* triangle);\r
+\r
+P2tTrianglePtrArray p2t_sweepcontext_get_triangles (P2tSweepContext *THIS);\r
+P2tTrianglePtrList p2t_sweepcontext_get_map (P2tSweepContext *THIS);\r
+\r
+void p2t_sweepcontext_init_triangulation (P2tSweepContext *THIS);\r
+void p2t_sweepcontext_init_edges (P2tSweepContext *THIS, P2tPointPtrArray polyline);\r
+\r
+#endif\r