+++ /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
-#include <math.h>
-
-#include <p2t/common/utils.h>
-#include "triangulation.h"
-#include <p2t/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 "../p2t/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 */