40#if ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 6)) || ( TCL_MAJOR_VERSION > 8)
42#ifndef Tcl_GetStringResult
43#define Tcl_GetStringResult(interp) interp->result
57#define HANDLE_FORMAT ("vgpane%" PRISIZE_T)
76 polys_append(&vgp->poly, (
poly){.id = id});
77 poly *rv = polys_back(&vgp->poly);
95 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++)
96 obs[i] = &polys_at(&vgp->
poly, i)->boundary;
98 fprintf(stderr,
"bad arrangement\n");
114 const char *separator =
"";
115 for (i = 0; i < npts; i++) {
116 agxbprint(result,
"%s%g %g", separator, p[i].x, p[i].y);
128 size_t vgcanvasHandle,
int npts,
138 char *
string = strchr(before,
'%');
139 if (
string !=
NULL) {
140 agxbput_n(&scripts, before, (
size_t)(
string - before));
161 if (before[1] ==
'\0') {
166 const char *script_value =
agxbuse(&scripts);
167 if (Tcl_GlobalEval(interp, script_value) != TCL_OK)
168 fprintf(stderr,
"%s while in binding: %s\n\n",
176 const size_t vgcanvasHandle = vgp->
index;
228 if (sscanf(argv[0],
"%lg", &(p->
x)) != 1) {
229 Tcl_AppendResult(interp,
"invalid x coordinate: \"", argv[0],
"\"",
NULL);
232 if (sscanf(argv[1],
"%lg", &(p->
y)) != 1) {
233 Tcl_AppendResult(interp,
"invalid y coordinate: \"", argv[1],
"\"",
NULL);
243 for (
size_t i = 0; i < n; i++) {
258 return hypot(
dx,
dy);
267 beta = atan2(p.
x - c.
x, p.
y - c.
y);
268 const double sina = sin(beta +
alpha);
269 const double cosa = cos(beta +
alpha);
270 q.
x = c.
x + r * sina;
271 q.
y = c.
y - r * cosa;
279 q.
x = c.
x + gain * (p.
x - c.
x);
280 q.
y = c.
y + gain * (p.
y - c.
y);
285 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++) {
286 if (polys_get(&vgp->
poly, i).id ==
id) {
287 free(polys_get(&vgp->
poly, i).boundary.ps);
288 for (
size_t j = i++; i < polys_size(&vgp->
poly); i++, j++) {
289 polys_set(&vgp->
poly, j, polys_get(&vgp->
poly, i));
291 polys_resize(&vgp->
poly, polys_size(&vgp->
poly) - 1, (
poly){0});
307 for (i = 0; i < vargc; i += 2) {
311 if (result != TCL_OK)
321 size_t *n_barriers) {
324 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++) {
325 if (polys_get(&vgp->
poly, i).id == pp)
327 if (polys_get(&vgp->
poly, i).id == qp)
329 n += polys_get(&vgp->
poly, i).boundary.pn;
333 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++) {
334 if (polys_get(&vgp->
poly, i).id == pp)
336 if (polys_get(&vgp->
poly, i).id == qp)
338 for (
size_t j = 0; j < polys_get(&vgp->
poly, i).boundary.pn; j++) {
340 if (k >= polys_get(&vgp->
poly, i).boundary.pn)
342 bar[b].
a = polys_get(&vgp->
poly, i).boundary.ps[j];
343 bar[b].
b = polys_get(&vgp->
poly, i).boundary.ps[k];
357 snprintf(buf,
sizeof(buf),
"%g", p.
x);
358 Tcl_AppendElement(interp, buf);
359 snprintf(buf,
sizeof(buf),
"%g", p.
y);
360 Tcl_AppendElement(interp, buf);
369 assert(panes !=
NULL);
370 assert(handle !=
NULL);
376 if (index >= vgpanes_size(panes)) {
379 vgpane_t *
const pane = vgpanes_at(panes, index);
400 assert(panes !=
NULL);
403 while (!vgpanes_is_empty(panes)) {
404 if (!vgpanes_back(panes)->valid) {
405 (void)vgpanes_pop_back(panes);
410 if (vgpanes_is_empty(panes)) {
417vgpanecmd(ClientData clientData, Tcl_Interp * interp,
int argc,
433 Tcl_AppendResult(interp,
"wrong # args: should be \"",
434 " ", argv[0],
" method ?arg arg ...?\"",
NULL);
438 Tcl_AppendResult(interp,
"Invalid handle: \"", argv[0],
"\"",
NULL);
442 if (strcmp(argv[1],
"coords") == 0) {
444 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
445 " ", argv[1],
" id ?x1 y1 x2 y2...?\"",
NULL);
448 if (sscanf(argv[2],
"%d", &
polyid) != 1) {
449 Tcl_AppendResult(interp,
"not an integer: ", argv[2],
NULL);
454 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++) {
456 const size_t n = polys_get(&vgp->
poly, i).boundary.pn;
457 for (
size_t j = 0; j < n; j++) {
463 Tcl_AppendResult(interp,
" no such polygon: ", argv[2],
NULL);
469 Tcl_SplitList(interp, argv[3], &vargc,
470 (
const char ***) &vargv);
471 if (result != TCL_OK) {
478 if (!vargc || vargc % 2) {
479 Tcl_AppendResult(interp,
480 "There must be a multiple of two terms in the list.",
NULL);
488 Tcl_AppendResult(interp,
" no such polygon: ", argv[2],
NULL);
494 }
else if (strcmp(argv[1],
"debug") == 0) {
496 printf(
"debug output goes here\n");
499 }
else if (strcmp(argv[1],
"delete") == 0) {
504 polys_free(&vgp->
poly);
505 Tcl_DeleteCommand(interp, argv[0]);
510 }
else if (strcmp(argv[1],
"find") == 0) {
514 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
515 " ", argv[1],
" x y\"",
NULL);
520 Tcl_SplitList(interp, argv[2], &vargc,
521 (
const char ***) &vargv);
522 if (result != TCL_OK) {
529 result =
scanpoint(interp, &vargv[0], &p);
530 if (result != TCL_OK)
534 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++) {
535 if (
in_poly(polys_get(&vgp->
poly, i).boundary, p)) {
536 snprintf(vbuf,
sizeof(vbuf),
"%d", polys_get(&vgp->
poly, i).id);
537 Tcl_AppendElement(interp, vbuf);
542 }
else if (strcmp(argv[1],
"insert") == 0) {
546 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
547 " ", argv[1],
" x1 y1 x2 y2 ...\"",
NULL);
553 Tcl_SplitList(interp, argv[2], &vargc,
554 (
const char ***) &vargv);
555 if (result != TCL_OK) {
563 if (!vargc || vargc % 2) {
564 Tcl_AppendResult(interp,
565 "There must be a multiple of two terms in the list.",
NULL);
572 if (result != TCL_OK)
575 snprintf(vbuf,
sizeof(vbuf),
"%d",
polyid);
576 Tcl_AppendResult(interp, vbuf,
NULL);
579 }
else if (strcmp(argv[1],
"list") == 0) {
581 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++) {
582 snprintf(vbuf,
sizeof(vbuf),
"%d", polys_get(&vgp->
poly, i).id);
583 Tcl_AppendElement(interp, vbuf);
587 }
else if (strcmp(argv[1],
"path") == 0) {
591 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
592 " ", argv[1],
" x1 y1 x2 y2\"",
NULL);
597 Tcl_SplitList(interp, argv[2], &vargc,
598 (
const char ***) &vargv);
599 if (result != TCL_OK) {
607 Tcl_AppendResult(interp,
608 "invalid points: should be: \"x1 y1 x2 y2\"",
NULL);
611 result =
scanpoint(interp, &vargv[0], &p);
612 if (result != TCL_OK)
614 result =
scanpoint(interp, &vargv[2], &q);
615 if (result != TCL_OK)
622 for (
size_t i = 0; i < line.
pn; i++) {
629 }
else if (strcmp(argv[1],
"bind") == 0) {
630 if (argc < 2 || argc > 4) {
631 Tcl_AppendResult(interp,
"wrong # args: should be \"",
632 argv[0],
" bind triangle ?command?\"",
NULL);
636 Tcl_AppendElement(interp,
"triangle");
640 if (strcmp(argv[2],
"triangle") == 0) {
645 Tcl_AppendResult(interp,
"unknown event \"", argv[2],
646 "\": must be one of:\n\ttriangle.",
NULL);
650 Tcl_AppendResult(interp,
s,
NULL);
653 }
else if (strcmp(argv[1],
"bpath") == 0) {
657 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
658 " ", argv[1],
" x1 y1 x2 y2\"",
NULL);
663 Tcl_SplitList(interp, argv[2], &vargc,
664 (
const char ***) &vargv);
665 if (result != TCL_OK) {
673 Tcl_AppendResult(interp,
674 "invalid points: should be: \"x1 y1 x2 y2\"",
NULL);
678 result =
scanpoint(interp, &vargv[0], &p);
679 if (result != TCL_OK)
681 result =
scanpoint(interp, &vargv[2], &q);
682 if (result != TCL_OK)
688 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++) {
689 const poly tpp = polys_get(&vgp->
poly, i);
700 slopes[0].
x = slopes[0].
y = 0.0;
701 slopes[1].
x = slopes[1].
y = 0.0;
702 Proutespline(barriers, n_barriers, line, slopes, &spline);
704 for (
size_t i = 0; i < spline.
pn; i++) {
710 }
else if (strcmp(argv[1],
"bbox") == 0) {
712 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
713 " ", argv[1],
" id\"",
NULL);
716 if (sscanf(argv[2],
"%d", &
polyid) != 1) {
717 Tcl_AppendResult(interp,
"not an integer: ", argv[2],
NULL);
720 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++) {
725 for (
size_t j = 1; j < pp.
pn; j++) {
727 UR.
x = fmax(UR.
x, p.
x);
728 UR.
y = fmax(UR.
y, p.
y);
729 LL.
x = fmin(LL.
x, p.
x);
730 LL.
y = fmin(LL.
y, p.
y);
737 Tcl_AppendResult(interp,
" no such polygon: ", argv[2],
NULL);
740 }
else if (strcmp(argv[1],
"center") == 0) {
742 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
743 " ", argv[1],
" id\"",
NULL);
746 if (sscanf(argv[2],
"%d", &
polyid) != 1) {
747 Tcl_AppendResult(interp,
"not an integer: ", argv[2],
NULL);
750 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++) {
753 polys_get(&vgp->
poly, i).boundary.pn));
757 Tcl_AppendResult(interp,
" no such polygon: ", argv[2],
NULL);
760 }
else if (strcmp(argv[1],
"triangulate") == 0) {
762 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
763 " ", argv[1],
" id\"",
NULL);
767 if (sscanf(argv[2],
"%d", &
polyid) != 1) {
768 Tcl_AppendResult(interp,
"not an integer: ", argv[2],
NULL);
772 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++) {
776 Tcl_AppendResult(interp,
"polygon ", argv[2],
" has fewer than 3 points "
777 "and thus cannot be triangulated",
NULL);
784 Tcl_AppendResult(interp,
" no such polygon: ", argv[2],
NULL);
786 }
else if (strcmp(argv[1],
"rotate") == 0) {
788 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
789 " ", argv[1],
" id alpha\"",
NULL);
792 if (sscanf(argv[2],
"%d", &
polyid) != 1) {
793 Tcl_AppendResult(interp,
"not an integer: ", argv[2],
NULL);
796 if (sscanf(argv[3],
"%lg", &
alpha) != 1) {
797 Tcl_AppendResult(interp,
"not an angle in radians: ", argv[3],
NULL);
800 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++) {
802 const size_t n = polys_get(&vgp->
poly, i).boundary.pn;
803 ps = polys_get(&vgp->
poly, i).boundary.ps;
805 for (
size_t j = 0; j < n; j++) {
811 Tcl_AppendResult(interp,
" no such polygon: ", argv[2],
NULL);
814 }
else if (strcmp(argv[1],
"scale") == 0) {
816 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
817 " ", argv[1],
" id gain\"",
NULL);
820 if (sscanf(argv[2],
"%d", &
polyid) != 1) {
821 Tcl_AppendResult(interp,
"not an integer: ", argv[2],
NULL);
824 if (sscanf(argv[3],
"%lg", &gain) != 1) {
825 Tcl_AppendResult(interp,
"not a number: ", argv[3],
NULL);
828 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++) {
830 const size_t n = polys_get(&vgp->
poly, i).boundary.pn;
831 ps = polys_get(&vgp->
poly, i).boundary.ps;
833 for (
size_t j = 0; j < n; j++) {
839 Tcl_AppendResult(interp,
" no such polygon: ", argv[2],
NULL);
842 }
else if (strcmp(argv[1],
"remove") == 0) {
844 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
845 " ", argv[1],
" id\"",
NULL);
848 if (sscanf(argv[2],
"%d", &
polyid) != 1) {
849 Tcl_AppendResult(interp,
"not an integer: ", argv[2],
NULL);
856 Tcl_AppendResult(interp,
" no such polygon: ", argv[2],
NULL);
860 Tcl_AppendResult(interp,
"bad method \"", argv[1],
861 "\" must be one of:",
862 "\n\tbbox, bind, bpath, center, coords, delete, find,",
863 "\n\tinsert, list, path, remove, rotate, scale, triangulate.",
NULL);
868vgpane(ClientData clientData, Tcl_Interp * interp,
int argc,
const char *argv[])
882 const char *
const vbuf =
agxbuse(&buffer);
885 Tcl_AppendResult(interp, vbuf,
NULL);
894 if (Tcl_InitStubs(interp, TCL_VERSION, 0) ==
NULL) {
898 if (Tcl_PkgRequire(interp,
"Tcl", TCL_VERSION, 0) ==
NULL) {
904 char adjusted_version[
sizeof(PACKAGE_VERSION)] = PACKAGE_VERSION;
905 char *tilde_dev = strstr(adjusted_version,
"~dev.");
906 if (tilde_dev !=
NULL) {
908 memmove(tilde_dev + 1, tilde_dev + strlen(
"~dev."),
909 strlen(tilde_dev + strlen(
"~dev.")) + 1);
911 if (Tcl_PkgProvide(interp,
"Tclpathplan", adjusted_version) != TCL_OK) {
static void agxbfree(agxbuf *xb)
free any malloced resources
static size_t agxbput_n(agxbuf *xb, const char *s, size_t ssz)
append string s of length ssz into xb
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
static WUR char * agxbuse(agxbuf *xb)
static size_t agxblen(const agxbuf *xb)
return number of characters currently stored
static int agxbputc(agxbuf *xb, char c)
add character to buffer
static char * agxbdisown(agxbuf *xb)
Memory allocation wrappers that exit on failure.
static char * gv_strdup(const char *original)
static void * gv_calloc(size_t nmemb, size_t size)
vconfig_t * Pobsopen(Ppoly_t **obs, int n_obs)
void Pobsclose(vconfig_t *config)
void Pobspath(vconfig_t *config, Ppoint_t p0, int poly0, Ppoint_t p1, int poly1, Ppolyline_t *output_route)
bool in_poly(const Ppoly_t poly, Ppoint_t q)
int Plegal_arrangement(Ppoly_t **polys, int n_polys)
#define DEFINE_LIST(name, type)
void make_CW(Ppoly_t *poly)
NEATOPROCS_API void s1(graph_t *, node_t *)
int Proutespline(Pedge_t *barriers, size_t n_barriers, Ppolyline_t input_route, Pvector_t endpoint_slopes[2], Ppolyline_t *output_route)
size_t index
position within allocated handles list
bool valid
is this pane currently allocated?
static void vc_stale(vgpane_t *vgp)
static int vgpane(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[])
int Tclpathplan_Init(Tcl_Interp *interp)
static char * buildBindings(char *s1, const char *s2)
static int vc_refresh(vgpane_t *vgp)
static poly * allocpoly(vgpane_t *vgp, int id, int npts)
static void garbage_collect_vgpanes(vgpanes_t *panes)
static vgpanes_t vgpaneTable
static int insert_poly(Tcl_Interp *interp, vgpane_t *vgp, int id, const char *vargv[], int vargc)
static void appendpoint(Tcl_Interp *interp, point p)
static point scale(point c, point p, double gain)
static void expandPercentsEval(Tcl_Interp *interp, char *before, size_t vgcanvasHandle, int npts, const point *ppos)
static void triangle_callback(void *vgparg, const point pqr[])
int Tclpathplan_SafeInit(Tcl_Interp *interp)
static vgpane_t * find_vgpane(vgpanes_t *panes, const char *handle)
#define HANDLE_FORMAT
printf format for TCL handles
static void make_barriers(vgpane_t *vgp, int pp, int qp, Pedge_t **barriers, size_t *n_barriers)
static void dgsprintxy(agxbuf *result, int npts, const point p[])
static int vgpanecmd(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[])
static point center(point vertex[], size_t n)
static double distance(point p, point q)
static point rotate(point c, point p, double alpha)
#define Tcl_GetStringResult(interp)
static int scanpoint(Tcl_Interp *interp, const char *argv[], point *p)
static bool remove_poly(vgpane_t *vgp, int id)
TRI_API int Ptriangulate(Ppoly_t *polygon, void(*fn)(void *closure, const Ppoint_t tri[]), void *vc)