00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
00112 static int dpd_isdiagonal(int i, int ip2, Ppoint_t ** pointp, int pointn)
00113 {
00114 int ip1, im1, j, jp1, res;
00115
00116
00117 ip1 = (i + 1) % pointn;
00118 im1 = (i + pointn - 1) % pointn;
00119
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
00124 else
00125 res = ((dpd_ccw(pointp[i], pointp[ip2], pointp[ip1]) == ISCW)
00126 );
00127
00128
00129
00130
00131 if (!res) {
00132 return FALSE;
00133 }
00134
00135
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
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 }