~ubuntu-branches/ubuntu/lucid/graphviz/lucid-security

« back to all changes in this revision

Viewing changes to tclpathplan/tclpathplan.c

  • Committer: Bazaar Package Importer
  • Author(s): Stephen M Moraco
  • Date: 2002-02-05 18:52:12 UTC
  • Revision ID: james.westby@ubuntu.com-20020205185212-8i04c70te00rc40y
Tags: upstream-1.7.16
ImportĀ upstreamĀ versionĀ 1.7.16

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Tcl binding to drive Stephen North's and
 
3
 * Emden Gansner's shortest path code.
 
4
 *
 
5
 * ellson@lucent.com   October 2nd, 1996
 
6
 */
 
7
 
 
8
#ifdef HAVE_AST
 
9
#include                <ast.h>
 
10
#include                <vmalloc.h>
 
11
#else
 
12
#include                <sys/types.h>
 
13
#include                <stdlib.h>
 
14
#include                <string.h>
 
15
#include                <unistd.h>
 
16
#endif
 
17
 
 
18
#include <assert.h>
 
19
#include <math.h>
 
20
#include <pathutil.h>
 
21
#include <vispath.h>
 
22
#include <tri.h>
 
23
#include <tcl.h>
 
24
#include "tclhandle.h"
 
25
 
 
26
#ifdef HAVE_CONFIG_H
 
27
#include "gvconfig.h"
 
28
#endif
 
29
 
 
30
typedef Ppoint_t point;
 
31
 
 
32
typedef struct poly_s {
 
33
        int                     id;
 
34
        Ppoly_t         boundary;
 
35
} poly;
 
36
 
 
37
typedef struct vgpane_s {
 
38
        int                     Npoly;                  /* number of polygons */
 
39
        poly            *poly;                  /* set of polygons */
 
40
        int                     N_poly_alloc;   /* for allocation */
 
41
        vconfig_t       *vc;                    /* visibility graph handle */
 
42
        Tcl_Interp      *interp;                /* interpreter that owns the binding */
 
43
        char            *triangle_cmd;  /* why is this here any more */
 
44
} vgpane_t;
 
45
 
 
46
#ifndef HAVE_SINCOS
 
47
#define sincos(x,s,c) *s = sin(x); *c = cos(x)
 
48
#endif
 
49
 
 
50
tblHeader_pt vgpaneTable;
 
51
 
 
52
extern void make_CW(Ppoly_t *poly);
 
53
extern int Plegal_arrangement( Ppoly_t  **polys, int    n_polys);
 
54
 
 
55
static int polyid=0;   /* unique and unchanging id for each poly */
 
56
 
 
57
static poly *allocpoly(vgpane_t *vgp, int id, int npts)
 
58
{
 
59
        poly    *rv;
 
60
        if (vgp->Npoly >= vgp->N_poly_alloc) {
 
61
                vgp->N_poly_alloc *= 2;
 
62
                vgp->poly = realloc(vgp->poly,vgp->N_poly_alloc*sizeof(poly));
 
63
        }
 
64
        rv = &(vgp->poly[vgp->Npoly++]);
 
65
        rv->id = id;
 
66
        rv->boundary.pn = 0;
 
67
        rv->boundary.ps = malloc(npts * sizeof(point));
 
68
        return rv;
 
69
}
 
70
 
 
71
static void vc_stale(vgpane_t *vgp)
 
72
{
 
73
        if (vgp->vc) {
 
74
                Pobsclose(vgp->vc);
 
75
                vgp->vc = (vconfig_t*)0;
 
76
        }
 
77
}
 
78
 
 
79
static int vc_refresh(vgpane_t *vgp)
 
80
{
 
81
        int                     i;
 
82
        Ppoly_t         **obs;
 
83
 
 
84
        if (vgp->vc == (vconfig_t*)0) {
 
85
                obs = malloc(vgp->Npoly * sizeof(Ppoly_t));
 
86
                for (i= 0; i < vgp->Npoly; i++)
 
87
                        obs[i] = &(vgp->poly[i].boundary);
 
88
                if (NOT(Plegal_arrangement(obs,vgp->Npoly)))
 
89
                        fprintf(stderr,"bad arrangement\n");
 
90
                else
 
91
                        vgp->vc = Pobsopen(obs, vgp->Npoly);
 
92
                free(obs);
 
93
        }
 
94
        return (vgp->vc != 0);
 
95
}
 
96
 
 
97
static void
 
98
dgsprintxy(Tcl_DString *result, int npts, point p[])
 
99
{
 
100
    int i;
 
101
    char buf[20];
 
102
 
 
103
    if (npts != 1) Tcl_DStringStartSublist(result);
 
104
    for (i = 0; i < npts; i++) {
 
105
        sprintf(buf, "%g", p[i].x);
 
106
        Tcl_DStringAppendElement(result, buf);
 
107
        sprintf(buf, "%g", p[i].y);
 
108
        Tcl_DStringAppendElement(result, buf);
 
109
    }
 
110
    if (npts != 1) Tcl_DStringEndSublist(result);
 
111
}
 
112
 
 
113
static void
 
114
expandPercentsEval(
 
115
    Tcl_Interp * interp,     /* interpreter context */
 
116
    register char *before,   /* Command with percent expressions */
 
117
    char *r,                 /* vgpaneHandle string to substitute for "%r" */
 
118
    int npts,                /* number of coordinates */
 
119
    point *ppos              /* Cordinates to substitute for %t */
 
120
)
 
121
{
 
122
    register char  *string;
 
123
    Tcl_DString     scripts;
 
124
 
 
125
    Tcl_DStringInit(&scripts);
 
126
    while (1) {
 
127
        /*
 
128
         * Find everything up to the next % character and append it to the
 
129
         * result string.
 
130
         */
 
131
 
 
132
        for (string = before; (*string != 0) && (*string != '%'); string++) {
 
133
            /* Empty loop body. */
 
134
        }
 
135
        if (string != before) {
 
136
            Tcl_DStringAppend(&scripts, before, string - before);
 
137
            before = string;
 
138
        }
 
139
        if (*before == 0) {
 
140
            break;
 
141
        }
 
142
        /*
 
143
         * There's a percent sequence here.  Process it.
 
144
         */
 
145
 
 
146
        switch (before[1]) {
 
147
        case 'r':
 
148
            Tcl_DStringAppend(&scripts, r, strlen(r));  /* vgcanvasHandle */
 
149
            break;
 
150
        case 't':
 
151
            dgsprintxy(&scripts, npts, ppos);
 
152
            break;
 
153
        default:
 
154
            Tcl_DStringAppend(&scripts, before+1, 1);
 
155
            break;
 
156
        }
 
157
        before += 2;
 
158
    }
 
159
    if (Tcl_GlobalEval(interp, Tcl_DStringValue(&scripts)) != TCL_OK)
 
160
        fprintf(stderr, "%s while in binding: %s\n\n",
 
161
                interp->result, Tcl_DStringValue(&scripts));
 
162
    Tcl_DStringFree(&scripts);
 
163
}
 
164
 
 
165
void
 
166
triangle_callback(void *vgparg, point pqr[])
 
167
{
 
168
    char                vbuf[20];
 
169
        vgpane_t        *vgp;
 
170
 
 
171
        vgp = vgparg;
 
172
 
 
173
/*          TBL_ENTRY((tblHeader_pt)vgpaneTable, (ubyte_pt)vgp));*/
 
174
 
 
175
    if (vgp->triangle_cmd) {
 
176
        sprintf(vbuf, "vgpane%lu", 
 
177
            (unsigned long) (((ubyte_pt)vgp - (vgpaneTable->bodyPtr)) / (vgpaneTable->entrySize)));
 
178
        expandPercentsEval(vgp->interp, vgp->triangle_cmd, vbuf, 3, pqr);
 
179
    }
 
180
}
 
181
 
 
182
static char *
 
183
buildBindings(char *s1, char *s2)
 
184
/*
 
185
 * previous binding in s1 binding to be added in s2 result in s3
 
186
 *
 
187
 * if s2 begins with + then append (separated by \n) else s2 replaces if
 
188
 * resultant string is null then bindings are deleted
 
189
 */
 
190
{
 
191
    char           *s3;
 
192
    int             l;
 
193
 
 
194
    if (s2[0] == '+') {
 
195
        if (s1) {
 
196
            l = strlen(s2) - 1;
 
197
            if (l) {
 
198
                s3 = malloc(strlen(s1) + l + 2);
 
199
                strcpy(s3, s1);
 
200
                strcat(s3, "\n");
 
201
                strcat(s3, s2 + 1);
 
202
                free(s1);
 
203
            } else {
 
204
                s3 = s1;
 
205
            }
 
206
        } else {
 
207
            l = strlen(s2) - 1;
 
208
            if (l) {
 
209
                s3 = malloc(l + 2);
 
210
                strcpy(s3, s2 + 1);
 
211
            } else {
 
212
                s3 = (char *) NULL;
 
213
            }
 
214
        }
 
215
    } else {
 
216
        if (s1)
 
217
            free(s1);
 
218
        l = strlen(s2);
 
219
        if (l) {
 
220
            s3 = malloc(l + 2);
 
221
            strcpy(s3, s2);
 
222
        } else {
 
223
            s3 = (char *) NULL;
 
224
        }
 
225
    }
 
226
    return s3;
 
227
}
 
228
 
 
229
 
 
230
 
 
231
/* convert x and y string args to point */
 
232
static int
 
233
scanpoint (Tcl_Interp *interp, char *argv[], point *p)
 
234
{
 
235
    if (sscanf(argv[0], "%lg", &(p->x)) != 1) {
 
236
        Tcl_AppendResult(interp, "invalid x coordinate: \"", argv[0],
 
237
            "\"", (char *)NULL);
 
238
        return TCL_ERROR;
 
239
    }
 
240
    if (sscanf(argv[1], "%lg", &(p->y)) != 1) {
 
241
        Tcl_AppendResult(interp, "invalid y coordinate: \"", argv[1],
 
242
            "\"", (char *)NULL);
 
243
        return TCL_ERROR;
 
244
    }
 
245
    return TCL_OK;
 
246
}
 
247
 
 
248
static point
 
249
center(point vertex[], int n)
 
250
{
 
251
    int i;
 
252
    point c;
 
253
 
 
254
    c.x = c.y = 0;
 
255
    for (i=0; i<n; i++) {
 
256
        c.x += vertex[i].x;
 
257
        c.y += vertex[i].y;
 
258
    }
 
259
    c.x /= n;
 
260
    c.y /= n;
 
261
    return c;
 
262
}
 
263
 
 
264
static double
 
265
distance(point p, point q)
 
266
{
 
267
    double dx, dy;
 
268
 
 
269
    dx = p.x - q.x;
 
270
    dy = p.y - q.y;
 
271
    return sqrt(dx*dx + dy*dy);
 
272
}
 
273
 
 
274
static point
 
275
rotate(point c, point p, double alpha)
 
276
{
 
277
    point q;
 
278
    double beta, r, sina, cosa;
 
279
 
 
280
    r = distance(c,p);
 
281
    beta = atan2(p.x - c.x, p.y - c.y);
 
282
    sincos(beta+alpha, &sina, &cosa);
 
283
    q.x = c.x +  r * sina;
 
284
    q.y = c.y -  r * cosa; /* adjust for tk y-down */
 
285
    return q;
 
286
}
 
287
 
 
288
static point
 
289
scale(point c, point p, double gain)
 
290
{
 
291
    point q;
 
292
 
 
293
    q.x = c.x + gain * (p.x - c.x);
 
294
    q.y = c.y + gain * (p.y - c.y);
 
295
    return q;
 
296
}
 
297
 
 
298
static int
 
299
remove_poly (vgpane_t *vgp, int polyid)
 
300
{
 
301
    int i, j;
 
302
 
 
303
    for (i=0; i < vgp->Npoly; i++) {
 
304
                if (vgp->poly[i].id == polyid) {
 
305
                        free(vgp->poly[i].boundary.ps);
 
306
                        for (j = i++; i < vgp->Npoly; i++, j++) {
 
307
                                vgp->poly[j] = vgp->poly[i];
 
308
                        }
 
309
                        vgp->Npoly -= 1;
 
310
                        vc_stale(vgp);
 
311
                        return TRUE;
 
312
                }
 
313
    }
 
314
    return FALSE;
 
315
}
 
316
 
 
317
static int
 
318
insert_poly (Tcl_Interp *interp, vgpane_t *vgp, int polyid, char *vargv[], int vargc)
 
319
{
 
320
        poly    *np;
 
321
    int i, result;
 
322
 
 
323
        np = allocpoly(vgp, polyid, vargc);
 
324
    for (i=0; i < vargc; i += 2) {
 
325
        result = scanpoint(interp, &vargv[i], &(np->boundary.ps[np->boundary.pn]));
 
326
        if (result != TCL_OK) return result;
 
327
                np->boundary.pn++;
 
328
    }
 
329
    make_CW(&(np->boundary));
 
330
        vc_stale(vgp);
 
331
    return TCL_OK;
 
332
}
 
333
 
 
334
static void
 
335
make_barriers(vgpane_t *vgp, int pp, int qp, Pedge_t **barriers, int *n_barriers)
 
336
{
 
337
        int             i, j, k, n, b;
 
338
        Pedge_t *bar;
 
339
 
 
340
        n = 0;
 
341
        for (i = 0; i < vgp->Npoly; i++) {
 
342
                if (vgp->poly[i].id == pp) continue;
 
343
                if (vgp->poly[i].id == qp) continue;
 
344
                n = n + vgp->poly[i].boundary.pn;
 
345
        }
 
346
        bar = malloc(n * sizeof(Pedge_t));
 
347
        b = 0;
 
348
        for (i = 0; i < vgp->Npoly; i++) {
 
349
                if (vgp->poly[i].id == pp) continue;
 
350
                if (vgp->poly[i].id == qp) continue;
 
351
                for (j = 0; j < vgp->poly[i].boundary.pn; j++) {
 
352
                        k = j + 1;
 
353
                        if (k >= vgp->poly[i].boundary.pn) k = 0;
 
354
                        bar[b].a = vgp->poly[i].boundary.ps[j];
 
355
                        bar[b].b = vgp->poly[i].boundary.ps[k];
 
356
                        b++;
 
357
                }
 
358
        }
 
359
        assert(b == n);
 
360
        *barriers = bar;
 
361
        *n_barriers = n;
 
362
}
 
363
 
 
364
/* append the x and y coordinates of a point to the Tcl result */
 
365
static void
 
366
appendpoint (Tcl_Interp *interp, point p)
 
367
{
 
368
    char buf[30];
 
369
 
 
370
    sprintf(buf, "%g", p.x);
 
371
    Tcl_AppendElement(interp, buf);
 
372
    sprintf(buf, "%g", p.y);
 
373
    Tcl_AppendElement(interp, buf);
 
374
}
 
375
 
 
376
/* process vgpane methods */
 
377
static int
 
378
vgpanecmd(ClientData clientData, Tcl_Interp * interp, int argc, char *argv[])
 
379
{
 
380
    int              vargc, length, i, j, n, result;
 
381
    char             c, *s, **vargv, vbuf[30];
 
382
    vgpane_t         *vgp, **vgpp;
 
383
    point            p, q, *ps;
 
384
    poly            *tpp;
 
385
    double           alpha, gain;
 
386
        Pvector_t               slopes[2];
 
387
        Ppolyline_t             line, spline;
 
388
        int                             pp, qp;         /* polygon indices for p, q */
 
389
        Pedge_t                 *barriers;
 
390
        int                             n_barriers;
 
391
 
 
392
    if (argc < 2) {
 
393
        Tcl_AppendResult(interp, "wrong # args: should be \"",
 
394
             " ", argv[0], " method ?arg arg ...?\"", (char *) NULL);
 
395
        return TCL_ERROR;
 
396
    }
 
397
    if (!(vgpp = (vgpane_t **)tclhandleXlate(vgpaneTable, argv[0]))) {
 
398
        Tcl_AppendResult(interp, "Invalid handle: \"", argv[0],
 
399
                "\"", (char *) NULL);
 
400
        return TCL_ERROR;
 
401
    }
 
402
        vgp = *vgpp;
 
403
 
 
404
    c = argv[1][0];
 
405
    length = strlen(argv[1]);
 
406
 
 
407
    if ((c == 'c') && (strncmp(argv[1], "coords", length) == 0)) {
 
408
        if ((argc < 3)) {
 
409
            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
 
410
                " ", argv[1], " id ?x1 y1 x2 y2...?\"", (char *) NULL);
 
411
            return TCL_ERROR;
 
412
        }
 
413
        if (sscanf(argv[2], "%d", &polyid) != 1) {
 
414
                        Tcl_AppendResult(interp, "not an integer: ", argv[2],
 
415
                                (char *) NULL);
 
416
                        return TCL_ERROR;
 
417
        }
 
418
                if (argc == 3) {
 
419
                        /* find poly and return its coordinates */
 
420
                        for (i=0; i < vgp->Npoly; i++) {
 
421
                                if (vgp->poly[i].id == polyid) {
 
422
                                        n = vgp->poly[i].boundary.pn;
 
423
                                        for (j = 0; j < n; j++) {
 
424
                                                appendpoint(interp, vgp->poly[i].boundary.ps[j]);
 
425
                                        }
 
426
                                        return TCL_OK;
 
427
                                }
 
428
                        }
 
429
                        Tcl_AppendResult(interp, " no such polygon: ", argv[2],
 
430
                                (char *) NULL);
 
431
                        return TCL_ERROR;
 
432
                }
 
433
                /* accept either inline or delimited list */
 
434
                if ((argc == 4)) {
 
435
                        result = Tcl_SplitList(interp, argv[3], &vargc, &vargv);
 
436
                        if (result != TCL_OK) {return result;}
 
437
                } else {
 
438
                        vargc = argc-3;
 
439
                        vargv = &argv[3];
 
440
                }
 
441
                if (!vargc || vargc%2) {
 
442
                        Tcl_AppendResult(interp, 
 
443
                                "There must be a multiple of two terms in the list.",
 
444
                                (char *) NULL);
 
445
                        return TCL_ERROR;
 
446
                }
 
447
 
 
448
                /* remove old poly, add modified polygon to the end with 
 
449
                   the same id as the original */
 
450
 
 
451
                if (! (remove_poly(vgp, polyid))) {
 
452
                        Tcl_AppendResult(interp, " no such polygon: ", argv[2],
 
453
                                (char *) NULL);
 
454
                        return TCL_ERROR;
 
455
                }
 
456
 
 
457
        return (insert_poly(interp, vgp, polyid, vargv, vargc));
 
458
 
 
459
    } else if ((c == 'd') && (strncmp(argv[1], "debug", length) == 0)) {
 
460
                /* debug only */
 
461
                printf("debug output goes here\n");
 
462
                return TCL_OK;
 
463
 
 
464
    } else if ((c == 'd') && (strncmp(argv[1], "delete", length) == 0)) {
 
465
                /* delete a vgpane and all memory associated with it */
 
466
                if (vgp->vc) Pobsclose(vgp->vc);
 
467
                free(vgp->poly);        /* ### */
 
468
                Tcl_DeleteCommand(interp, argv[0]);
 
469
                free((char *)tclhandleFree(vgpaneTable, argv[0]));
 
470
        return TCL_OK;
 
471
 
 
472
    } else if ((c == 'f') && (strncmp(argv[1], "find", length) == 0)) {
 
473
                /* find the polygon that the point is inside and return it
 
474
                   id, or null */
 
475
                if ((argc < 3)) {
 
476
                        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
 
477
                                " ", argv[1], " x y\"", (char *) NULL);
 
478
                        return TCL_ERROR;
 
479
        }
 
480
                if (argc == 3) {
 
481
                        result = Tcl_SplitList(interp, argv[2], &vargc, &vargv);
 
482
                        if (result != TCL_OK) {return result;}
 
483
                } else {
 
484
                        vargc = argc-2;
 
485
                        vargv = &argv[2];
 
486
                }
 
487
                result = scanpoint(interp, &vargv[0], &p);
 
488
                if (result != TCL_OK) return result;
 
489
 
 
490
                /* determine the polygons (if any) that contain the point */
 
491
                for (i = 0; i < vgp->Npoly; i++) {
 
492
                        if (in_poly(vgp->poly[i].boundary, p)) {
 
493
                                sprintf(vbuf, "%d", vgp->poly[i].id);
 
494
                                Tcl_AppendElement(interp, vbuf);
 
495
                        }
 
496
                }
 
497
                return TCL_OK;
 
498
 
 
499
        } else if ((c == 'i') && (strncmp(argv[1], "insert", length) == 0)) {
 
500
                /* add poly to end poly list, and it coordinates to the end of 
 
501
                   the point list */
 
502
                if ((argc < 3)) {
 
503
                        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
 
504
                                " ", argv[1], " x1 y1 x2 y2 ...\"", (char *) NULL);
 
505
                        return TCL_ERROR;
 
506
                }
 
507
                /* accept either inline or delimited list */
 
508
                if ((argc == 3)) {
 
509
                        result = Tcl_SplitList(interp, argv[2], &vargc, &vargv);
 
510
                        if (result != TCL_OK) {return result;}
 
511
                } else {
 
512
                        vargc = argc-2;
 
513
                        vargv = &argv[2];
 
514
                }
 
515
 
 
516
                if (!vargc || vargc%2) {
 
517
                        Tcl_AppendResult(interp, 
 
518
                                "There must be a multiple of two terms in the list.",
 
519
                                (char *) NULL);
 
520
                        return TCL_ERROR;
 
521
                }
 
522
 
 
523
                polyid++;
 
524
 
 
525
                result = insert_poly(interp, vgp, polyid, vargv, vargc);
 
526
                if (result != TCL_OK) return result;
 
527
 
 
528
                sprintf(vbuf, "%d", polyid);
 
529
                Tcl_AppendResult(interp, vbuf, (char *) NULL);
 
530
                return TCL_OK;
 
531
 
 
532
        } else if ((c == 'l') && (strncmp(argv[1], "list", length) == 0)) {
 
533
                /* return list of polygon ids */
 
534
                for (i = 0; i < vgp->Npoly; i++) {
 
535
                        sprintf(vbuf, "%d", vgp->poly[i].id);
 
536
                        Tcl_AppendElement(interp, vbuf);
 
537
                }
 
538
                return TCL_OK;
 
539
 
 
540
        } else if ((c == 'p') && (strncmp(argv[1], "path", length) == 0)) {
 
541
                /* return a list of points corresponding to the shortest path
 
542
                   that does not cross the remaining "visible" polygons. */
 
543
        if ((argc < 3)) {
 
544
                        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
 
545
                                " ", argv[1], " x1 y1 x2 y2\"", (char *) NULL);
 
546
                        return TCL_ERROR;
 
547
        }
 
548
                if (argc == 3) {
 
549
            result = Tcl_SplitList(interp, argv[2], &vargc, &vargv);
 
550
            if (result != TCL_OK) {return result;}
 
551
                } else {
 
552
                        vargc = argc-2;
 
553
                        vargv = &argv[2];
 
554
        }
 
555
        if ((vargc < 4)) {
 
556
                        Tcl_AppendResult(interp,
 
557
                                "invalid points: should be: \"x1 y1 x2 y2\"",
 
558
                                (char *) NULL);
 
559
                        return TCL_ERROR;
 
560
        }
 
561
                result = scanpoint(interp, &vargv[0], &p);
 
562
                if (result != TCL_OK) return result;
 
563
                result = scanpoint(interp, &vargv[2], &q);
 
564
                if (result != TCL_OK) return result;
 
565
 
 
566
                /* only recompute the visibility graph if we have to */
 
567
                if ((vc_refresh(vgp))) {
 
568
                        Pobspath(vgp->vc, p, POLYID_UNKNOWN, q, POLYID_UNKNOWN, &line);
 
569
 
 
570
                        for (i = 0; i < line.pn; i++) {
 
571
                                appendpoint(interp, line.ps[i]);
 
572
                        }
 
573
                }
 
574
                
 
575
                return TCL_OK;
 
576
 
 
577
   } else if ((c == 'b') && (strncmp(argv[1], "bind", length) == 0)) {
 
578
        if ((argc < 2) || (argc > 4)) {
 
579
            Tcl_AppendResult(interp, "wrong # args: should be \"",
 
580
                 argv[0], " bind triangle ?command?\"", (char *) NULL);
 
581
            return TCL_ERROR;
 
582
        }
 
583
        if (argc == 2) {
 
584
            Tcl_AppendElement(interp, "triangle");
 
585
            return TCL_OK;
 
586
        }
 
587
        length = strlen(argv[2]);
 
588
        if (strncmp(argv[2], "triangle", length) == 0) {
 
589
            s = vgp->triangle_cmd;
 
590
            if (argc == 4) vgp->triangle_cmd = s = buildBindings(s, argv[3]) ;
 
591
        } else {
 
592
            Tcl_AppendResult(interp, "unknown event \"", argv[2],
 
593
                 "\": must be one of:\n\ttriangle.", (char *) NULL);
 
594
            return TCL_ERROR;
 
595
        }
 
596
        if (argc == 3) Tcl_AppendResult(interp, s, (char *) NULL);
 
597
        return TCL_OK;
 
598
 
 
599
   } else if ((c == 'b') && (strncmp(argv[1], "bpath", length) == 0)) {
 
600
        /* return a list of points corresponding to the shortest path
 
601
           that does not cross the remaining "visible" polygons. */
 
602
        if ((argc < 3)) {
 
603
                        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
 
604
                                " ", argv[1], " x1 y1 x2 y2\"", (char *) NULL);
 
605
                        return TCL_ERROR;
 
606
        }
 
607
                if (argc == 3) {
 
608
            result = Tcl_SplitList(interp, argv[2], &vargc, &vargv);
 
609
            if (result != TCL_OK) {return result;}
 
610
                } else {
 
611
                        vargc = argc-2;
 
612
                        vargv = &argv[2];
 
613
        }
 
614
        if ((vargc < 4)) {
 
615
                        Tcl_AppendResult(interp,
 
616
                                "invalid points: should be: \"x1 y1 x2 y2\"",
 
617
                                (char *) NULL);
 
618
                        return TCL_ERROR;
 
619
        }
 
620
 
 
621
                result = scanpoint(interp, &vargv[0], &p);
 
622
                if (result != TCL_OK) return result;
 
623
                result = scanpoint(interp, &vargv[2], &q);
 
624
                if (result != TCL_OK) return result;
 
625
 
 
626
                /* determine the polygons (if any) that contain the endpoints */
 
627
                pp = qp = POLYID_NONE;
 
628
                for (i = 0; i < vgp->Npoly; i++) {
 
629
                        tpp = &(vgp->poly[i]);
 
630
                        if ((pp == POLYID_NONE) && in_poly(tpp->boundary, p)) pp = i;
 
631
                        if ((qp == POLYID_NONE) && in_poly(tpp->boundary, q)) qp = i;
 
632
                }
 
633
        
 
634
                if (vc_refresh(vgp)) {
 
635
                        /*Pobspath(vgp->vc, p, pp, q, qp, &line);*/
 
636
                        Pobspath(vgp->vc, p, POLYID_UNKNOWN, q, POLYID_UNKNOWN, &line);
 
637
                        make_barriers(vgp, pp, qp, &barriers, &n_barriers);
 
638
                        slopes[0].x = slopes[0].y = 0.0;
 
639
                        slopes[1].x = slopes[1].y = 0.0;
 
640
                        Proutespline (barriers, n_barriers, line, slopes, &spline);
 
641
 
 
642
                        for (i = 0; i < spline.pn; i++) {
 
643
                                appendpoint(interp, spline.ps[i]);
 
644
                        }
 
645
                }
 
646
                return TCL_OK;
 
647
 
 
648
    } else if ((c == 'b') && (strncmp(argv[1], "bbox", length) == 0)) {
 
649
        if ((argc < 3)) {
 
650
                        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
 
651
                                " ", argv[1], " id\"", (char *) NULL);
 
652
                        return TCL_ERROR;
 
653
                }
 
654
                if (sscanf(argv[2], "%d", &polyid) != 1) {
 
655
                        Tcl_AppendResult(interp, "not an integer: ", argv[2],
 
656
                                (char *) NULL);
 
657
                        return TCL_ERROR;
 
658
                }
 
659
                for (i=0; i < vgp->Npoly; i++) {
 
660
                        if (vgp->poly[i].id == polyid) {
 
661
                                Ppoly_t pp = vgp->poly[i].boundary;
 
662
                                point   LL, UR;
 
663
                                LL = UR = pp.ps[0];
 
664
                                for (j = 1; j < pp.pn; j++) {
 
665
                                        p = pp.ps[j];
 
666
                                        if (p.x > UR.x) UR.x = p.x;
 
667
                                        if (p.y > UR.y) UR.y = p.y;
 
668
                                        if (p.x < LL.x) LL.x = p.x;
 
669
                                        if (p.y < LL.y) LL.y = p.y;
 
670
                                }
 
671
                                appendpoint(interp, LL);
 
672
                                appendpoint(interp, UR);
 
673
                                return TCL_OK;
 
674
                        }
 
675
                }
 
676
                Tcl_AppendResult(interp, " no such polygon: ", argv[2],
 
677
                        (char *) NULL);
 
678
                return TCL_ERROR;
 
679
 
 
680
    } else if ((c == 'c') && (strncmp(argv[1], "center", length) == 0)) {
 
681
        if ((argc < 3)) {
 
682
                        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
 
683
                                " ", argv[1], " id\"", (char *) NULL);
 
684
                        return TCL_ERROR;
 
685
        }
 
686
        if (sscanf(argv[2], "%d", &polyid) != 1) {
 
687
                        Tcl_AppendResult(interp, "not an integer: ", argv[2],
 
688
                                (char *) NULL);
 
689
                        return TCL_ERROR;
 
690
        }
 
691
                for (i=0; i < vgp->Npoly; i++) {
 
692
                        if (vgp->poly[i].id == polyid) {
 
693
                                appendpoint(interp, center(vgp->poly[i].boundary.ps,
 
694
                                        vgp->poly[i].boundary.pn));
 
695
                                return TCL_OK;
 
696
                        }
 
697
        }
 
698
        Tcl_AppendResult(interp, " no such polygon: ", argv[2],
 
699
                        (char *) NULL);
 
700
        return TCL_ERROR;
 
701
 
 
702
        } else if ((c == 't') && (strncmp(argv[1], "triangulate", length) == 0)) {
 
703
        if ((argc < 2)) {
 
704
                        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
 
705
                                " id ", (char *) NULL);
 
706
                        return TCL_ERROR;
 
707
        }
 
708
 
 
709
        if (sscanf(argv[2], "%d", &polyid) != 1) {
 
710
                        Tcl_AppendResult(interp, "not an integer: ", argv[2],
 
711
                                (char *) NULL);
 
712
                        return TCL_ERROR;
 
713
        }
 
714
 
 
715
                for (i=0; i < vgp->Npoly; i++) {
 
716
                        if (vgp->poly[i].id == polyid) {
 
717
                                Ptriangulate(&(vgp->poly[i].boundary),triangle_callback,vgp);
 
718
                                return TCL_OK;
 
719
                        }
 
720
                }
 
721
                Tcl_AppendResult(interp, " no such polygon: ", argv[2], (char *) NULL);
 
722
        return TCL_ERROR;
 
723
    } else if ((c == 'r') && (strncmp(argv[1], "rotate", length) == 0)) {
 
724
        if ((argc < 4)) {
 
725
                        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
 
726
                                " ", argv[1], " id alpha\"", (char *) NULL);
 
727
                        return TCL_ERROR;
 
728
        }
 
729
        if (sscanf(argv[2], "%d", &polyid) != 1) {
 
730
                        Tcl_AppendResult(interp, "not an integer: ", argv[2],
 
731
                                (char *) NULL);
 
732
                        return TCL_ERROR;
 
733
        }
 
734
        if (sscanf(argv[3], "%lg", &alpha) != 1) {
 
735
                        Tcl_AppendResult(interp, "not an angle in radians: ", argv[3],
 
736
                                (char *) NULL);
 
737
                        return TCL_ERROR;
 
738
        }
 
739
                for (i=0; i < vgp->Npoly; i++) {
 
740
                        if (vgp->poly[i].id == polyid) {
 
741
                                n = vgp->poly[i].boundary.pn;
 
742
                                ps = vgp->poly[i].boundary.ps;
 
743
                                p = center(ps, n);
 
744
                                for (j = 0; j < n; j++) {
 
745
                                        appendpoint(interp, rotate(p, ps[j], alpha));
 
746
                                }
 
747
                                return TCL_OK;
 
748
                        }
 
749
        }
 
750
        Tcl_AppendResult(interp, " no such polygon: ", argv[2],
 
751
            (char *) NULL);
 
752
        return TCL_ERROR;
 
753
 
 
754
    } else if ((c == 's') && (strncmp(argv[1], "scale", length) == 0)) {
 
755
        if ((argc < 4)) {
 
756
                        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
 
757
                                " ", argv[1], " id gain\"", (char *) NULL);
 
758
                        return TCL_ERROR;
 
759
        }
 
760
        if (sscanf(argv[2], "%d", &polyid) != 1) {
 
761
                        Tcl_AppendResult(interp, "not an integer: ", argv[2],
 
762
                                (char *) NULL);
 
763
                        return TCL_ERROR;
 
764
        }
 
765
        if (sscanf(argv[3], "%lg", &gain) != 1) {
 
766
                        Tcl_AppendResult(interp, "not a number: ", argv[3],
 
767
                                (char *) NULL);
 
768
                        return TCL_ERROR;
 
769
        }
 
770
                for (i=0; i < vgp->Npoly; i++) {
 
771
                        if (vgp->poly[i].id == polyid) {
 
772
                                n = vgp->poly[i].boundary.pn;
 
773
                                ps = vgp->poly[i].boundary.ps;
 
774
                                for (j = 0; j < n; j++) {
 
775
                                        appendpoint(interp, scale(p, ps[j], gain));
 
776
                                }
 
777
                                return TCL_OK;
 
778
                        }
 
779
        }
 
780
        Tcl_AppendResult(interp, " no such polygon: ", argv[2],
 
781
                        (char *) NULL);
 
782
        return TCL_ERROR;
 
783
 
 
784
    } else if ((c == 'r') && (strncmp(argv[1], "remove", length) == 0)) {
 
785
        if ((argc < 3)) {
 
786
                        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
 
787
                                " ", argv[1], " id\"", (char *) NULL);
 
788
                        return TCL_ERROR;
 
789
        }
 
790
        if (sscanf(argv[2], "%d", &polyid) != 1) {
 
791
                        Tcl_AppendResult(interp, "not an integer: ", argv[2],
 
792
                                (char *) NULL);
 
793
                        return TCL_ERROR;
 
794
        }
 
795
 
 
796
                if (remove_poly(vgp, polyid))
 
797
                        return TCL_OK;
 
798
 
 
799
        Tcl_AppendResult(interp, " no such polygon: ", argv[2],
 
800
                (char *) NULL);
 
801
        return TCL_ERROR;
 
802
    }
 
803
 
 
804
    Tcl_AppendResult(interp, "bad method \"", argv[1], "\" must be one of:",
 
805
        "\n\tbbox, bind, bpath, center, coords, delete, find,",
 
806
        "\n\tinsert, list, path, remove, rotate, scale, triangulate.", (char *) NULL);
 
807
    return TCL_ERROR;
 
808
}
 
809
 
 
810
static int
 
811
vgpane(ClientData clientData, Tcl_Interp * interp, int argc, char *argv[])
 
812
{
 
813
    char        vbuf[30];
 
814
    vgpane_t    *vgp;
 
815
 
 
816
        vgp = (vgpane_t *)malloc(sizeof(vgpane_t));
 
817
    *(vgpane_t **)tclhandleAlloc(vgpaneTable, vbuf, NULL) = vgp; 
 
818
 
 
819
        vgp->vc = (vconfig_t*)0;
 
820
    vgp->Npoly = 0;
 
821
    vgp->N_poly_alloc = 250;
 
822
    vgp->poly = malloc(vgp->N_poly_alloc * sizeof(poly));
 
823
    vgp->interp = interp;
 
824
    vgp->triangle_cmd = (char *) NULL;
 
825
 
 
826
    Tcl_CreateCommand(interp, vbuf, vgpanecmd, (ClientData) NULL,
 
827
        (Tcl_CmdDeleteProc *) NULL);
 
828
    Tcl_AppendResult(interp, vbuf, (char *) NULL);
 
829
    return TCL_OK;
 
830
}
 
831
 
 
832
int Tclpathplan_Init(Tcl_Interp * interp)
 
833
{
 
834
#ifdef USE_TCL_STUBS
 
835
        if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
 
836
                return TCL_ERROR;
 
837
        }
 
838
#else
 
839
    if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 0) == NULL) {
 
840
                return TCL_ERROR;
 
841
    }
 
842
#endif
 
843
    if (Tcl_PkgProvide(interp, "Tclpathplan", VERSION) != TCL_OK) {
 
844
                return TCL_ERROR;
 
845
    }
 
846
 
 
847
    Tcl_CreateCommand(interp, "vgpane", vgpane, (ClientData) NULL,
 
848
                (Tcl_CmdDeleteProc *) NULL);
 
849
 
 
850
    vgpaneTable = tclhandleInit("vgpane", sizeof(vgpane_t), 10);
 
851
 
 
852
    return TCL_OK;
 
853
}
 
854
 
 
855
int Tclpathplan_SafeInit(Tcl_Interp * interp)
 
856
{
 
857
    return Tclpathplan_Init(interp);
 
858
}