|
Graphviz
2.31.20130525.0447
|
00001 /* $Id$ $Revision$ */ 00002 /* vim:set shiftwidth=4 ts=8: */ 00003 00004 /************************************************************************* 00005 * Copyright (c) 2011 AT&T Intellectual Property 00006 * All rights reserved. This program and the accompanying materials 00007 * are made available under the terms of the Eclipse Public License v1.0 00008 * which accompanies this distribution, and is available at 00009 * http://www.eclipse.org/legal/epl-v10.html 00010 * 00011 * Contributors: See CVS logs. Details at http://www.graphviz.org/ 00012 *************************************************************************/ 00013 00014 00015 #include <stdio.h> 00016 #include <math.h> 00017 #include <stdlib.h> 00018 #include <setjmp.h> 00019 #include "pathutil.h" 00020 #include "tri.h" 00021 00022 #ifdef DMALLOC 00023 #include "dmalloc.h" 00024 #endif 00025 00026 typedef struct lvertex_2_t { 00027 double x, y; 00028 } lvertex_2_t; 00029 00030 typedef struct dpd_triangle { 00031 Ppoint_t *v[3]; 00032 } ltriangle_t; 00033 00034 #define ISCCW 1 00035 #define ISCW 2 00036 #define ISON 3 00037 00038 #ifndef TRUE 00039 #define TRUE 1 00040 #define FALSE 0 00041 #endif 00042 00043 static jmp_buf jbuf; 00044 static int dpd_ccw(Ppoint_t *, Ppoint_t *, Ppoint_t *); 00045 static int dpd_isdiagonal(int, int, Ppoint_t **, int); 00046 static int dpd_intersects(Ppoint_t *, Ppoint_t *, Ppoint_t *, Ppoint_t *); 00047 static int dpd_between(Ppoint_t *, Ppoint_t *, Ppoint_t *); 00048 static void triangulate(Ppoint_t ** pointp, int pointn, 00049 void (*fn) (void *, Ppoint_t *), void *vc); 00050 00051 static int dpd_ccw(Ppoint_t * p1, Ppoint_t * p2, Ppoint_t * p3) 00052 { 00053 double d = 00054 ((p1->y - p2->y) * (p3->x - p2->x)) - 00055 ((p3->y - p2->y) * (p1->x - p2->x)); 00056 return (d > 0) ? ISCW : ((d < 0) ? ISCCW : ISON); 00057 } 00058 00059 /* Ptriangulate: 00060 * Return 0 on success; non-zero on error. 00061 */ 00062 int Ptriangulate(Ppoly_t * polygon, void (*fn) (void *, Ppoint_t *), 00063 void *vc) 00064 { 00065 int i; 00066 int pointn; 00067 Ppoint_t **pointp; 00068 00069 pointn = polygon->pn; 00070 00071 pointp = (Ppoint_t **) malloc(pointn * sizeof(Ppoint_t *)); 00072 00073 for (i = 0; i < pointn; i++) 00074 pointp[i] = &(polygon->ps[i]); 00075 00076 if (setjmp(jbuf)) { 00077 free(pointp); 00078 return 1; 00079 } 00080 triangulate(pointp, pointn, fn, vc); 00081 00082 free(pointp); 00083 return 0; 00084 } 00085 00086 /* triangulate: 00087 * Triangulates the given polygon. 00088 * Throws an exception if no diagonal exists. 00089 */ 00090 static void 00091 triangulate(Ppoint_t ** pointp, int pointn, 00092 void (*fn) (void *, Ppoint_t *), void *vc) 00093 { 00094 int i, ip1, ip2, j; 00095 Ppoint_t A[3]; 00096 if (pointn > 3) { 00097 for (i = 0; i < pointn; i++) { 00098 ip1 = (i + 1) % pointn; 00099 ip2 = (i + 2) % pointn; 00100 if (dpd_isdiagonal(i, ip2, pointp, pointn)) { 00101 A[0] = *pointp[i]; 00102 A[1] = *pointp[ip1]; 00103 A[2] = *pointp[ip2]; 00104 fn(vc, A); 00105 j = 0; 00106 for (i = 0; i < pointn; i++) 00107 if (i != ip1) 00108 pointp[j++] = pointp[i]; 00109 triangulate(pointp, pointn - 1, fn, vc); 00110 return; 00111 } 00112 } 00113 longjmp(jbuf,1); 00114 } else { 00115 A[0] = *pointp[0]; 00116 A[1] = *pointp[1]; 00117 A[2] = *pointp[2]; 00118 fn(vc, A); 00119 } 00120 } 00121 00122 /* check if (i, i + 2) is a diagonal */ 00123 static int dpd_isdiagonal(int i, int ip2, Ppoint_t ** pointp, int pointn) 00124 { 00125 int ip1, im1, j, jp1, res; 00126 00127 /* neighborhood test */ 00128 ip1 = (i + 1) % pointn; 00129 im1 = (i + pointn - 1) % pointn; 00130 /* If P[i] is a convex vertex [ i+1 left of (i-1,i) ]. */ 00131 if (dpd_ccw(pointp[im1], pointp[i], pointp[ip1]) == ISCCW) 00132 res = (dpd_ccw(pointp[i], pointp[ip2], pointp[im1]) == ISCCW) && 00133 (dpd_ccw(pointp[ip2], pointp[i], pointp[ip1]) == ISCCW); 00134 /* Assume (i - 1, i, i + 1) not collinear. */ 00135 else 00136 res = ((dpd_ccw(pointp[i], pointp[ip2], pointp[ip1]) == ISCW) 00137 ); 00138 /* 00139 && 00140 (dpd_ccw (pointp[ip2], pointp[i], pointp[im1]) != ISCW)); 00141 */ 00142 if (!res) { 00143 return FALSE; 00144 } 00145 00146 /* check against all other edges */ 00147 for (j = 0; j < pointn; j++) { 00148 jp1 = (j + 1) % pointn; 00149 if (!((j == i) || (jp1 == i) || (j == ip2) || (jp1 == ip2))) 00150 if (dpd_intersects 00151 (pointp[i], pointp[ip2], pointp[j], pointp[jp1])) { 00152 return FALSE; 00153 } 00154 } 00155 return TRUE; 00156 } 00157 00158 /* line to line intersection */ 00159 static int dpd_intersects(Ppoint_t * pa, Ppoint_t * pb, Ppoint_t * pc, 00160 Ppoint_t * pd) 00161 { 00162 int ccw1, ccw2, ccw3, ccw4; 00163 00164 if (dpd_ccw(pa, pb, pc) == ISON || dpd_ccw(pa, pb, pd) == ISON || 00165 dpd_ccw(pc, pd, pa) == ISON || dpd_ccw(pc, pd, pb) == ISON) { 00166 if (dpd_between(pa, pb, pc) || dpd_between(pa, pb, pd) || 00167 dpd_between(pc, pd, pa) || dpd_between(pc, pd, pb)) 00168 return TRUE; 00169 } else { 00170 ccw1 = (dpd_ccw(pa, pb, pc) == ISCCW) ? 1 : 0; 00171 ccw2 = (dpd_ccw(pa, pb, pd) == ISCCW) ? 1 : 0; 00172 ccw3 = (dpd_ccw(pc, pd, pa) == ISCCW) ? 1 : 0; 00173 ccw4 = (dpd_ccw(pc, pd, pb) == ISCCW) ? 1 : 0; 00174 return (ccw1 ^ ccw2) && (ccw3 ^ ccw4); 00175 } 00176 return FALSE; 00177 } 00178 00179 static int dpd_between(Ppoint_t * pa, Ppoint_t * pb, Ppoint_t * pc) 00180 { 00181 Ppoint_t pba, pca; 00182 00183 pba.x = pb->x - pa->x, pba.y = pb->y - pa->y; 00184 pca.x = pc->x - pa->x, pca.y = pc->y - pa->y; 00185 if (dpd_ccw(pa, pb, pc) != ISON) 00186 return FALSE; 00187 return (pca.x * pba.x + pca.y * pba.y >= 0) && 00188 (pca.x * pca.x + pca.y * pca.y <= pba.x * pba.x + pba.y * pba.y); 00189 }
1.7.5