20#include "../tcl-compat.h"
42#if (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 6) || TCL_MAJOR_VERSION > 8
44#ifndef Tcl_GetStringResult
45#define Tcl_GetStringResult(interp) interp->result
59#define HANDLE_FORMAT ("vgpane%" PRISIZE_T)
77 polys_append(&vgp->poly, (
poly){.id = id});
78 poly *rv = polys_back(&vgp->poly);
96 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++)
97 obs[i] = &polys_at(&vgp->
poly, i)->boundary;
99 fprintf(stderr,
"bad arrangement\n");
115 const char *separator =
"";
116 for (i = 0; i < npts; i++) {
117 agxbprint(result,
"%s%g %g", separator, p[i].x, p[i].y);
129 size_t vgcanvasHandle,
int npts,
139 char *
string = strchr(before,
'%');
140 if (
string !=
NULL) {
141 agxbput_n(&scripts, before, (
size_t)(
string - before));
162 if (before[1] ==
'\0') {
167 const char *script_value =
agxbuse(&scripts);
168 if (Tcl_GlobalEval(interp, script_value) != TCL_OK)
169 fprintf(stderr,
"%s while in binding: %s\n\n",
177 const size_t vgcanvasHandle = vgp->
index;
229 if (sscanf(argv[0],
"%lg", &p->
x) != 1) {
230 Tcl_AppendResult(interp,
"invalid x coordinate: \"", argv[0],
"\"",
NULL);
233 if (sscanf(argv[1],
"%lg", &p->
y) != 1) {
234 Tcl_AppendResult(interp,
"invalid y coordinate: \"", argv[1],
"\"",
NULL);
244 for (
size_t i = 0; i < n; i++) {
259 return hypot(
dx,
dy);
268 beta = atan2(p.
x - c.
x, p.
y - c.
y);
269 const double sina = sin(beta +
alpha);
270 const double cosa = cos(beta +
alpha);
271 q.
x = c.
x + r * sina;
272 q.
y = c.
y - r * cosa;
280 q.
x = c.
x + gain * (p.
x - c.
x);
281 q.
y = c.
y + gain * (p.
y - c.
y);
286 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++) {
287 if (polys_get(&vgp->
poly, i).id ==
id) {
288 free(polys_get(&vgp->
poly, i).boundary.ps);
289 for (
size_t j = i++; i < polys_size(&vgp->
poly); i++, j++) {
290 polys_set(&vgp->
poly, j, polys_get(&vgp->
poly, i));
292 polys_resize(&vgp->
poly, polys_size(&vgp->
poly) - 1, (
poly){0});
301 const char *vargv[],
Tcl_Size vargc) {
306 for (
Tcl_Size i = 0; i < vargc; i += 2) {
308 if (result != TCL_OK)
318 size_t *n_barriers) {
321 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++) {
322 if (polys_get(&vgp->
poly, i).id == pp)
324 if (polys_get(&vgp->
poly, i).id == qp)
326 n += polys_get(&vgp->
poly, i).boundary.pn;
330 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++) {
331 if (polys_get(&vgp->
poly, i).id == pp)
333 if (polys_get(&vgp->
poly, i).id == qp)
335 for (
size_t j = 0; j < polys_get(&vgp->
poly, i).boundary.pn; j++) {
337 if (k >= polys_get(&vgp->
poly, i).boundary.pn)
339 bar[b].
a = polys_get(&vgp->
poly, i).boundary.ps[j];
340 bar[b].
b = polys_get(&vgp->
poly, i).boundary.ps[k];
354 snprintf(buf,
sizeof(buf),
"%g", p.
x);
355 Tcl_AppendElement(interp, buf);
356 snprintf(buf,
sizeof(buf),
"%g", p.
y);
357 Tcl_AppendElement(interp, buf);
366 assert(panes !=
NULL);
367 assert(handle !=
NULL);
373 if (index >= vgpanes_size(panes)) {
376 vgpane_t *
const pane = vgpanes_at(panes, index);
397 assert(panes !=
NULL);
400 while (!vgpanes_is_empty(panes)) {
401 if (!vgpanes_back(panes)->valid) {
402 (void)vgpanes_pop_back(panes);
407 if (vgpanes_is_empty(panes)) {
414vgpanecmd(ClientData clientData, Tcl_Interp * interp,
int argc,
428 Tcl_AppendResult(interp,
"wrong # args: should be \"",
429 " ", argv[0],
" method ?arg arg ...?\"",
NULL);
433 Tcl_AppendResult(interp,
"Invalid handle: \"", argv[0],
"\"",
NULL);
437 if (strcmp(argv[1],
"coords") == 0) {
439 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
440 " ", argv[1],
" id ?x1 y1 x2 y2...?\"",
NULL);
443 if (sscanf(argv[2],
"%d", &
polyid) != 1) {
444 Tcl_AppendResult(interp,
"not an integer: ", argv[2],
NULL);
449 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++) {
451 const size_t n = polys_get(&vgp->
poly, i).boundary.pn;
452 for (
size_t j = 0; j < n; j++) {
458 Tcl_AppendResult(interp,
" no such polygon: ", argv[2],
NULL);
464 bool vargv_needs_free =
false;
466 result = Tcl_SplitList(interp, argv[3], &vargc, &vargv);
467 if (result != TCL_OK) {
470 vargv_needs_free =
true;
475 if (!vargc || vargc % 2) {
476 Tcl_AppendResult(interp,
477 "There must be a multiple of two terms in the list.",
NULL);
478 if (vargv_needs_free) {
479 Tcl_Free((
char *)vargv);
488 Tcl_AppendResult(interp,
" no such polygon: ", argv[2],
NULL);
489 if (vargv_needs_free) {
490 Tcl_Free((
char *)vargv);
496 if (vargv_needs_free) {
497 Tcl_Free((
char *)vargv);
501 }
else if (strcmp(argv[1],
"debug") == 0) {
503 printf(
"debug output goes here\n");
506 }
else if (strcmp(argv[1],
"delete") == 0) {
511 polys_free(&vgp->
poly);
512 Tcl_DeleteCommand(interp, argv[0]);
517 }
else if (strcmp(argv[1],
"find") == 0) {
521 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
522 " ", argv[1],
" x y\"",
NULL);
526 bool vargv_needs_free =
false;
528 result = Tcl_SplitList(interp, argv[2], &(
Tcl_Size){0}, &vargv);
529 if (result != TCL_OK) {
532 vargv_needs_free =
true;
536 result =
scanpoint(interp, &vargv[0], &p);
537 if (vargv_needs_free) {
538 Tcl_Free((
char *)vargv);
540 if (result != TCL_OK)
544 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++) {
545 if (
in_poly(polys_get(&vgp->
poly, i).boundary, p)) {
546 Tcl_AppendElement(interp,
ITOS(polys_get(&vgp->
poly, i).id));
551 }
else if (strcmp(argv[1],
"insert") == 0) {
555 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
556 " ", argv[1],
" x1 y1 x2 y2 ...\"",
NULL);
562 bool vargv_needs_free =
false;
564 result = Tcl_SplitList(interp, argv[2], &vargc, &vargv);
565 if (result != TCL_OK) {
568 vargv_needs_free =
true;
574 if (!vargc || vargc % 2) {
575 Tcl_AppendResult(interp,
576 "There must be a multiple of two terms in the list.",
NULL);
577 if (vargv_needs_free) {
578 Tcl_Free((
char *)vargv);
586 if (vargv_needs_free) {
587 Tcl_Free((
char *)vargv);
589 if (result != TCL_OK)
595 }
else if (strcmp(argv[1],
"list") == 0) {
597 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++) {
598 Tcl_AppendElement(interp,
ITOS(polys_get(&vgp->
poly, i).id));
602 }
else if (strcmp(argv[1],
"path") == 0) {
606 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
607 " ", argv[1],
" x1 y1 x2 y2\"",
NULL);
612 bool vargv_needs_free =
false;
614 result = Tcl_SplitList(interp, argv[2], &vargc, &vargv);
615 if (result != TCL_OK) {
618 vargv_needs_free =
true;
624 Tcl_AppendResult(interp,
625 "invalid points: should be: \"x1 y1 x2 y2\"",
NULL);
626 if (vargv_needs_free) {
627 Tcl_Free((
char *)vargv);
631 result =
scanpoint(interp, &vargv[0], &p);
632 if (result != TCL_OK) {
633 if (vargv_needs_free) {
634 Tcl_Free((
char *)vargv);
638 result =
scanpoint(interp, &vargv[2], &q);
639 if (vargv_needs_free) {
640 Tcl_Free((
char *)vargv);
642 if (result != TCL_OK)
649 for (
size_t i = 0; i < line.
pn; i++) {
656 }
else if (strcmp(argv[1],
"bind") == 0) {
657 if (argc < 2 || argc > 4) {
658 Tcl_AppendResult(interp,
"wrong # args: should be \"",
659 argv[0],
" bind triangle ?command?\"",
NULL);
663 Tcl_AppendElement(interp,
"triangle");
667 if (strcmp(argv[2],
"triangle") == 0) {
672 Tcl_AppendResult(interp,
"unknown event \"", argv[2],
673 "\": must be one of:\n\ttriangle.",
NULL);
677 Tcl_AppendResult(interp,
s,
NULL);
680 }
else if (strcmp(argv[1],
"bpath") == 0) {
684 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
685 " ", argv[1],
" x1 y1 x2 y2\"",
NULL);
690 bool vargv_needs_free =
false;
692 result = Tcl_SplitList(interp, argv[2], &vargc, &vargv);
693 if (result != TCL_OK) {
696 vargv_needs_free =
true;
702 Tcl_AppendResult(interp,
703 "invalid points: should be: \"x1 y1 x2 y2\"",
NULL);
707 result =
scanpoint(interp, &vargv[0], &p);
708 if (result != TCL_OK) {
709 if (vargv_needs_free) {
710 Tcl_Free((
char *)vargv);
714 result =
scanpoint(interp, &vargv[2], &q);
715 if (vargv_needs_free) {
716 Tcl_Free((
char *)vargv);
718 if (result != TCL_OK)
724 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++) {
725 const poly tpp = polys_get(&vgp->
poly, i);
736 slopes[0].
x = slopes[0].
y = 0.0;
737 slopes[1].
x = slopes[1].
y = 0.0;
738 Proutespline(barriers, n_barriers, line, slopes, &spline);
740 for (
size_t i = 0; i < spline.
pn; i++) {
746 }
else if (strcmp(argv[1],
"bbox") == 0) {
748 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
749 " ", argv[1],
" id\"",
NULL);
752 if (sscanf(argv[2],
"%d", &
polyid) != 1) {
753 Tcl_AppendResult(interp,
"not an integer: ", argv[2],
NULL);
756 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++) {
761 for (
size_t j = 1; j < pp.
pn; j++) {
763 UR.
x = fmax(UR.
x, p.
x);
764 UR.
y = fmax(UR.
y, p.
y);
765 LL.
x = fmin(LL.
x, p.
x);
766 LL.
y = fmin(LL.
y, p.
y);
773 Tcl_AppendResult(interp,
" no such polygon: ", argv[2],
NULL);
776 }
else if (strcmp(argv[1],
"center") == 0) {
778 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
779 " ", argv[1],
" id\"",
NULL);
782 if (sscanf(argv[2],
"%d", &
polyid) != 1) {
783 Tcl_AppendResult(interp,
"not an integer: ", argv[2],
NULL);
786 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++) {
789 polys_get(&vgp->
poly, i).boundary.pn));
793 Tcl_AppendResult(interp,
" no such polygon: ", argv[2],
NULL);
796 }
else if (strcmp(argv[1],
"triangulate") == 0) {
798 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
799 " ", argv[1],
" id\"",
NULL);
803 if (sscanf(argv[2],
"%d", &
polyid) != 1) {
804 Tcl_AppendResult(interp,
"not an integer: ", argv[2],
NULL);
808 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++) {
812 Tcl_AppendResult(interp,
"polygon ", argv[2],
" has fewer than 3 points "
813 "and thus cannot be triangulated",
NULL);
820 Tcl_AppendResult(interp,
" no such polygon: ", argv[2],
NULL);
822 }
else if (strcmp(argv[1],
"rotate") == 0) {
824 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
825 " ", argv[1],
" id alpha\"",
NULL);
828 if (sscanf(argv[2],
"%d", &
polyid) != 1) {
829 Tcl_AppendResult(interp,
"not an integer: ", argv[2],
NULL);
832 if (sscanf(argv[3],
"%lg", &
alpha) != 1) {
833 Tcl_AppendResult(interp,
"not an angle in radians: ", argv[3],
NULL);
836 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++) {
838 const size_t n = polys_get(&vgp->
poly, i).boundary.pn;
839 ps = polys_get(&vgp->
poly, i).boundary.ps;
841 for (
size_t j = 0; j < n; j++) {
847 Tcl_AppendResult(interp,
" no such polygon: ", argv[2],
NULL);
850 }
else if (strcmp(argv[1],
"scale") == 0) {
852 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
853 " ", argv[1],
" id gain\"",
NULL);
856 if (sscanf(argv[2],
"%d", &
polyid) != 1) {
857 Tcl_AppendResult(interp,
"not an integer: ", argv[2],
NULL);
860 if (sscanf(argv[3],
"%lg", &gain) != 1) {
861 Tcl_AppendResult(interp,
"not a number: ", argv[3],
NULL);
864 for (
size_t i = 0; i < polys_size(&vgp->
poly); i++) {
866 const size_t n = polys_get(&vgp->
poly, i).boundary.pn;
867 ps = polys_get(&vgp->
poly, i).boundary.ps;
869 for (
size_t j = 0; j < n; j++) {
875 Tcl_AppendResult(interp,
" no such polygon: ", argv[2],
NULL);
878 }
else if (strcmp(argv[1],
"remove") == 0) {
880 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
881 " ", argv[1],
" id\"",
NULL);
884 if (sscanf(argv[2],
"%d", &
polyid) != 1) {
885 Tcl_AppendResult(interp,
"not an integer: ", argv[2],
NULL);
892 Tcl_AppendResult(interp,
" no such polygon: ", argv[2],
NULL);
896 Tcl_AppendResult(interp,
"bad method \"", argv[1],
897 "\" must be one of:",
898 "\n\tbbox, bind, bpath, center, coords, delete, find,",
899 "\n\tinsert, list, path, remove, rotate, scale, triangulate.",
NULL);
904vgpane(ClientData clientData, Tcl_Interp * interp,
int argc,
const char *argv[])
918 const char *
const vbuf =
agxbuse(&buffer);
921 Tcl_AppendResult(interp, vbuf,
NULL);
930 if (Tcl_InitStubs(interp, TCL_VERSION, 0) ==
NULL) {
934 if (Tcl_PkgRequire(interp,
"Tcl", TCL_VERSION, 0) ==
NULL) {
940 char adjusted_version[
sizeof(PACKAGE_VERSION)] = PACKAGE_VERSION;
941 char *tilde_dev = strstr(adjusted_version,
"~dev.");
942 if (tilde_dev !=
NULL) {
944 memmove(tilde_dev + 1, tilde_dev + strlen(
"~dev."),
945 strlen(tilde_dev + strlen(
"~dev.")) + 1);
947 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 void garbage_collect_vgpanes(vgpanes_t *panes)
static vgpanes_t vgpaneTable
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 insert_poly(Tcl_Interp *interp, vgpane_t *vgp, int id, const char *vargv[], Tcl_Size vargc)
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)
static poly * allocpoly(vgpane_t *vgp, int id, Tcl_Size npts)
TRI_API int Ptriangulate(Ppoly_t *polygon, void(*fn)(void *closure, const Ppoint_t tri[]), void *vc)