#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#define USE_NON_CONST
#define _GNU_SOURCE 1
#ifdef HAVE_AST
#include <ast.h>
#include <vmalloc.h>
#else
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#endif
#include <assert.h>
#include <math.h>
#include <pathutil.h>
#include <vispath.h>
#include <tri.h>
#include <tcl.h>
#include "tclhandle.h"
#ifndef CONST84
#define CONST84
#endif
typedef Ppoint_t point;
typedef struct poly_s {
int id;
Ppoly_t boundary;
} poly;
typedef struct vgpane_s {
int Npoly;
poly *poly;
int N_poly_alloc;
vconfig_t *vc;
Tcl_Interp *interp;
char *triangle_cmd;
} vgpane_t;
#ifndef HAVE_SINCOS
# define sincos(x,s,c) *s = sin(x); *c = cos(x)
#endif
tblHeader_pt vgpaneTable;
extern void make_CW(Ppoly_t *poly);
extern int Plegal_arrangement( Ppoly_t **polys, int n_polys);
static int polyid=0;
static poly *allocpoly(vgpane_t *vgp, int id, int npts)
{
poly *rv;
if (vgp->Npoly >= vgp->N_poly_alloc) {
vgp->N_poly_alloc *= 2;
vgp->poly = realloc(vgp->poly,vgp->N_poly_alloc*sizeof(poly));
}
rv = &(vgp->poly[vgp->Npoly++]);
rv->id = id;
rv->boundary.pn = 0;
rv->boundary.ps = malloc(npts * sizeof(point));
return rv;
}
static void vc_stale(vgpane_t *vgp)
{
if (vgp->vc) {
Pobsclose(vgp->vc);
vgp->vc = (vconfig_t*)0;
}
}
static int vc_refresh(vgpane_t *vgp)
{
int i;
Ppoly_t **obs;
if (vgp->vc == (vconfig_t*)0) {
obs = malloc(vgp->Npoly * sizeof(Ppoly_t));
for (i= 0; i < vgp->Npoly; i++)
obs[i] = &(vgp->poly[i].boundary);
if (NOT(Plegal_arrangement(obs,vgp->Npoly)))
fprintf(stderr,"bad arrangement\n");
else
vgp->vc = Pobsopen(obs, vgp->Npoly);
free(obs);
}
return (vgp->vc != 0);
}
static void
dgsprintxy(Tcl_DString *result, int npts, point p[])
{
int i;
char buf[20];
if (npts != 1) Tcl_DStringStartSublist(result);
for (i = 0; i < npts; i++) {
sprintf(buf, "%g", p[i].x);
Tcl_DStringAppendElement(result, buf);
sprintf(buf, "%g", p[i].y);
Tcl_DStringAppendElement(result, buf);
}
if (npts != 1) Tcl_DStringEndSublist(result);
}
static void
expandPercentsEval(
Tcl_Interp * interp,
register char *before,
char *r,
int npts,
point *ppos
)
{
register char *string;
Tcl_DString scripts;
Tcl_DStringInit(&scripts);
while (1) {
for (string = before; (*string != 0) && (*string != '%'); string++) {
}
if (string != before) {
Tcl_DStringAppend(&scripts, before, string - before);
before = string;
}
if (*before == 0) {
break;
}
switch (before[1]) {
case 'r':
Tcl_DStringAppend(&scripts, r, strlen(r));
break;
case 't':
dgsprintxy(&scripts, npts, ppos);
break;
default:
Tcl_DStringAppend(&scripts, before+1, 1);
break;
}
before += 2;
}
if (Tcl_GlobalEval(interp, Tcl_DStringValue(&scripts)) != TCL_OK)
fprintf(stderr, "%s while in binding: %s\n\n",
interp->result, Tcl_DStringValue(&scripts));
Tcl_DStringFree(&scripts);
}
void
triangle_callback(void *vgparg, point pqr[])
{
char vbuf[20];
vgpane_t *vgp;
vgp = vgparg;
if (vgp->triangle_cmd) {
sprintf(vbuf, "vgpane%lu",
(unsigned long) (((ubyte_pt)vgp - (vgpaneTable->bodyPtr)) / (vgpaneTable->entrySize)));
expandPercentsEval(vgp->interp, vgp->triangle_cmd, vbuf, 3, pqr);
}
}
static char *
buildBindings(char *s1, char *s2)
{
char *s3;
int l;
if (s2[0] == '+') {
if (s1) {
l = strlen(s2) - 1;
if (l) {
s3 = malloc(strlen(s1) + l + 2);
strcpy(s3, s1);
strcat(s3, "\n");
strcat(s3, s2 + 1);
free(s1);
} else {
s3 = s1;
}
} else {
l = strlen(s2) - 1;
if (l) {
s3 = malloc(l + 2);
strcpy(s3, s2 + 1);
} else {
s3 = (char *) NULL;
}
}
} else {
if (s1)
free(s1);
l = strlen(s2);
if (l) {
s3 = malloc(l + 2);
strcpy(s3, s2);
} else {
s3 = (char *) NULL;
}
}
return s3;
}
static int
scanpoint (Tcl_Interp *interp, char *argv[], point *p)
{
if (sscanf(argv[0], "%lg", &(p->x)) != 1) {
Tcl_AppendResult(interp, "invalid x coordinate: \"", argv[0],
"\"", (char *)NULL);
return TCL_ERROR;
}
if (sscanf(argv[1], "%lg", &(p->y)) != 1) {
Tcl_AppendResult(interp, "invalid y coordinate: \"", argv[1],
"\"", (char *)NULL);
return TCL_ERROR;
}
return TCL_OK;
}
static point
center(point vertex[], int n)
{
int i;
point c;
c.x = c.y = 0;
for (i=0; i<n; i++) {
c.x += vertex[i].x;
c.y += vertex[i].y;
}
c.x /= n;
c.y /= n;
return c;
}
static double
distance(point p, point q)
{
double dx, dy;
dx = p.x - q.x;
dy = p.y - q.y;
return sqrt(dx*dx + dy*dy);
}
static point
rotate(point c, point p, double alpha)
{
point q;
double beta, r, sina, cosa;
r = distance(c,p);
beta = atan2(p.x - c.x, p.y - c.y);
sincos(beta+alpha, &sina, &cosa);
q.x = c.x + r * sina;
q.y = c.y - r * cosa;
return q;
}
static point
scale(point c, point p, double gain)
{
point q;
q.x = c.x + gain * (p.x - c.x);
q.y = c.y + gain * (p.y - c.y);
return q;
}
static int
remove_poly (vgpane_t *vgp, int polyid)
{
int i, j;
for (i=0; i < vgp->Npoly; i++) {
if (vgp->poly[i].id == polyid) {
free(vgp->poly[i].boundary.ps);
for (j = i++; i < vgp->Npoly; i++, j++) {
vgp->poly[j] = vgp->poly[i];
}
vgp->Npoly -= 1;
vc_stale(vgp);
return TRUE;
}
}
return FALSE;
}
static int
insert_poly (Tcl_Interp *interp, vgpane_t *vgp, int polyid, char *vargv[], int vargc)
{
poly *np;
int i, result;
np = allocpoly(vgp, polyid, vargc);
for (i=0; i < vargc; i += 2) {
result = scanpoint(interp, &vargv[i], &(np->boundary.ps[np->boundary.pn]));
if (result != TCL_OK) return result;
np->boundary.pn++;
}
make_CW(&(np->boundary));
vc_stale(vgp);
return TCL_OK;
}
static void
make_barriers(vgpane_t *vgp, int pp, int qp, Pedge_t **barriers, int *n_barriers)
{
int i, j, k, n, b;
Pedge_t *bar;
n = 0;
for (i = 0; i < vgp->Npoly; i++) {
if (vgp->poly[i].id == pp) continue;
if (vgp->poly[i].id == qp) continue;
n = n + vgp->poly[i].boundary.pn;
}
bar = malloc(n * sizeof(Pedge_t));
b = 0;
for (i = 0; i < vgp->Npoly; i++) {
if (vgp->poly[i].id == pp) continue;
if (vgp->poly[i].id == qp) continue;
for (j = 0; j < vgp->poly[i].boundary.pn; j++) {
k = j + 1;
if (k >= vgp->poly[i].boundary.pn) k = 0;
bar[b].a = vgp->poly[i].boundary.ps[j];
bar[b].b = vgp->poly[i].boundary.ps[k];
b++;
}
}
assert(b == n);
*barriers = bar;
*n_barriers = n;
}
static void
appendpoint (Tcl_Interp *interp, point p)
{
char buf[30];
sprintf(buf, "%g", p.x);
Tcl_AppendElement(interp, buf);
sprintf(buf, "%g", p.y);
Tcl_AppendElement(interp, buf);
}
static int
vgpanecmd(ClientData clientData, Tcl_Interp * interp, int argc, char *argv[])
{
int vargc, length, i, j, n, result;
char c, *s, **vargv, vbuf[30];
vgpane_t *vgp, **vgpp;
point p, q, *ps;
poly *tpp;
double alpha, gain;
Pvector_t slopes[2];
Ppolyline_t line, spline;
int pp, qp;
Pedge_t *barriers;
int n_barriers;
if (argc < 2) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
" ", argv[0], " method ?arg arg ...?\"", (char *) NULL);
return TCL_ERROR;
}
if (!(vgpp = (vgpane_t **)tclhandleXlate(vgpaneTable, argv[0]))) {
Tcl_AppendResult(interp, "Invalid handle: \"", argv[0],
"\"", (char *) NULL);
return TCL_ERROR;
}
vgp = *vgpp;
c = argv[1][0];
length = strlen(argv[1]);
if ((c == 'c') && (strncmp(argv[1], "coords", length) == 0)) {
if ((argc < 3)) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ", argv[1], " id ?x1 y1 x2 y2...?\"", (char *) NULL);
return TCL_ERROR;
}
if (sscanf(argv[2], "%d", &polyid) != 1) {
Tcl_AppendResult(interp, "not an integer: ", argv[2],
(char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
for (i=0; i < vgp->Npoly; i++) {
if (vgp->poly[i].id == polyid) {
n = vgp->poly[i].boundary.pn;
for (j = 0; j < n; j++) {
appendpoint(interp, vgp->poly[i].boundary.ps[j]);
}
return TCL_OK;
}
}
Tcl_AppendResult(interp, " no such polygon: ", argv[2],
(char *) NULL);
return TCL_ERROR;
}
if ((argc == 4)) {
result = Tcl_SplitList(interp, argv[3], &vargc, (CONST84 char ***) &vargv);
if (result != TCL_OK) {return result;}
} else {
vargc = argc-3;
vargv = &argv[3];
}
if (!vargc || vargc%2) {
Tcl_AppendResult(interp,
"There must be a multiple of two terms in the list.",
(char *) NULL);
return TCL_ERROR;
}
if (! (remove_poly(vgp, polyid))) {
Tcl_AppendResult(interp, " no such polygon: ", argv[2],
(char *) NULL);
return TCL_ERROR;
}
return (insert_poly(interp, vgp, polyid, vargv, vargc));
} else if ((c == 'd') && (strncmp(argv[1], "debug", length) == 0)) {
printf("debug output goes here\n");
return TCL_OK;
} else if ((c == 'd') && (strncmp(argv[1], "delete", length) == 0)) {
if (vgp->vc) Pobsclose(vgp->vc);
free(vgp->poly);
Tcl_DeleteCommand(interp, argv[0]);
free((char *)tclhandleFree(vgpaneTable, argv[0]));
return TCL_OK;
} else if ((c == 'f') && (strncmp(argv[1], "find", length) == 0)) {
if ((argc < 3)) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ", argv[1], " x y\"", (char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
result = Tcl_SplitList(interp, argv[2], &vargc, (CONST84 char ***) &vargv);
if (result != TCL_OK) {return result;}
} else {
vargc = argc-2;
vargv = &argv[2];
}
result = scanpoint(interp, &vargv[0], &p);
if (result != TCL_OK) return result;
for (i = 0; i < vgp->Npoly; i++) {
if (in_poly(vgp->poly[i].boundary, p)) {
sprintf(vbuf, "%d", vgp->poly[i].id);
Tcl_AppendElement(interp, vbuf);
}
}
return TCL_OK;
} else if ((c == 'i') && (strncmp(argv[1], "insert", length) == 0)) {
if ((argc < 3)) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ", argv[1], " x1 y1 x2 y2 ...\"", (char *) NULL);
return TCL_ERROR;
}
if ((argc == 3)) {
result = Tcl_SplitList(interp, argv[2], &vargc, (CONST84 char ***) &vargv);
if (result != TCL_OK) {return result;}
} else {
vargc = argc-2;
vargv = &argv[2];
}
if (!vargc || vargc%2) {
Tcl_AppendResult(interp,
"There must be a multiple of two terms in the list.",
(char *) NULL);
return TCL_ERROR;
}
polyid++;
result = insert_poly(interp, vgp, polyid, vargv, vargc);
if (result != TCL_OK) return result;
sprintf(vbuf, "%d", polyid);
Tcl_AppendResult(interp, vbuf, (char *) NULL);
return TCL_OK;
} else if ((c == 'l') && (strncmp(argv[1], "list", length) == 0)) {
for (i = 0; i < vgp->Npoly; i++) {
sprintf(vbuf, "%d", vgp->poly[i].id);
Tcl_AppendElement(interp, vbuf);
}
return TCL_OK;
} else if ((c == 'p') && (strncmp(argv[1], "path", length) == 0)) {
if ((argc < 3)) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ", argv[1], " x1 y1 x2 y2\"", (char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
result = Tcl_SplitList(interp, argv[2], &vargc, (CONST84 char ***) &vargv);
if (result != TCL_OK) {return result;}
} else {
vargc = argc-2;
vargv = &argv[2];
}
if ((vargc < 4)) {
Tcl_AppendResult(interp,
"invalid points: should be: \"x1 y1 x2 y2\"",
(char *) NULL);
return TCL_ERROR;
}
result = scanpoint(interp, &vargv[0], &p);
if (result != TCL_OK) return result;
result = scanpoint(interp, &vargv[2], &q);
if (result != TCL_OK) return result;
if ((vc_refresh(vgp))) {
Pobspath(vgp->vc, p, POLYID_UNKNOWN, q, POLYID_UNKNOWN, &line);
for (i = 0; i < line.pn; i++) {
appendpoint(interp, line.ps[i]);
}
}
return TCL_OK;
} else if ((c == 'b') && (strncmp(argv[1], "bind", length) == 0)) {
if ((argc < 2) || (argc > 4)) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " bind triangle ?command?\"", (char *) NULL);
return TCL_ERROR;
}
if (argc == 2) {
Tcl_AppendElement(interp, "triangle");
return TCL_OK;
}
length = strlen(argv[2]);
if (strncmp(argv[2], "triangle", length) == 0) {
s = vgp->triangle_cmd;
if (argc == 4) vgp->triangle_cmd = s = buildBindings(s, argv[3]) ;
} else {
Tcl_AppendResult(interp, "unknown event \"", argv[2],
"\": must be one of:\n\ttriangle.", (char *) NULL);
return TCL_ERROR;
}
if (argc == 3) Tcl_AppendResult(interp, s, (char *) NULL);
return TCL_OK;
} else if ((c == 'b') && (strncmp(argv[1], "bpath", length) == 0)) {
if ((argc < 3)) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ", argv[1], " x1 y1 x2 y2\"", (char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
result = Tcl_SplitList(interp, argv[2], &vargc, (CONST84 char ***) &vargv);
if (result != TCL_OK) {return result;}
} else {
vargc = argc-2;
vargv = &argv[2];
}
if ((vargc < 4)) {
Tcl_AppendResult(interp,
"invalid points: should be: \"x1 y1 x2 y2\"",
(char *) NULL);
return TCL_ERROR;
}
result = scanpoint(interp, &vargv[0], &p);
if (result != TCL_OK) return result;
result = scanpoint(interp, &vargv[2], &q);
if (result != TCL_OK) return result;
pp = qp = POLYID_NONE;
for (i = 0; i < vgp->Npoly; i++) {
tpp = &(vgp->poly[i]);
if ((pp == POLYID_NONE) && in_poly(tpp->boundary, p)) pp = i;
if ((qp == POLYID_NONE) && in_poly(tpp->boundary, q)) qp = i;
}
if (vc_refresh(vgp)) {
Pobspath(vgp->vc, p, POLYID_UNKNOWN, q, POLYID_UNKNOWN, &line);
make_barriers(vgp, pp, qp, &barriers, &n_barriers);
slopes[0].x = slopes[0].y = 0.0;
slopes[1].x = slopes[1].y = 0.0;
Proutespline (barriers, n_barriers, line, slopes, &spline);
for (i = 0; i < spline.pn; i++) {
appendpoint(interp, spline.ps[i]);
}
}
return TCL_OK;
} else if ((c == 'b') && (strncmp(argv[1], "bbox", length) == 0)) {
if ((argc < 3)) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ", argv[1], " id\"", (char *) NULL);
return TCL_ERROR;
}
if (sscanf(argv[2], "%d", &polyid) != 1) {
Tcl_AppendResult(interp, "not an integer: ", argv[2],
(char *) NULL);
return TCL_ERROR;
}
for (i=0; i < vgp->Npoly; i++) {
if (vgp->poly[i].id == polyid) {
Ppoly_t pp = vgp->poly[i].boundary;
point LL, UR;
LL = UR = pp.ps[0];
for (j = 1; j < pp.pn; j++) {
p = pp.ps[j];
if (p.x > UR.x) UR.x = p.x;
if (p.y > UR.y) UR.y = p.y;
if (p.x < LL.x) LL.x = p.x;
if (p.y < LL.y) LL.y = p.y;
}
appendpoint(interp, LL);
appendpoint(interp, UR);
return TCL_OK;
}
}
Tcl_AppendResult(interp, " no such polygon: ", argv[2],
(char *) NULL);
return TCL_ERROR;
} else if ((c == 'c') && (strncmp(argv[1], "center", length) == 0)) {
if ((argc < 3)) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ", argv[1], " id\"", (char *) NULL);
return TCL_ERROR;
}
if (sscanf(argv[2], "%d", &polyid) != 1) {
Tcl_AppendResult(interp, "not an integer: ", argv[2],
(char *) NULL);
return TCL_ERROR;
}
for (i=0; i < vgp->Npoly; i++) {
if (vgp->poly[i].id == polyid) {
appendpoint(interp, center(vgp->poly[i].boundary.ps,
vgp->poly[i].boundary.pn));
return TCL_OK;
}
}
Tcl_AppendResult(interp, " no such polygon: ", argv[2],
(char *) NULL);
return TCL_ERROR;
} else if ((c == 't') && (strncmp(argv[1], "triangulate", length) == 0)) {
if ((argc < 2)) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" id ", (char *) NULL);
return TCL_ERROR;
}
if (sscanf(argv[2], "%d", &polyid) != 1) {
Tcl_AppendResult(interp, "not an integer: ", argv[2],
(char *) NULL);
return TCL_ERROR;
}
for (i=0; i < vgp->Npoly; i++) {
if (vgp->poly[i].id == polyid) {
Ptriangulate(&(vgp->poly[i].boundary),triangle_callback,vgp);
return TCL_OK;
}
}
Tcl_AppendResult(interp, " no such polygon: ", argv[2], (char *) NULL);
return TCL_ERROR;
} else if ((c == 'r') && (strncmp(argv[1], "rotate", length) == 0)) {
if ((argc < 4)) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ", argv[1], " id alpha\"", (char *) NULL);
return TCL_ERROR;
}
if (sscanf(argv[2], "%d", &polyid) != 1) {
Tcl_AppendResult(interp, "not an integer: ", argv[2],
(char *) NULL);
return TCL_ERROR;
}
if (sscanf(argv[3], "%lg", &alpha) != 1) {
Tcl_AppendResult(interp, "not an angle in radians: ", argv[3],
(char *) NULL);
return TCL_ERROR;
}
for (i=0; i < vgp->Npoly; i++) {
if (vgp->poly[i].id == polyid) {
n = vgp->poly[i].boundary.pn;
ps = vgp->poly[i].boundary.ps;
p = center(ps, n);
for (j = 0; j < n; j++) {
appendpoint(interp, rotate(p, ps[j], alpha));
}
return TCL_OK;
}
}
Tcl_AppendResult(interp, " no such polygon: ", argv[2],
(char *) NULL);
return TCL_ERROR;
} else if ((c == 's') && (strncmp(argv[1], "scale", length) == 0)) {
if ((argc < 4)) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ", argv[1], " id gain\"", (char *) NULL);
return TCL_ERROR;
}
if (sscanf(argv[2], "%d", &polyid) != 1) {
Tcl_AppendResult(interp, "not an integer: ", argv[2],
(char *) NULL);
return TCL_ERROR;
}
if (sscanf(argv[3], "%lg", &gain) != 1) {
Tcl_AppendResult(interp, "not a number: ", argv[3],
(char *) NULL);
return TCL_ERROR;
}
for (i=0; i < vgp->Npoly; i++) {
if (vgp->poly[i].id == polyid) {
n = vgp->poly[i].boundary.pn;
ps = vgp->poly[i].boundary.ps;
for (j = 0; j < n; j++) {
appendpoint(interp, scale(p, ps[j], gain));
}
return TCL_OK;
}
}
Tcl_AppendResult(interp, " no such polygon: ", argv[2],
(char *) NULL);
return TCL_ERROR;
} else if ((c == 'r') && (strncmp(argv[1], "remove", length) == 0)) {
if ((argc < 3)) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ", argv[1], " id\"", (char *) NULL);
return TCL_ERROR;
}
if (sscanf(argv[2], "%d", &polyid) != 1) {
Tcl_AppendResult(interp, "not an integer: ", argv[2],
(char *) NULL);
return TCL_ERROR;
}
if (remove_poly(vgp, polyid))
return TCL_OK;
Tcl_AppendResult(interp, " no such polygon: ", argv[2],
(char *) NULL);
return TCL_ERROR;
}
Tcl_AppendResult(interp, "bad method \"", argv[1], "\" must be one of:",
"\n\tbbox, bind, bpath, center, coords, delete, find,",
"\n\tinsert, list, path, remove, rotate, scale, triangulate.", (char *) NULL);
return TCL_ERROR;
}
static int
vgpane(ClientData clientData, Tcl_Interp * interp, int argc, char *argv[])
{
char vbuf[30];
vgpane_t *vgp;
vgp = (vgpane_t *)malloc(sizeof(vgpane_t));
*(vgpane_t **)tclhandleAlloc(vgpaneTable, vbuf, NULL) = vgp;
vgp->vc = (vconfig_t*)0;
vgp->Npoly = 0;
vgp->N_poly_alloc = 250;
vgp->poly = malloc(vgp->N_poly_alloc * sizeof(poly));
vgp->interp = interp;
vgp->triangle_cmd = (char *) NULL;
Tcl_CreateCommand(interp, vbuf, vgpanecmd,
(ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
Tcl_AppendResult(interp, vbuf, (char *) NULL);
return TCL_OK;
}
int Tclpathplan_Init(Tcl_Interp * interp)
{
#ifdef USE_TCL_STUBS
if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
return TCL_ERROR;
}
#else
if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 0) == NULL) {
return TCL_ERROR;
}
#endif
if (Tcl_PkgProvide(interp, "Tclpathplan", VERSION) != TCL_OK) {
return TCL_ERROR;
}
Tcl_CreateCommand(interp, "vgpane", vgpane,
(ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
vgpaneTable = tclhandleInit("vgpane", sizeof(vgpane_t), 10);
return TCL_OK;
}
int Tclpathplan_SafeInit(Tcl_Interp * interp)
{
return Tclpathplan_Init(interp);
}