]> granicus.if.org Git - poly2tri-c/commitdiff
Lots of clean up to the flip-fix code, including using virtual edges
authorBarak Itkin <lightningismyname@gmail.com>
Sat, 30 Jun 2012 18:42:18 +0000 (21:42 +0300)
committerBarak Itkin <lightningismyname@gmail.com>
Sat, 30 Jun 2012 18:42:18 +0000 (21:42 +0300)
poly2tri-c/refine/Makefile.am
poly2tri-c/refine/cdt-flipfix.c [new file with mode: 0644]
poly2tri-c/refine/cdt-flipfix.h [new file with mode: 0644]
poly2tri-c/refine/cdt.c
poly2tri-c/refine/vedge.c
poly2tri-c/refine/vedge.h

index c96f4666376f2c705a4d1ac321f13a51310a7c63..17ea5083e24e26ae172b3f87390c56c2323af34c 100644 (file)
@@ -1,6 +1,6 @@
 noinst_LTLIBRARIES = libp2tc-refine.la
 
-libp2tc_refine_la_SOURCES = bounded-line.c bounded-line.h cdt.c cdt.h circle.c circle.h cluster.c cluster.h delaunay-terminator.c delaunay-terminator.h edge.c edge.h line.c line.h rmath.c rmath.h mesh.c mesh.h point.c point.h pslg.c pslg.h refine.h refiner.c refiner.h triangle.c triangle.h triangulation.h utils.c utils.h vector2.c vector2.h vedge.c vedge.h vtriangle.c vtriangle.h visibility.c visibility.h
+libp2tc_refine_la_SOURCES = bounded-line.c bounded-line.h cdt.c cdt.h cdt-flipfix.c cdt-flipfix.h circle.c circle.h cluster.c cluster.h delaunay-terminator.c delaunay-terminator.h edge.c edge.h line.c line.h rmath.c rmath.h mesh.c mesh.h point.c point.h pslg.c pslg.h refine.h refiner.c refiner.h triangle.c triangle.h triangulation.h utils.c utils.h vector2.c vector2.h vedge.c vedge.h vtriangle.c vtriangle.h visibility.c visibility.h
 
 P2TC_REFINE_publicdir = $(P2TC_publicdir)/refine
 P2TC_REFINE_public_HEADERS = bounded-line.h cdt.h circle.h cluster.h edge.h line.h mesh.h point.h pslg.h refine.h refiner.h rmath.h triangle.h triangulation.h utils.h vector2.h vedge.h vtriangle.h visibility.h
diff --git a/poly2tri-c/refine/cdt-flipfix.c b/poly2tri-c/refine/cdt-flipfix.c
new file mode 100644 (file)
index 0000000..7811393
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * This file is a part of Poly2Tri-C
+ * (c) Barak Itkin <lightningismyname@gmail.com>
+ * http://code.google.com/p/poly2tri-c/
+ *
+ * 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 <glib.h>
+
+#include "point.h"
+#include "edge.h"
+#include "triangle.h"
+#include "vedge.h"
+
+#include "cdt-flipfix.h"
+
+
+static P2trEdge*  p2tr_cdt_try_flip  (P2trCDT   *self,
+                                      P2trEdge  *to_flip);
+
+P2trFlipSet*
+p2tr_flip_set_new ()
+{
+  return p2tr_hash_set_new (
+      (GHashFunc)      p2tr_vedge_undirected_hash,
+      (GEqualFunc)     p2tr_vedge_undirected_equals,
+      NULL
+  );
+}
+
+void
+p2tr_flip_set_add (P2trFlipSet *self,
+                   P2trEdge    *to_flip)
+{
+  p2tr_flip_set_add2 (self, p2tr_vedge_new2 (to_flip));
+  p2tr_edge_unref (to_flip);
+}
+
+void
+p2tr_flip_set_add2 (P2trFlipSet *self,
+                    P2trVEdge   *to_flip)
+{
+  if (p2tr_hash_set_contains (self, to_flip))
+    p2tr_vedge_unref (to_flip);
+  else
+    p2tr_hash_set_insert (self, to_flip);
+}
+
+gboolean
+p2tr_flip_set_pop (P2trFlipSet  *self,
+                   P2trVEdge   **value)
+{
+  P2trHashSetIter iter;
+  p2tr_hash_set_iter_init (&iter, self);
+  if (p2tr_hash_set_iter_next (&iter, (gpointer*) value))
+    {
+      p2tr_hash_set_remove (self, *value);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+void
+p2tr_flip_set_free (P2trFlipSet *self)
+{
+  g_assert (p2tr_hash_set_size (self) == 0);
+  p2tr_hash_set_free (self);
+}
+
+/* This function implements "Lawson's algorithm", also known as "The
+ * diagonal swapping algorithm". This algorithm takes a CDT, and a list
+ * of triangles that were formed by the insertion of a new point into
+ * the triangular mesh, and makes the triangulation a CDT once more. Its
+ * logic is explained below:
+ *
+ *   If a point is added to an existing triangular mesh then
+ *   circumcircles are formed for all new triangles formed. If any of
+ *   the neighbours lie inside the circumcircle of any triangle, then a
+ *   quadrilateral is formed using the triangle and its neighbour. The
+ *   diagonals of this quadrilateral are swapped to give a new
+ *   triangulation. This process is continued till there are no more
+ *   faulty triangles and no more swaps are required.
+ *
+ * The description above may seem slightly inaccurate, as it does not
+ * consider the case were the diagonals can not be swapped since the
+ * quadrilateral is concave (then swapping the diagonals would result
+ * in a diagonal outside the quad, which is undesired).
+ *
+ * However, the description above is accurate. If the opposite point
+ * is inside the circular cut created by the edge, then since the
+ * circular cut is inside the infinite area created by extending the
+ * two other edges of the triangle, therefor the point is also inside
+ * that area - meaning that the quadrilateral is not concave!
+ */
+
+void
+p2tr_cdt_flip_fix (P2trCDT     *self,
+                   P2trFlipSet *candidates)
+{
+  P2trEdge *edge;
+  P2trVEdge *vedge;
+
+  while (p2tr_flip_set_pop (candidates, &vedge))
+    {
+      if (! p2tr_vedge_try_get_and_unref (vedge, &edge))
+        continue;
+
+      if (! edge->constrained
+          /* TODO: we probably don't need this check... */
+          && ! p2tr_edge_is_removed (edge))
+        {
+          /* If the edge is not constrained, then it should be
+           * a part of two triangles */
+          P2trPoint *A  = P2TR_EDGE_START(edge), *B = edge->end;
+          P2trPoint *C1 = p2tr_triangle_get_opposite_point (edge->tri, edge, FALSE);
+          P2trPoint *C2 = p2tr_triangle_get_opposite_point (edge->mirror->tri, edge->mirror, FALSE);
+
+          P2trEdge *flipped = p2tr_cdt_try_flip (self, edge);
+          if (flipped != NULL)
+            {
+              p2tr_flip_set_add2 (candidates, p2tr_vedge_new (A, C1));
+              p2tr_flip_set_add2 (candidates, p2tr_vedge_new (A, C2));
+              p2tr_flip_set_add2 (candidates, p2tr_vedge_new (B, C1));
+              p2tr_flip_set_add2 (candidates, p2tr_vedge_new (B, C2));
+              p2tr_edge_unref (flipped);
+            }
+        }
+
+      p2tr_edge_unref (edge);
+    }
+}
+
+/**
+ * Try to flip a given edge, If successfull, return the new edge (reffed!),
+ * otherwise return NULL
+ */
+P2trEdge*
+p2tr_cdt_try_flip (P2trCDT   *self,
+                   P2trEdge  *to_flip)
+{
+  /*    C
+   *  / | \
+   * B-----A    to_flip: A->B
+   *  \ | /     to_flip.Tri: ABC
+   *    D
+   */
+  P2trPoint *A, *B, *C, *D;
+  P2trEdge *AB, *CA, *AD, *DB, *BC, *DC;
+
+  g_assert (! to_flip->constrained && ! to_flip->delaunay);
+
+  A = P2TR_EDGE_START (to_flip);
+  B = to_flip->end;
+  C = p2tr_triangle_get_opposite_point (to_flip->tri, to_flip, FALSE);
+  D = p2tr_triangle_get_opposite_point (to_flip->mirror->tri, to_flip->mirror, FALSE);
+
+  AB = to_flip;
+
+  CA = p2tr_point_get_edge_to (C, A, FALSE);
+  AD = p2tr_point_get_edge_to (A, D, FALSE);
+  DB = p2tr_point_get_edge_to (D, B, FALSE);
+  BC = p2tr_point_get_edge_to (B, C, FALSE);
+
+  /* Check if the quadriliteral ADBC is concave (because if it is, we
+   * can't flip the edge) */
+  if (p2tr_triangle_circumcircle_contains_point (AB->tri, &D->c) != P2TR_INCIRCLE_IN)
+    return NULL;
+
+  p2tr_edge_remove (AB);
+
+  DC = p2tr_mesh_new_edge (self->mesh, D, C, FALSE);
+
+  p2tr_triangle_unref (p2tr_mesh_new_triangle (self->mesh,
+      CA, AD, DC));
+
+  p2tr_triangle_unref (p2tr_mesh_new_triangle (self->mesh,
+      DB, BC, DC->mirror));
+
+  return DC;
+}
+
+gboolean
+p2tr_vedge_undirected_equals (const P2trVEdge *e1,
+                              const P2trVEdge *e2)
+{
+  return ((e1 == NULL) == (e2 == NULL)) &&
+      (e1 == e2
+      || (e1->start == e2->start && e1->end == e2->end)
+      || (e1->end == e2->start && e1->start == e2->end));
+}
+
+guint
+p2tr_vedge_undirected_hash (const P2trVEdge *edge)
+{
+  return g_direct_hash (edge->start) ^ g_direct_hash (edge->end);
+}
+
diff --git a/poly2tri-c/refine/cdt-flipfix.h b/poly2tri-c/refine/cdt-flipfix.h
new file mode 100644 (file)
index 0000000..e7fa0e9
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * This file is a part of Poly2Tri-C
+ * (c) Barak Itkin <lightningismyname@gmail.com>
+ * http://code.google.com/p/poly2tri-c/
+ *
+ * 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 __P2TC_REFINE_CDT_FLIPFIX_H__
+#define __P2TC_REFINE_CDT_FLIPFIX_H__
+
+#include <glib.h>
+
+#include "edge.h"
+#include "vedge.h"
+#include "cdt.h"
+#include "utils.h"
+
+/**
+ * A set of edges to flip is basically a hash set, with unique equality
+ * and hashing function to prevent the same edge from appearing twice
+ * in different directions
+ */
+typedef P2trHashSet P2trFlipSet;
+
+/**
+ * Create a new flip-set - a set of virtual edges that should possibly
+ * be flipped to restore the Constrained Delaunay property to a
+ * triangulation
+*/
+P2trFlipSet* p2tr_flip_set_new  ();
+
+/**
+ * Add the given edge to the flip set. THE EDGE MUST HAVE BEEN REFFED
+ * BEFORE THE CALL TO THIS FUNCTION!
+ */
+void         p2tr_flip_set_add  (P2trFlipSet *self,
+                                 P2trEdge    *to_flip);
+
+/**
+ * Add the given virtual edge to the flip set. THE VIRTUAL EDGE MUST
+ * HAVE BEEN REFFED BEFORE THE CALL TO THIS FUNCTION!
+ */
+void         p2tr_flip_set_add2 (P2trFlipSet *self,
+                                 P2trVEdge   *to_flip);
+
+/**
+ * Try popping a virtual edge from the set. If succeeds, THE RETURNED
+ * VIRTUAL EDGE MUST BE UNREFFED!
+ */
+gboolean     p2tr_flip_set_pop  (P2trFlipSet  *self,
+                                 P2trVEdge   **value);
+
+/**
+ * Free the flip set. IT IS THE REPONSIBILITY OF THE CALLER TO MAKE
+ * SURE NO VIRTUAL EDGES WERE LEFT IN THE SET!
+ */
+void         p2tr_flip_set_free (P2trFlipSet *self);
+
+/**
+ * Flip-Fix all the virtual edges inside the given set
+ */
+void         p2tr_cdt_flip_fix  (P2trCDT     *self,
+                                 P2trFlipSet *candidates);
+
+
+gboolean    p2tr_vedge_undirected_equals (const P2trVEdge *e1,
+                                          const P2trVEdge *e2);
+
+guint       p2tr_vedge_undirected_hash   (const P2trVEdge *edge);
+
+#endif
index b53c3b14465c258c668049db7119b368ebc3f09c..f664c56d21331225fd2daa892dd3f4e91576ca72 100644 (file)
@@ -39,6 +39,7 @@
 
 #include "cdt.h"
 #include "visibility.h"
+#include "cdt-flipfix.h"
 
 static gboolean  p2tr_cdt_visible_from_tri        (P2trCDT      *self,
                                                    P2trTriangle *tri,
@@ -51,18 +52,6 @@ static P2trHashSet* p2tr_cdt_triangulate_fan         (P2trCDT   *self,
                                                       P2trPoint *center,
                                                       GList     *edge_pts);
 
-static void         p2tr_cdt_add_edge (P2trHashSet *candidates,
-                                       P2trEdge    *candidate);
-
-static void      p2tr_cdt_flip_fix                (P2trCDT     *self,
-                                                   P2trHashSet *candidates);
-
-static P2trEdge*  p2tr_cdt_try_flip                (P2trCDT   *self,
-                                                    P2trEdge  *to_flip);
-
-static void      p2tr_cdt_on_new_point            (P2trCDT   *self,
-                                                   P2trPoint *pt);
-
 void
 p2tr_cdt_validate_unused (P2trCDT* self)
 {
@@ -90,7 +79,8 @@ p2tr_cdt_new (P2tCDT *cdt)
   P2trCDT *rmesh = g_slice_new (P2trCDT);
   GHashTableIter iter;
   P2trPoint *pt_iter = NULL;
-  P2trHashSet *new_edges = p2tr_hash_set_new_default ();
+
+  P2trFlipSet *new_edges = p2tr_flip_set_new ();
 
   gint i, j;
 
@@ -142,7 +132,7 @@ p2tr_cdt_new (P2tCDT *cdt)
 
             /* We only wanted to create the edge now. We will use it
              * later */
-            p2tr_cdt_add_edge (new_edges, edge);
+            p2tr_flip_set_add (new_edges, edge);
           }
       }
   }
@@ -167,7 +157,7 @@ p2tr_cdt_new (P2tCDT *cdt)
 
   /* And do an extra flip fix */
   p2tr_cdt_flip_fix (rmesh, new_edges);
-  p2tr_hash_set_free (new_edges);
+  p2tr_flip_set_free (new_edges);
 
   /* Now finally unref the points we added into the map */
   g_hash_table_iter_init (&iter, point_map);
@@ -336,8 +326,6 @@ p2tr_cdt_insert_point (P2trCDT           *self,
     /* If we reached this line, then the point is inside the triangle */
     p2tr_cdt_insert_point_into_triangle (self, pt, tri);
 
-  p2tr_cdt_on_new_point (self, pt);
-
   /* We no longer need the triangle */
   p2tr_triangle_unref (tri);
 
@@ -353,7 +341,7 @@ p2tr_cdt_insert_point_into_triangle (P2trCDT      *self,
                                      P2trPoint    *P,
                                      P2trTriangle *tri)
 {
-  P2trHashSet *flip_candidates = p2tr_hash_set_new_default ();
+  P2trFlipSet *flip_candidates = p2tr_flip_set_new ();
 
   P2trPoint *A = tri->edges[0]->end;
   P2trPoint *B = tri->edges[1]->end;
@@ -375,20 +363,20 @@ p2tr_cdt_insert_point_into_triangle (P2trCDT      *self,
   p2tr_triangle_unref (p2tr_mesh_new_triangle (self->mesh, BC, CP, BP->mirror));
   p2tr_triangle_unref (p2tr_mesh_new_triangle (self->mesh, CA, AP, CP->mirror));
 
-  p2tr_cdt_add_edge (flip_candidates, CP);
-  p2tr_cdt_add_edge (flip_candidates, AP);
-  p2tr_cdt_add_edge (flip_candidates, BP);
+  p2tr_flip_set_add (flip_candidates, CP);
+  p2tr_flip_set_add (flip_candidates, AP);
+  p2tr_flip_set_add (flip_candidates, BP);
 
-  p2tr_cdt_add_edge (flip_candidates, p2tr_edge_ref (CA));
-  p2tr_cdt_add_edge (flip_candidates, p2tr_edge_ref (AB));
-  p2tr_cdt_add_edge (flip_candidates, p2tr_edge_ref (BC));
+  p2tr_flip_set_add (flip_candidates, p2tr_edge_ref (CA));
+  p2tr_flip_set_add (flip_candidates, p2tr_edge_ref (AB));
+  p2tr_flip_set_add (flip_candidates, p2tr_edge_ref (BC));
 
   /* Flip fix the newly created triangles to preserve the the
    * constrained delaunay property. The flip-fix function will unref the
    * new triangles for us! */
   p2tr_cdt_flip_fix (self, flip_candidates);
 
-  p2tr_hash_set_free (flip_candidates);
+  p2tr_flip_set_free (flip_candidates);
 }
 
 /**
@@ -397,12 +385,12 @@ p2tr_cdt_insert_point_into_triangle (P2trCDT      *self,
  *    created (these are the two that would have used it)
  * 2. THE RETURNED EDGES MUST BE UNREFFED!
  */
-static P2trHashSet*
+static P2trFlipSet*
 p2tr_cdt_triangulate_fan (P2trCDT   *self,
                           P2trPoint *center,
                           GList     *edge_pts)
 {
-  P2trHashSet* fan_edges = p2tr_hash_set_new_default ();
+  P2trFlipSet* fan_edges = p2tr_flip_set_new ();
   GList *iter;
 
   /* We can not triangulate unless at least two points are given */
@@ -427,9 +415,9 @@ p2tr_cdt_triangulate_fan (P2trCDT   *self,
 
       p2tr_triangle_unref (p2tr_mesh_new_triangle (self->mesh, AB, BC, CA));
 
-      p2tr_cdt_add_edge (fan_edges, CA);
-      p2tr_cdt_add_edge (fan_edges, BC);
-      p2tr_cdt_add_edge (fan_edges, AB);
+      p2tr_flip_set_add (fan_edges, CA);
+      p2tr_flip_set_add (fan_edges, BC);
+      p2tr_flip_set_add (fan_edges, AB);
     }
 
   return fan_edges;
@@ -494,159 +482,8 @@ p2tr_cdt_split_edge (P2trCDT   *self,
       p2tr_edge_unref (CY);
     }
 
-  p2tr_cdt_on_new_point (self, C);
   p2tr_cdt_validate_unused (self);
 
   return new_edges;
 }
 
-/* This function implements "Lawson's algorithm", also known as "The
- * diagonal swapping algorithm". This algorithm takes a CDT, and a list
- * of triangles that were formed by the insertion of a new point into
- * the triangular mesh, and makes the triangulation a CDT once more. Its
- * logic is explained below:
- *
- *   If a point is added to an existing triangular mesh then
- *   circumcircles are formed for all new triangles formed. If any of
- *   the neighbours lie inside the circumcircle of any triangle, then a
- *   quadrilateral is formed using the triangle and its neighbour. The
- *   diagonals of this quadrilateral are swapped to give a new
- *   triangulation. This process is continued till there are no more
- *   faulty triangles and no more swaps are required.
- *
- * The description above is slightly inaccurate, as it does not consider
- * the case were the diagonals can not be swapped since the
- * quadrilateral is concave (then swapping the diagonals would result in
- * a diagonal outside the quad, which is undesired). This code does also
- * handle that case.
- */
-
-#define CDT_180_EPS (1e-4)
-/**
- * Try to flip a given edge, If successfull, return the new edge (reffed!),
- * otherwise return NULL
- */
-static P2trEdge*
-p2tr_cdt_try_flip (P2trCDT   *self,
-                   P2trEdge  *to_flip)
-{
-  /*    C
-   *  / | \
-   * B-----A    to_flip: A->B
-   *  \ | /     to_flip.Tri: ABC
-   *    D
-   */
-  P2trPoint *A, *B, *C, *D;
-  P2trEdge *AB, *CA, *AD, *DB, *BC, *DC;
-
-  g_assert (! to_flip->constrained && ! to_flip->delaunay);
-
-  A = P2TR_EDGE_START (to_flip);
-  B = to_flip->end;
-  C = p2tr_triangle_get_opposite_point (to_flip->tri, to_flip, FALSE);
-  D = p2tr_triangle_get_opposite_point (to_flip->mirror->tri, to_flip->mirror, FALSE);
-
-  AB = to_flip;
-
-  CA = p2tr_point_get_edge_to (C, A, FALSE);
-  AD = p2tr_point_get_edge_to (A, D, FALSE);
-  DB = p2tr_point_get_edge_to (D, B, FALSE);
-  BC = p2tr_point_get_edge_to (B, C, FALSE);
-
-  /* Check if the quadriliteral ADBC is concave (because if it is, we
-   * can't flip the edge) */
-  if (p2tr_triangle_circumcircle_contains_point (AB->tri, &D->c) != P2TR_INCIRCLE_IN)
-    return NULL;
-
-  p2tr_edge_remove (AB);
-
-  DC = p2tr_mesh_new_edge (self->mesh, D, C, FALSE);
-
-  p2tr_triangle_unref (p2tr_mesh_new_triangle (self->mesh,
-      CA, AD, DC));
-
-  p2tr_triangle_unref (p2tr_mesh_new_triangle (self->mesh,
-      DB, BC, DC->mirror));
-
-  return DC;
-}
-
-static void
-p2tr_cdt_add_edge (P2trHashSet *candidates,
-                   P2trEdge    *candidate)
-{
-  if (p2tr_hash_set_contains (candidates, candidate->mirror) ||
-      p2tr_hash_set_contains (candidates, candidate))
-    p2tr_edge_unref (candidate);
-  else
-    p2tr_hash_set_insert (candidates, candidate);
-}
-
-static void
-p2tr_cdt_flip_fix (P2trCDT     *self,
-                   P2trHashSet *candidates)
-{
-  P2trHashSetIter iter;
-  while (TRUE)
-    {
-      P2trEdge* edge = NULL;
-      p2tr_hash_set_iter_init (&iter, candidates);
-      if (! p2tr_hash_set_iter_next (&iter, (gpointer*)&edge))
-        break;
-
-      p2tr_hash_set_remove (candidates, edge);
-
-      if (! edge->constrained && ! p2tr_edge_is_removed (edge))
-        {
-          /* If the edge is not constrained, then it should be
-           * a part of two triangles */
-          P2trPoint *A  = P2TR_EDGE_START(edge), *B = edge->end;
-          P2trPoint *C1 = p2tr_triangle_get_opposite_point (edge->tri, edge, FALSE);
-          P2trPoint *C2 = p2tr_triangle_get_opposite_point (edge->mirror->tri, edge->mirror, FALSE);
-
-          P2trEdge *flipped = p2tr_cdt_try_flip (self, edge);
-          if (flipped != NULL)
-            {
-              p2tr_cdt_add_edge (candidates, p2tr_point_get_edge_to (A, C1, TRUE));
-              p2tr_cdt_add_edge (candidates, p2tr_point_get_edge_to (A, C2, TRUE));
-              p2tr_cdt_add_edge (candidates, p2tr_point_get_edge_to (B, C1, TRUE));
-              p2tr_cdt_add_edge (candidates, p2tr_point_get_edge_to (B, C2, TRUE));
-              p2tr_edge_unref (flipped);
-            }
-        }
-
-      p2tr_edge_unref (edge);
-    }
-}
-
-/* Whenever a new point was inserted, it may disturb triangles
- * that are extremly skinny and therefor their circumscribing
- * circles are very large and will contain that point, even though they
- * may be very far from that point.
- * We have no choice but to check these and fix them if necessary
- */
-static void
-p2tr_cdt_on_new_point (P2trCDT   *self,
-                       P2trPoint *pt)
-{
-#if FALSE
-  GList *bad_tris = NULL;
-  P2trTriangle *tri;
-  P2trHashSetIter iter;
-
-  p2tr_hash_set_iter_init (&iter, self->mesh->triangles);
-  while (p2tr_hash_set_iter_next (&iter, (gpointer*)&tri))
-    {
-      if (p2tr_triangle_circumcircle_contains_point (tri, &pt->c)
-          != P2TR_INCIRCLE_OUT)
-        {
-          bad_tris = g_list_prepend (bad_tris, tri);
-          p2tr_triangle_ref (tri);
-        }
-    }
-
-  p2tr_cdt_flip_fix (self, bad_tris);
-  g_list_free (bad_tris);
-#endif
-}
-
index f37e16db5716de4645958f8e8412d061ff628d06..8afbffe81a812acb4360e363f3bb6abe8e34e649 100644 (file)
@@ -85,7 +85,7 @@ p2tr_vedge_unref (P2trVEdge *self)
 }
 
 P2trEdge*
-p2tr_edge_is_real (P2trVEdge *self)
+p2tr_vedge_is_real (P2trVEdge *self)
 {
   return p2tr_point_has_edge_to (self->start, self->end);
 }
@@ -109,3 +109,14 @@ p2tr_vedge_get (P2trVEdge *self)
 {
   return p2tr_point_get_edge_to (self->start, self->end, TRUE);
 }
+
+gboolean
+p2tr_vedge_try_get_and_unref (P2trVEdge  *self,
+                              P2trEdge  **real)
+{
+  P2trEdge *real_one = p2tr_vedge_is_real (self);
+  if (real_one)
+    p2tr_edge_ref (real_one);
+  p2tr_vedge_unref (self);
+  return (*real = real_one) != NULL;
+}
index 1aa8f8f7bb57970e9b160a4e621a4005cc3af577..1e3ac05da80366ff0e962f909cf472ab96d8bcad 100644 (file)
@@ -69,4 +69,16 @@ P2trMesh*   p2tr_vedge_get_mesh  (P2trVEdge *self);
 P2trEdge*   p2tr_vedge_is_real   (P2trVEdge *self);
 
 P2trEdge*   p2tr_vedge_get       (P2trVEdge *self);
+
+/**
+ * Try get a real edge from a virtual edge, and then
+ * unref the virtual edge. IF A MATCHING REAL EDGE IS
+ * RETURNED, IT MUST BE UNREFFED BY THE CALLER!
+ * @param self The virtual edge to test
+ * @param real The place to store the matching real edge
+ * @return TRUE if a real edge was returned, FALSE if no
+ *         matching edge exists.
+ */
+gboolean    p2tr_vedge_try_get_and_unref (P2trVEdge  *self,
+                                          P2trEdge  **real);
 #endif