Revision: 71842
          http://sourceforge.net/p/brlcad/code/71842
Author:   starseeker
Date:     2018-09-26 00:32:26 +0000 (Wed, 26 Sep 2018)
Log Message:
-----------
split point-in-polygon test and ear clipping triangulation into their own files

Modified Paths:
--------------
    brlcad/trunk/src/libbg/CMakeLists.txt
    brlcad/trunk/src/libbg/polygon.c

Added Paths:
-----------
    brlcad/trunk/src/libbg/polygon_ear_clipping.c
    brlcad/trunk/src/libbg/polygon_point_in.c

Modified: brlcad/trunk/src/libbg/CMakeLists.txt
===================================================================
--- brlcad/trunk/src/libbg/CMakeLists.txt       2018-09-26 00:05:23 UTC (rev 
71841)
+++ brlcad/trunk/src/libbg/CMakeLists.txt       2018-09-26 00:32:26 UTC (rev 
71842)
@@ -12,6 +12,8 @@
   chull3d.cpp
   obr.c
   polygon.c
+  polygon_ear_clipping.c
+  polygon_point_in.c
   spsr.c
   tri_ray.c
   tri_tri.c

Modified: brlcad/trunk/src/libbg/polygon.c
===================================================================
--- brlcad/trunk/src/libbg/polygon.c    2018-09-26 00:05:23 UTC (rev 71841)
+++ brlcad/trunk/src/libbg/polygon.c    2018-09-26 00:32:26 UTC (rev 71842)
@@ -18,9 +18,8 @@
  * information.
  */
 
-#include "limits.h" /* for INT_MAX */
-#include "bu/list.h"
-#include "bu/log.h"
+#include "common.h"
+
 #include "bu/malloc.h"
 #include "bu/sort.h"
 #include "bn/plane.h"
@@ -222,717 +221,6 @@
 }
 
 /*
- * Translation to libbn data types of Franklin's point-in-polygon test.
- * See http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
- * for a discussion of the subtleties involved with the inequality tests.
- * The below copyright applies to just the function bg_pt_in_polygon,
- * not the whole of polygon.c
- *
- * Copyright (c) 1970-2003, Wm. Randolph Franklin
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimers.  Redistributions
- * in binary form must reproduce the above copyright notice in the
- * documentation and/or other materials provided with the distribution.
- * The name of W. Randolph Franklin may not be used to endorse or promote
- * products derived from this Software without specific prior written
- * permission.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-int
-bg_pt_in_polygon(size_t nvert, const point2d_t *pnts, const point2d_t *test)
-{
-    size_t i = 0;
-    size_t j = 0;
-    int c = 0;
-    for (i = 0, j = nvert-1; i < nvert; j = i++) {
-       if ( ((pnts[i][1] > (*test)[1]) != (pnts[j][1] > (*test)[1])) &&
-               ((*test)[0] < (pnts[j][0]-pnts[i][0]) * ((*test)[1]-pnts[i][1]) 
/ (pnts[j][1]-pnts[i][1]) + pnts[i][0]) )
-           c = !c;
-    }
-    return c;
-}
-
-
-/**
- * Implementation of Ear Clipping Polygon Triangulation
- *
- * Input polygon points must be in a CCW direction.
- *
- * Based off of David Eberly's documentation of the algorithm in Triangulation
- * by Ear Clipping, section 2.
- * http://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf
- *
- * Helpful reference implementations included
- * https://code.google.com/p/polypartition/ and
- * http://www.geometrictools.com/GTEngine/Include/GteTriangulateEC.h
- *
- * A couple of functions are direct translations from polypartition, which
- * is licensed as follows:
- *
- * Copyright (C) 2011 by Ivan Fratric
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to 
deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-
-typedef struct pt_vertex_ref pt_vr;
-
-struct pt_vertex {
-    struct bu_list l;
-    int index;
-    int isConvex;
-    int isEar;
-    double angle;
-    pt_vr *convex_ref;
-    pt_vr *reflex_ref;
-    pt_vr *ear_ref;
-};
-
-struct pt_vertex_ref {
-    struct bu_list l;
-    struct pt_vertex *v;
-};
-
-struct pt_lists {
-    struct pt_vertex *vertex_list;
-    struct pt_vertex_ref *convex_list;
-    struct pt_vertex_ref *reflex_list;
-    struct pt_vertex_ref *ear_list;
-};
-
-#define PT_ADD_CONVEX_VREF(_list, vert) {\
-    struct pt_vertex_ref *n_ref; \
-    BU_GET(n_ref, struct pt_vertex_ref); \
-    n_ref->v = vert; \
-    BU_LIST_APPEND(&(_list->l), &(n_ref->l)); \
-    vert->convex_ref = n_ref; \
-    vert->isConvex = 1; \
-}
-
-#define PT_ADD_REFLEX_VREF(_list, vert) {\
-    struct pt_vertex_ref *n_ref; \
-    BU_GET(n_ref, struct pt_vertex_ref); \
-    n_ref->v = vert; \
-    BU_LIST_APPEND(&(_list->l), &(n_ref->l)); \
-    vert->reflex_ref = n_ref; \
-    vert->isConvex = 0; \
-}
-
-#define PT_ADD_EAR_VREF(_list, vert, pts) {\
-    struct pt_vertex_ref *n_ref; \
-    BU_GET(n_ref, struct pt_vertex_ref); \
-    n_ref->v = vert; \
-    BU_LIST_APPEND(&(_list->l), &(n_ref->l)); \
-    vert->ear_ref = n_ref; \
-    vert->isConvex = 1; \
-    vert->isEar = 1; \
-}
-
-#define PT_DEQUEUE_CONVEX_VREF(_list, vert) {\
-    BU_LIST_DEQUEUE(&(vert->convex_ref->l)); \
-    BU_PUT(vert->convex_ref, struct pt_vertex_ref); \
-    vert->convex_ref = NULL; \
-    vert->isConvex = 0; \
-}
-
-#define PT_DEQUEUE_REFLEX_VREF(_list, vert) {\
-    BU_LIST_DEQUEUE(&(vert->reflex_ref->l)); \
-    BU_PUT(vert->reflex_ref, struct pt_vertex_ref); \
-    vert->reflex_ref = NULL; \
-}
-
-#define PT_DEQUEUE_EAR_VREF(_list, vert) {\
-    BU_LIST_DEQUEUE(&(vert->ear_ref->l)); \
-    BU_PUT(vert->ear_ref, struct pt_vertex_ref); \
-    vert->ear_ref = NULL; \
-    vert->isEar = 0; \
-}
-
-#define PT_ADD_TRI(ear) { \
-    struct pt_vertex *p = PT_NEXT(ear); \
-    struct pt_vertex *n = PT_PREV(ear); \
-    local_faces[offset+0] = p->index; \
-    local_faces[offset+1] = ear->index; \
-    local_faces[offset+2] = n->index; \
-    offset = offset + 3; \
-    face_cnt++; \
-}
-
-#define PT_NEXT(v) BU_LIST_PNEXT_CIRC(pt_vertex, &(v->l))
-#define PT_PREV(v) BU_LIST_PPREV_CIRC(pt_vertex, &(v->l))
-
-#define PT_NEXT_REF(v) BU_LIST_PNEXT_CIRC(pt_vertex_ref, &(v->l))
-#define PT_PREV_REF(v) BU_LIST_PPREV_CIRC(pt_vertex_ref, &(v->l))
-
-HIDDEN int
-is_inside(const point2d_t p1, const point2d_t p2, const point2d_t p3, const 
point2d_t *test) {
-    point2d_t tri[3];
-    V2MOVE(tri[0], p1);
-    V2MOVE(tri[1], p2);
-    V2MOVE(tri[2], p3);
-    return bg_pt_in_polygon(3, (const point2d_t *)tri, test);
-}
-
-
-HIDDEN int
-is_ear(int p_ind, int p_prev_ind, int p_next_ind, struct pt_vertex_ref 
*reflex_list, const point2d_t *pts)
-{
-    int ear = 1;
-    struct pt_vertex_ref *vref = NULL;
-    for (BU_LIST_FOR_BACKWARDS(vref, pt_vertex_ref, &(reflex_list->l))) {
-       int vrind = vref->v->index;
-       if (vrind == p_ind || vrind == p_prev_ind || vrind == p_next_ind) 
continue;
-       if (is_inside(pts[p_ind], pts[p_prev_ind], pts[p_next_ind], (const 
point2d_t *)&pts[vrind])) {
-           ear = 0;
-           break;
-       }
-    }
-    return ear;
-}
-
-/* Use the convexity test from polypartition */
-HIDDEN int
-is_convex(const point2d_t test, const point2d_t p1, const point2d_t p2) {
-
-    double testval;
-    testval = (p2[1]-p1[1])*(test[0]-p1[0])-(p2[0]-p1[0])*(test[1]-p1[1]);
-    return (testval > 0) ? 1 : 0;
-}
-
-/* 2D angle */
-HIDDEN double
-pt_angle(const point2d_t test, const point2d_t p1, const point2d_t p2) {
-
-    double dot, det;
-    vect_t v1;
-    vect_t v2;
-    V2MOVE(v1, p1);
-    V2MOVE(v2, p2);
-    V2SUB2(v1, v1, test);
-    V2SUB2(v2, v2, test);
-    dot = v1[0]*v2[0] + v1[1]*v2[1];
-    det = v1[0]*v2[1] - v1[1]*v2[0];
-    return -1*atan2(det, dot) * 180/M_PI;
-}
-
-HIDDEN void
-pt_v_get(struct bu_list *l, int i)
-{
-    struct pt_vertex *v;
-    BU_GET(v, struct pt_vertex);
-    v->index = i;
-    v->isConvex = -1;
-    v->isEar = -1;
-    v->convex_ref = NULL;
-    v->reflex_ref = NULL;
-    v->ear_ref = NULL;
-    BU_LIST_PUSH(l, &(v->l));
-}
-
-HIDDEN void
-pt_v_put(struct pt_vertex *v)
-{
-    if (v->convex_ref) {
-       BU_LIST_DEQUEUE(&(v->convex_ref->l));
-       BU_PUT(v->convex_ref, struct pt_vertex_ref);
-    }
-    if (v->reflex_ref) {
-       bu_log("Warning - trying to remove a reflex point! %d\n", v->index);
-       BU_LIST_DEQUEUE(&(v->reflex_ref->l));
-       BU_PUT(v->reflex_ref, struct pt_vertex_ref);
-    }
-    if (v->ear_ref) {
-       BU_LIST_DEQUEUE(&(v->ear_ref->l));
-       BU_PUT(v->ear_ref, struct pt_vertex_ref);
-    }
-    BU_LIST_DEQUEUE(&(v->l));
-    BU_PUT(v, struct pt_vertex);
-}
-
-HIDDEN void
-remove_ear(struct pt_vertex *ear, struct pt_lists *lists, const point2d_t *pts)
-{
-    struct pt_vertex *vp;
-    struct pt_vertex *vn;
-    if (!ear) return;
-
-    /* First, make a note of the two vertices whose status might change */
-    vp = PT_NEXT(ear);
-    vn = PT_PREV(ear);
-
-    /* Remove the ear vertex */
-    pt_v_put(ear);
-
-    /* Update the status of the two neighbor points */
-    if (vp->isConvex) {
-       /* Check ear status */
-       int prev_ear_status = vp->isEar;
-       struct pt_vertex *p = PT_NEXT(vp);
-       struct pt_vertex *n = PT_PREV(vp);
-       vp->angle = pt_angle(pts[vp->index], pts[p->index], pts[n->index]);
-       vp->isEar = is_ear(vp->index, p->index, n->index, lists->reflex_list, 
pts);
-       if (prev_ear_status != vp->isEar) {
-           if (vp->isEar) {
-               PT_ADD_EAR_VREF(lists->ear_list, vp, pts);
-           } else {
-               PT_DEQUEUE_EAR_VREF(lists->ear_list, vp);
-           }
-       }
-    } else {
-       struct pt_vertex *p = PT_NEXT(vp);
-       struct pt_vertex *n = PT_PREV(vp);
-       /* Check if it became convex */
-       vp->isConvex = is_convex(pts[vp->index], pts[p->index], pts[n->index]);
-       /* Check if it became an ear */
-       if (vp->isConvex) {
-           vp->angle = pt_angle(pts[vp->index], pts[p->index], pts[n->index]);
-           PT_DEQUEUE_REFLEX_VREF(lists->reflex_list, vp);
-           PT_ADD_CONVEX_VREF(lists->convex_list, vp);
-           vp->isEar = is_ear(vp->index, p->index, n->index, 
lists->reflex_list, pts);
-           if (vp->isEar) {
-               PT_ADD_EAR_VREF(lists->ear_list, vp, pts);
-           }
-       }
-    }
-    if (vn->isConvex) {
-       int prev_ear_status = vn->isEar;
-       struct pt_vertex *p = PT_NEXT(vn);
-       struct pt_vertex *n = PT_PREV(vn);
-       vn->angle = pt_angle(pts[vn->index], pts[p->index], pts[n->index]);
-       vn->isEar = is_ear(vn->index, p->index, n->index, lists->reflex_list, 
pts);
-       if (prev_ear_status != vn->isEar) {
-           if (vn->isEar) {
-               PT_ADD_EAR_VREF(lists->ear_list, vn, pts);
-           } else {
-               PT_DEQUEUE_EAR_VREF(lists->ear_list, vn);
-           }
-       }
-    } else {
-       struct pt_vertex *p = PT_NEXT(vn);
-       struct pt_vertex *n = PT_PREV(vn);
-       /* Check if it became convex */
-       vn->isConvex = is_convex(pts[vn->index], pts[p->index], pts[n->index]);
-       /* Check if it became an ear */
-       if (vn->isConvex) {
-           vn->angle = pt_angle(pts[vn->index], pts[p->index], pts[n->index]);
-           PT_DEQUEUE_REFLEX_VREF(lists->reflex_list, vn);
-           PT_ADD_CONVEX_VREF(lists->convex_list, vn);
-           vn->isEar = is_ear(vn->index, p->index, n->index, 
lists->reflex_list, pts);
-           if (vn->isEar) {
-               PT_ADD_EAR_VREF(lists->ear_list, vn, pts);
-           }
-       }
-    }
-
-    return;
-}
-
-HIDDEN int
-remove_hole(int **poly, const size_t poly_npts, const int *hole, const size_t 
hole_npts, const point2d_t *pts)
-{
-    size_t iter, i, i2;
-    size_t itrpt = 0;
-    size_t polypointindex = 0;
-    int holepoint = -1;
-    int point_found = 0;
-    fastf_t dist[2];
-    double min_dist = DBL_MAX;
-    size_t poly_pnt_cnt = poly_npts + hole_npts + 2;
-    int *new_poly;
-    double poly_largest_x = -DBL_MAX;
-    double hole_largest_x = -DBL_MAX;
-    point2d_t hpnt, ep, e1, e2, isect;
-    vect_t hdir;
-    struct bn_tol ltol = {BN_TOL_MAGIC, BN_TOL_DIST, BN_TOL_DIST * 
BN_TOL_DIST, 1e-6, 1.0 - 1e-6 };
-    V2SETALL(e1,0);
-    V2SETALL(e2,0);
-    V2SETALL(isect,0);
-    for (iter = 0; iter < poly_npts; iter++) {
-       if (pts[(*poly)[iter]][0] > poly_largest_x) {
-           poly_largest_x = pts[(*poly)[iter]][0];
-       }
-    }
-    for (iter = 0; iter < hole_npts; iter++) {
-       if (pts[hole[iter]][0] > hole_largest_x) {
-           hole_largest_x = pts[hole[iter]][0];
-           holepoint = hole[iter];
-       }
-    }
-    V2MOVE(hpnt, pts[holepoint]);
-
-    /* Find the outer polygon edge with a horizontal line intersect closest
-     * to the maximum x value hole point */
-    V2SET(hdir, (poly_largest_x - hole_largest_x)*1.1, hpnt[1]);
-    for (iter = 0; iter < poly_npts; iter++) {
-       point2d_t tmp1, tmp2;
-       vect_t tmpdir;
-       V2MOVE(tmp1, pts[(*poly)[iter]]);
-       V2MOVE(tmp2, pts[(*poly)[(iter+1)%(poly_npts)]]);
-       V2SUB2(tmpdir, tmp2, tmp1);
-       if (bn_isect_lseg2_lseg2(dist, hpnt, hdir, tmp1, tmpdir, &ltol) == 1) {
-           if (dist[0] < min_dist) {
-               V2MOVE(e1, tmp1);
-               V2MOVE(e2, tmp2);
-               V2SET(isect, hpnt[0] + hdir[0]*dist[0], hpnt[1]);
-               min_dist = dist[0];
-               itrpt = iter;
-           }
-       }
-    }
-    /* Check for near-exact vertex intersections */
-    if(V2NEAR_EQUAL(e1, isect, 1e-6)) {
-       polypointindex = itrpt;
-       point_found = 1;
-    }
-    if(V2NEAR_EQUAL(e2, isect, 1e-6)) {
-       polypointindex = (itrpt+1)%(poly_npts);
-       point_found = 1;
-    }
-
-    /* Check for points inside the triangle hpnt/ep/isect */
-    if (!point_found) {
-       int have_interior_pt = 0;
-       double angle = DBL_MAX - 1;
-       min_dist = DBL_MAX;
-       if (e1[0] > e2[0]) {
-           V2MOVE(ep, e1);
-       } else {
-           V2MOVE(ep, e2);
-           itrpt = (itrpt+1)%(poly_npts);
-       }
-       for (iter = 0; iter < poly_npts; iter++) {
-           point2d_t test_pt;
-           V2MOVE(test_pt, pts[(*poly)[iter]]);
-           if (iter == itrpt) continue;
-           if (test_pt[0] < hole_largest_x) continue;
-           if (is_inside(hpnt, ep, isect, (const point2d_t *)&test_pt)) {
-               vect_t ih;
-               double tang;
-               V2SUB2(ih, test_pt, hpnt);
-               have_interior_pt = 1;
-               tang = acos(V2DOT(ih, hdir));
-               /* if we've got interior points, we want the lowest angle */
-               if (NEAR_ZERO(angle - DBL_MAX - 1, 0.001)) {
-                   angle = tang;
-                   polypointindex = iter;
-                   continue;
-               }
-               /* If the angle doesn't differentiate, go with distance */
-               if (NEAR_ZERO(tang - angle, 1e-6)) {
-                   if (DIST_PT2_PT2_SQ(test_pt, hpnt) < min_dist) {
-                       polypointindex = iter;
-                   }
-                   continue;
-               }
-               if (tang < angle) {
-                   polypointindex = iter;
-               }
-           }
-       }
-
-       /* If none of the points ended up in the interior, go with ep */
-       if (!have_interior_pt) {
-           polypointindex = itrpt;
-       }
-
-    }
-
-    new_poly = (int *)bu_calloc(poly_pnt_cnt, sizeof(int), "local poly ind 
array");
-
-    i2 = 0;
-    for (i = 0; i <= polypointindex; i++) {
-       new_poly[i2] = (*poly)[i];
-       i2++;
-    }
-
-    for (i = 0; i <=hole_npts ; i++) {
-       new_poly[i2] = hole[(i+holepoint)%hole_npts];
-       i2++;
-    }
-
-    for (i = polypointindex; i < poly_npts; i++) {
-       new_poly[i2] = (*poly)[i];
-       i2++;
-    }
-#if 0
-    for (iter = 0; iter < poly_pnt_cnt; iter++) {
-       bu_log("new poly pnt[%d](%d): %f, %f\n", iter, new_poly[iter], 
pts[new_poly[iter]][0], pts[new_poly[iter]][1]);
-    }
-#endif
-
-    bu_free((*poly), "free old poly");
-    (*poly) = new_poly;
-
-    return poly_pnt_cnt;
-}
-
-int bg_nested_polygon_triangulate(int **faces, int *num_faces, point2d_t 
**out_pts, int *num_outpts,
-       const int *poly, const size_t poly_pnts,
-       const int **holes_array, const size_t *holes_npts, const size_t nholes,
-       const point2d_t *pts, const size_t npts, triangulation_t type)
-{
-    size_t i = 0;
-    size_t face_cnt = 0;
-    int offset = 0;
-    int ret = 0;
-    int ccw = 0;
-    int *local_faces;
-    struct pt_lists *lists = NULL;
-    struct pt_vertex *v = NULL;
-    struct pt_vertex_ref *vref = NULL;
-    struct pt_vertex *vertex_list = NULL;
-    struct pt_vertex_ref *convex_list = NULL;
-    struct pt_vertex_ref *reflex_list = NULL;
-    struct pt_vertex_ref *ear_list = NULL;
-    size_t poly_pnt_cnt = poly_pnts;
-    const int *local_poly = NULL;
-
-    BU_GET(lists, struct pt_lists);
-    if (npts < 3 || poly_pnts < 3) return 1;
-    if (!faces || !num_faces || !pts || !poly) return 1;
-
-    if (nholes > 0) {
-       if (!holes_array || !holes_npts) return 1;
-    }
-
-    if (type == DELAUNAY && (!out_pts || !num_outpts)) return 1;
-
-    ccw = bg_polygon_direction(poly_pnts, pts, poly);
-
-    if (ccw != BG_CCW) {
-       bu_log("Warning - non-CCW point loop!\n");
-    }
-
-
-    BU_GET(lists->vertex_list, struct pt_vertex);
-    BU_LIST_INIT(&(lists->vertex_list->l));
-    lists->vertex_list->index = -1;
-
-    BU_GET(lists->ear_list, struct pt_vertex_ref);
-    BU_LIST_INIT(&(lists->ear_list->l));
-    lists->ear_list->v = NULL;
-
-    BU_GET(lists->reflex_list, struct pt_vertex_ref);
-    BU_LIST_INIT(&(lists->reflex_list->l));
-    lists->reflex_list->v = NULL;
-
-    BU_GET(lists->convex_list, struct pt_vertex_ref);
-    BU_LIST_INIT(&(lists->convex_list->l));
-    lists->convex_list->v = NULL;
-
-    vertex_list = lists->vertex_list;
-    convex_list = lists->convex_list;
-    reflex_list = lists->reflex_list;
-    ear_list = lists->ear_list;
-
-    local_faces = (int *)bu_calloc(3*3*npts, sizeof(int), "triangles");
-
-    /* If we have holes, we need to incorporate them into the polygon */
-    if (nholes > 0) {
-       /* Bookkeeping */
-       size_t handled_hole_cnt = 0;
-       int *handled_holes = (int *)bu_calloc(nholes, sizeof(int), "hole status 
array");
-
-       /* polygon size will change - start with input polygon */
-       local_poly = (int *)bu_calloc(poly_pnts, sizeof(int), "local poly ind 
array");
-       for (i = 0; i < (size_t)poly_pnts; i++) ((int *)local_poly)[i] = 
poly[i];
-
-       /* Loop over and remove all holes */
-       while (handled_hole_cnt < nholes) {
-           size_t ch, ph;
-           /* find the unhandled hole point with the largest x */
-           double hole_largest_x = -DBL_MAX;
-           int xp = -1;
-           for (ch = 0; ch < nholes; ch++) {
-               if (!handled_holes[ch]) {
-                   for (ph = 0; ph < holes_npts[ch]; ph++) {
-                       if (pts[holes_array[ch][ph]][0] > hole_largest_x) {
-                           hole_largest_x = pts[holes_array[ch][ph]][0];
-                           xp = ch;
-                       }
-                   }
-               }
-           }
-           /* Identified the next hole - process it */
-           poly_pnt_cnt = remove_hole((int **)&local_poly, poly_pnt_cnt, 
holes_array[xp], holes_npts[xp], pts);
-           handled_holes[xp] = 1;
-           handled_hole_cnt++;
-           if (!poly_pnt_cnt) {
-               bu_log("Error removing hole\n");
-               if (local_poly) bu_free((int *)local_poly, "free tmp array");
-               return 1;
-           }
-       }
-       bu_free(handled_holes, "done with array");
-    } else {
-       local_poly = poly;
-    }
-
-    /* Initialize vertex list. */
-    for (i = 0; i < poly_pnt_cnt; i++) {
-       pt_v_get(&(vertex_list->l), local_poly[i]);
-    }
-    if (local_poly != poly) bu_free((int *)local_poly, "done with local_poly 
array");
-
-    /* Point ordering ends up opposite to that of the points in the array, so
-     * everything is backwards */
-
-    /* Find the initial convex and reflex point sets */
-    for (BU_LIST_FOR_BACKWARDS(v, pt_vertex, &(vertex_list->l)))
-    {
-       struct pt_vertex *prev = PT_NEXT(v);
-       struct pt_vertex *next = PT_PREV(v);
-       v->isConvex = is_convex(pts[v->index], pts[prev->index], 
pts[next->index]);
-       if (v->isConvex) {
-           v->angle = pt_angle(pts[v->index], pts[prev->index], 
pts[next->index]);
-           PT_ADD_CONVEX_VREF(convex_list, v);
-       } else {
-           v->angle = 0;
-           v->isEar = 0;
-           PT_ADD_REFLEX_VREF(reflex_list, v);
-       }
-    }
-
-    /* Now that we know which are the convex and reflex verts, find the 
initial ears */
-    for (BU_LIST_FOR_BACKWARDS(vref, pt_vertex_ref, &(convex_list->l)))
-    {
-       struct pt_vertex *p = PT_NEXT(vref->v);
-       struct pt_vertex *n = PT_PREV(vref->v);
-       vref->v->isEar = is_ear(vref->v->index, p->index, n->index, 
reflex_list, pts);
-       if (vref->v->isEar) PT_ADD_EAR_VREF(ear_list, vref->v, pts);
-    }
-
-    /* If we didn't find any ears, something is wrong */
-    if (BU_LIST_IS_EMPTY(&(lists->ear_list->l))) {
-       ret = 1;
-       goto cleanup;
-    }
-
-    /* We know what we need to begin - remove ears, build triangles and update 
accordingly */
-    {
-       struct pt_vertex *one_vert = PT_NEXT(vertex_list);
-       struct pt_vertex *four_vert = PT_NEXT(PT_NEXT(PT_NEXT(one_vert)));
-       while(one_vert->index != four_vert->index) {
-           struct pt_vertex_ref *ear_ref = NULL;
-           int min_angle = INT_MAX;
-           for (BU_LIST_FOR_BACKWARDS(vref, pt_vertex_ref, &(ear_list->l))){
-               if (vref->v->angle < min_angle && vref->v) {
-                   min_angle = vref->v->angle;
-                   ear_ref = vref;
-               }
-           }
-           if (!ear_ref || !ear_ref->v) {
-               bu_log("ear list error!\n");
-               ret = 1;
-               goto cleanup;
-           }
-           PT_ADD_TRI(ear_ref->v);
-           remove_ear(ear_ref->v, lists, pts);
-           one_vert = PT_NEXT(vertex_list);
-           four_vert = PT_NEXT(PT_NEXT(PT_NEXT(one_vert)));
-       }
-    }
-
-    /* Last triangle */
-    for (BU_LIST_FOR_BACKWARDS(v, pt_vertex, &(vertex_list->l))){
-       if (!v->isConvex) PT_DEQUEUE_REFLEX_VREF(lists->reflex_list, v);
-    }
-    PT_ADD_TRI(PT_NEXT(vertex_list));
-
-    /* Finalize the face set */
-    (*num_faces) = face_cnt;
-    (*faces) = (int *)bu_calloc(face_cnt*3, sizeof(int), "final faces array");
-    for (i = 0; i < face_cnt; i++) {
-       (*faces)[i*3] = local_faces[i*3];
-       (*faces)[i*3+1] = local_faces[i*3+1];
-       (*faces)[i*3+2] = local_faces[i*3+2];
-    }
-
-cleanup:
-    bu_free(local_faces, "free local faces array");
-
-    /* Make sure the lists are empty */
-
-    while (BU_LIST_WHILE(v, pt_vertex , &(vertex_list->l))) {
-       /*bu_log("clear vert: %d\n", v->index);*/
-       pt_v_put(v);
-    }
-
-    /* TODO - this should always be empty by this point? */
-    while (BU_LIST_WHILE(vref, pt_vertex_ref , &(reflex_list->l))) {
-       BU_LIST_DEQUEUE(&(vref->l));
-       BU_PUT(vref, struct pt_vertex_ref);
-    }
-
-    while (BU_LIST_WHILE(vref, pt_vertex_ref , &(convex_list->l))) {
-       BU_LIST_DEQUEUE(&(vref->l));
-       BU_PUT(vref, struct pt_vertex_ref);
-    }
-    /* TODO - this should always be empty by this point? */
-    while (BU_LIST_WHILE(vref, pt_vertex_ref , &(ear_list->l))) {
-       BU_LIST_DEQUEUE(&(vref->l));
-       BU_PUT(vref, struct pt_vertex_ref);
-    }
-
-    BU_PUT(ear_list, struct pt_vertex_ref);
-    BU_PUT(reflex_list, struct pt_vertex_ref);
-    BU_PUT(convex_list, struct pt_vertex_ref);
-    BU_PUT(vertex_list, struct pt_vertex);
-    BU_PUT(lists, struct pt_lists);
-
-    return ret;
-}
-
-int bg_polygon_triangulate(int **faces, int *num_faces, point2d_t **out_pts, 
int *num_outpts,
-       const point2d_t *pts, const size_t npts, triangulation_t type)
-{
-    int ret;
-    size_t i;
-    int *verts_ind = NULL;
-
-    if (type == DELAUNAY && (!out_pts || !num_outpts)) return 1;
-    verts_ind = (int *)bu_calloc(npts, sizeof(int), "vert indices");
-    for (i = 0; i < npts; i++) verts_ind[i] = i;
-    ret = bg_nested_polygon_triangulate(faces, num_faces, out_pts, num_outpts, 
verts_ind, npts, NULL, NULL, 0, pts, npts, type);
-    bu_free(verts_ind, "free verts");
-    return ret;
-}
-
-
-/*
  * Local Variables:
  * mode: C
  * tab-width: 8

Added: brlcad/trunk/src/libbg/polygon_ear_clipping.c
===================================================================
--- brlcad/trunk/src/libbg/polygon_ear_clipping.c                               
(rev 0)
+++ brlcad/trunk/src/libbg/polygon_ear_clipping.c       2018-09-26 00:32:26 UTC 
(rev 71842)
@@ -0,0 +1,681 @@
+/**
+ * Implementation of Ear Clipping Polygon Triangulation
+ *
+ * Input polygon points must be in a CCW direction.
+ *
+ * Based off of David Eberly's documentation of the algorithm in Triangulation
+ * by Ear Clipping, section 2.
+ * http://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf
+ *
+ * Helpful reference implementations included
+ * https://code.google.com/p/polypartition/ and
+ * http://www.geometrictools.com/GTEngine/Include/GteTriangulateEC.h
+ *
+ * A couple of functions are direct translations from polypartition, which
+ * is licensed as follows:
+ *
+ * Copyright (C) 2011 by Ivan Fratric
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "common.h"
+
+#include "limits.h" /* for INT_MAX */
+#include "bu/list.h"
+#include "bu/log.h"
+#include "bu/malloc.h"
+#include "bn/plane.h"
+#include "bn/tol.h"
+#include "bg/polygon.h"
+
+typedef struct pt_vertex_ref pt_vr;
+
+struct pt_vertex {
+    struct bu_list l;
+    int index;
+    int isConvex;
+    int isEar;
+    double angle;
+    pt_vr *convex_ref;
+    pt_vr *reflex_ref;
+    pt_vr *ear_ref;
+};
+
+struct pt_vertex_ref {
+    struct bu_list l;
+    struct pt_vertex *v;
+};
+
+struct pt_lists {
+    struct pt_vertex *vertex_list;
+    struct pt_vertex_ref *convex_list;
+    struct pt_vertex_ref *reflex_list;
+    struct pt_vertex_ref *ear_list;
+};
+
+#define PT_ADD_CONVEX_VREF(_list, vert) {\
+    struct pt_vertex_ref *n_ref; \
+    BU_GET(n_ref, struct pt_vertex_ref); \
+    n_ref->v = vert; \
+    BU_LIST_APPEND(&(_list->l), &(n_ref->l)); \
+    vert->convex_ref = n_ref; \
+    vert->isConvex = 1; \
+}
+
+#define PT_ADD_REFLEX_VREF(_list, vert) {\
+    struct pt_vertex_ref *n_ref; \
+    BU_GET(n_ref, struct pt_vertex_ref); \
+    n_ref->v = vert; \
+    BU_LIST_APPEND(&(_list->l), &(n_ref->l)); \
+    vert->reflex_ref = n_ref; \
+    vert->isConvex = 0; \
+}
+
+#define PT_ADD_EAR_VREF(_list, vert, pts) {\
+    struct pt_vertex_ref *n_ref; \
+    BU_GET(n_ref, struct pt_vertex_ref); \
+    n_ref->v = vert; \
+    BU_LIST_APPEND(&(_list->l), &(n_ref->l)); \
+    vert->ear_ref = n_ref; \
+    vert->isConvex = 1; \
+    vert->isEar = 1; \
+}
+
+#define PT_DEQUEUE_CONVEX_VREF(_list, vert) {\
+    BU_LIST_DEQUEUE(&(vert->convex_ref->l)); \
+    BU_PUT(vert->convex_ref, struct pt_vertex_ref); \
+    vert->convex_ref = NULL; \
+    vert->isConvex = 0; \
+}
+
+#define PT_DEQUEUE_REFLEX_VREF(_list, vert) {\
+    BU_LIST_DEQUEUE(&(vert->reflex_ref->l)); \
+    BU_PUT(vert->reflex_ref, struct pt_vertex_ref); \
+    vert->reflex_ref = NULL; \
+}
+
+#define PT_DEQUEUE_EAR_VREF(_list, vert) {\
+    BU_LIST_DEQUEUE(&(vert->ear_ref->l)); \
+    BU_PUT(vert->ear_ref, struct pt_vertex_ref); \
+    vert->ear_ref = NULL; \
+    vert->isEar = 0; \
+}
+
+#define PT_ADD_TRI(ear) { \
+    struct pt_vertex *p = PT_NEXT(ear); \
+    struct pt_vertex *n = PT_PREV(ear); \
+    local_faces[offset+0] = p->index; \
+    local_faces[offset+1] = ear->index; \
+    local_faces[offset+2] = n->index; \
+    offset = offset + 3; \
+    face_cnt++; \
+}
+
+#define PT_NEXT(v) BU_LIST_PNEXT_CIRC(pt_vertex, &(v->l))
+#define PT_PREV(v) BU_LIST_PPREV_CIRC(pt_vertex, &(v->l))
+
+#define PT_NEXT_REF(v) BU_LIST_PNEXT_CIRC(pt_vertex_ref, &(v->l))
+#define PT_PREV_REF(v) BU_LIST_PPREV_CIRC(pt_vertex_ref, &(v->l))
+
+HIDDEN int
+is_inside(const point2d_t p1, const point2d_t p2, const point2d_t p3, const 
point2d_t *test) {
+    point2d_t tri[3];
+    V2MOVE(tri[0], p1);
+    V2MOVE(tri[1], p2);
+    V2MOVE(tri[2], p3);
+    return bg_pt_in_polygon(3, (const point2d_t *)tri, test);
+}
+
+
+HIDDEN int
+is_ear(int p_ind, int p_prev_ind, int p_next_ind, struct pt_vertex_ref 
*reflex_list, const point2d_t *pts)
+{
+    int ear = 1;
+    struct pt_vertex_ref *vref = NULL;
+    for (BU_LIST_FOR_BACKWARDS(vref, pt_vertex_ref, &(reflex_list->l))) {
+       int vrind = vref->v->index;
+       if (vrind == p_ind || vrind == p_prev_ind || vrind == p_next_ind) 
continue;
+       if (is_inside(pts[p_ind], pts[p_prev_ind], pts[p_next_ind], (const 
point2d_t *)&pts[vrind])) {
+           ear = 0;
+           break;
+       }
+    }
+    return ear;
+}
+
+/* Use the convexity test from polypartition */
+HIDDEN int
+is_convex(const point2d_t test, const point2d_t p1, const point2d_t p2) {
+
+    double testval;
+    testval = (p2[1]-p1[1])*(test[0]-p1[0])-(p2[0]-p1[0])*(test[1]-p1[1]);
+    return (testval > 0) ? 1 : 0;
+}
+
+/* 2D angle */
+HIDDEN double
+pt_angle(const point2d_t test, const point2d_t p1, const point2d_t p2) {
+
+    double dot, det;
+    vect_t v1;
+    vect_t v2;
+    V2MOVE(v1, p1);
+    V2MOVE(v2, p2);
+    V2SUB2(v1, v1, test);
+    V2SUB2(v2, v2, test);
+    dot = v1[0]*v2[0] + v1[1]*v2[1];
+    det = v1[0]*v2[1] - v1[1]*v2[0];
+    return -1*atan2(det, dot) * 180/M_PI;
+}
+
+HIDDEN void
+pt_v_get(struct bu_list *l, int i)
+{
+    struct pt_vertex *v;
+    BU_GET(v, struct pt_vertex);
+    v->index = i;
+    v->isConvex = -1;
+    v->isEar = -1;
+    v->convex_ref = NULL;
+    v->reflex_ref = NULL;
+    v->ear_ref = NULL;
+    BU_LIST_PUSH(l, &(v->l));
+}
+
+HIDDEN void
+pt_v_put(struct pt_vertex *v)
+{
+    if (v->convex_ref) {
+       BU_LIST_DEQUEUE(&(v->convex_ref->l));
+       BU_PUT(v->convex_ref, struct pt_vertex_ref);
+    }
+    if (v->reflex_ref) {
+       bu_log("Warning - trying to remove a reflex point! %d\n", v->index);
+       BU_LIST_DEQUEUE(&(v->reflex_ref->l));
+       BU_PUT(v->reflex_ref, struct pt_vertex_ref);
+    }
+    if (v->ear_ref) {
+       BU_LIST_DEQUEUE(&(v->ear_ref->l));
+       BU_PUT(v->ear_ref, struct pt_vertex_ref);
+    }
+    BU_LIST_DEQUEUE(&(v->l));
+    BU_PUT(v, struct pt_vertex);
+}
+
+HIDDEN void
+remove_ear(struct pt_vertex *ear, struct pt_lists *lists, const point2d_t *pts)
+{
+    struct pt_vertex *vp;
+    struct pt_vertex *vn;
+    if (!ear) return;
+
+    /* First, make a note of the two vertices whose status might change */
+    vp = PT_NEXT(ear);
+    vn = PT_PREV(ear);
+
+    /* Remove the ear vertex */
+    pt_v_put(ear);
+
+    /* Update the status of the two neighbor points */
+    if (vp->isConvex) {
+       /* Check ear status */
+       int prev_ear_status = vp->isEar;
+       struct pt_vertex *p = PT_NEXT(vp);
+       struct pt_vertex *n = PT_PREV(vp);
+       vp->angle = pt_angle(pts[vp->index], pts[p->index], pts[n->index]);
+       vp->isEar = is_ear(vp->index, p->index, n->index, lists->reflex_list, 
pts);
+       if (prev_ear_status != vp->isEar) {
+           if (vp->isEar) {
+               PT_ADD_EAR_VREF(lists->ear_list, vp, pts);
+           } else {
+               PT_DEQUEUE_EAR_VREF(lists->ear_list, vp);
+           }
+       }
+    } else {
+       struct pt_vertex *p = PT_NEXT(vp);
+       struct pt_vertex *n = PT_PREV(vp);
+       /* Check if it became convex */
+       vp->isConvex = is_convex(pts[vp->index], pts[p->index], pts[n->index]);
+       /* Check if it became an ear */
+       if (vp->isConvex) {
+           vp->angle = pt_angle(pts[vp->index], pts[p->index], pts[n->index]);
+           PT_DEQUEUE_REFLEX_VREF(lists->reflex_list, vp);
+           PT_ADD_CONVEX_VREF(lists->convex_list, vp);
+           vp->isEar = is_ear(vp->index, p->index, n->index, 
lists->reflex_list, pts);
+           if (vp->isEar) {
+               PT_ADD_EAR_VREF(lists->ear_list, vp, pts);
+           }
+       }
+    }
+    if (vn->isConvex) {
+       int prev_ear_status = vn->isEar;
+       struct pt_vertex *p = PT_NEXT(vn);
+       struct pt_vertex *n = PT_PREV(vn);
+       vn->angle = pt_angle(pts[vn->index], pts[p->index], pts[n->index]);
+       vn->isEar = is_ear(vn->index, p->index, n->index, lists->reflex_list, 
pts);
+       if (prev_ear_status != vn->isEar) {
+           if (vn->isEar) {
+               PT_ADD_EAR_VREF(lists->ear_list, vn, pts);
+           } else {
+               PT_DEQUEUE_EAR_VREF(lists->ear_list, vn);
+           }
+       }
+    } else {
+       struct pt_vertex *p = PT_NEXT(vn);
+       struct pt_vertex *n = PT_PREV(vn);
+       /* Check if it became convex */
+       vn->isConvex = is_convex(pts[vn->index], pts[p->index], pts[n->index]);
+       /* Check if it became an ear */
+       if (vn->isConvex) {
+           vn->angle = pt_angle(pts[vn->index], pts[p->index], pts[n->index]);
+           PT_DEQUEUE_REFLEX_VREF(lists->reflex_list, vn);
+           PT_ADD_CONVEX_VREF(lists->convex_list, vn);
+           vn->isEar = is_ear(vn->index, p->index, n->index, 
lists->reflex_list, pts);
+           if (vn->isEar) {
+               PT_ADD_EAR_VREF(lists->ear_list, vn, pts);
+           }
+       }
+    }
+
+    return;
+}
+
+HIDDEN int
+remove_hole(int **poly, const size_t poly_npts, const int *hole, const size_t 
hole_npts, const point2d_t *pts)
+{
+    size_t iter, i, i2;
+    size_t itrpt = 0;
+    size_t polypointindex = 0;
+    int holepoint = -1;
+    int point_found = 0;
+    fastf_t dist[2];
+    double min_dist = DBL_MAX;
+    size_t poly_pnt_cnt = poly_npts + hole_npts + 2;
+    int *new_poly;
+    double poly_largest_x = -DBL_MAX;
+    double hole_largest_x = -DBL_MAX;
+    point2d_t hpnt, ep, e1, e2, isect;
+    vect_t hdir;
+    struct bn_tol ltol = {BN_TOL_MAGIC, BN_TOL_DIST, BN_TOL_DIST * 
BN_TOL_DIST, 1e-6, 1.0 - 1e-6 };
+    V2SETALL(e1,0);
+    V2SETALL(e2,0);
+    V2SETALL(isect,0);
+    for (iter = 0; iter < poly_npts; iter++) {
+       if (pts[(*poly)[iter]][0] > poly_largest_x) {
+           poly_largest_x = pts[(*poly)[iter]][0];
+       }
+    }
+    for (iter = 0; iter < hole_npts; iter++) {
+       if (pts[hole[iter]][0] > hole_largest_x) {
+           hole_largest_x = pts[hole[iter]][0];
+           holepoint = hole[iter];
+       }
+    }
+    V2MOVE(hpnt, pts[holepoint]);
+
+    /* Find the outer polygon edge with a horizontal line intersect closest
+     * to the maximum x value hole point */
+    V2SET(hdir, (poly_largest_x - hole_largest_x)*1.1, hpnt[1]);
+    for (iter = 0; iter < poly_npts; iter++) {
+       point2d_t tmp1, tmp2;
+       vect_t tmpdir;
+       V2MOVE(tmp1, pts[(*poly)[iter]]);
+       V2MOVE(tmp2, pts[(*poly)[(iter+1)%(poly_npts)]]);
+       V2SUB2(tmpdir, tmp2, tmp1);
+       if (bn_isect_lseg2_lseg2(dist, hpnt, hdir, tmp1, tmpdir, &ltol) == 1) {
+           if (dist[0] < min_dist) {
+               V2MOVE(e1, tmp1);
+               V2MOVE(e2, tmp2);
+               V2SET(isect, hpnt[0] + hdir[0]*dist[0], hpnt[1]);
+               min_dist = dist[0];
+               itrpt = iter;
+           }
+       }
+    }
+    /* Check for near-exact vertex intersections */
+    if(V2NEAR_EQUAL(e1, isect, 1e-6)) {
+       polypointindex = itrpt;
+       point_found = 1;
+    }
+    if(V2NEAR_EQUAL(e2, isect, 1e-6)) {
+       polypointindex = (itrpt+1)%(poly_npts);
+       point_found = 1;
+    }
+
+    /* Check for points inside the triangle hpnt/ep/isect */
+    if (!point_found) {
+       int have_interior_pt = 0;
+       double angle = DBL_MAX - 1;
+       min_dist = DBL_MAX;
+       if (e1[0] > e2[0]) {
+           V2MOVE(ep, e1);
+       } else {
+           V2MOVE(ep, e2);
+           itrpt = (itrpt+1)%(poly_npts);
+       }
+       for (iter = 0; iter < poly_npts; iter++) {
+           point2d_t test_pt;
+           V2MOVE(test_pt, pts[(*poly)[iter]]);
+           if (iter == itrpt) continue;
+           if (test_pt[0] < hole_largest_x) continue;
+           if (is_inside(hpnt, ep, isect, (const point2d_t *)&test_pt)) {
+               vect_t ih;
+               double tang;
+               V2SUB2(ih, test_pt, hpnt);
+               have_interior_pt = 1;
+               tang = acos(V2DOT(ih, hdir));
+               /* if we've got interior points, we want the lowest angle */
+               if (NEAR_ZERO(angle - DBL_MAX - 1, 0.001)) {
+                   angle = tang;
+                   polypointindex = iter;
+                   continue;
+               }
+               /* If the angle doesn't differentiate, go with distance */
+               if (NEAR_ZERO(tang - angle, 1e-6)) {
+                   if (DIST_PT2_PT2_SQ(test_pt, hpnt) < min_dist) {
+                       polypointindex = iter;
+                   }
+                   continue;
+               }
+               if (tang < angle) {
+                   polypointindex = iter;
+               }
+           }
+       }
+
+       /* If none of the points ended up in the interior, go with ep */
+       if (!have_interior_pt) {
+           polypointindex = itrpt;
+       }
+
+    }
+
+    new_poly = (int *)bu_calloc(poly_pnt_cnt, sizeof(int), "local poly ind 
array");
+
+    i2 = 0;
+    for (i = 0; i <= polypointindex; i++) {
+       new_poly[i2] = (*poly)[i];
+       i2++;
+    }
+
+    for (i = 0; i <=hole_npts ; i++) {
+       new_poly[i2] = hole[(i+holepoint)%hole_npts];
+       i2++;
+    }
+
+    for (i = polypointindex; i < poly_npts; i++) {
+       new_poly[i2] = (*poly)[i];
+       i2++;
+    }
+#if 0
+    for (iter = 0; iter < poly_pnt_cnt; iter++) {
+       bu_log("new poly pnt[%d](%d): %f, %f\n", iter, new_poly[iter], 
pts[new_poly[iter]][0], pts[new_poly[iter]][1]);
+    }
+#endif
+
+    bu_free((*poly), "free old poly");
+    (*poly) = new_poly;
+
+    return poly_pnt_cnt;
+}
+
+int bg_nested_polygon_triangulate(int **faces, int *num_faces, point2d_t 
**out_pts, int *num_outpts,
+       const int *poly, const size_t poly_pnts,
+       const int **holes_array, const size_t *holes_npts, const size_t nholes,
+       const point2d_t *pts, const size_t npts, triangulation_t type)
+{
+    size_t i = 0;
+    size_t face_cnt = 0;
+    int offset = 0;
+    int ret = 0;
+    int ccw = 0;
+    int *local_faces;
+    struct pt_lists *lists = NULL;
+    struct pt_vertex *v = NULL;
+    struct pt_vertex_ref *vref = NULL;
+    struct pt_vertex *vertex_list = NULL;
+    struct pt_vertex_ref *convex_list = NULL;
+    struct pt_vertex_ref *reflex_list = NULL;
+    struct pt_vertex_ref *ear_list = NULL;
+    size_t poly_pnt_cnt = poly_pnts;
+    const int *local_poly = NULL;
+
+    BU_GET(lists, struct pt_lists);
+    if (npts < 3 || poly_pnts < 3) return 1;
+    if (!faces || !num_faces || !pts || !poly) return 1;
+
+    if (nholes > 0) {
+       if (!holes_array || !holes_npts) return 1;
+    }
+
+    if (type == DELAUNAY && (!out_pts || !num_outpts)) return 1;
+
+    ccw = bg_polygon_direction(poly_pnts, pts, poly);
+
+    if (ccw != BG_CCW) {
+       bu_log("Warning - non-CCW point loop!\n");
+    }
+
+
+    BU_GET(lists->vertex_list, struct pt_vertex);
+    BU_LIST_INIT(&(lists->vertex_list->l));
+    lists->vertex_list->index = -1;
+
+    BU_GET(lists->ear_list, struct pt_vertex_ref);
+    BU_LIST_INIT(&(lists->ear_list->l));
+    lists->ear_list->v = NULL;
+
+    BU_GET(lists->reflex_list, struct pt_vertex_ref);
+    BU_LIST_INIT(&(lists->reflex_list->l));
+    lists->reflex_list->v = NULL;
+
+    BU_GET(lists->convex_list, struct pt_vertex_ref);
+    BU_LIST_INIT(&(lists->convex_list->l));
+    lists->convex_list->v = NULL;
+
+    vertex_list = lists->vertex_list;
+    convex_list = lists->convex_list;
+    reflex_list = lists->reflex_list;
+    ear_list = lists->ear_list;
+
+    local_faces = (int *)bu_calloc(3*3*npts, sizeof(int), "triangles");
+
+    /* If we have holes, we need to incorporate them into the polygon */
+    if (nholes > 0) {
+       /* Bookkeeping */
+       size_t handled_hole_cnt = 0;
+       int *handled_holes = (int *)bu_calloc(nholes, sizeof(int), "hole status 
array");
+
+       /* polygon size will change - start with input polygon */
+       local_poly = (int *)bu_calloc(poly_pnts, sizeof(int), "local poly ind 
array");
+       for (i = 0; i < (size_t)poly_pnts; i++) ((int *)local_poly)[i] = 
poly[i];
+
+       /* Loop over and remove all holes */
+       while (handled_hole_cnt < nholes) {
+           size_t ch, ph;
+           /* find the unhandled hole point with the largest x */
+           double hole_largest_x = -DBL_MAX;
+           int xp = -1;
+           for (ch = 0; ch < nholes; ch++) {
+               if (!handled_holes[ch]) {
+                   for (ph = 0; ph < holes_npts[ch]; ph++) {
+                       if (pts[holes_array[ch][ph]][0] > hole_largest_x) {
+                           hole_largest_x = pts[holes_array[ch][ph]][0];
+                           xp = ch;
+                       }
+                   }
+               }
+           }
+           /* Identified the next hole - process it */
+           poly_pnt_cnt = remove_hole((int **)&local_poly, poly_pnt_cnt, 
holes_array[xp], holes_npts[xp], pts);
+           handled_holes[xp] = 1;
+           handled_hole_cnt++;
+           if (!poly_pnt_cnt) {
+               bu_log("Error removing hole\n");
+               if (local_poly) bu_free((int *)local_poly, "free tmp array");
+               return 1;
+           }
+       }
+       bu_free(handled_holes, "done with array");
+    } else {
+       local_poly = poly;
+    }
+
+    /* Initialize vertex list. */
+    for (i = 0; i < poly_pnt_cnt; i++) {
+       pt_v_get(&(vertex_list->l), local_poly[i]);
+    }
+    if (local_poly != poly) bu_free((int *)local_poly, "done with local_poly 
array");
+
+    /* Point ordering ends up opposite to that of the points in the array, so
+     * everything is backwards */
+
+    /* Find the initial convex and reflex point sets */
+    for (BU_LIST_FOR_BACKWARDS(v, pt_vertex, &(vertex_list->l)))
+    {
+       struct pt_vertex *prev = PT_NEXT(v);
+       struct pt_vertex *next = PT_PREV(v);
+       v->isConvex = is_convex(pts[v->index], pts[prev->index], 
pts[next->index]);
+       if (v->isConvex) {
+           v->angle = pt_angle(pts[v->index], pts[prev->index], 
pts[next->index]);
+           PT_ADD_CONVEX_VREF(convex_list, v);
+       } else {
+           v->angle = 0;
+           v->isEar = 0;
+           PT_ADD_REFLEX_VREF(reflex_list, v);
+       }
+    }
+
+    /* Now that we know which are the convex and reflex verts, find the 
initial ears */
+    for (BU_LIST_FOR_BACKWARDS(vref, pt_vertex_ref, &(convex_list->l)))
+    {
+       struct pt_vertex *p = PT_NEXT(vref->v);
+       struct pt_vertex *n = PT_PREV(vref->v);
+       vref->v->isEar = is_ear(vref->v->index, p->index, n->index, 
reflex_list, pts);
+       if (vref->v->isEar) PT_ADD_EAR_VREF(ear_list, vref->v, pts);
+    }
+
+    /* If we didn't find any ears, something is wrong */
+    if (BU_LIST_IS_EMPTY(&(lists->ear_list->l))) {
+       ret = 1;
+       goto cleanup;
+    }
+
+    /* We know what we need to begin - remove ears, build triangles and update 
accordingly */
+    {
+       struct pt_vertex *one_vert = PT_NEXT(vertex_list);
+       struct pt_vertex *four_vert = PT_NEXT(PT_NEXT(PT_NEXT(one_vert)));
+       while(one_vert->index != four_vert->index) {
+           struct pt_vertex_ref *ear_ref = NULL;
+           int min_angle = INT_MAX;
+           for (BU_LIST_FOR_BACKWARDS(vref, pt_vertex_ref, &(ear_list->l))){
+               if (vref->v->angle < min_angle && vref->v) {
+                   min_angle = vref->v->angle;
+                   ear_ref = vref;
+               }
+           }
+           if (!ear_ref || !ear_ref->v) {
+               bu_log("ear list error!\n");
+               ret = 1;
+               goto cleanup;
+           }
+           PT_ADD_TRI(ear_ref->v);
+           remove_ear(ear_ref->v, lists, pts);
+           one_vert = PT_NEXT(vertex_list);
+           four_vert = PT_NEXT(PT_NEXT(PT_NEXT(one_vert)));
+       }
+    }
+
+    /* Last triangle */
+    for (BU_LIST_FOR_BACKWARDS(v, pt_vertex, &(vertex_list->l))){
+       if (!v->isConvex) PT_DEQUEUE_REFLEX_VREF(lists->reflex_list, v);
+    }
+    PT_ADD_TRI(PT_NEXT(vertex_list));
+
+    /* Finalize the face set */
+    (*num_faces) = face_cnt;
+    (*faces) = (int *)bu_calloc(face_cnt*3, sizeof(int), "final faces array");
+    for (i = 0; i < face_cnt; i++) {
+       (*faces)[i*3] = local_faces[i*3];
+       (*faces)[i*3+1] = local_faces[i*3+1];
+       (*faces)[i*3+2] = local_faces[i*3+2];
+    }
+
+cleanup:
+    bu_free(local_faces, "free local faces array");
+
+    /* Make sure the lists are empty */
+
+    while (BU_LIST_WHILE(v, pt_vertex , &(vertex_list->l))) {
+       /*bu_log("clear vert: %d\n", v->index);*/
+       pt_v_put(v);
+    }
+
+    /* TODO - this should always be empty by this point? */
+    while (BU_LIST_WHILE(vref, pt_vertex_ref , &(reflex_list->l))) {
+       BU_LIST_DEQUEUE(&(vref->l));
+       BU_PUT(vref, struct pt_vertex_ref);
+    }
+
+    while (BU_LIST_WHILE(vref, pt_vertex_ref , &(convex_list->l))) {
+       BU_LIST_DEQUEUE(&(vref->l));
+       BU_PUT(vref, struct pt_vertex_ref);
+    }
+    /* TODO - this should always be empty by this point? */
+    while (BU_LIST_WHILE(vref, pt_vertex_ref , &(ear_list->l))) {
+       BU_LIST_DEQUEUE(&(vref->l));
+       BU_PUT(vref, struct pt_vertex_ref);
+    }
+
+    BU_PUT(ear_list, struct pt_vertex_ref);
+    BU_PUT(reflex_list, struct pt_vertex_ref);
+    BU_PUT(convex_list, struct pt_vertex_ref);
+    BU_PUT(vertex_list, struct pt_vertex);
+    BU_PUT(lists, struct pt_lists);
+
+    return ret;
+}
+
+int bg_polygon_triangulate(int **faces, int *num_faces, point2d_t **out_pts, 
int *num_outpts,
+       const point2d_t *pts, const size_t npts, triangulation_t type)
+{
+    int ret;
+    size_t i;
+    int *verts_ind = NULL;
+
+    if (type == DELAUNAY && (!out_pts || !num_outpts)) return 1;
+    verts_ind = (int *)bu_calloc(npts, sizeof(int), "vert indices");
+    for (i = 0; i < npts; i++) verts_ind[i] = i;
+    ret = bg_nested_polygon_triangulate(faces, num_faces, out_pts, num_outpts, 
verts_ind, npts, NULL, NULL, 0, pts, npts, type);
+    bu_free(verts_ind, "free verts");
+    return ret;
+}
+
+
+/*
+ * Local Variables:
+ * mode: C
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * c-file-style: "stroustrup"
+ * End:
+ * ex: shiftwidth=4 tabstop=8
+ */


Property changes on: brlcad/trunk/src/libbg/polygon_ear_clipping.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: brlcad/trunk/src/libbg/polygon_point_in.c
===================================================================
--- brlcad/trunk/src/libbg/polygon_point_in.c                           (rev 0)
+++ brlcad/trunk/src/libbg/polygon_point_in.c   2018-09-26 00:32:26 UTC (rev 
71842)
@@ -0,0 +1,61 @@
+/*
+ * Translation to libbn data types of Franklin's point-in-polygon test.
+ * See http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
+ * for a discussion of the subtleties involved with the inequality tests.
+ * The below copyright applies to just the function bg_pt_in_polygon,
+ * not the whole of polygon.c
+ *
+ * Copyright (c) 1970-2003, Wm. Randolph Franklin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimers.  Redistributions
+ * in binary form must reproduce the above copyright notice in the
+ * documentation and/or other materials provided with the distribution.
+ * The name of W. Randolph Franklin may not be used to endorse or promote
+ * products derived from this Software without specific prior written
+ * permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "common.h"
+#include <stdlib.h>
+#include "bg/polygon.h"
+
+int
+bg_pt_in_polygon(size_t nvert, const point2d_t *pnts, const point2d_t *test)
+{
+    size_t i = 0;
+    size_t j = 0;
+    int c = 0;
+    for (i = 0, j = nvert-1; i < nvert; j = i++) {
+       if ( ((pnts[i][1] > (*test)[1]) != (pnts[j][1] > (*test)[1])) &&
+               ((*test)[0] < (pnts[j][0]-pnts[i][0]) * ((*test)[1]-pnts[i][1]) 
/ (pnts[j][1]-pnts[i][1]) + pnts[i][0]) )
+           c = !c;
+    }
+    return c;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * c-file-style: "stroustrup"
+ * End:
+ * ex: shiftwidth=4 tabstop=8
+ */


Property changes on: brlcad/trunk/src/libbg/polygon_point_in.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.



_______________________________________________
BRL-CAD Source Commits mailing list
brlcad-commits@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/brlcad-commits

Reply via email to