gnash-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gnash-commit] gnash ChangeLog libbase/Makefile.am libbase/tri...


From: Sandro Santilli
Subject: [Gnash-commit] gnash ChangeLog libbase/Makefile.am libbase/tri...
Date: Sat, 01 Dec 2007 15:50:00 +0000

CVSROOT:        /sources/gnash
Module name:    gnash
Changes by:     Sandro Santilli <strk>  07/12/01 15:49:59

Modified files:
        .              : ChangeLog 
        libbase        : Makefile.am 
Removed files:
        libbase        : triangulate.h triangulate_float.cpp 
                         triangulate_impl.h triangulate_sint32.cpp 

Log message:
        drop more dead code.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&r1=1.5042&r2=1.5043
http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/Makefile.am?cvsroot=gnash&r1=1.89&r2=1.90
http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/triangulate.h?cvsroot=gnash&r1=1.4&r2=0
http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/triangulate_float.cpp?cvsroot=gnash&r1=1.5&r2=0
http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/triangulate_impl.h?cvsroot=gnash&r1=1.27&r2=0
http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/triangulate_sint32.cpp?cvsroot=gnash&r1=1.6&r2=0

Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/gnash/gnash/ChangeLog,v
retrieving revision 1.5042
retrieving revision 1.5043
diff -u -b -r1.5042 -r1.5043
--- ChangeLog   1 Dec 2007 15:40:58 -0000       1.5042
+++ ChangeLog   1 Dec 2007 15:49:57 -0000       1.5043
@@ -1,5 +1,10 @@
 2007-12-01 Sandro Santilli <address@hidden>
 
+       * libbase/: Makefile.am, triangulate.h, triangulate_float.cpp,
+         triangulate_impl.h, triangulate_sint32.cpp: drop dead code.
+
+2007-12-01 Sandro Santilli <address@hidden>
+
        * server/: Makefile.am, fontlib.cpp, shape.{cpp,h},
          tesselate.{cpp,h}, parser/morph2_character_def.{cpp,h},
          parser/shape_character_def.{cpp,h}:

Index: libbase/Makefile.am
===================================================================
RCS file: /sources/gnash/gnash/libbase/Makefile.am,v
retrieving revision 1.89
retrieving revision 1.90
diff -u -b -r1.89 -r1.90
--- libbase/Makefile.am 3 Oct 2007 21:43:04 -0000       1.89
+++ libbase/Makefile.am 1 Dec 2007 15:49:58 -0000       1.90
@@ -90,8 +90,6 @@
        rc.cpp \
        sharedlib.cpp \
        string_table.cpp \
-       triangulate_float.cpp \
-       triangulate_sint32.cpp \
        tu_file.cpp \
        $(SDL_FILE) \
        tu_random.cpp \
@@ -134,8 +132,6 @@
        sharedlib.h \
        string_table.h \
        tree.hh \
-       triangulate.h \
-       triangulate_impl.h \
        tu_config.h \
        tu_file.h \
        tu_math.h \

Index: libbase/triangulate.h
===================================================================
RCS file: libbase/triangulate.h
diff -N libbase/triangulate.h
--- libbase/triangulate.h       11 Apr 2007 17:54:21 -0000      1.4
+++ /dev/null   1 Jan 1970 00:00:00 -0000
@@ -1,56 +0,0 @@
-// triangulate.h       -- Thatcher Ulrich 2004
-
-// This source code has been donated to the Public Domain.  Do
-// whatever you want with it.
-
-// Code to triangulate arbitrary 2D polygonal regions.
-
-
-#ifndef TRIANGULATE_H
-#define TRIANGULATE_H
-
-#include "container.h"
-#include "tu_types.h"
-
-namespace triangulate
-{
-       // Input is a list of closed paths that form the overall
-       // region.  The region does not need to be connected, and may
-       // contain holes/islands.  The paths should not intersect each
-       // other, or themselves.
-       // 
-       // The paths should be in counter-clockwise orientation,
-       // meaning that the inside of the shape is to the left of the
-       // directed path.  So a closed region is in CCW order, while
-       // an island inside a closed region is in CW (reverse) order.
-       //
-       // The output is a triangle list; each tri consists of 6
-       // coords: (x0, y0, x1, y1, x2, y2).
-
-       // Version using float coords
-       void    compute(
-               std::vector<float>* results,
-               int path_count,
-               const std::vector<float> paths[],
-               int debug_halt_step = -1,
-               std::vector<float>* debug_remaining_loop = NULL);
-
-       // Version using short coords
-       void    compute(
-               std::vector<int16_t>* results,  // indexed trilist
-               int path_count,
-               const std::vector<int16_t> paths[],
-               int debug_halt_step = -1,
-               std::vector<int16_t>* debug_remaining_loop = NULL);
-
-       // Version using int coords
-       void    compute(
-               std::vector<int32_t>* results,  // indexed trilist
-               int path_count,
-               const std::vector<int32_t> paths[],
-               int debug_halt_step = -1,
-               std::vector<int32_t>* debug_remaining_loop = NULL);
-}
-
-
-#endif // TRIANGULATE

Index: libbase/triangulate_float.cpp
===================================================================
RCS file: libbase/triangulate_float.cpp
diff -N libbase/triangulate_float.cpp
--- libbase/triangulate_float.cpp       10 Feb 2007 18:33:03 -0000      1.5
+++ /dev/null   1 Jan 1970 00:00:00 -0000
@@ -1,80 +0,0 @@
-// triangulate_float.cpp       -- Thatcher Ulrich 2004
-
-// This source code has been donated to the Public Domain.  Do
-// whatever you want with it.
-
-// Code to triangulate arbitrary 2D polygonal regions.
-//
-// Instantiate our templated algo from triangulate_inst.h
-
-/* $Id: triangulate_float.cpp,v 1.5 2007/02/10 18:33:03 nihilus Exp $ */
-
-#include "triangulate_impl.h"
-
-using namespace std;
-
-namespace triangulate
-{
-       // Version using float coords
-       void    compute(
-               std::vector<float>* result,     // trilist
-               int path_count,
-               const std::vector<float> paths[],
-               int debug_halt_step /* = -1 */,
-               std::vector<float>* debug_remaining_loop /* = NULL */)
-       {
-               compute_triangulation<float>(result, path_count, paths, 
debug_halt_step, debug_remaining_loop);
-       }
-}
-
-
-
-#ifdef TEST_TRIANGULATE_FLOAT
-
-// Compile test with something like:
-//
-// gcc -o triangulate_test -I../ triangulate_float.cpp tu_random.cpp 
-DTEST_TRIANGULATE_FLOAT -lstdc++
-//
-// or
-//
-// cl -Od -Zi -o triangulate_test.exe -I../ triangulate_float.cpp 
tu_random.cpp -DTEST_TRIANGULATE_FLOAT
-
-
-void   test_square()
-// A very minimal, easy test.
-{
-       std::vector<float>      result;
-       std::vector<std::vector<float> >        paths;
-
-       // Make a square.
-       paths.resize(1);
-       paths[0].push_back(0);
-       paths[0].push_back(0);
-       paths[0].push_back(1);
-       paths[0].push_back(0);
-       paths[0].push_back(1);
-       paths[0].push_back(1);
-       paths[0].push_back(0);
-       paths[0].push_back(1);
-
-       // Triangulate.
-       triangulate::compute(&result, paths.size(), &paths[0]);
-
-       // Dump.
-       for (int i = 0; i < result.size(); i++)
-       {
-               printf("%f\n", result[i]);
-       }
-}
-
-
-int    main()
-{
-       test_square();
-
-       return 0;
-}
-
-
-#endif // TEST_TRIANGULATE_FLOAT
-

Index: libbase/triangulate_impl.h
===================================================================
RCS file: libbase/triangulate_impl.h
diff -N libbase/triangulate_impl.h
--- libbase/triangulate_impl.h  30 Oct 2007 18:55:41 -0000      1.27
+++ /dev/null   1 Jan 1970 00:00:00 -0000
@@ -1,2512 +0,0 @@
-// triangulate_impl.h  -- Thatcher Ulrich 2004
-
-// This source code has been donated to the Public Domain.  Do
-// whatever you want with it.
-
-// Code to triangulate arbitrary 2D polygonal regions.
-//
-// Use the basic robust ear-clipping algorithm from "FIST: Fast
-// Industrial-Strength Triangulation of Polygons" by Martin Held.
-//
-// NOTE: This code is based on the algorithm described in the FIST
-// paper, but this is NOT the official FIST code written by Martin
-// Held!  This code may not be as robust or as fast as FIST, and is
-// certainly not as well tested.  Also, it deviates in some places
-// from the algorithm as described in the FIST paper; I have tried to
-// document those places in the code, along with my reasoning, but
-// this code is not warranted in any way.
-//
-// In particular, the recovery_process is currently not as good as
-// official FIST or even what's in the FIST paper.  This routine may
-// do some ugly stuff with self-intersecting input.
-//
-// For information on obtaining the offical industrial-strength FIST
-// code, see the FIST web page at:
-// http://www.cosy.sbg.ac.at/~held/projects/triang/triang.html
-
-/* $Id: triangulate_impl.h,v 1.27 2007/10/30 18:55:41 strk Exp $ */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "utility.h"
-#include "triangulate.h"
-#include "tu_random.h"
-#include "grid_index.h"
-#include "log.h"
-
-#define PROFILE_TRIANGULATE
-#ifdef PROFILE_TRIANGULATE
-#include "tu_timer.h"
-#endif // PROFILE_TRIANGULATE
-
-// Template this whole thing on coord_t, so int16_t and float versions
-// can easily reuse the code.
-//
-// These templates are instantiated in triangulate_<type>.cpp files.
-// They're in separate cpp files so the linker will discard code for
-// unused types.
-
-
-// convenience class; this could use some public vec2 type, but often
-// it's nicer for users if the external interface is smaller and more
-// c-like, since they probably have their own vec2 that they prefer.
-template<class coord_t>
-class vec2
-{
-public:
-       vec2() : x(0), y(0) {}
-       vec2(coord_t _x, coord_t _y) : x(_x), y(_y) {}
-
-       bool    operator==(const vec2<coord_t>& v) const
-       {
-               return x == v.x && y == v.y;
-       }
-
-//data:
-       coord_t x, y;
-};
-
-
-inline double  determinant_float(const vec2<float>& a, const vec2<float>& b, 
const vec2<float>& c)
-{
-       return (double(b.x) - double(a.x)) * (double(c.y) - double(a.y))
-               - (double(b.y) - double(a.y)) * (double(c.x) - double(a.x));
-}
-
-
-inline int64_t determinant_sint32(const vec2<int32_t>& a, const vec2<int32_t>& 
b, const vec2<int32_t>& c)
-{
-       return (int64_t(b.x) - int64_t(a.x)) * (int64_t(c.y) - int64_t(a.y))
-               - (int64_t(b.y) - int64_t(a.y)) * (int64_t(c.x) - int64_t(a.x));
-}
-
-
-// Return {-1,0,1} if c is {to the right, on, to the left} of the
-// directed edge defined by a->b.
-template<class coord_t>
-inline int     vertex_left_test(const vec2<coord_t>& a, const vec2<coord_t>& 
b, const vec2<coord_t>& c)
-{
-       compiler_assert(0);     // must specialize
-       return -1;
-}
-
-
-template<>
-inline int     vertex_left_test(const vec2<float>& a, const vec2<float>& b, 
const vec2<float>& c)
-// Specialize for vec2<float>
-{
-       double  det = determinant_float(a, b, c);
-       if (det > 0) return 1;
-       else if (det < 0) return -1;
-       else return 0;
-}
-
-
-template<>
-inline int     vertex_left_test(const vec2<int32_t>& a, const vec2<int32_t>& 
b, const vec2<int32_t>& c)
-// Specialize for vec2<int32_t>
-{
-       int64_t det = determinant_sint32(a, b, c);
-       if (det > 0) return 1;
-       else if (det < 0) return -1;
-       else return 0;
-}
-
-
-template<class coord_t>
-bool   vertex_in_ear(const vec2<coord_t>& v, const vec2<coord_t>& a, const 
vec2<coord_t>& b, const vec2<coord_t>& c)
-// Return true if v is on or inside the ear (a,b,c).
-// (a,b,c) must be in ccw order!
-{
-       assert(vertex_left_test(b, a, c) <= 0); // check ccw order
-
-       if (v == a || v == c)
-       {
-               // Special case; we don't care if v is coincident with a or c.
-               return false;
-       }
-
-       // Include the triangle boundary in our test.
-       bool    ab_in = vertex_left_test(a, b, v) >= 0;
-       bool    bc_in = vertex_left_test(b, c, v) >= 0;
-       bool    ca_in = vertex_left_test(c, a, v) >= 0;
-
-       return ab_in && bc_in && ca_in;
-}
-
-
-template<class coord_t> class poly;
-
-
-
-inline int     remap_index_for_duped_verts(int index, int duped_v0, int 
duped_v1)
-// Helper.  Return the new value of index, for the case of verts [duped_v0]
-// and [duped_v1] being duplicated and subsequent verts being shifted up.
-{
-       assert(duped_v0 < duped_v1);
-       if (index <= duped_v0)
-       {
-               // No shift.
-               return index;
-       }
-       else if (index <= duped_v1)
-       {
-               // Shift up one.
-               return index + 1;
-       }
-       else
-       {
-               // Shift up two.
-               return index + 2;
-       }
-}
-
-
-template<class coord_t>
-class poly_vert
-{
-public:
-       poly_vert() {}
-       poly_vert(coord_t x, coord_t y, poly<coord_t>* owner, int my_index)
-               :
-               m_v(x, y),
-               m_my_index(my_index),
-               m_next(-1),
-               m_prev(-1),
-               m_convex_result(0),     // 1 (convex), 0 (colinear), -1 (reflex)
-               m_is_ear(false),
-               m_poly_owner(owner)
-       {
-       }
-
-       void    remap(const std::vector<int>& remap_table)
-       {
-               m_my_index = remap_table[m_my_index];
-               m_next = remap_table[m_next];
-               m_prev = remap_table[m_prev];
-       }
-
-       index_point<coord_t>    get_index_point() const { return 
index_point<coord_t>(m_v.x, m_v.y); }
-
-//data:
-       vec2<coord_t>   m_v;
-       int     m_my_index;     // my index into sorted_verts array
-       int     m_next;
-       int     m_prev;
-       int     m_convex_result;        // (@@ only need 2 bits)
-       bool    m_is_ear;
-       poly<coord_t>*  m_poly_owner;    // needed?
-};
-
-
-template<class coord_t>
-int    compare_vertices(const void* a, const void* b)
-// For qsort.  Sort by x, then by y.
-{
-       const poly_vert<coord_t>* vert_a = (const poly_vert<coord_t>*) a;
-       const poly_vert<coord_t>* vert_b = (const poly_vert<coord_t>*) b;
-
-       if (vert_a->m_v.x < vert_b->m_v.x)
-               return -1;
-       else if (vert_a->m_v.x > vert_b->m_v.x)
-               return 1;
-       else
-       {
-               if (vert_a->m_v.y < vert_b->m_v.y)
-                       return -1;
-               else if (vert_a->m_v.y > vert_b->m_v.y)
-                       return 1;
-       }
-
-       return 0;
-}
-
-
-template<class coord_t>
-inline bool    edges_intersect_sub(const std::vector<poly_vert<coord_t> >& 
sorted_verts, int e0v0, int e0v1, int e1v0, int e1v1)
-// Return true if edge (e0v0,e0v1) intersects (e1v0,e1v1).
-{
-       // Need to specialize this on coord_t, in order to get it
-       // correct and avoid overflow.
-       compiler_assert(0);
-       return -1;
-}
-
-
-template<>
-inline bool    edges_intersect_sub(const std::vector<poly_vert<float> >& 
sorted_verts, int e0v0i, int e0v1i, int e1v0i, int e1v1i)
-// Return true if edge (e0v0,e0v1) intersects (e1v0,e1v1).
-//
-// Specialized for float.
-{
-       // If e1v0,e1v1 are on opposite sides of e0, and e0v0,e0v1 are
-       // on opposite sides of e1, then the segments cross.  These
-       // are all determinant checks.
-
-       // The main degenerate case we need to watch out for is if
-       // both segments are zero-length.
-       //
-       // If only one is degenerate, our tests are still OK.
-
-       const vec2<float>&      e0v0 = sorted_verts[e0v0i].m_v;
-       const vec2<float>&      e0v1 = sorted_verts[e0v1i].m_v;
-       const vec2<float>&      e1v0 = sorted_verts[e1v0i].m_v;
-       const vec2<float>&      e1v1 = sorted_verts[e1v1i].m_v;
-
-       // Note: exact equality here.  I think the reason to use
-       // epsilons would be underflow in case of very small
-       // determinants.  Our determinants are doubles, so I think
-       // we're good.
-       if (e0v0.x == e0v1.x && e0v0.y == e0v1.y)
-       {
-               // e0 is zero length.
-               if (e1v0.x == e1v1.x && e1v0.y == e1v1.y)
-               {
-                       // Both edges are zero length.
-                       // They intersect only if they're coincident.
-                       return e0v0.x == e1v0.x && e0v0.y == e1v0.y;
-               }
-       }
-
-       // See if e1 crosses line of e0.
-       double  det10 = determinant_float(e0v0, e0v1, e1v0);
-       double  det11 = determinant_float(e0v0, e0v1, e1v1);
-
-       // Note: we do > 0, which means a vertex on a line counts as
-       // intersecting.  In general, if one vert is on the other
-       // segment, we have to go searching along the path in either
-       // direction to see if it crosses or not, and it gets
-       // complicated.  Better to treat it as intersection.
-
-       if (det10 * det11 > 0)
-       {
-               // e1 doesn't cross the line of e0.
-               return false;
-       }
-
-       // See if e0 crosses line of e1.
-       double  det00 = determinant_float(e1v0, e1v1, e0v0);
-       double  det01 = determinant_float(e1v0, e1v1, e0v1);
-
-       if (det00 * det01 > 0)
-       {
-               // e0 doesn't cross the line of e1.
-               return false;
-       }
-
-       // They both cross each other; the segments intersect.
-       return true;
-}
-
-
-template<>
-inline bool    edges_intersect_sub(const std::vector<poly_vert<int32_t> >& 
sorted_verts, int e0v0i, int e0v1i, int e1v0i, int e1v1i)
-// Return true if edge (e0v0,e0v1) intersects (e1v0,e1v1).
-//
-// Specialized for int32_t
-{
-       // If e1v0,e1v1 are on opposite sides of e0, and e0v0,e0v1 are
-       // on opposite sides of e1, then the segments cross.  These
-       // are all determinant checks.
-
-       // The main degenerate case we need to watch out for is if
-       // both segments are zero-length.
-       //
-       // If only one is degenerate, our tests are still OK.
-
-       const vec2<int32_t>&    e0v0 = sorted_verts[e0v0i].m_v;
-       const vec2<int32_t>&    e0v1 = sorted_verts[e0v1i].m_v;
-       const vec2<int32_t>&    e1v0 = sorted_verts[e1v0i].m_v;
-       const vec2<int32_t>&    e1v1 = sorted_verts[e1v1i].m_v;
-
-       if (e0v0.x == e0v1.x && e0v0.y == e0v1.y)
-       {
-               // e0 is zero length.
-               if (e1v0.x == e1v1.x && e1v0.y == e1v1.y)
-               {
-                       // Both edges are zero length.  Treat them as
-                       // non-coincident (even if they're all on the
-                       // same point).
-                       return false;
-               }
-       }
-
-       // See if e1 crosses line of e0.
-       int64_t det10 = determinant_sint32(e0v0, e0v1, e1v0);
-       int64_t det11 = determinant_sint32(e0v0, e0v1, e1v1);
-
-       // Note: we do > 0, which means a vertex on a line counts as
-       // intersecting.  In general, if one vert is on the other
-       // segment, we have to go searching along the path in either
-       // direction to see if it crosses or not, and it gets
-       // complicated.  Better to treat it as intersection.
-
-       if (det10 * det11 > 0)
-       {
-               // e1 doesn't cross the line of e0.
-               return false;
-       }
-
-       // See if e0 crosses line of e1.
-       int64_t det00 = determinant_sint32(e1v0, e1v1, e0v0);
-       int64_t det01 = determinant_sint32(e1v0, e1v1, e0v1);
-
-       if (det00 * det01 > 0)
-       {
-               // e0 doesn't cross the line of e1.
-               return false;
-       }
-
-       // They both cross each other; the segments intersect.
-       return true;
-}
-
-
-template<class coord_t>
-bool   edges_intersect(const std::vector<poly_vert<coord_t> >& sorted_verts, 
int e0v0, int e0v1, int e1v0, int e1v1)
-// Return true if edge (e0v0,e0v1) intersects (e1v0,e1v1).
-{
-       // Deal with special case: edges that share exactly one vert.
-       // We treat these as no intersection, even though technically
-       // they share one point.
-       //
-       // We're not just comparing indices, because duped verts (for
-       // bridges) might have different indices.
-       //
-       // @@ this needs review -- might be wrong.
-       bool    coincident[2][2];
-       coincident[0][0] = (sorted_verts[e0v0].m_v == sorted_verts[e1v0].m_v);
-       coincident[0][1] = (sorted_verts[e0v0].m_v == sorted_verts[e1v1].m_v);
-       coincident[1][0] = (sorted_verts[e0v1].m_v == sorted_verts[e1v0].m_v);
-       coincident[1][1] = (sorted_verts[e0v1].m_v == sorted_verts[e1v1].m_v);
-       if (coincident[0][0] && !coincident[1][1]) return false;
-       if (coincident[1][0] && !coincident[0][1]) return false;
-       if (coincident[0][1] && !coincident[1][0]) return false;
-       if (coincident[1][1] && !coincident[0][0]) return false;
-
-// @@ eh, I think we really want this to be an intersection
-#if 0
-       // Both verts identical: early out.
-       //
-       // Note: treat this as no intersection!  This is mainly useful
-       // for things like coincident vertical bridge edges.
-       if (coincident[0][0] && coincident[1][1]) return false;
-       if (coincident[1][0] && coincident[0][1]) return false;
-#endif // 0
-
-       // Check for intersection.
-       return edges_intersect_sub(sorted_verts, e0v0, e0v1, e1v0, e1v1);
-}
-
-
-
-template<class coord_t>
-bool   is_convex_vert(const std::vector<poly_vert<coord_t> >& sorted_verts, 
int vi)
-// Return true if vert vi is convex.
-{
-       const poly_vert<coord_t>*       pvi = &(sorted_verts[vi]);
-       const poly_vert<coord_t>*       pv_prev = &(sorted_verts[pvi->m_prev]);
-       const poly_vert<coord_t>*       pv_next = &(sorted_verts[pvi->m_next]);
-
-       return vertex_left_test<coord_t>(pv_prev->m_v, pvi->m_v, pv_next->m_v) 
> 0;
-}
-
-
-template<class coord_t>
-class poly
-{
-public:
-       typedef poly_vert<coord_t> vert_t;
-
-       poly(/*@@ TODO std::vector<vert_t>* sorted_verts*/)
-               :
-               // @@ TODO m_sorted_verts(sorted_verts),
-               m_loop(-1),
-               m_leftmost_vert(-1),
-               m_vertex_count(0),
-               m_ear_count(0),
-               m_edge_index(NULL),
-               m_reflex_point_index(NULL)
-       {
-       }
-
-       ~poly()
-       {
-               delete m_edge_index;
-               m_edge_index = NULL;
-
-               delete m_reflex_point_index;
-               m_reflex_point_index = NULL;
-       }
-
-       bool    is_valid(const std::vector<vert_t>& sorted_verts, bool 
check_consecutive_dupes = true) const;
-
-       // init/prep
-       void    append_vert(std::vector<vert_t>* sorted_verts, int vert_index);
-       void    remap(const std::vector<int>& remap_table);
-       void    remap_for_duped_verts(const std::vector<vert_t>& sorted_verts, 
int v0, int v1);
-
-       void    init_edge_index(const std::vector<vert_t>& sorted_verts, 
index_box<coord_t>& bound_of_all_verts);
-       int     find_valid_bridge_vert(const std::vector<vert_t>& sorted_verts, 
int v1);
-       void    update_connected_sub_poly(std::vector<vert_t>* sorted_verts, 
int v_start, int v_stop);
-       void    init_for_ear_clipping(std::vector<vert_t>* sorted_verts);
-
-       // Edges are indexed using their first vert (i.e. edge (v1,v2) is 
indexed using v1)
-       void    add_edge(const std::vector<vert_t>& sorted_verts, int vi);
-       void    remove_edge(const std::vector<vert_t>& sorted_verts, int vi);
-
-       // tests/queries
-       bool    any_edge_intersection(const std::vector<vert_t>& sorted_verts, 
int external_vert, int v2);
-       bool    vert_can_see_cone_a(const std::vector<vert_t>& sorted_verts, 
int v, int cone_a_vert, int cone_b_vert);
-       bool    vert_in_cone(const std::vector<vert_t>& sorted_verts, int vert, 
int cone_v0, int cone_v1, int cone_v2);
-       bool    vert_is_duplicated(const std::vector<vert_t>& sorted_verts, int 
v0);
-       bool    ear_contains_reflex_vertex(const std::vector<vert_t>& 
sorted_verts, int v0, int v1, int v2);
-
-       void    classify_vert(std::vector<vert_t>* sorted_verts, int vi);
-       void    dirty_vert(std::vector<vert_t>* sorted_verts, int vi);
-
-       int     get_vertex_count() const { return m_vertex_count; }
-       int     get_ear_count() const { return m_ear_count; }
-       int     get_next_ear(const std::vector<vert_t>& sorted_verts, 
tu_random::generator* rg);
-       int     remove_degenerate_chain(std::vector<vert_t>* sorted_verts, int 
vi);
-       void    emit_and_remove_ear(std::vector<coord_t>* result, 
std::vector<vert_t>* sorted_verts, int v0, int v1, int v2);
-       bool    build_ear_list(std::vector<vert_t>* sorted_verts, 
tu_random::generator* rg);
-
-       void    invalidate(const std::vector<vert_t>& sorted_verts);
-
-//data:
-//@@ TODO      std::vector<vert_t>*    m_sorted_verts;
-       int     m_loop; // index of first vert
-       int     m_leftmost_vert;
-       int     m_vertex_count;
-       int     m_ear_count;
-
-       // edge search_index (for finding possibly intersecting edges during 
bridge finding)
-       //
-       // The payload stored is the index of the first vert in the edge.
-       typedef grid_index_box<coord_t, int>    box_index_t;
-       typedef typename box_index_t::iterator ib_iterator;
-       grid_index_box<coord_t, int>*   m_edge_index;
-
-       // point search index (for finding reflex verts within a potential ear)
-       typedef grid_index_point<coord_t, int>  point_index_t;
-       typedef typename point_index_t::iterator ip_iterator;
-       point_index_t*  m_reflex_point_index;
-};
-
-
-template<class coord_t>
-bool   poly<coord_t>::is_valid(const std::vector<vert_t>& sorted_verts, bool 
check_consecutive_dupes /* = true */) const
-// Assert validity.
-{
-#ifndef NDEBUG
-
-       if (m_loop == -1 && m_leftmost_vert == -1 && m_vertex_count == 0)
-       {
-               // Empty poly.
-               return true;
-       }
-
-       assert(m_leftmost_vert == -1 || 
sorted_verts[m_leftmost_vert].m_poly_owner == this);
-
-       // Check vert count.
-       int     first_vert = m_loop;
-       int     vi = first_vert;
-       int     vert_count = 0;
-       int     ear_count = 0;
-       bool    found_leftmost = false;
-       int     reflex_vert_count = 0;
-       do
-       {
-               const poly_vert<coord_t>*       pvi = &sorted_verts[vi];
-
-               // Check ownership.
-               assert(pvi->m_poly_owner == this);
-
-               // Check leftmost vert.
-               assert(m_leftmost_vert == -1
-                      || compare_vertices<coord_t>(
-                              (const void*) &sorted_verts[m_leftmost_vert],
-                              (const void*) &sorted_verts[vi]) <= 0);
-
-               // Check link integrity.
-               int     v_next = pvi->m_next;
-               assert(sorted_verts[v_next].m_prev == vi);
-
-               if (vi == m_leftmost_vert)
-               {
-                       found_leftmost = true;
-               }
-
-               if (check_consecutive_dupes && v_next != vi)
-               {
-                       // Subsequent verts are not allowed to be
-                       // coincident; that causes errors in ear
-                       // classification.
-                       assert((pvi->m_v == sorted_verts[v_next].m_v) == false);
-               }
-
-               if (pvi->m_convex_result < 0)
-               {
-                       reflex_vert_count++;
-               }
-               if (pvi->m_is_ear)
-               {
-                       ear_count++;
-               }
-               vert_count++;
-               vi = v_next;
-       }
-       while (vi != first_vert);
-
-       assert(ear_count == m_ear_count);
-       assert(vert_count == m_vertex_count);
-       assert(found_leftmost || m_leftmost_vert == -1);
-
-       // Count reflex verts in the grid index.
-       if (m_reflex_point_index)
-       {
-               int     check_count = 0;
-               for (ip_iterator it = 
m_reflex_point_index->begin(m_reflex_point_index->get_bound());
-                    ! it.at_end();
-                    ++it)
-               {
-                       check_count++;
-               }
-
-               assert(check_count == reflex_vert_count);
-       }
-
-       // Count edges in the edge index.  There should be exactly one edge per 
vert.
-       if (m_edge_index)
-       {
-               int     check_count = 0;
-               for (ib_iterator it = 
m_edge_index->begin(m_edge_index->get_bound());
-                    ! it.at_end();
-                    ++it)
-               {
-                       check_count++;
-               }
-
-               assert(check_count == vert_count);
-       }
-
-       // Might be nice to check that all verts with (m_poly_owner ==
-       // this) are in our loop.
-
-#endif // not NDEBUG
-
-       return true;
-}
-
-
-template<class coord_t>
-void   poly<coord_t>::invalidate(const std::vector<vert_t>& sorted_verts)
-// Mark as invalid/empty.  Do this after linking into another poly,
-// for safety/debugging.
-{
-       assert(m_loop == -1 || sorted_verts[m_loop].m_poly_owner != this);      
// make sure our verts have been stolen already.
-
-       m_loop = -1;
-       m_leftmost_vert = -1;
-       m_vertex_count = 0;
-
-       assert(is_valid(sorted_verts));
-}
-
-
-template<class coord_t>
-int    compare_polys_by_leftmost_vert(const void* a, const void* b)
-{
-       const poly<coord_t>*    poly_a = * (const poly<coord_t>* const *) a;
-       const poly<coord_t>*    poly_b = * (const poly<coord_t>* const *) b;
-
-       // Vert indices are sorted, so we just compare the indices,
-       // not the actual vert coords.
-       if (poly_a->m_leftmost_vert < poly_b->m_leftmost_vert)
-       {
-               return -1;
-       }
-       else
-       {
-               // polys are not allowed to share verts, so the
-               // leftmost vert must be different!
-               assert(poly_a->m_leftmost_vert > poly_b->m_leftmost_vert);
-
-               return 1;
-       }
-}
-
-
-template<class coord_t>
-void   poly<coord_t>::append_vert(std::vector<vert_t>* sorted_verts, int 
vert_index)
-// Link the specified vert into our loop.
-{
-  assert(vert_index >= 0 && vert_index < (int) sorted_verts->size());
-       assert(is_valid(*sorted_verts, false /* don't check for consecutive 
dupes, poly is not finished */));
-
-       m_vertex_count++;
-
-       if (m_loop == -1)
-       {
-               // First vert.
-               assert(m_vertex_count == 1);
-               m_loop = vert_index;
-               poly_vert<coord_t>*     pv = &(*sorted_verts)[vert_index];
-               pv->m_next = vert_index;
-               pv->m_prev = vert_index;
-               pv->m_poly_owner = this;
-
-               m_leftmost_vert = vert_index;
-       }
-       else
-       {
-               // We have a loop.  Link the new vert in, behind the
-               // first vert.
-               poly_vert<coord_t>*     pv0 = &(*sorted_verts)[m_loop];
-               poly_vert<coord_t>*     pv = &(*sorted_verts)[vert_index];
-               pv->m_next = m_loop;
-               pv->m_prev = pv0->m_prev;
-               pv->m_poly_owner = this;
-               (*sorted_verts)[pv0->m_prev].m_next = vert_index;
-               pv0->m_prev = vert_index;
-
-               // Update m_leftmost_vert
-               poly_vert<coord_t>*     pvl = &(*sorted_verts)[m_leftmost_vert];
-               if (compare_vertices<coord_t>(pv, pvl) < 0)
-               {
-                       // v is to the left of vl; it's the new leftmost vert
-                       m_leftmost_vert = vert_index;
-               }
-       }
-
-       assert(is_valid(*sorted_verts, false /* don't check for consecutive 
dupes, poly is not finished */));
-}
-
-
-template<class coord_t>
-int    poly<coord_t>::find_valid_bridge_vert(const std::vector<vert_t>& 
sorted_verts, int v1)
-// Find a vert v, in this poly, such that v is to the left of v1, and
-// the edge (v,v1) doesn't intersect any edges in this poly.
-{
-       assert(is_valid(sorted_verts));
-
-       const poly_vert<coord_t>*       pv1 = &(sorted_verts[v1]);
-       assert(pv1->m_poly_owner != this);      // v1 must not be part of this 
poly already
-
-       // Held recommends searching verts near v1 first.  And for
-       // correctness, we may only consider verts to the left of v1.
-       // A fast & easy way to implement this is to walk backwards in
-       // our vert array, starting with v1-1.
-
-       // Walk forward to include all coincident but later verts!
-       int     vi = v1;
-       while ((vi + 1) < (int) sorted_verts.size() && sorted_verts[vi + 1].m_v 
== pv1->m_v)
-       {
-               vi++;
-       }
-
-       // Now scan backwards for the vert to bridge onto.
-       for ( ; vi >= 0; vi--)
-       {
-               const poly_vert<coord_t>*       pvi = &sorted_verts[vi];
-
-               assert(compare_vertices<coord_t>((const void*) pvi, (const 
void*) pv1) <= 0);
-
-               if (pvi->m_poly_owner == this)
-               {
-                       // Candidate is to the left of pv1, so it
-                       // might be valid.  We don't consider verts to
-                       // the right of v1, because of possible
-                       // intersection with other polys.  Due to the
-                       // poly sorting, we know that the edge
-                       // (pvi,pv1) can only intersect this poly.
-
-                       if (any_edge_intersection(sorted_verts, v1, vi) == 
false)
-                       {
-                               return vi;
-                       }
-               }
-       }
-
-       // Ugh!  No valid bridge vert.  Shouldn't happen with valid
-       // data.  For invalid data, just pick something and live with
-       // the intersection.
-       fprintf(stderr, "can't find bridge for vert %d!\n", v1);//xxxxxxxxx
-
-       return m_leftmost_vert;
-}
-
-
-template<class coord_t>
-void   poly<coord_t>::remap(const std::vector<int>& remap_table)
-{
-       assert(m_loop > -1);
-       assert(m_leftmost_vert > -1);
-
-       m_loop = remap_table[m_loop];
-       m_leftmost_vert = remap_table[m_leftmost_vert];
-}
-
-
-template<class coord_t>
-void   poly<coord_t>::remap_for_duped_verts(const std::vector<vert_t>& 
sorted_verts, int v0, int v1)
-// Remap for the case of v0 and v1 being duplicated, and subsequent
-// verts being shifted up.
-{
-       assert(m_loop > -1);
-       assert(m_leftmost_vert > -1);
-
-       m_loop = remap_index_for_duped_verts(m_loop, v0, v1);
-       m_leftmost_vert = remap_index_for_duped_verts(m_leftmost_vert, v0, v1);
-
-       // Remap the vert indices stored in the edge index.
-       if (m_edge_index)
-       {
-               // Optimization: we don't need to remap anything
-               // that's wholly to the left of v0.  Towards the end
-               // of bridge building, this could be the vast majority
-               // of edges.
-               assert(v0 < v1);
-               index_box<coord_t>      bound = m_edge_index->get_bound();
-               bound.min.x = sorted_verts[v0].m_v.x;
-
-               for (ib_iterator it = m_edge_index->begin(bound);
-                    ! it.at_end();
-                    ++it)
-               {
-                       it->value = remap_index_for_duped_verts(it->value, v0, 
v1);
-               }
-       }
-
-       // We shouldn't have a point index right now.
-       assert(m_reflex_point_index == NULL);
-}
-
-
-template<class coord_t>
-void   poly<coord_t>::classify_vert(std::vector<vert_t>* sorted_verts, int vi)
-// Decide if vi is an ear, and mark its m_is_ear flag & update counts.
-{
-       poly_vert<coord_t>*     pvi = &((*sorted_verts)[vi]);
-       const poly_vert<coord_t>*       pv_prev = 
&((*sorted_verts)[pvi->m_prev]);
-       const poly_vert<coord_t>*       pv_next = 
&((*sorted_verts)[pvi->m_next]);
-
-       if (pvi->m_convex_result > 0)
-       {
-               if (vert_in_cone(*sorted_verts, pvi->m_prev, vi, pvi->m_next, 
pv_next->m_next)
-                   && vert_in_cone(*sorted_verts, pvi->m_next, 
pv_prev->m_prev, pvi->m_prev, vi))
-               {
-                       if (! ear_contains_reflex_vertex(*sorted_verts, 
pvi->m_prev, vi, pvi->m_next))
-                       {
-                               // Valid ear.
-                               assert(pvi->m_is_ear == false);
-                               pvi->m_is_ear = true;
-                               m_ear_count++;
-                       }
-               }
-       }
-}
-
-
-template<class coord_t>
-void   poly<coord_t>::dirty_vert(std::vector<vert_t>* sorted_verts, int vi)
-// Call when an adjacent vert gets clipped.  Recomputes
-// m_convex_result and clears m_is_ear for the vert.
-{
-       poly_vert<coord_t>*     pvi = &((*sorted_verts)[vi]);
-
-       int     new_convex_result =
-               vertex_left_test<coord_t>((*sorted_verts)[pvi->m_prev].m_v, 
pvi->m_v, (*sorted_verts)[pvi->m_next].m_v);
-       if (new_convex_result < 0 && pvi->m_convex_result >= 0)
-       {
-               // Vert is newly reflex.
-               // Add to reflex vert index
-               assert(m_reflex_point_index);
-               m_reflex_point_index->add(index_point<coord_t>(pvi->m_v.x, 
pvi->m_v.y), vi);
-       }
-       else if (pvi->m_convex_result < 0 && new_convex_result >= 0)
-       {
-               // Vert is newly convex/colinear.
-               // Remove from reflex vert index.
-               assert(m_reflex_point_index);
-               ip_iterator     it = 
m_reflex_point_index->find(index_point<coord_t>(pvi->m_v.x, pvi->m_v.y), vi);
-               assert(it.at_end() == false);
-
-               m_reflex_point_index->remove(&(*it));
-       }
-       pvi->m_convex_result = new_convex_result;
-
-       if (pvi->m_is_ear)
-       {
-               // Clear its ear flag.
-               pvi->m_is_ear = false;
-               m_ear_count--;
-       }
-}
-
-
-template<class coord_t>
-bool   poly<coord_t>::build_ear_list(std::vector<vert_t>* sorted_verts, 
tu_random::generator* /* rg */)
-// Initialize our ear loop with all the ears that can be clipped.
-//
-// Returns true if we clipped any degenerates while looking for ears.
-{
-       assert(is_valid(*sorted_verts));
-       assert(m_ear_count == 0);
-
-       bool    clipped_any_degenerates = false;
-
-       if (m_vertex_count < 3)
-       {
-               // Not a real poly, no ears.
-               return false;
-       }
-
-       // Go around the loop, evaluating the verts.
-       int     vi = m_loop;
-       int     verts_processed_count = 0;
-       for (;;)
-       {
-               const poly_vert<coord_t>*       pvi = &((*sorted_verts)[vi]);
-               const poly_vert<coord_t>*       pv_prev = 
&((*sorted_verts)[pvi->m_prev]);
-               const poly_vert<coord_t>*       pv_next = 
&((*sorted_verts)[pvi->m_next]);
-
-               // classification of ear, CE2 from FIST paper:
-               //
-               // v[i-1],v[i],v[i+1] of P form an ear of P iff
-               //
-               // 1. v[i] is a convex vertex
-               //
-               // 2. the interior plus boundary of triangle
-               // v[i-1],v[i],v[i+1] does not contain any reflex vertex of P
-               // (except v[i-1] or v[i+1])
-               //
-               // 3. v[i-1] is in the cone(v[i],v[i+1],v[i+2]) and v[i+1] is
-               // in the cone(v[i-2],v[i-1],v[i]) (not strictly necessary,
-               // but used for efficiency and robustness)
-
-               if ((pvi->m_v == pv_next->m_v)
-                   || (pvi->m_v == pv_prev->m_v)
-                   || (vertex_left_test(pv_prev->m_v, pvi->m_v, pv_next->m_v) 
== 0
-                       && vert_is_duplicated(*sorted_verts, vi) == false))
-               {
-                       // Degenerate case: zero-area triangle.
-                       //
-                       // Remove it (and any additional degenerates chained 
onto this ear).
-                       vi = remove_degenerate_chain(sorted_verts, vi);
-
-                       clipped_any_degenerates = true;
-
-                       if (m_vertex_count < 3)
-                       {
-                               break;
-                       }
-
-                       continue;
-               }
-               else
-               {
-                       classify_vert(sorted_verts, vi);
-               }
-
-               vi = pvi->m_next;
-               verts_processed_count++;
-
-               if (verts_processed_count >= m_vertex_count)
-               {
-                       break;
-               }
-
-               // Performance optimization: if we're finding lots of
-               // ears, keep our working set local by processing a
-               // few ears soon after examining them.
-               if (m_ear_count > 5 && verts_processed_count > 10)
-               {
-                       break;
-               }
-       }
-
-       assert(is_valid(*sorted_verts, true /* do check for dupes */));
-
-       // @@ idea for cheap ear shape control: m_loop = best_ear_found;
-
-       return clipped_any_degenerates;
-}
-
-
-template<class coord_t>
-int    poly<coord_t>::get_next_ear(const std::vector<vert_t>& sorted_verts, 
tu_random::generator* /* rg */)
-// Return the next ear to be clipped.
-{
-       assert(m_ear_count > 0);
-
-       while (sorted_verts[m_loop].m_is_ear == false)
-       {
-               m_loop = sorted_verts[m_loop].m_next;
-       }
-
-       int     next_ear = m_loop;
-
-// define this if you want to randomize the ear selection (should
-// improve the average ear shape, at low cost).
-//#define RANDOMIZE
-#ifdef RANDOMIZE
-       // Randomization: skip a random number of ears.
-       if (m_ear_count > 6)
-       {
-               // Decide how many ears to skip.
-
-               // Here's a lot of twiddling to avoid a % op.  Worth it?
-               int     random_range = m_ear_count >> 2;
-               static const int        MASK_TABLE_SIZE = 8;
-               int     random_mask[MASK_TABLE_SIZE] = {
-                       1, 1, 1, 3, 3, 3, 3, 7  // roughly, the largest (2^N-1) 
<= index
-               };
-               if (random_range >= MASK_TABLE_SIZE) random_range = 
MASK_TABLE_SIZE - 1;
-               assert(random_range > 0);
-
-               int     random_skip = rg->next_random() & 
random_mask[random_range];
-
-               // Do the skipping, by manipulating m_loop.
-               while (random_skip > 0)
-               {
-                       if (sorted_verts[m_loop].m_is_ear)
-                       {
-                               random_skip--;
-                       }
-                       m_loop = sorted_verts[m_loop].m_next;
-               }
-
-               assert(is_valid(sorted_verts));
-       }
-#endif // RANDOMIZE
-
-       assert(sorted_verts[next_ear].m_is_ear == true);
-
-       return next_ear;
-}
-
-
-template<class coord_t>
-void   poly<coord_t>::emit_and_remove_ear(
-       std::vector<coord_t>* result,
-       std::vector<vert_t>* sorted_verts,
-       int v0,
-       int v1,
-       int v2)
-// Push the ear triangle into the output; remove the triangle
-// (i.e. vertex v1) from this poly.
-{
-       assert(is_valid(*sorted_verts));
-       assert(m_vertex_count >= 3);
-
-       poly_vert<coord_t>*     pv0 = &(*sorted_verts)[v0];
-       poly_vert<coord_t>*     pv1 = &(*sorted_verts)[v1];
-       poly_vert<coord_t>*     pv2 = &(*sorted_verts)[v2];
-
-       assert((*sorted_verts)[v1].m_is_ear);
-
-       if (m_loop == v1)
-       {
-               // Change m_loop, since we're about to lose it.
-               m_loop = v0;
-       }
-
-       // Make sure m_leftmost_vert is dead; we don't need it now.
-       m_leftmost_vert = -1;
-
-       if (vertex_left_test(pv0->m_v, pv1->m_v, pv2->m_v) == 0)
-       {
-               // Degenerate triangle!  Don't emit it.
-               abort();        // This should have already been removed by 
remove_degenerate_chain().
-       }
-       else
-       {
-               // emit the vertex list for the triangle.
-               result->push_back(pv0->m_v.x);
-               result->push_back(pv0->m_v.y);
-               result->push_back(pv1->m_v.x);
-               result->push_back(pv1->m_v.y);
-               result->push_back(pv2->m_v.x);
-               result->push_back(pv2->m_v.y);
-       }
-
-       // Unlink v1.
-
-       if (pv1->m_convex_result < 0)
-       {
-               // Vert was reflex (can happen due to e.g. recovery).
-               // Remove from reflex vert index.
-               assert(m_reflex_point_index);
-               ip_iterator it = 
m_reflex_point_index->find(index_point<coord_t>(pv1->m_v.x, pv1->m_v.y), v1);
-               assert(it.at_end() == false);
-
-               m_reflex_point_index->remove(&(*it));
-       }
-
-       assert(pv0->m_poly_owner == this);
-       assert(pv1->m_poly_owner == this);
-       assert(pv2->m_poly_owner == this);
-
-       pv0->m_next = v2;
-       pv2->m_prev = v0;
-
-       pv1->m_next = -1;
-       pv1->m_prev = -1;
-       pv1->m_poly_owner = NULL;
-
-       // We lost v1.
-       m_vertex_count--;
-       m_ear_count--;
-
-       if (pv0->m_v == pv2->m_v)
-       {
-               // remove_degenerate_chain() should have taken care of
-               // this before we got here.
-               abort();
-       }
-
-       // ear status of v0 and v2 could have changed now.
-       dirty_vert(sorted_verts, v0);
-       dirty_vert(sorted_verts, v2);
-
-       // Big huge performance boost: recheck these local verts now;
-       // often we'll clip them right away.
-       //
-       // @@ what happens if v0 or v2 are now degenerate???
-       classify_vert(sorted_verts, v0);        
-       classify_vert(sorted_verts, v2);
-
-       assert(is_valid(*sorted_verts));
-}
-
-
-template<class coord_t>
-int    poly<coord_t>::remove_degenerate_chain(std::vector<vert_t>* 
sorted_verts, int vi)
-// Remove the degenerate ear at vi, and any degenerate ear formed as
-// we remove the previous one.
-//
-// Return the index of a vertex just prior to the chain we've removed.
-{
-       assert(m_leftmost_vert == -1);
-
-       int     retval = vi;
-
-       for (;;)
-       {
-               assert(is_valid(*sorted_verts, false /* don't check for dupes 
yet */));
-
-               poly_vert<coord_t>*     pv1 = &(*sorted_verts)[vi];
-               poly_vert<coord_t>*     pv0 = &(*sorted_verts)[pv1->m_prev];
-               poly_vert<coord_t>*     pv2 = &(*sorted_verts)[pv1->m_next];
-
-               if (m_loop == vi)
-               {
-                       // Change m_loop, since we're about to lose it.
-                       m_loop = pv0->m_my_index;
-               }
-
-               // Unlink vi.
-
-               assert(pv0->m_poly_owner == this);
-               assert(pv1->m_poly_owner == this);
-               assert(pv2->m_poly_owner == this);
-
-               pv0->m_next = pv2->m_my_index;
-               pv2->m_prev = pv0->m_my_index;
-
-               pv1->m_next = -1;
-               pv1->m_prev = -1;
-               pv1->m_poly_owner = NULL;
-
-               if (pv1->m_convex_result < 0)
-               {
-                       // vi was reflex, remove it from index
-                       assert(m_reflex_point_index);
-                       ip_iterator     it =
-                               
m_reflex_point_index->find(index_point<coord_t>(pv1->m_v.x, pv1->m_v.y), vi);
-                       assert(it.at_end() == false);
-
-                       m_reflex_point_index->remove(&(*it));
-               }
-
-               if (pv1->m_is_ear)
-               {
-                       m_ear_count--;
-               }
-
-               // We lost vi.
-               m_vertex_count--;
-
-               assert(is_valid(*sorted_verts, false /* don't check for dupes 
yet */));
-
-               if (m_vertex_count < 3)
-               {
-                       retval = pv0->m_my_index;
-                       break;
-               }
-
-               // If we've created another degenerate, then remove it as well.
-               if (pv0->m_v == pv2->m_v)
-               {
-                       // We've created a dupe in the chain, remove it now.
-                       vi = pv0->m_my_index;
-               }
-               else if (vertex_left_test((*sorted_verts)[pv0->m_prev].m_v, 
pv0->m_v, pv2->m_v) == 0)
-               {
-                       // More degenerate.
-                       vi = pv0->m_my_index;
-               }
-               else if (vertex_left_test(pv0->m_v, pv2->m_v, 
(*sorted_verts)[pv2->m_next].m_v) == 0)
-               {
-                       // More degenerate.
-                       vi = pv2->m_my_index;
-               }
-               else
-               {
-                       // ear/reflex status of pv0 & pv2 may have changed.
-                       dirty_vert(sorted_verts, pv0->m_my_index);
-                       dirty_vert(sorted_verts, pv2->m_my_index);
-
-                       retval = pv0->m_my_index;
-
-                       break;
-               }
-       }
-
-       assert(is_valid(*sorted_verts, true /* do check for dupes; there 
shouldn't be any! */));
-
-       return retval;
-}
-
-
-template<class coord_t>
-void   poly<coord_t>::update_connected_sub_poly(std::vector<vert_t>* 
sorted_verts, int v_first_in_subloop, int v_first_after_subloop)
-// Given the beginning and end of a sub-loop that has just been linked
-// into our loop, update the verts on the sub-loop to have the correct
-// owner, update our m_leftmost_vert and our m_vert_count.
-{
-       assert(v_first_in_subloop != v_first_after_subloop);
-
-       int     vi = v_first_in_subloop;
-       do
-       {
-               vert_t* pv = &(*sorted_verts)[vi];
-
-               pv->m_poly_owner = this;
-               m_vertex_count++;
-
-               // Update leftmost vert.
-               if (pv->m_my_index < m_leftmost_vert)
-               {
-                       m_leftmost_vert = pv->m_my_index;
-               }
-
-               // Insert new edge into the edge index.
-               add_edge(*sorted_verts, vi);
-
-               vi = pv->m_next;
-       }
-       while (vi != v_first_after_subloop);
-
-       assert(is_valid(*sorted_verts));
-}
-
-
-
-template<class coord_t>
-void   poly<coord_t>::init_edge_index(const std::vector<vert_t>& sorted_verts, 
index_box<coord_t>& bound_of_all_verts)
-// Initialize our edge-search structure, for quickly finding possible
-// intersecting edges (when constructing bridges to join polys).
-{
-       assert(is_valid(sorted_verts));
-       assert(m_edge_index == NULL);
-
-       // Compute grid density.
-       int     x_cells = 1;
-       int     y_cells = 1;
-       if (sorted_verts.size() > 0)
-       {
-               const float     GRID_SCALE = sqrtf(0.5f);
-               coord_t width = bound_of_all_verts.get_width();
-               coord_t height = bound_of_all_verts.get_height();
-               float   area = float(width) * float(height);
-               if (area > 0)
-               {
-                       float   sqrt_n = sqrt((float) sorted_verts.size());
-                       float   w = width * width / area * GRID_SCALE;
-                       float   h = height * height / area * GRID_SCALE;
-                       x_cells = int(w * sqrt_n);
-                       y_cells = int(h * sqrt_n);
-               }
-               else
-               {
-                       // Zero area.
-                       if (width > 0)
-                       {
-                               x_cells = int(GRID_SCALE * GRID_SCALE * 
sorted_verts.size());
-                       }
-                       else
-                       {
-                               y_cells = int(GRID_SCALE * GRID_SCALE * 
sorted_verts.size());
-                       }
-               }
-               x_cells = iclamp(x_cells, 1, 256);
-               y_cells = iclamp(y_cells, 1, 256);
-       }
-       
-       m_edge_index = new grid_index_box<coord_t, int>(bound_of_all_verts, 
x_cells, y_cells);
-
-       // Insert current edges into the index.
-       int     vi = m_loop;
-       for (;;)
-       {
-               add_edge(sorted_verts, vi);
-
-               vi = sorted_verts[vi].m_next;
-               if (vi == m_loop)
-               {
-                       break;
-               }
-       }
-
-       assert(is_valid(sorted_verts));
-}
-
-
-template<class coord_t>
-void   poly<coord_t>::init_for_ear_clipping(std::vector<vert_t>* sorted_verts)
-// Classify all verts for convexity.
-//
-// Initialize our point-search structure, for quickly finding reflex
-// verts within a potential ear.
-{
-       assert(is_valid(*sorted_verts));
-
-       // Kill m_leftmost_vert; don't need it once all the polys are
-       // joined together into one loop.
-       m_leftmost_vert = -1;
-
-       // Kill edge index; we don't need it for ear clipping.
-       delete m_edge_index;
-       m_edge_index = NULL;
-
-       int     reflex_vert_count = 0;
-
-       bool    bound_inited = false;
-       index_box<coord_t>      reflex_bound(index_point<coord_t>(0, 0), 
index_point<coord_t>(0, 0));
-
-       int     vi = m_loop;
-       for (;;)
-       {
-               // Classify vi as reflex/convex.
-               vert_t* pvi = &(*sorted_verts)[vi];
-               pvi->m_convex_result =
-                       
vertex_left_test<coord_t>((*sorted_verts)[pvi->m_prev].m_v, pvi->m_v, 
(*sorted_verts)[pvi->m_next].m_v);
-               
-               if (pvi->m_convex_result < 0)
-               {
-                       reflex_vert_count++;
-
-                       // Update bounds.
-                       index_point<coord_t>    location(pvi->m_v.x, 
pvi->m_v.y);
-                       if (bound_inited == false)
-                       {
-                               bound_inited = true;
-                               reflex_bound = index_box<coord_t>(location, 
location);
-                       }
-                       else
-                       {
-                               reflex_bound.expand_to_enclose(location);
-                       }
-               }
-
-               vi = (*sorted_verts)[vi].m_next;
-               if (vi == m_loop)
-               {
-                       break;
-               }
-       }
-
-       // Compute grid density.  FIST recommends w * sqrt(N) * h *
-       // sqrt(N), where w*h is between 0.5 and 2.  (N is the reflex
-       // vert count.)
-       int     x_cells = 1;
-       int     y_cells = 1;
-       if (reflex_vert_count > 0)
-       {
-               const float     GRID_SCALE = sqrtf(0.5f);
-               coord_t width = reflex_bound.get_width();
-               coord_t height = reflex_bound.get_height();
-               float   area = float(width) * float(height);
-               if (area > 0)
-               {
-                       float   sqrt_n = sqrt((float) reflex_vert_count);
-                       float   w = width * width / area * GRID_SCALE;
-                       float   h = height * height / area * GRID_SCALE;
-                       x_cells = int(w * sqrt_n);
-                       y_cells = int(h * sqrt_n);
-               }
-               else
-               {
-                       // Zero area.
-                       if (width > 0)
-                       {
-                               x_cells = int(GRID_SCALE * GRID_SCALE * 
reflex_vert_count);
-                       }
-                       else
-                       {
-                               y_cells = int(GRID_SCALE * GRID_SCALE * 
reflex_vert_count);
-                       }
-               }
-               x_cells = iclamp(x_cells, 1, 256);
-               y_cells = iclamp(y_cells, 1, 256);
-       }
-       
-       m_reflex_point_index = new grid_index_point<coord_t, int>(reflex_bound, 
x_cells, y_cells);
-
-       // Insert reflex verts into the index.
-       vi = m_loop;
-       for (;;)
-       {
-               vert_t* pvi = &(*sorted_verts)[vi];
-               if (pvi->m_convex_result < 0)
-               {
-                       // Reflex.  Insert it.
-                       
m_reflex_point_index->add(index_point<coord_t>(pvi->m_v.x, pvi->m_v.y), vi);
-               }
-
-               vi = (*sorted_verts)[vi].m_next;
-               if (vi == m_loop)
-               {
-                       break;
-               }
-       }
-
-       assert(is_valid(*sorted_verts));
-}
-
-
-template<class coord_t>
-void   poly<coord_t>::add_edge(const std::vector<vert_t>& sorted_verts, int vi)
-// Insert the edge (vi, vi->m_next) into the index.
-{
-       index_box<coord_t>      ib(sorted_verts[vi].get_index_point());
-       
ib.expand_to_enclose(sorted_verts[sorted_verts[vi].m_next].get_index_point());
-
-       assert(m_edge_index);
-
-       // Make sure edge isn't already in the index.
-       
assert(m_edge_index->find_payload_from_point(sorted_verts[vi].get_index_point(),
 vi) == NULL);
-
-       m_edge_index->add(ib, vi);
-}
-
-
-template<class coord_t>
-void   poly<coord_t>::remove_edge(const std::vector<vert_t>& sorted_verts, int 
vi)
-// Remove the edge (vi, vi->m_next) from the index.
-{
-       assert(m_edge_index);
-
-       grid_entry_box<coord_t, int>*   entry = 
m_edge_index->find_payload_from_point(sorted_verts[vi].get_index_point(), vi);
-       assert(entry);
-
-       m_edge_index->remove(entry);
-}
-
-
-template<class coord_t>
-bool   poly<coord_t>::vert_can_see_cone_a(const std::vector<vert_t>& 
sorted_verts, int v, int cone_a_vert, int cone_b_vert)
-// Return true if v can see cone_a_vert, without logically crossing cone_b.
-// cone_a_vert and cone_b_vert are coincident.
-{
-       assert(sorted_verts[cone_a_vert].m_v == sorted_verts[cone_b_vert].m_v);
-       
-       // @@ Thought: Would it be more robust to know whether v is
-       // part of a ccw or cw loop, and then decide based on the
-       // relative insideness/outsideness of v w/r/t the cones?
-
-       // Analyze the two cones, to see if the segment
-       // (v,cone_a_vert) is blocked by cone_b_vert.  Since
-       // cone_a_vert and cone_b_vert are coincident, we need to
-       // figure out the relationship among v and the cones.
-
-       // Sort the cones so that they're in convex order.
-       const vert_t*   pa = &sorted_verts[cone_a_vert];
-       vec2<coord_t>   cone_a[3] = { sorted_verts[pa->m_prev].m_v, pa->m_v, 
sorted_verts[pa->m_next].m_v };
-       if (vertex_left_test(cone_a[0], cone_a[1], cone_a[2]) < 0)
-       {
-               swap(&cone_a[0], &cone_a[2]);
-       }
-
-       const vert_t*   pb = &sorted_verts[cone_b_vert];
-       vec2<coord_t>   cone_b[3] = { sorted_verts[pb->m_prev].m_v, pb->m_v, 
sorted_verts[pb->m_next].m_v };
-       if (vertex_left_test(cone_b[0], cone_b[1], cone_b[2]) < 0)
-       {
-               swap(&cone_b[0], &cone_b[2]);
-       }
-
-       // Characterize the cones w/r/t each other.
-       int     a_in_b_sum = 0;
-       a_in_b_sum += vertex_left_test(cone_b[0], cone_b[1], cone_a[0]);
-       a_in_b_sum += vertex_left_test(cone_b[1], cone_b[2], cone_a[0]);
-       a_in_b_sum += vertex_left_test(cone_b[0], cone_b[1], cone_a[2]);
-       a_in_b_sum += vertex_left_test(cone_b[1], cone_b[2], cone_a[2]);
-
-       int     b_in_a_sum = 0;
-       b_in_a_sum += vertex_left_test(cone_a[0], cone_a[1], cone_b[0]);
-       b_in_a_sum += vertex_left_test(cone_a[1], cone_a[2], cone_b[0]);
-       b_in_a_sum += vertex_left_test(cone_a[0], cone_a[1], cone_b[2]);
-       b_in_a_sum += vertex_left_test(cone_a[1], cone_a[2], cone_b[2]);
-
-       // Eeek!  Need a better way of doing this...
-       bool    a_in_b = false;
-       if (a_in_b_sum >= 4)
-       {
-               assert(b_in_a_sum <= -2);
-               a_in_b = true;
-       }
-       else if (a_in_b_sum == 3)
-       {
-               assert(b_in_a_sum <= 3);
-
-               if (b_in_a_sum >= 3)
-               {
-                       // Inconsistent (crossing cones).  No good.
-                       return false;
-               }
-               a_in_b = true;
-       }
-       else if (a_in_b_sum <= -4)
-       {
-               assert(b_in_a_sum >= 2);
-               a_in_b = false;
-       }
-       else if (a_in_b_sum == -3)
-       {
-               assert(b_in_a_sum >= -3);
-
-               if (b_in_a_sum <= -3)
-               {
-                       // Inconsistent (crossing cones).  No good.
-                       return false;
-               }
-               a_in_b = false;
-       }
-       else
-       {
-               if (b_in_a_sum >= 4)
-               {
-                       assert(a_in_b_sum <= -2);
-                       a_in_b = false;
-               }
-               else if (b_in_a_sum == 3)
-               {
-                       a_in_b = false;
-               }
-               else if (b_in_a_sum <= -4)
-               {
-                       assert(a_in_b_sum >= 2);
-                       a_in_b = true;
-               }
-               else if (b_in_a_sum == -3)
-               {
-                       a_in_b = true;
-               }
-               else
-               {
-                       // Inconsistent or coincident.  No good.
-                       return false;
-               }
-       }
-
-       if (a_in_b)
-       {
-               assert(a_in_b);
-
-               bool    v_in_a =
-                       (vertex_left_test(cone_a[0], cone_a[1], 
sorted_verts[v].m_v) > 0)
-                       && (vertex_left_test(cone_a[1], cone_a[2], 
sorted_verts[v].m_v) > 0);
-               if (v_in_a)
-               {
-                       return true;
-               }
-               else
-               {
-                       return false;
-               }
-       }
-       else
-       {
-               bool    v_in_b =
-                       (vertex_left_test(cone_b[0], cone_b[1], 
sorted_verts[v].m_v) > 0)
-                       && (vertex_left_test(cone_b[1], cone_b[2], 
sorted_verts[v].m_v) > 0);
-               if (v_in_b)
-               {
-                       return false;
-               }
-               else
-               {
-                       return true;
-               }
-       }
-}
-
-
-template<class coord_t>
-bool   poly<coord_t>::any_edge_intersection(const std::vector<vert_t>& 
sorted_verts, int external_vert, int my_vert)
-// Return true if edge (external_vert,my_vert) intersects any edge in our poly.
-{
-       // Check the edge index for potentially overlapping edges.
-
-       const vert_t*   pmv = &sorted_verts[my_vert];
-       const vert_t*   pev = &sorted_verts[external_vert];
-
-       assert(m_edge_index);
-
-       index_box<coord_t>      query_box(pmv->get_index_point());
-       query_box.expand_to_enclose(pev->get_index_point());
-
-       for (ib_iterator it = m_edge_index->begin(query_box);
-            ! it.at_end();
-            ++it)
-       {
-               int     vi = it->value;
-               int     v_next = sorted_verts[vi].m_next;
-
-               if (vi != my_vert)
-               {
-                       if (sorted_verts[vi].m_v == sorted_verts[my_vert].m_v)
-                       {
-                               // Coincident verts.
-                               if (vert_can_see_cone_a(sorted_verts, 
external_vert, my_vert, vi) == false)
-                               {
-                                       // Logical edge crossing.
-                                       return true;
-                               }
-                       }
-                       else if (edges_intersect(sorted_verts, vi, v_next, 
external_vert, my_vert))
-                       {
-                               return true;
-                       }
-               }
-       }
-
-       return false;
-}
-
-
-template<class coord_t>
-bool   poly<coord_t>::ear_contains_reflex_vertex(const std::vector<vert_t>& 
sorted_verts, int v0, int v1, int v2)
-// Return true if any of this poly's reflex verts are inside the
-// specified ear.  The definition of inside is: a reflex vertex in the
-// interior of the triangle (v0,v1,v2), or on the segments [v1,v0) or
-// [v1,v2).
-{
-       // Compute the bounding box of reflex verts we want to check.
-       index_box<coord_t>      query_bound(sorted_verts[v0].get_index_point());
-       
query_bound.expand_to_enclose(index_point<coord_t>(sorted_verts[v1].m_v.x, 
sorted_verts[v1].m_v.y));
-       
query_bound.expand_to_enclose(index_point<coord_t>(sorted_verts[v2].m_v.x, 
sorted_verts[v2].m_v.y));
-
-       for (ip_iterator it = m_reflex_point_index->begin(query_bound);
-            ! it.at_end();
-            ++it)
-       {
-               int     vk = it->value;
-
-               const vert_t*   pvk = &sorted_verts[vk];
-               if (pvk->m_poly_owner != this)
-               {
-                       // Not part of this poly; ignore it.
-                       continue;
-               }
-
-               if (vk != v0 && vk != v1 && vk != v2
-                   && 
query_bound.contains_point(index_point<coord_t>(pvk->m_v.x, pvk->m_v.y)))
-               {
-#if 0
-                       //xxxxxx debug hook
-                       if (v1 == 131 && vk == 132)
-                       {
-                               vk = vk;//xxxxx breakpoint here
-                       }
-#endif
-
-                       int     v_next = pvk->m_next;
-                       int     v_prev = pvk->m_prev;
-
-                       if (pvk->m_v == sorted_verts[v1].m_v)
-                       {
-                               // Tricky case.  See section 4.3 in FIST paper.
-
-                               // Note: I'm explicitly considering convex vk 
in here, unlike FIST.
-                               // This is to handle the triple dupe case, 
where a loop validly comes
-                               // straight through our cone.
-                               //
-                               // Note: the triple-dupe case is technically 
not a valid poly, since
-                               // it contains a twist.
-                               //
-                               // @@ Fix this back to the FIST way?
-
-                               int     v_prev_left01 = vertex_left_test(
-                                       sorted_verts[v0].m_v,
-                                       sorted_verts[v1].m_v,
-                                       sorted_verts[v_prev].m_v);
-                               int     v_next_left01 = vertex_left_test(
-                                       sorted_verts[v0].m_v,
-                                       sorted_verts[v1].m_v,
-                                       sorted_verts[v_next].m_v);
-                               int     v_prev_left12 = vertex_left_test(
-                                       sorted_verts[v1].m_v,
-                                       sorted_verts[v2].m_v,
-                                       sorted_verts[v_prev].m_v);
-                               int     v_next_left12 = vertex_left_test(
-                                       sorted_verts[v1].m_v,
-                                       sorted_verts[v2].m_v,
-                                       sorted_verts[v_next].m_v);
-
-                               if ((v_prev_left01 > 0 && v_prev_left12 > 0)
-                                   || (v_next_left01 > 0 && v_next_left12 > 0))
-                               {
-                                       // Local interior near vk intersects 
this
-                                       // ear; ear is clearly not valid.
-                                       return true;
-                               }
-
-                               // Check colinear case, where cones of vk and 
v1 overlap exactly.
-                               if ((v_prev_left01 == 0 && v_next_left12 == 0)
-                                   || (v_prev_left12 == 0 && v_next_left01 == 
0))
-                               {
-                                       // @@ TODO: there's a somewhat complex 
non-local area test that tells us
-                                       // whether vk qualifies as a contained 
reflex vert.
-                                       //
-                                       // For the moment, deny the ear.
-                                       //
-                                       // The question is, is this test 
required for correctness?  Because it
-                                       // seems pretty expensive to compute.  
If it's not required, I think it's
-                                       // better to always assume the ear is 
invalidated.
-
-                                       //xxx
-                                       //fprintf(stderr, "colinear case in 
ear_contains_reflex_vertex; returning true\n");
-
-                                       return true;
-                               }
-                       }
-                       else
-                       {
-                               assert(pvk->m_convex_result < 0);
-                               if (vertex_in_ear(
-                                           pvk->m_v, sorted_verts[v0].m_v, 
sorted_verts[v1].m_v, sorted_verts[v2].m_v))
-                               {
-                                       // Found one.
-                                       return true;
-                               }
-                       }
-               }
-       }
-
-       // Didn't find any qualifying verts.
-       return false;
-}
-
-
-template<class coord_t>
-bool   poly<coord_t>::vert_in_cone(const std::vector<vert_t>& sorted_verts, 
int vert, int cone_v0, int cone_v1, int cone_v2)
-// Returns true if vert is within the cone defined by [v0,v1,v2].
-/*
-//  (out)  v0
-//        /
-//    v1 <   (in)
-//        \
-//         v2
-*/
-{
-       bool    acute_cone = vertex_left_test(sorted_verts[cone_v0].m_v, 
sorted_verts[cone_v1].m_v, sorted_verts[cone_v2].m_v) > 0;
-
-       // Include boundary in our tests.
-       bool    left_of_01 =
-               vertex_left_test(sorted_verts[cone_v0].m_v, 
sorted_verts[cone_v1].m_v, sorted_verts[vert].m_v) >= 0;
-       bool    left_of_12 =
-               vertex_left_test(sorted_verts[cone_v1].m_v, 
sorted_verts[cone_v2].m_v, sorted_verts[vert].m_v) >= 0;
-
-       if (acute_cone)
-       {
-               // Acute cone.  Cone is intersection of half-planes.
-               return left_of_01 && left_of_12;
-       }
-       else
-       {
-               // Obtuse cone.  Cone is union of half-planes.
-               return left_of_01 || left_of_12;
-       }
-}
-
-
-template<class coord_t>
-bool   poly<coord_t>::vert_is_duplicated(const std::vector<vert_t>& 
sorted_verts, int vert)
-// Return true if there's another vertex in this poly, coincident with vert.
-{
-       // Scan backwards.
-       {for (int vi = vert - 1; vi >= 0; vi--)
-       {
-               if ((sorted_verts[vi].m_v == sorted_verts[vert].m_v) == false)
-               {
-                       // No more coincident verts scanning backward.
-                       break;
-               }
-               if (sorted_verts[vi].m_poly_owner == this)
-               {
-                       // Found a dupe vert.
-                       return true;
-               }
-       }}
-
-       // Scan forwards.
-       {for (int vi = vert + 1, n = sorted_verts.size(); vi < n; vi++)
-       {
-               if ((sorted_verts[vi].m_v == sorted_verts[vert].m_v) == false)
-               {
-                       // No more coincident verts scanning forward.
-                       break;
-               }
-               if (sorted_verts[vi].m_poly_owner == this)
-               {
-                       // Found a dupe vert.
-                       return true;
-               }
-       }}
-
-       // Didn't find a dupe.
-       return false;
-}
-
-
-//
-// poly_env
-//
-
-
-template<class coord_t>
-class poly_env
-// Struct that holds the state of a triangulation.
-{
-public:
-//data:
-       std::vector<poly_vert<coord_t> >        m_sorted_verts;
-       std::vector<poly<coord_t>*>     m_polys;
-
-       index_box<coord_t>      m_bound;
-       int     m_estimated_triangle_count;
-//code:
-       void    init(int path_count, const std::vector<coord_t> paths[]);
-       void    join_paths_into_one_poly();
-
-       int     get_estimated_triangle_count() const { return 
m_estimated_triangle_count; }
-
-       poly_env()
-               :
-               m_bound(index_point<coord_t>(0, 0), index_point<coord_t>(0, 0)),
-               m_estimated_triangle_count(0)
-       {
-       }
-
-       ~poly_env()
-       {
-               // delete the polys that got new'd during init()
-               for (int i = 0, n = m_polys.size(); i < n; i++)
-               {
-                       delete m_polys[i];
-               }
-       }
-
-private:
-       // Internal helpers.
-       void    join_paths_with_bridge(
-               poly<coord_t>* main_poly,
-               poly<coord_t>* sub_poly,
-               int vert_on_main_poly,
-               int vert_on_sub_poly);
-       void    dupe_two_verts(int v0, int v1);
-};
-
-
-template<class coord_t>
-void   poly_env<coord_t>::init(int path_count, const std::vector<coord_t> 
paths[])
-// Initialize our state, from the given set of paths.  Sort vertices
-// and component polys.
-{
-       // Only call this on a fresh poly_env
-       assert(m_sorted_verts.size() == 0);
-       assert(m_polys.size() == 0);
-
-       // Count total verts.
-       int     vert_count = 0;
-       for (int i = 0; i < path_count; i++)
-       {
-               vert_count += paths[i].size();
-       }
-
-       // Slight over-estimate; the true number depends on how many
-       // of the paths are actually islands.
-       m_estimated_triangle_count = vert_count /* - 2 * path_count */;
-
-       // Collect the input verts and create polys for the input paths.
-       m_sorted_verts.reserve(vert_count + (path_count - 1) * 2);      // 
verts, plus two duped verts for each path, for bridges
-       m_polys.reserve(path_count);
-
-       for (int i = 0; i < path_count; i++)
-       {
-               // Create a poly for this path.
-               const std::vector<coord_t>&     path = paths[i];
-
-               if (path.size() < 3)
-               {
-                       // Degenerate path, ignore it.
-                       continue;
-               }
-
-               poly<coord_t>*  p = new poly<coord_t>;
-               m_polys.push_back(p);
-
-               // Add this path's verts to our list.
-               int     path_size = path.size();
-               if (path.size() & 1)
-               {
-                       // Bad input, odd number of coords.
-                       abort();                        
-                       fprintf(stderr, "path[%d] has odd number of coords (" 
SIZET_FMT 
-                               "), dropping last value\n", i, 
path.size());//xxxx
-                       path_size--;
-               }
-               for (int j = 0; j < path_size; j += 2)  // vertex coords come 
in pairs.
-               {
-                       int     prev_point = j - 2;
-                       if (j == 0) prev_point = path_size - 2;
-
-                       if (path[j] == path[prev_point] && path[j + 1] == 
path[prev_point + 1])
-                       {
-                               // Duplicate point; drop it.
-                               continue;
-                       }
-
-                       // Insert point.
-                       int     vert_index = m_sorted_verts.size();
-
-                       poly_vert<coord_t>      vert(path[j], path[j+1], p, 
vert_index);
-                       m_sorted_verts.push_back(vert);
-
-                       p->append_vert(&m_sorted_verts, vert_index);
-
-                       index_point<coord_t>    ip(vert.m_v.x, vert.m_v.y);
-                       if (vert_index == 0)
-                       {
-                               // Initialize the bounding box.
-                               m_bound.min = ip;
-                               m_bound.max = ip;
-                       }
-                       else
-                       {
-                               // Expand the bounding box.
-                               m_bound.expand_to_enclose(ip);
-                       }
-                       assert(m_bound.contains_point(ip));
-               }
-               assert(p->is_valid(m_sorted_verts));
-
-               if (p->m_vertex_count == 0)
-               {
-                       // This path was degenerate; kill it.
-                       delete p;
-                       m_polys.pop_back();
-               }
-       }
-
-       // Sort the vertices.
-       qsort(&m_sorted_verts[0], m_sorted_verts.size(), 
sizeof(m_sorted_verts[0]), compare_vertices<coord_t>);
-       assert(m_sorted_verts.size() <= 1
-              || compare_vertices<coord_t>((void*) &m_sorted_verts[0], (void*) 
&m_sorted_verts[1]) <= 0);      // check order
-
-       // Remap the vertex indices, so that the polys and the
-       // sorted_verts have the correct, sorted, indices.  We can
-       // then use vert indices to judge the left/right relationship
-       // of two verts.
-       std::vector<int>        vert_remap;     // vert_remap[i] == new index 
of original vert[i]
-       vert_remap.resize(m_sorted_verts.size());
-       for (int i = 0, n = m_sorted_verts.size(); i < n; i++)
-       {
-               int     new_index = i;
-               int     original_index = m_sorted_verts[new_index].m_my_index;
-               vert_remap[original_index] = new_index;
-       }
-       {for (int i = 0, n = m_sorted_verts.size(); i < n; i++)
-       {
-               m_sorted_verts[i].remap(vert_remap);
-       }}
-       {for (int i = 0, n = m_polys.size(); i < n; i++)
-       {
-               m_polys[i]->remap(vert_remap);
-               assert(m_polys[i]->is_valid(m_sorted_verts));
-       }}
-}
-
-
-template<class coord_t>
-void   poly_env<coord_t>::join_paths_into_one_poly()
-// Use zero-area bridges to connect separate polys & islands into one
-// big continuous poly.
-{
-       // Connect separate paths with bridge edges, into one big path.
-       //
-       // Bridges are zero-area regions that connect a vert on each
-       // of two paths.
-       if (m_polys.size() > 1)
-       {
-               // Sort polys in order of each poly's leftmost vert.
-               qsort(&m_polys[0], m_polys.size(), sizeof(m_polys[0]), 
compare_polys_by_leftmost_vert<coord_t>);
-               assert(m_polys.size() <= 1
-                      || compare_polys_by_leftmost_vert<coord_t>((void*) 
&m_polys[0], (void*) &m_polys[1]) == -1);
-
-               // assume that the enclosing boundary is the leftmost
-               // path; this is true if the regions are valid and
-               // don't intersect.
-               poly<coord_t>*  full_poly = m_polys[0];
-
-               full_poly->init_edge_index(m_sorted_verts, m_bound);
-
-               // Iterate from left to right
-               while (m_polys.size() > 1)
-               {
-                       int     v1 = m_polys[1]->m_leftmost_vert;
-
-                       //     find v2 in full_poly, such that:
-                       //       v2 is to the left of v1,
-                       //       and v1-v2 seg doesn't intersect any other edges
-
-                       //     // (note that since v1 is next-most-leftmost, 
v1-v2 can't
-                       //     // hit anything in p, or any paths further down 
the list,
-                       //     // it can only hit edges in full_poly) (need to 
think
-                       //     // about equality cases)
-                       //
-                       int     v2 = 
full_poly->find_valid_bridge_vert(m_sorted_verts, v1);
-
-                       //     once we've found v1 & v2, we use it to make a 
bridge,
-                       //     inserting p into full_poly
-                       //
-                       assert(m_sorted_verts[v2].m_poly_owner == m_polys[0]);
-                       assert(m_sorted_verts[v1].m_poly_owner == m_polys[1]);
-                       join_paths_with_bridge(full_poly, m_polys[1], v2, v1);
-
-                       // Drop the joined poly.
-                       delete m_polys[1];
-                       m_polys.erase(m_polys.begin() + 1);
-               }
-       }
-
-       m_polys[0]->init_for_ear_clipping(&m_sorted_verts);
-
-       assert(m_polys.size() == 1);
-       // assert(all verts in m_sorted_verts have m_polys[0] as their owner);
-}
-
-
-template<class coord_t>
-void   poly_env<coord_t>::join_paths_with_bridge(
-       poly<coord_t>* main_poly,
-       poly<coord_t>* sub_poly,
-       int vert_on_main_poly,
-       int vert_on_sub_poly)
-// Absorb the sub-poly into the main poly, using a zero-area bridge
-// between the two given verts.
-{
-       assert(vert_on_main_poly != vert_on_sub_poly);
-       assert(main_poly != NULL);
-       assert(sub_poly != NULL);
-       assert(main_poly != sub_poly);
-       assert(main_poly == m_sorted_verts[vert_on_main_poly].m_poly_owner);
-       assert(sub_poly == m_sorted_verts[vert_on_sub_poly].m_poly_owner);
-
-       if (m_sorted_verts[vert_on_main_poly].m_v == 
m_sorted_verts[vert_on_sub_poly].m_v)
-       {
-               // Special case: verts to join are coincident.  We
-               // don't actually need to make a bridge with new
-               // verts; we only need to adjust the links and do
-               // fixup.
-               poly_vert<coord_t>*     pv_main = 
&m_sorted_verts[vert_on_main_poly];
-               poly_vert<coord_t>*     pv_sub = 
&m_sorted_verts[vert_on_sub_poly];
-
-               int     main_next = pv_main->m_next;
-
-               // Remove the edge we're about to break.
-               main_poly->remove_edge(m_sorted_verts, vert_on_main_poly);
-
-               pv_main->m_next = pv_sub->m_next;
-               m_sorted_verts[pv_main->m_next].m_prev = vert_on_main_poly;
-
-               pv_sub->m_next = main_next;
-               m_sorted_verts[main_next].m_prev = vert_on_sub_poly;
-
-               // Add edge that connects to sub poly.
-               main_poly->add_edge(m_sorted_verts, vert_on_main_poly);
-
-               // Fixup sub poly so it's now properly a part of the main poly.
-               main_poly->update_connected_sub_poly(&m_sorted_verts, 
pv_main->m_next, main_next);
-               sub_poly->invalidate(m_sorted_verts);
-
-               return;
-       }
-
-       // Normal case, need to dupe verts and create zero-area bridge.
-       dupe_two_verts(vert_on_main_poly, vert_on_sub_poly);
-
-       // Fixup the old indices to account for the new dupes.
-       if (vert_on_sub_poly < vert_on_main_poly)
-       {
-               vert_on_main_poly++;
-       }
-       else
-       {
-               vert_on_sub_poly++;
-       }
-
-       poly_vert<coord_t>*     pv_main = &m_sorted_verts[vert_on_main_poly];
-       poly_vert<coord_t>*     pv_sub = &m_sorted_verts[vert_on_sub_poly];
-       poly_vert<coord_t>*     pv_main2 = &m_sorted_verts[vert_on_main_poly + 
1];
-       poly_vert<coord_t>*     pv_sub2 = &m_sorted_verts[vert_on_sub_poly + 1];
-
-       // Remove the edge we're about to break.
-       main_poly->remove_edge(m_sorted_verts, vert_on_main_poly);
-
-       // Link the loops together.
-       pv_main2->m_next = pv_main->m_next;
-       pv_main2->m_prev = vert_on_sub_poly + 1;        // (pv_sub2)
-       m_sorted_verts[pv_main2->m_next].m_prev = pv_main2->m_my_index;
-
-       pv_sub2->m_prev = pv_sub->m_prev;
-       pv_sub2->m_next = vert_on_main_poly + 1;        // (pv_main2)
-       m_sorted_verts[pv_sub2->m_prev].m_next = pv_sub2->m_my_index;
-
-       pv_main->m_next = vert_on_sub_poly;             // (pv_sub)
-       pv_sub->m_prev = vert_on_main_poly;             // (pv_main)
-
-       // Add edge that connects to sub poly.
-       main_poly->add_edge(m_sorted_verts, vert_on_main_poly);
-
-       // Fixup sub poly so it's now properly a part of the main poly.
-       main_poly->update_connected_sub_poly(&m_sorted_verts, vert_on_sub_poly, 
pv_main2->m_next);
-       sub_poly->invalidate(m_sorted_verts);
-
-       assert(pv_main->m_poly_owner->is_valid(m_sorted_verts));
-}
-
-
-template<class coord_t>
-void   poly_env<coord_t>::dupe_two_verts(int v0, int v1)
-// Duplicate the two indexed verts, remapping polys & verts as necessary.
-{
-       // Order the verts.
-       if (v0 > v1)
-       {
-               swap(&v0, &v1);
-       }
-       assert(v0 < v1);
-
-       // Duplicate verts.
-       poly_vert<coord_t>      v0_copy = m_sorted_verts[v0];
-       poly_vert<coord_t>      v1_copy = m_sorted_verts[v1];
-
-       // @@ This stuff can be costly!  E.g. lots of separate little
-       // polys that need bridges, with a high total vert count.
-
-       // Slower, clearer code to insert the two new verts.  This
-       // ends up moving the data between ((v1+1), end) twice.
-       if (0) {
-               // Insert v1 first, so v0 doesn't get moved.
-               m_sorted_verts.insert(m_sorted_verts.begin() + v1 + 1, v1_copy);
-               m_sorted_verts.insert(m_sorted_verts.begin() + v0 + 1, v0_copy);
-       }
-       else
-       // Faster, more obfuscated code to insert the two new verts.
-       //
-       // NOTE: I tried doing this in one pass, with a complicated
-       // explicit move & remap in the same pass.  It was much
-       // slower!  (VC7, Win2K.)  memmove() must be magical?
-       {
-               // Make room.
-               m_sorted_verts.resize(m_sorted_verts.size() + 2);
-
-               // Move the two subsegments.
-               memmove(&m_sorted_verts[v1 + 3], &m_sorted_verts[v1 + 1], 
sizeof(m_sorted_verts[0]) * (m_sorted_verts.size() - 3 - v1));
-               memmove(&m_sorted_verts[v0 + 2], &m_sorted_verts[v0 + 1], 
sizeof(m_sorted_verts[0]) * (v1 - v0));
-
-               // Insert the new duplicate verts.
-               m_sorted_verts[v0 + 1] = v0_copy;
-               m_sorted_verts[v1 + 2] = v1_copy;
-       }
-
-       // Remap the indices within the verts.
-       for (int i = 0, n = m_sorted_verts.size(); i < n; i++)
-       {
-               m_sorted_verts[i].m_my_index = i;
-               m_sorted_verts[i].m_next = 
remap_index_for_duped_verts(m_sorted_verts[i].m_next, v0, v1);
-               m_sorted_verts[i].m_prev = 
remap_index_for_duped_verts(m_sorted_verts[i].m_prev, v0, v1);
-       }
-
-       // Remap the polys.
-       {for (int i = 0, n = m_polys.size(); i < n; i++)
-       {
-               m_polys[i]->remap_for_duped_verts(m_sorted_verts, v0, v1);
-
-               assert(m_polys[i]->is_valid(m_sorted_verts));
-       }}
-}
-
-
-//
-// Helpers.
-//
-
-
-template<class coord_t>
-static void    recovery_process(
-       std::vector<poly<coord_t>*>* polys,     // polys waiting to be processed
-       poly<coord_t>* P,       // current poly
-       std::vector<poly_vert<coord_t> >* sorted_verts,
-       tu_random::generator* rg);
-
-
-template<class coord_t>
-inline void    debug_emit_poly_loop(
-       std::vector<coord_t>* result,
-       const std::vector<poly_vert<coord_t> >& sorted_verts,
-       poly<coord_t>* P)
-// Fill *result with a poly loop representing P.
-{
-       result->resize(0);      // clear existing junk.
-
-       int     first_vert = P->m_loop;
-       int     vi = first_vert;
-       do
-       {
-               result->push_back(sorted_verts[vi].m_v.x);
-               result->push_back(sorted_verts[vi].m_v.y);
-               vi = sorted_verts[vi].m_next;
-       }
-       while (vi != first_vert);
-
-       // Loop back to beginning, and pad to a multiple of 3 coords.
-       do
-       {
-               result->push_back(sorted_verts[vi].m_v.x);
-               result->push_back(sorted_verts[vi].m_v.y);
-       }
-       while (result->size() % 6);
-}
-
-
-template<class coord_t>
-static void compute_triangulation(
-       std::vector<coord_t>* result,
-       int path_count,
-       const std::vector<coord_t> paths[],
-       int debug_halt_step,
-       std::vector<coord_t>* debug_remaining_loop)
-// Compute triangulation.
-//
-// The debug_ args are optional; they're for terminating early and
-// returning the remaining loop to be triangulated.
-{
-       if (path_count <= 0)
-       {
-               // Empty paths --> no triangles to emit.
-               return;
-       }
-
-#ifdef PROFILE_TRIANGULATE
-       uint64_t        start_ticks = tu_timer::get_profile_ticks();
-#endif // PROFILE_TRIANGULATE
-
-       // Local generator, for some parts of the algo that need random numbers.
-       tu_random::generator    rand_gen;
-
-       // Poly environment; most of the state of the algo.
-       poly_env<coord_t>       penv;
-
-       penv.init(path_count, paths);
-
-       penv.join_paths_into_one_poly();
-
-       result->reserve(2 * 3 * penv.get_estimated_triangle_count());
-
-       int     input_vert_count = 0;
-       if (penv.m_polys.size() > 0)
-       {
-               input_vert_count = penv.m_polys[0]->get_vertex_count();
-       }
-
-#ifdef PROFILE_TRIANGULATE
-       uint64_t        join_ticks = tu_timer::get_profile_ticks();
-       fprintf(stderr, "join poly = %1.6f sec\n", 
tu_timer::profile_ticks_to_seconds(join_ticks - start_ticks));
-#endif // PROFILE_TRIANGULATE
-
-// Debugging only: dump coords of joined poly.
-//#define DUMP_JOINED_POLY
-#ifdef DUMP_JOINED_POLY
-       {
-               int     first_vert = penv.m_polys[0]->m_loop;
-               int     vi = first_vert;
-               do
-               {
-                       printf("%f, %f\n", penv.m_sorted_verts[vi].m_v.x, 
penv.m_sorted_verts[vi].m_v.y);
-                       vi = penv.m_sorted_verts[vi].m_next;
-               }
-               while (vi != first_vert);
-       }
-#endif
-
-// Debugging only: just emit our joined poly, without triangulating.
-//#define EMIT_JOINED_POLY
-#ifdef EMIT_JOINED_POLY
-       {
-               int     first_vert = penv.m_polys[0]->m_loop;
-               int     vi = first_vert;
-               do
-               {
-                       result->push_back(penv.m_sorted_verts[vi].m_v.x);
-                       result->push_back(penv.m_sorted_verts[vi].m_v.y);
-                       vi = penv.m_sorted_verts[vi].m_next;
-               }
-               while (vi != first_vert);
-
-               // Loop back to beginning, and pad to a multiple of 3 coords.
-               do
-               {
-                       result->push_back(penv.m_sorted_verts[vi].m_v.x);
-                       result->push_back(penv.m_sorted_verts[vi].m_v.y);
-               }
-               while (result->size() % 6);
-       }
-
-       return;
-#endif // EMIT_JOINED_POLY
-
-       // ear-clip, adapted from FIST paper:
-       //
-       //   list<poly> L;
-       //   L.insert(full_poly)
-       //   while L not empty:
-       //     P = L.pop()
-       //     Q = priority queue of ears of P
-       //     while P.vert_count > 3 do:
-       //       if Q not empty:
-       //         e = Q.pop
-       //         emit e
-       //         update P by deleting e
-       //       else if an ear was clipped in previous pass then:
-       //         Q = priority queue of ears of P (i.e. reexamine P)
-       //       else
-       //         // we're stuck
-       //         recovery_process()   // do something drastic to make the 
next move
-       //     emit last 3 verts of P as the final triangle
-
-       while (penv.m_polys.size())
-       {
-               poly<coord_t>*  P = penv.m_polys.back();
-               penv.m_polys.pop_back();
-
-               P->build_ear_list(&penv.m_sorted_verts, &rand_gen);
-
-               bool    ear_was_clipped = false;
-               while (P->get_vertex_count() > 3)
-               {
-                       if (P->get_ear_count() > 0)
-                       {
-                               // Clip the next ear from Q.
-                               int     v1 = 
P->get_next_ear(penv.m_sorted_verts, &rand_gen);
-                               int     v0 = penv.m_sorted_verts[v1].m_prev;
-                               int     v2 = penv.m_sorted_verts[v1].m_next;
-
-                               P->emit_and_remove_ear(result, 
&penv.m_sorted_verts, v0, v1, v2);
-                               ear_was_clipped = true;
-
-                               // For debugging -- terminate early if the 
debug counter hits zero.
-                               debug_halt_step--;
-                               if (debug_halt_step == 0) {
-                                       if (debug_remaining_loop) {
-                                               
debug_emit_poly_loop(debug_remaining_loop, penv.m_sorted_verts, P);
-                                       }
-                                       return;
-                               }
-                       }
-                       else if (ear_was_clipped == true)
-                       {
-                               // Re-examine P for new ears.
-                               ear_was_clipped = 
P->build_ear_list(&penv.m_sorted_verts, &rand_gen);
-                       }
-                       else
-                       {
-                               // No valid ears; we're in trouble so try some 
fallbacks.
-
-#if 1
-                               // xxx hack for debugging: show the state of P 
when we hit the recovery process.
-                               debug_emit_poly_loop(result, 
penv.m_sorted_verts, P);
-                               return;
-#endif
-
-                               recovery_process(&penv.m_polys, P, 
&penv.m_sorted_verts, &rand_gen);
-                               ear_was_clipped = false;
-                       }
-               }
-
-               if (P->get_vertex_count() == 3)
-               {
-                       // Emit the final triangle.
-                       if (penv.m_sorted_verts[P->m_loop].m_is_ear == false)
-                       {
-                               // Force an arbitrary vert to be an ear.
-                               penv.m_sorted_verts[P->m_loop].m_is_ear = true;
-                               P->m_ear_count++;
-                       }
-                       P->emit_and_remove_ear(
-                               result,
-                               &penv.m_sorted_verts,
-                               penv.m_sorted_verts[P->m_loop].m_prev,
-                               P->m_loop,
-                               penv.m_sorted_verts[P->m_loop].m_next);
-               }
-               delete P;
-       }
-       
-#ifdef PROFILE_TRIANGULATE
-       uint64_t        clip_ticks = tu_timer::get_profile_ticks();
-       fprintf(stderr, "clip poly = %1.6f sec\n", 
tu_timer::profile_ticks_to_seconds(clip_ticks - join_ticks));
-       fprintf(stderr, "total for poly = %1.6f sec\n", 
tu_timer::profile_ticks_to_seconds(clip_ticks - start_ticks));
-       fprintf(stderr, "vert count = %d, verts clipped / sec = %f\n",
-               input_vert_count,
-               input_vert_count / 
tu_timer::profile_ticks_to_seconds(clip_ticks - join_ticks));
-#endif // PROFILE_TRIANGULATE
-
-       assert(penv.m_polys.size() == 0);
-       // assert(for all penv.m_sorted_verts: owning poly == NULL);
-
-       assert((result->size() % 6) == 0);
-}
-
-
-template<class coord_t>
-void   recovery_process(
-                         std::vector<poly<coord_t>*>* /* polys */,
-       poly<coord_t>* P,
-       std::vector<poly_vert<coord_t> >* sorted_verts,
-       tu_random::generator* rg)
-{
-       // recovery_process:
-       //   if two edges in P, e[i-1] and e[i+1] intersect:
-       //     insert two tris incident on e[i-1] & e[i+1] as ears into Q
-       //   else if P can be split with a valid diagonal:
-       //     P = one side
-       //     L += the other side
-       //     Q = ears of P
-       //   else if P has any convex vertex:
-       //     pick a random convex vert and add it to Q
-       //   else
-       //     pick a random vert and add it to Q
-
-       // Case 1: two edges, e[i-1] and e[i+1], intersect; we insert
-       // the overlapping ears into Q and resume.
-       {for (int vi = (*sorted_verts)[P->m_loop].m_next; vi != P->m_loop; vi = 
(*sorted_verts)[vi].m_next)
-       {
-               int     ev0 = vi;
-               int     ev1 = (*sorted_verts)[ev0].m_next;
-               int     ev2 = (*sorted_verts)[ev1].m_next;
-               int     ev3 = (*sorted_verts)[ev2].m_next;
-               if (edges_intersect(*sorted_verts, ev0, ev1, ev2, ev3))
-               {
-                       // Insert (1,2,3) as an ear.
-                       (*sorted_verts)[ev2].m_is_ear = true;
-                       P->m_ear_count++;
-
-                       fprintf(stderr, "recovery_process: self-intersecting 
sequence, treating %d as an ear\n", ev2);//xxxx
-
-                       // Resume regular processing.
-                       return;
-               }
-       }}
-
-// Deviation from FIST: Because I'm lazy, I'm skipping this test for
-// now...
-//
-// @@ This seems to be helpful for doing reasonable things in case the
-// input is a little bit self-intersecting.  Otherwise, clipping any
-// old convex or random vert can create crazy junk in the
-// triangulation.  It's probably worth implementing at some point.
-#if 0
-       // Case 2: P can be split with a valid diagonal.
-       //
-       // A "valid diagonal" passes these checks, according to FIST:
-       //
-       // 1. diagonal is locally within poly
-       //
-       // 2. its relative interior does not intersect any edge of the poly
-       //
-       // 3. the winding number of the polygon w/r/t the midpoint of
-       // the diagonal is one
-       //
-       {for (int vi = verts[0, end])
-       {
-               for (int vj = verts[vi->m_next, end])
-               {
-                       if (P->valid_diagonal(vi, vj))
-                       {
-                               // Split P, insert leftover piece into polys
-                               poly*   leftover = P->split(vi, vj);
-                               polys->push_back(leftover);
-
-                               // Resume regular processing.
-                               return;
-                       }
-               }
-       }}
-#endif // 0
-
-       // Case 3: P has any convex vert
-       int     first_vert = P->m_loop;
-       int     vi = first_vert;
-       int     vert_count = 0;
-       do
-       {
-               if (is_convex_vert(*sorted_verts, vi))
-               {
-                       // vi is convex; treat it as an ear,
-                       // regardless of other problems it may have.
-                       (*sorted_verts)[vi].m_is_ear = true;
-                       P->m_ear_count++;
-
-                       fprintf(stderr, "recovery_process: found convex vert, 
treating %d as an ear\n", vi);//xxxx
-
-                       // Resume regular processing.
-                       return;
-               }
-
-               vert_count++;
-               vi = (*sorted_verts)[vi].m_next;
-       }
-       while (vi != first_vert);
-
-       // Case 4: Pick a random vert and treat it as an ear.
-       int     random_vert = rg->next_random() % vert_count;
-       for (vi = first_vert; random_vert > 0; random_vert--)
-       {
-               vi = (*sorted_verts)[vi].m_next;
-       }
-       (*sorted_verts)[vi].m_is_ear = true;
-       P->m_ear_count++;
-
-       fprintf(stderr, "recovery_process: treating random vert %d as an 
ear\n", vi);//xxxx
-
-       // Resume.
-       return;
-}

Index: libbase/triangulate_sint32.cpp
===================================================================
RCS file: libbase/triangulate_sint32.cpp
diff -N libbase/triangulate_sint32.cpp
--- libbase/triangulate_sint32.cpp      11 Apr 2007 17:54:21 -0000      1.6
+++ /dev/null   1 Jan 1970 00:00:00 -0000
@@ -1,28 +0,0 @@
-// triangulate_sint32.cpp      -- Thatcher Ulrich 2004
-
-// This source code has been donated to the Public Domain.  Do
-// whatever you want with it.
-
-// Code to triangulate arbitrary 2D polygonal regions.
-//
-// Instantiate our templated algo from triangulate_inst.h
-
-/* $Id: triangulate_sint32.cpp,v 1.6 2007/04/11 17:54:21 bjacques Exp $ */
-
-#include "triangulate_impl.h"
-
-using namespace std;
-
-namespace triangulate
-{
-       // Version using int32_t coords
-       void    compute(
-               std::vector<int32_t>* result,   // trilist
-               int path_count,
-               const std::vector<int32_t> paths[],
-               int debug_halt_step /* = -1 */,
-               std::vector<int32_t>* debug_remaining_loop /* = NULL */)
-       {
-               compute_triangulation<int32_t>(result, path_count, paths, 
debug_halt_step, debug_remaining_loop);
-       }
-}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]