/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/lib/pathplan/triang.c

Go to the documentation of this file.
00001 /* $Id: triang.c,v 1.1.1.1 2004/12/23 04:04:05 ellson Exp $ $Revision: 1.1.1.1 $ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /**********************************************************
00005 *      This software is part of the graphviz package      *
00006 *                http://www.graphviz.org/                 *
00007 *                                                         *
00008 *            Copyright (c) 1994-2004 AT&T Corp.           *
00009 *                and is licensed under the                *
00010 *            Common Public License, Version 1.0           *
00011 *                      by AT&T Corp.                      *
00012 *                                                         *
00013 *        Information and Software Systems Research        *
00014 *              AT&T Research, Florham Park NJ             *
00015 **********************************************************/
00016 
00017 
00018 #include <stdio.h>
00019 #include <math.h>
00020 #include <stdlib.h>
00021 #include <pathutil.h>
00022 #include <tri.h>
00023 
00024 #ifdef DMALLOC
00025 #include "dmalloc.h"
00026 #endif
00027 
00028 typedef struct lvertex_2_t {
00029     double x, y;
00030 } lvertex_2_t;
00031 
00032 typedef struct dpd_triangle {
00033     Ppoint_t *v[3];
00034 } ltriangle_t;
00035 
00036 #define ISCCW 1
00037 #define ISCW  2
00038 #define ISON  3
00039 
00040 #ifndef TRUE
00041 #define TRUE 1
00042 #define FALSE 0
00043 #endif
00044 
00045 static int dpd_ccw(Ppoint_t *, Ppoint_t *, Ppoint_t *);
00046 static int dpd_isdiagonal(int, int, Ppoint_t **, int);
00047 static int dpd_intersects(Ppoint_t *, Ppoint_t *, Ppoint_t *, Ppoint_t *);
00048 static int dpd_between(Ppoint_t *, Ppoint_t *, Ppoint_t *);
00049 static void triangulate(Ppoint_t ** pointp, int pointn,
00050                         void (*fn) (void *, Ppoint_t *), void *vc);
00051 
00052 static int dpd_ccw(Ppoint_t * p1, Ppoint_t * p2, Ppoint_t * p3)
00053 {
00054     double d =
00055         ((p1->y - p2->y) * (p3->x - p2->x)) -
00056         ((p3->y - p2->y) * (p1->x - p2->x));
00057     return (d > 0) ? ISCW : ((d < 0) ? ISCCW : ISON);
00058 }
00059 
00060 void Ptriangulate(Ppoly_t * polygon, void (*fn) (void *, Ppoint_t *),
00061                   void *vc)
00062 {
00063     int i;
00064     int pointn;
00065     Ppoint_t **pointp;
00066 
00067     pointn = polygon->pn;
00068 
00069     pointp = (Ppoint_t **) malloc(pointn * sizeof(Ppoint_t *));
00070 
00071     for (i = 0; i < pointn; i++)
00072         pointp[i] = &(polygon->ps[i]);
00073 
00074     triangulate(pointp, pointn, fn, vc);
00075 
00076     free(pointp);
00077 }
00078 
00079 static void
00080 triangulate(Ppoint_t ** pointp, int pointn,
00081             void (*fn) (void *, Ppoint_t *), void *vc)
00082 {
00083     int i, ip1, ip2, j;
00084     Ppoint_t A[3];
00085     if (pointn > 3) {
00086         for (i = 0; i < pointn; i++) {
00087             ip1 = (i + 1) % pointn;
00088             ip2 = (i + 2) % pointn;
00089             if (dpd_isdiagonal(i, ip2, pointp, pointn)) {
00090                 A[0] = *pointp[i];
00091                 A[1] = *pointp[ip1];
00092                 A[2] = *pointp[ip2];
00093                 fn(vc, A);
00094                 j = 0;
00095                 for (i = 0; i < pointn; i++)
00096                     if (i != ip1)
00097                         pointp[j++] = pointp[i];
00098                 triangulate(pointp, pointn - 1, fn, vc);
00099                 return;
00100             }
00101         }
00102         abort();
00103     } else {
00104         A[0] = *pointp[0];
00105         A[1] = *pointp[1];
00106         A[2] = *pointp[2];
00107         fn(vc, A);
00108     }
00109 }
00110 
00111 /* check if (i, i + 2) is a diagonal */
00112 static int dpd_isdiagonal(int i, int ip2, Ppoint_t ** pointp, int pointn)
00113 {
00114     int ip1, im1, j, jp1, res;
00115 
00116     /* neighborhood test */
00117     ip1 = (i + 1) % pointn;
00118     im1 = (i + pointn - 1) % pointn;
00119     /* If P[i] is a convex vertex [ i+1 left of (i-1,i) ]. */
00120     if (dpd_ccw(pointp[im1], pointp[i], pointp[ip1]) == ISCCW)
00121         res = (dpd_ccw(pointp[i], pointp[ip2], pointp[im1]) == ISCCW) &&
00122             (dpd_ccw(pointp[ip2], pointp[i], pointp[ip1]) == ISCCW);
00123     /* Assume (i - 1, i, i + 1) not collinear. */
00124     else
00125         res = ((dpd_ccw(pointp[i], pointp[ip2], pointp[ip1]) == ISCW)
00126             );
00127 /*
00128                 &&
00129                 (dpd_ccw (pointp[ip2], pointp[i], pointp[im1]) != ISCW));
00130 */
00131     if (!res) {
00132         return FALSE;
00133     }
00134 
00135     /* check against all other edges */
00136     for (j = 0; j < pointn; j++) {
00137         jp1 = (j + 1) % pointn;
00138         if (!((j == i) || (jp1 == i) || (j == ip2) || (jp1 == ip2)))
00139             if (dpd_intersects
00140                 (pointp[i], pointp[ip2], pointp[j], pointp[jp1])) {
00141                 return FALSE;
00142             }
00143     }
00144     return TRUE;
00145 }
00146 
00147 /* line to line intersection */
00148 static int dpd_intersects(Ppoint_t * pa, Ppoint_t * pb, Ppoint_t * pc,
00149                           Ppoint_t * pd)
00150 {
00151     int ccw1, ccw2, ccw3, ccw4;
00152 
00153     if (dpd_ccw(pa, pb, pc) == ISON || dpd_ccw(pa, pb, pd) == ISON ||
00154         dpd_ccw(pc, pd, pa) == ISON || dpd_ccw(pc, pd, pb) == ISON) {
00155         if (dpd_between(pa, pb, pc) || dpd_between(pa, pb, pd) ||
00156             dpd_between(pc, pd, pa) || dpd_between(pc, pd, pb))
00157             return TRUE;
00158     } else {
00159         ccw1 = (dpd_ccw(pa, pb, pc) == ISCCW) ? 1 : 0;
00160         ccw2 = (dpd_ccw(pa, pb, pd) == ISCCW) ? 1 : 0;
00161         ccw3 = (dpd_ccw(pc, pd, pa) == ISCCW) ? 1 : 0;
00162         ccw4 = (dpd_ccw(pc, pd, pb) == ISCCW) ? 1 : 0;
00163         return (ccw1 ^ ccw2) && (ccw3 ^ ccw4);
00164     }
00165     return FALSE;
00166 }
00167 
00168 static int dpd_between(Ppoint_t * pa, Ppoint_t * pb, Ppoint_t * pc)
00169 {
00170     Ppoint_t pba, pca;
00171 
00172     pba.x = pb->x - pa->x, pba.y = pb->y - pa->y;
00173     pca.x = pc->x - pa->x, pca.y = pc->y - pa->y;
00174     if (dpd_ccw(pa, pb, pc) != ISON)
00175         return FALSE;
00176     return (pca.x * pba.x + pca.y * pba.y >= 0) &&
00177         (pca.x * pca.x + pca.y * pca.y <= pba.x * pba.x + pba.y * pba.y);
00178 }

Generated on Mon Mar 31 19:03:28 2008 for Graphviz by  doxygen 1.5.1