Graphviz  2.29.20120524.0446
lib/pathplan/route.c
Go to the documentation of this file.
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 <stdlib.h>
00016 #include <stdio.h>
00017 #include <setjmp.h>
00018 #ifdef HAVE_MALLOC_H
00019 #include <malloc.h>
00020 #endif
00021 #include <math.h>
00022 #include "pathutil.h"
00023 #include "solvers.h"
00024 
00025 #ifdef DMALLOC
00026 #include "dmalloc.h"
00027 #endif
00028 
00029 #define EPSILON1 1E-3
00030 #define EPSILON2 1E-6
00031 
00032 #define ABS(a) ((a) >= 0 ? (a) : -(a))
00033 
00034 typedef struct tna_t {
00035     double t;
00036     Ppoint_t a[2];
00037 } tna_t;
00038 
00039 #define prerror(msg) \
00040         fprintf (stderr, "libpath/%s:%d: %s\n", __FILE__, __LINE__, (msg))
00041 
00042 #define DISTSQ(a, b) ( \
00043     (((a).x - (b).x) * ((a).x - (b).x)) + (((a).y - (b).y) * ((a).y - (b).y)) \
00044 )
00045 
00046 #define POINTSIZE sizeof (Ppoint_t)
00047 
00048 #define LT(pa, pbp) ((pa.y > pbp->y) || ((pa.y == pbp->y) && (pa.x < pbp->x)))
00049 #define GT(pa, pbp) ((pa.y < pbp->y) || ((pa.y == pbp->y) && (pa.x > pbp->x)))
00050 
00051 typedef struct p2e_t {
00052     Ppoint_t *pp;
00053     Pedge_t *ep;
00054 } p2e_t;
00055 
00056 typedef struct elist_t {
00057     Pedge_t *ep;
00058     struct elist_t *next, *prev;
00059 } elist_t;
00060 
00061 static jmp_buf jbuf;
00062 
00063 #if 0
00064 static p2e_t *p2es;
00065 static int p2en;
00066 #endif
00067 
00068 #if 0
00069 static elist_t *elist;
00070 #endif
00071 
00072 static Ppoint_t *ops;
00073 static int opn, opl;
00074 
00075 static int reallyroutespline(Pedge_t *, int,
00076                              Ppoint_t *, int, Ppoint_t, Ppoint_t);
00077 static int mkspline(Ppoint_t *, int, tna_t *, Ppoint_t, Ppoint_t,
00078                     Ppoint_t *, Ppoint_t *, Ppoint_t *, Ppoint_t *);
00079 static int splinefits(Pedge_t *, int, Ppoint_t, Pvector_t, Ppoint_t,
00080                       Pvector_t, Ppoint_t *, int);
00081 static int splineisinside(Pedge_t *, int, Ppoint_t *);
00082 static int splineintersectsline(Ppoint_t *, Ppoint_t *, double *);
00083 static void points2coeff(double, double, double, double, double *);
00084 static void addroot(double, double *, int *);
00085 
00086 static Pvector_t normv(Pvector_t);
00087 
00088 static void growops(int);
00089 
00090 static Ppoint_t add(Ppoint_t, Ppoint_t);
00091 static Ppoint_t sub(Ppoint_t, Ppoint_t);
00092 static double dist(Ppoint_t, Ppoint_t);
00093 static Ppoint_t scale(Ppoint_t, double);
00094 static double dot(Ppoint_t, Ppoint_t);
00095 static double B0(double t);
00096 static double B1(double t);
00097 static double B2(double t);
00098 static double B3(double t);
00099 static double B01(double t);
00100 static double B23(double t);
00101 #if 0
00102 static int cmpp2efunc(const void *, const void *);
00103 
00104 static void listdelete(Pedge_t *);
00105 static void listreplace(Pedge_t *, Pedge_t *);
00106 static void listinsert(Pedge_t *, Ppoint_t);
00107 #endif
00108 
00109 /* Proutespline:
00110  * Given a set of edgen line segments edges as obstacles, a template
00111  * path input, and endpoint vectors evs, construct a spline fitting the
00112  * input and endpoing vectors, and return in output.
00113  * Return 0 on success and -1 on failure, including no memory.
00114  */
00115 int Proutespline(Pedge_t * edges, int edgen, Ppolyline_t input,
00116                  Ppoint_t * evs, Ppolyline_t * output)
00117 {
00118 #if 0
00119     Ppoint_t p0, p1, p2, p3;
00120     Ppoint_t *pp;
00121     Pvector_t v1, v2, v12, v23;
00122     int ipi, opi;
00123     int ei, p2ei;
00124     Pedge_t *e0p, *e1p;
00125 #endif
00126     Ppoint_t *inps;
00127     int inpn;
00128 
00129     /* unpack into previous format rather than modify legacy code */
00130     inps = input.ps;
00131     inpn = input.pn;
00132 
00133 #if 0
00134     if (!(p2es = (p2e_t *) malloc(sizeof(p2e_t) * (p2en = edgen * 2)))) {
00135         prerror("cannot malloc p2es");
00136         return -1;
00137     }
00138     for (ei = 0, p2ei = 0; ei < edgen; ei++) {
00139         if (edges[ei].a.x == edges[ei].b.x
00140             && edges[ei].a.y == edges[ei].b.y)
00141             continue;
00142         p2es[p2ei].pp = &edges[ei].a;
00143         p2es[p2ei++].ep = &edges[ei];
00144         p2es[p2ei].pp = &edges[ei].b;
00145         p2es[p2ei++].ep = &edges[ei];
00146     }
00147     p2en = p2ei;
00148     qsort(p2es, p2en, sizeof(p2e_t), cmpp2efunc);
00149     elist = NULL;
00150     for (p2ei = 0; p2ei < p2en; p2ei += 2) {
00151         pp = p2es[p2ei].pp;
00152 #if DEBUG >= 1
00153         fprintf(stderr, "point: %d %lf %lf\n", p2ei, pp->x, pp->y);
00154 #endif
00155         e0p = p2es[p2ei].ep;
00156         e1p = p2es[p2ei + 1].ep;
00157         p0 = (&e0p->a == p2es[p2ei].pp) ? e0p->b : e0p->a;
00158         p1 = (&e0p->a == p2es[p2ei + 1].pp) ? e1p->b : e1p->a;
00159         if (LT(p0, pp) && LT(p1, pp)) {
00160             listdelete(e0p), listdelete(e1p);
00161         } else if (GT(p0, pp) && GT(p1, pp)) {
00162             listinsert(e0p, *pp), listinsert(e1p, *pp);
00163         } else {
00164             if (LT(p0, pp))
00165                 listreplace(e0p, e1p);
00166             else
00167                 listreplace(e1p, e0p);
00168         }
00169     }
00170 #endif
00171     if (setjmp(jbuf))
00172         return -1;
00173 
00174     /* generate the splines */
00175     evs[0] = normv(evs[0]);
00176     evs[1] = normv(evs[1]);
00177     opl = 0;
00178     growops(4);
00179     ops[opl++] = inps[0];
00180     if (reallyroutespline(edges, edgen, inps, inpn, evs[0], evs[1]) == -1)
00181         return -1;
00182     output->pn = opl;
00183     output->ps = ops;
00184 
00185 #if 0
00186     fprintf(stderr, "edge\na\nb\n");
00187     fprintf(stderr, "points\n%d\n", inpn);
00188     for (ipi = 0; ipi < inpn; ipi++)
00189         fprintf(stderr, "%f %f\n", inps[ipi].x, inps[ipi].y);
00190     fprintf(stderr, "splpoints\n%d\n", opl);
00191     for (opi = 0; opi < opl; opi++)
00192         fprintf(stderr, "%f %f\n", ops[opi].x, ops[opi].y);
00193 #endif
00194 
00195     return 0;
00196 }
00197 
00198 static int reallyroutespline(Pedge_t * edges, int edgen,
00199                              Ppoint_t * inps, int inpn, Ppoint_t ev0,
00200                              Ppoint_t ev1)
00201 {
00202     Ppoint_t p1, p2, cp1, cp2, p;
00203     Pvector_t v1, v2, splitv, splitv1, splitv2;
00204     double maxd, d, t;
00205     int maxi, i, spliti;
00206 
00207     static tna_t *tnas;
00208     static int tnan;
00209 
00210     if (tnan < inpn) {
00211         if (!tnas) {
00212             if (!(tnas = malloc(sizeof(tna_t) * inpn)))
00213                 return -1;
00214         } else {
00215             if (!(tnas = realloc(tnas, sizeof(tna_t) * inpn)))
00216                 return -1;
00217         }
00218         tnan = inpn;
00219     }
00220     tnas[0].t = 0;
00221     for (i = 1; i < inpn; i++)
00222         tnas[i].t = tnas[i - 1].t + dist(inps[i], inps[i - 1]);
00223     for (i = 1; i < inpn; i++)
00224         tnas[i].t /= tnas[inpn - 1].t;
00225     for (i = 0; i < inpn; i++) {
00226         tnas[i].a[0] = scale(ev0, B1(tnas[i].t));
00227         tnas[i].a[1] = scale(ev1, B2(tnas[i].t));
00228     }
00229     if (mkspline(inps, inpn, tnas, ev0, ev1, &p1, &v1, &p2, &v2) == -1)
00230         return -1;
00231     if (splinefits(edges, edgen, p1, v1, p2, v2, inps, inpn))
00232         return 0;
00233     cp1 = add(p1, scale(v1, 1 / 3.0));
00234     cp2 = sub(p2, scale(v2, 1 / 3.0));
00235     for (maxd = -1, maxi = -1, i = 1; i < inpn - 1; i++) {
00236         t = tnas[i].t;
00237         p.x = B0(t) * p1.x + B1(t) * cp1.x + B2(t) * cp2.x + B3(t) * p2.x;
00238         p.y = B0(t) * p1.y + B1(t) * cp1.y + B2(t) * cp2.y + B3(t) * p2.y;
00239         if ((d = dist(p, inps[i])) > maxd)
00240             maxd = d, maxi = i;
00241     }
00242     spliti = maxi;
00243     splitv1 = normv(sub(inps[spliti], inps[spliti - 1]));
00244     splitv2 = normv(sub(inps[spliti + 1], inps[spliti]));
00245     splitv = normv(add(splitv1, splitv2));
00246     reallyroutespline(edges, edgen, inps, spliti + 1, ev0, splitv);
00247     reallyroutespline(edges, edgen, &inps[spliti], inpn - spliti, splitv,
00248                       ev1);
00249     return 0;
00250 }
00251 
00252 static int mkspline(Ppoint_t * inps, int inpn, tna_t * tnas, Ppoint_t ev0,
00253                     Ppoint_t ev1, Ppoint_t * sp0, Ppoint_t * sv0,
00254                     Ppoint_t * sp1, Ppoint_t * sv1)
00255 {
00256     Ppoint_t tmp;
00257     double c[2][2], x[2], det01, det0X, detX1;
00258     double d01, scale0, scale3;
00259     int i;
00260 
00261     scale0 = scale3 = 0.0;
00262     c[0][0] = c[0][1] = c[1][0] = c[1][1] = 0.0;
00263     x[0] = x[1] = 0.0;
00264     for (i = 0; i < inpn; i++) {
00265         c[0][0] += dot(tnas[i].a[0], tnas[i].a[0]);
00266         c[0][1] += dot(tnas[i].a[0], tnas[i].a[1]);
00267         c[1][0] = c[0][1];
00268         c[1][1] += dot(tnas[i].a[1], tnas[i].a[1]);
00269         tmp = sub(inps[i], add(scale(inps[0], B01(tnas[i].t)),
00270                                scale(inps[inpn - 1], B23(tnas[i].t))));
00271         x[0] += dot(tnas[i].a[0], tmp);
00272         x[1] += dot(tnas[i].a[1], tmp);
00273     }
00274     det01 = c[0][0] * c[1][1] - c[1][0] * c[0][1];
00275     det0X = c[0][0] * x[1] - c[0][1] * x[0];
00276     detX1 = x[0] * c[1][1] - x[1] * c[0][1];
00277     if (ABS(det01) >= 1e-6) {
00278         scale0 = detX1 / det01;
00279         scale3 = det0X / det01;
00280     }
00281     if (ABS(det01) < 1e-6 || scale0 <= 0.0 || scale3 <= 0.0) {
00282         d01 = dist(inps[0], inps[inpn - 1]) / 3.0;
00283         scale0 = d01;
00284         scale3 = d01;
00285     }
00286     *sp0 = inps[0];
00287     *sv0 = scale(ev0, scale0);
00288     *sp1 = inps[inpn - 1];
00289     *sv1 = scale(ev1, scale3);
00290     return 0;
00291 }
00292 
00293 static double dist_n(Ppoint_t * p, int n)
00294 {
00295     int i;
00296     double rv;
00297 
00298     rv = 0.0;
00299     for (i = 1; i < n; i++) {
00300         rv +=
00301             sqrt((p[i].x - p[i - 1].x) * (p[i].x - p[i - 1].x) +
00302                  (p[i].y - p[i - 1].y) * (p[i].y - p[i - 1].y));
00303     }
00304     return rv;
00305 }
00306 
00307 static int splinefits(Pedge_t * edges, int edgen, Ppoint_t pa,
00308                       Pvector_t va, Ppoint_t pb, Pvector_t vb,
00309                       Ppoint_t * inps, int inpn)
00310 {
00311     Ppoint_t sps[4];
00312     double a, b;
00313 #if 0
00314     double d;
00315 #endif
00316     int pi;
00317     int forceflag;
00318     int first = 1;
00319 
00320     forceflag = (inpn == 2 ? 1 : 0);
00321 
00322 #if 0
00323     d = sqrt((pb.x - pa.x) * (pb.x - pa.x) +
00324              (pb.y - pa.y) * (pb.y - pa.y));
00325     a = d, b = d;
00326 #else
00327     a = b = 4;
00328 #endif
00329     for (;;) {
00330         sps[0].x = pa.x;
00331         sps[0].y = pa.y;
00332         sps[1].x = pa.x + a * va.x / 3.0;
00333         sps[1].y = pa.y + a * va.y / 3.0;
00334         sps[2].x = pb.x - b * vb.x / 3.0;
00335         sps[2].y = pb.y - b * vb.y / 3.0;
00336         sps[3].x = pb.x;
00337         sps[3].y = pb.y;
00338 
00339         /* shortcuts (paths shorter than the shortest path) not allowed -
00340          * they must be outside the constraint polygon.  this can happen
00341          * if the candidate spline intersects the constraint polygon exactly
00342          * on sides or vertices.  maybe this could be more elegant, but
00343          * it solves the immediate problem. we could also try jittering the
00344          * constraint polygon, or computing the candidate spline more carefully,
00345          * for example using the path. SCN */
00346 
00347         if (first && (dist_n(sps, 4) < (dist_n(inps, inpn) - EPSILON1)))
00348             return 0;
00349         first = 0;
00350 
00351         if (splineisinside(edges, edgen, &sps[0])) {
00352             growops(opl + 4);
00353             for (pi = 1; pi < 4; pi++)
00354                 ops[opl].x = sps[pi].x, ops[opl++].y = sps[pi].y;
00355 #if DEBUG >= 1
00356             fprintf(stderr, "success: %f %f\n", a, b);
00357 #endif
00358             return 1;
00359         }
00360         if (a == 0 && b == 0) {
00361             if (forceflag) {
00362                 growops(opl + 4);
00363                 for (pi = 1; pi < 4; pi++)
00364                     ops[opl].x = sps[pi].x, ops[opl++].y = sps[pi].y;
00365 #if DEBUG >= 1
00366                 fprintf(stderr, "forced straight line: %f %f\n", a, b);
00367 #endif
00368                 return 1;
00369             }
00370             break;
00371         }
00372         if (a > .01)
00373             a /= 2, b /= 2;
00374         else
00375             a = b = 0;
00376     }
00377 #if DEBUG >= 1
00378     fprintf(stderr, "failure\n");
00379 #endif
00380     return 0;
00381 }
00382 
00383 static int splineisinside(Pedge_t * edges, int edgen, Ppoint_t * sps)
00384 {
00385     double roots[4];
00386     int rooti, rootn;
00387     int ei;
00388     Ppoint_t lps[2], ip;
00389     double t, ta, tb, tc, td;
00390 
00391     for (ei = 0; ei < edgen; ei++) {
00392         lps[0] = edges[ei].a, lps[1] = edges[ei].b;
00393         /* if ((rootn = splineintersectsline (sps, lps, roots)) == 4)
00394            return 1; */
00395         if ((rootn = splineintersectsline(sps, lps, roots)) == 4)
00396             continue;
00397         for (rooti = 0; rooti < rootn; rooti++) {
00398             if (roots[rooti] < EPSILON2 || roots[rooti] > 1 - EPSILON2)
00399                 continue;
00400             t = roots[rooti];
00401             td = t * t * t;
00402             tc = 3 * t * t * (1 - t);
00403             tb = 3 * t * (1 - t) * (1 - t);
00404             ta = (1 - t) * (1 - t) * (1 - t);
00405             ip.x = ta * sps[0].x + tb * sps[1].x +
00406                 tc * sps[2].x + td * sps[3].x;
00407             ip.y = ta * sps[0].y + tb * sps[1].y +
00408                 tc * sps[2].y + td * sps[3].y;
00409             if (DISTSQ(ip, lps[0]) < EPSILON1 ||
00410                 DISTSQ(ip, lps[1]) < EPSILON1)
00411                 continue;
00412             return 0;
00413         }
00414     }
00415     return 1;
00416 }
00417 
00418 static int splineintersectsline(Ppoint_t * sps, Ppoint_t * lps,
00419                                 double *roots)
00420 {
00421     double scoeff[4], xcoeff[2], ycoeff[2];
00422     double xroots[3], yroots[3], tv, sv, rat;
00423     int rootn, xrootn, yrootn, i, j;
00424 
00425     xcoeff[0] = lps[0].x;
00426     xcoeff[1] = lps[1].x - lps[0].x;
00427     ycoeff[0] = lps[0].y;
00428     ycoeff[1] = lps[1].y - lps[0].y;
00429     rootn = 0;
00430     if (xcoeff[1] == 0) {
00431         if (ycoeff[1] == 0) {
00432             points2coeff(sps[0].x, sps[1].x, sps[2].x, sps[3].x, scoeff);
00433             scoeff[0] -= xcoeff[0];
00434             xrootn = solve3(scoeff, xroots);
00435             points2coeff(sps[0].y, sps[1].y, sps[2].y, sps[3].y, scoeff);
00436             scoeff[0] -= ycoeff[0];
00437             yrootn = solve3(scoeff, yroots);
00438             if (xrootn == 4)
00439                 if (yrootn == 4)
00440                     return 4;
00441                 else
00442                     for (j = 0; j < yrootn; j++)
00443                         addroot(yroots[j], roots, &rootn);
00444             else if (yrootn == 4)
00445                 for (i = 0; i < xrootn; i++)
00446                     addroot(xroots[i], roots, &rootn);
00447             else
00448                 for (i = 0; i < xrootn; i++)
00449                     for (j = 0; j < yrootn; j++)
00450                         if (xroots[i] == yroots[j])
00451                             addroot(xroots[i], roots, &rootn);
00452             return rootn;
00453         } else {
00454             points2coeff(sps[0].x, sps[1].x, sps[2].x, sps[3].x, scoeff);
00455             scoeff[0] -= xcoeff[0];
00456             xrootn = solve3(scoeff, xroots);
00457             if (xrootn == 4)
00458                 return 4;
00459             for (i = 0; i < xrootn; i++) {
00460                 tv = xroots[i];
00461                 if (tv >= 0 && tv <= 1) {
00462                     points2coeff(sps[0].y, sps[1].y, sps[2].y, sps[3].y,
00463                                  scoeff);
00464                     sv = scoeff[0] + tv * (scoeff[1] + tv *
00465                                            (scoeff[2] + tv * scoeff[3]));
00466                     sv = (sv - ycoeff[0]) / ycoeff[1];
00467                     if ((0 <= sv) && (sv <= 1))
00468                         addroot(tv, roots, &rootn);
00469                 }
00470             }
00471             return rootn;
00472         }
00473     } else {
00474         rat = ycoeff[1] / xcoeff[1];
00475         points2coeff(sps[0].y - rat * sps[0].x, sps[1].y - rat * sps[1].x,
00476                      sps[2].y - rat * sps[2].x, sps[3].y - rat * sps[3].x,
00477                      scoeff);
00478         scoeff[0] += rat * xcoeff[0] - ycoeff[0];
00479         xrootn = solve3(scoeff, xroots);
00480         if (xrootn == 4)
00481             return 4;
00482         for (i = 0; i < xrootn; i++) {
00483             tv = xroots[i];
00484             if (tv >= 0 && tv <= 1) {
00485                 points2coeff(sps[0].x, sps[1].x, sps[2].x, sps[3].x,
00486                              scoeff);
00487                 sv = scoeff[0] + tv * (scoeff[1] +
00488                                        tv * (scoeff[2] + tv * scoeff[3]));
00489                 sv = (sv - xcoeff[0]) / xcoeff[1];
00490                 if ((0 <= sv) && (sv <= 1))
00491                     addroot(tv, roots, &rootn);
00492             }
00493         }
00494         return rootn;
00495     }
00496 }
00497 
00498 static void points2coeff(double v0, double v1, double v2, double v3,
00499                          double *coeff)
00500 {
00501     coeff[3] = v3 + 3 * v1 - (v0 + 3 * v2);
00502     coeff[2] = 3 * v0 + 3 * v2 - 6 * v1;
00503     coeff[1] = 3 * (v1 - v0);
00504     coeff[0] = v0;
00505 }
00506 
00507 static void addroot(double root, double *roots, int *rootnp)
00508 {
00509     if (root >= 0 && root <= 1)
00510         roots[*rootnp] = root, (*rootnp)++;
00511 }
00512 
00513 static Pvector_t normv(Pvector_t v)
00514 {
00515     double d;
00516 
00517     d = v.x * v.x + v.y * v.y;
00518     if (d > 1e-6) {
00519         d = sqrt(d);
00520         v.x /= d, v.y /= d;
00521     }
00522     return v;
00523 }
00524 
00525 static void growops(int newopn)
00526 {
00527     if (newopn <= opn)
00528         return;
00529     if (!ops) {
00530         if (!(ops = (Ppoint_t *) malloc(POINTSIZE * newopn))) {
00531             prerror("cannot malloc ops");
00532             longjmp(jbuf,1);
00533         }
00534     } else {
00535         if (!(ops = (Ppoint_t *) realloc((void *) ops,
00536                                          POINTSIZE * newopn))) {
00537             prerror("cannot realloc ops");
00538             longjmp(jbuf,1);
00539         }
00540     }
00541     opn = newopn;
00542 }
00543 
00544 static Ppoint_t add(Ppoint_t p1, Ppoint_t p2)
00545 {
00546     p1.x += p2.x, p1.y += p2.y;
00547     return p1;
00548 }
00549 
00550 static Ppoint_t sub(Ppoint_t p1, Ppoint_t p2)
00551 {
00552     p1.x -= p2.x, p1.y -= p2.y;
00553     return p1;
00554 }
00555 
00556 static double dist(Ppoint_t p1, Ppoint_t p2)
00557 {
00558     double dx, dy;
00559 
00560     dx = p2.x - p1.x, dy = p2.y - p1.y;
00561     return sqrt(dx * dx + dy * dy);
00562 }
00563 
00564 static Ppoint_t scale(Ppoint_t p, double c)
00565 {
00566     p.x *= c, p.y *= c;
00567     return p;
00568 }
00569 
00570 static double dot(Ppoint_t p1, Ppoint_t p2)
00571 {
00572     return p1.x * p2.x + p1.y * p2.y;
00573 }
00574 
00575 static double B0(double t)
00576 {
00577     double tmp = 1.0 - t;
00578     return tmp * tmp * tmp;
00579 }
00580 
00581 static double B1(double t)
00582 {
00583     double tmp = 1.0 - t;
00584     return 3 * t * tmp * tmp;
00585 }
00586 
00587 static double B2(double t)
00588 {
00589     double tmp = 1.0 - t;
00590     return 3 * t * t * tmp;
00591 }
00592 
00593 static double B3(double t)
00594 {
00595     return t * t * t;
00596 }
00597 
00598 static double B01(double t)
00599 {
00600     double tmp = 1.0 - t;
00601     return tmp * tmp * (tmp + 3 * t);
00602 }
00603 
00604 static double B23(double t)
00605 {
00606     double tmp = 1.0 - t;
00607     return t * t * (3 * tmp + t);
00608 }
00609 
00610 #if 0
00611 static int cmpp2efunc(const void *v0p, const void *v1p)
00612 {
00613     p2e_t *p2e0p, *p2e1p;
00614     double x0, x1;
00615 
00616     p2e0p = (p2e_t *) v0p, p2e1p = (p2e_t *) v1p;
00617     if (p2e0p->pp->y > p2e1p->pp->y)
00618         return -1;
00619     else if (p2e0p->pp->y < p2e1p->pp->y)
00620         return 1;
00621     if (p2e0p->pp->x < p2e1p->pp->x)
00622         return -1;
00623     else if (p2e0p->pp->x > p2e1p->pp->x)
00624         return 1;
00625     x0 = (p2e0p->pp == &p2e0p->ep->a) ? p2e0p->ep->b.x : p2e0p->ep->a.x;
00626     x1 = (p2e1p->pp == &p2e1p->ep->a) ? p2e1p->ep->b.x : p2e1p->ep->a.x;
00627     if (x0 < x1)
00628         return -1;
00629     else if (x0 > x1)
00630         return 1;
00631     return 0;
00632 }
00633 
00634 static void listdelete(Pedge_t * ep)
00635 {
00636     elist_t *lp;
00637 
00638     for (lp = elist; lp; lp = lp->next) {
00639         if (lp->ep != ep)
00640             continue;
00641         if (lp->prev)
00642             lp->prev->next = lp->next;
00643         if (lp->next)
00644             lp->next->prev = lp->prev;
00645         if (elist == lp)
00646             elist = lp->next;
00647         free(lp);
00648         return;
00649     }
00650     if (!lp) {
00651         prerror("cannot find list element to delete");
00652         abort();
00653     }
00654 }
00655 
00656 static void listreplace(Pedge_t * oldep, Pedge_t * newep)
00657 {
00658     elist_t *lp;
00659 
00660     for (lp = elist; lp; lp = lp->next) {
00661         if (lp->ep != oldep)
00662             continue;
00663         lp->ep = newep;
00664         return;
00665     }
00666     if (!lp) {
00667         prerror("cannot find list element to replace");
00668         abort();
00669     }
00670 }
00671 
00672 static void listinsert(Pedge_t * ep, Ppoint_t p)
00673 {
00674     elist_t *lp, *newlp, *lastlp;
00675     double lx;
00676 
00677     if (!(newlp = (elist_t *) malloc(sizeof(elist_t)))) {
00678         prerror("cannot malloc newlp");
00679         abort();
00680     }
00681     newlp->ep = ep;
00682     newlp->next = newlp->prev = NULL;
00683     if (!elist) {
00684         elist = newlp;
00685         return;
00686     }
00687     for (lp = elist; lp; lp = lp->next) {
00688         lastlp = lp;
00689         lx = lp->ep->a.x + (lp->ep->b.x - lp->ep->a.x) * (p.y -
00690                                                           lp->ep->a.y) /
00691             (lp->ep->b.y - lp->ep->a.y);
00692         if (lx <= p.x)
00693             continue;
00694         if (lp->prev)
00695             lp->prev->next = newlp;
00696         newlp->prev = lp->prev;
00697         newlp->next = lp;
00698         lp->prev = newlp;
00699         if (elist == lp)
00700             elist = newlp;
00701         return;
00702     }
00703     lastlp->next = newlp;
00704     newlp->prev = lastlp;
00705     if (!elist)
00706         elist = newlp;
00707 }
00708 #endif