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
57#define HANDLE_FORMAT ("vgpane%" PRISIZE_T)
70static vgpanes_t vgpaneTable;
92 if (vgp->vc ==
NULL) {
94 for (
size_t i = 0; i <
LIST_SIZE(&vgp->poly); i++)
95 obs[i] = &
LIST_AT(&vgp->poly, i)->boundary;
97 fprintf(stderr,
"bad arrangement\n");
102 return vgp->vc !=
NULL;
113 const char *separator =
"";
114 for (i = 0; i < npts; i++) {
115 agxbprint(result,
"%s%g %g", separator, p[i].x, p[i].y);
127 size_t vgcanvasHandle,
int npts,
137 char *
string = strchr(before,
'%');
138 if (
string !=
NULL) {
139 agxbput_n(&scripts, before, (
size_t)(
string - before));
160 if (before[1] ==
'\0') {
165 const char *script_value =
agxbuse(&scripts);
166 if (Tcl_GlobalEval(interp, script_value) != TCL_OK)
167 fprintf(stderr,
"%s while in binding: %s\n\n",
174 if (vgp->triangle_cmd) {
175 const size_t vgcanvasHandle = vgp->index;
227 if (sscanf(argv[0],
"%lg", &p->
x) != 1) {
228 Tcl_AppendResult(interp,
"invalid x coordinate: \"", argv[0],
"\"",
NULL);
231 if (sscanf(argv[1],
"%lg", &p->
y) != 1) {
232 Tcl_AppendResult(interp,
"invalid y coordinate: \"", argv[1],
"\"",
NULL);
242 for (
size_t i = 0; i < n; i++) {
257 return hypot(
dx,
dy);
266 beta = atan2(p.
x - c.
x, p.
y - c.
y);
267 const double sina = sin(beta +
alpha);
268 const double cosa = cos(beta +
alpha);
269 q.
x = c.
x + r * sina;
270 q.
y = c.
y - r * cosa;
278 q.
x = c.
x + gain * (p.
x - c.
x);
279 q.
y = c.
y + gain * (p.
y - c.
y);
284 for (
size_t i = 0; i <
LIST_SIZE(&vgp->poly); i++) {
287 for (
size_t j = i++; i <
LIST_SIZE(&vgp->poly); i++, j++) {
299 const char *vargv[],
Tcl_Size vargc) {
303 np = allocpoly(vgp,
id, vargc);
304 for (
Tcl_Size i = 0; i < vargc; i += 2) {
306 if (result != TCL_OK)
316 size_t *n_barriers) {
319 for (
size_t i = 0; i <
LIST_SIZE(&vgp->poly); i++) {
320 if (
LIST_GET(&vgp->poly, i).id == pp)
322 if (
LIST_GET(&vgp->poly, i).id == qp)
324 n +=
LIST_GET(&vgp->poly, i).boundary.pn;
328 for (
size_t i = 0; i <
LIST_SIZE(&vgp->poly); i++) {
329 if (
LIST_GET(&vgp->poly, i).id == pp)
331 if (
LIST_GET(&vgp->poly, i).id == qp)
333 for (
size_t j = 0; j <
LIST_GET(&vgp->poly, i).boundary.pn; j++) {
335 if (k >=
LIST_GET(&vgp->poly, i).boundary.pn)
337 bar[b].
a =
LIST_GET(&vgp->poly, i).boundary.ps[j];
338 bar[b].
b =
LIST_GET(&vgp->poly, i).boundary.ps[k];
352 snprintf(buf,
sizeof(buf),
"%g", p.
x);
353 Tcl_AppendElement(interp, buf);
354 snprintf(buf,
sizeof(buf),
"%g", p.
y);
355 Tcl_AppendElement(interp, buf);
364 assert(panes !=
NULL);
365 assert(handle !=
NULL);
395 assert(panes !=
NULL);
412vgpanecmd(ClientData clientData, Tcl_Interp * interp,
int argc,
425 Tcl_AppendResult(interp,
"wrong # args: should be \"",
426 " ", argv[0],
" method ?arg arg ...?\"",
NULL);
430 Tcl_AppendResult(interp,
"Invalid handle: \"", argv[0],
"\"",
NULL);
434 if (strcmp(argv[1],
"coords") == 0) {
436 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
437 " ", argv[1],
" id ?x1 y1 x2 y2...?\"",
NULL);
440 if (sscanf(argv[2],
"%d", &polyid) != 1) {
441 Tcl_AppendResult(interp,
"not an integer: ", argv[2],
NULL);
446 for (
size_t i = 0; i <
LIST_SIZE(&vgp->poly); i++) {
447 if (
LIST_GET(&vgp->poly, i).id == polyid) {
448 const size_t n =
LIST_GET(&vgp->poly, i).boundary.pn;
449 for (
size_t j = 0; j < n; j++) {
455 Tcl_AppendResult(interp,
" no such polygon: ", argv[2],
NULL);
461 bool vargv_needs_free =
false;
463 result = Tcl_SplitList(interp, argv[3], &vargc, &vargv);
464 if (result != TCL_OK) {
467 vargv_needs_free =
true;
472 if (!vargc || vargc % 2) {
473 Tcl_AppendResult(interp,
474 "There must be a multiple of two terms in the list.",
NULL);
475 if (vargv_needs_free) {
476 Tcl_Free((
char *)vargv);
485 Tcl_AppendResult(interp,
" no such polygon: ", argv[2],
NULL);
486 if (vargv_needs_free) {
487 Tcl_Free((
char *)vargv);
492 result =
insert_poly(interp, vgp, polyid, vargv, vargc);
493 if (vargv_needs_free) {
494 Tcl_Free((
char *)vargv);
498 }
else if (strcmp(argv[1],
"debug") == 0) {
500 printf(
"debug output goes here\n");
503 }
else if (strcmp(argv[1],
"delete") == 0) {
505 free(vgp->triangle_cmd);
509 Tcl_DeleteCommand(interp, argv[0]);
514 }
else if (strcmp(argv[1],
"find") == 0) {
518 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
519 " ", argv[1],
" x y\"",
NULL);
523 bool vargv_needs_free =
false;
525 result = Tcl_SplitList(interp, argv[2], &(
Tcl_Size){0}, &vargv);
526 if (result != TCL_OK) {
529 vargv_needs_free =
true;
533 result =
scanpoint(interp, &vargv[0], &p);
534 if (vargv_needs_free) {
535 Tcl_Free((
char *)vargv);
537 if (result != TCL_OK)
541 for (
size_t i = 0; i <
LIST_SIZE(&vgp->poly); i++) {
543 Tcl_AppendElement(interp,
ITOS(
LIST_GET(&vgp->poly, i).id));
548 }
else if (strcmp(argv[1],
"insert") == 0) {
552 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
553 " ", argv[1],
" x1 y1 x2 y2 ...\"",
NULL);
559 bool vargv_needs_free =
false;
561 result = Tcl_SplitList(interp, argv[2], &vargc, &vargv);
562 if (result != TCL_OK) {
565 vargv_needs_free =
true;
571 if (!vargc || vargc % 2) {
572 Tcl_AppendResult(interp,
573 "There must be a multiple of two terms in the list.",
NULL);
574 if (vargv_needs_free) {
575 Tcl_Free((
char *)vargv);
582 result =
insert_poly(interp, vgp, polyid, vargv, vargc);
583 if (vargv_needs_free) {
584 Tcl_Free((
char *)vargv);
586 if (result != TCL_OK)
589 Tcl_AppendResult(interp,
ITOS(polyid),
NULL);
592 }
else if (strcmp(argv[1],
"list") == 0) {
594 for (
size_t i = 0; i <
LIST_SIZE(&vgp->poly); i++) {
595 Tcl_AppendElement(interp,
ITOS(
LIST_GET(&vgp->poly, i).id));
599 }
else if (strcmp(argv[1],
"path") == 0) {
603 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
604 " ", argv[1],
" x1 y1 x2 y2\"",
NULL);
609 bool vargv_needs_free =
false;
611 result = Tcl_SplitList(interp, argv[2], &vargc, &vargv);
612 if (result != TCL_OK) {
615 vargv_needs_free =
true;
621 Tcl_AppendResult(interp,
622 "invalid points: should be: \"x1 y1 x2 y2\"",
NULL);
623 if (vargv_needs_free) {
624 Tcl_Free((
char *)vargv);
628 result =
scanpoint(interp, &vargv[0], &p);
629 if (result != TCL_OK) {
630 if (vargv_needs_free) {
631 Tcl_Free((
char *)vargv);
635 result =
scanpoint(interp, &vargv[2], &q);
636 if (vargv_needs_free) {
637 Tcl_Free((
char *)vargv);
639 if (result != TCL_OK)
646 for (
size_t i = 0; i < line.
pn; i++) {
653 }
else if (strcmp(argv[1],
"bind") == 0) {
654 if (argc < 2 || argc > 4) {
655 Tcl_AppendResult(interp,
"wrong # args: should be \"",
656 argv[0],
" bind triangle ?command?\"",
NULL);
660 Tcl_AppendElement(interp,
"triangle");
664 if (strcmp(argv[2],
"triangle") == 0) {
665 s = vgp->triangle_cmd;
669 Tcl_AppendResult(interp,
"unknown event \"", argv[2],
670 "\": must be one of:\n\ttriangle.",
NULL);
674 Tcl_AppendResult(interp,
s,
NULL);
677 }
else if (strcmp(argv[1],
"bpath") == 0) {
681 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
682 " ", argv[1],
" x1 y1 x2 y2\"",
NULL);
687 bool vargv_needs_free =
false;
689 result = Tcl_SplitList(interp, argv[2], &vargc, &vargv);
690 if (result != TCL_OK) {
693 vargv_needs_free =
true;
699 Tcl_AppendResult(interp,
700 "invalid points: should be: \"x1 y1 x2 y2\"",
NULL);
704 result =
scanpoint(interp, &vargv[0], &p);
705 if (result != TCL_OK) {
706 if (vargv_needs_free) {
707 Tcl_Free((
char *)vargv);
711 result =
scanpoint(interp, &vargv[2], &q);
712 if (vargv_needs_free) {
713 Tcl_Free((
char *)vargv);
715 if (result != TCL_OK)
721 for (
size_t i = 0; i <
LIST_SIZE(&vgp->poly); i++) {
735 for (
size_t i = 0; i < spline.
pn; i++) {
741 }
else if (strcmp(argv[1],
"bbox") == 0) {
743 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
744 " ", argv[1],
" id\"",
NULL);
747 if (sscanf(argv[2],
"%d", &polyid) != 1) {
748 Tcl_AppendResult(interp,
"not an integer: ", argv[2],
NULL);
751 for (
size_t i = 0; i <
LIST_SIZE(&vgp->poly); i++) {
752 if (
LIST_GET(&vgp->poly, i).id == polyid) {
756 for (
size_t j = 1; j < pp.
pn; j++) {
758 UR.
x = fmax(UR.
x, p.
x);
759 UR.
y = fmax(UR.
y, p.
y);
760 LL.
x = fmin(LL.
x, p.
x);
761 LL.
y = fmin(LL.
y, p.
y);
768 Tcl_AppendResult(interp,
" no such polygon: ", argv[2],
NULL);
771 }
else if (strcmp(argv[1],
"center") == 0) {
773 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
774 " ", argv[1],
" id\"",
NULL);
777 if (sscanf(argv[2],
"%d", &polyid) != 1) {
778 Tcl_AppendResult(interp,
"not an integer: ", argv[2],
NULL);
781 for (
size_t i = 0; i <
LIST_SIZE(&vgp->poly); i++) {
782 if (
LIST_GET(&vgp->poly, i).id == polyid) {
784 LIST_GET(&vgp->poly, i).boundary.pn));
788 Tcl_AppendResult(interp,
" no such polygon: ", argv[2],
NULL);
791 }
else if (strcmp(argv[1],
"triangulate") == 0) {
793 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
794 " ", argv[1],
" id\"",
NULL);
798 if (sscanf(argv[2],
"%d", &polyid) != 1) {
799 Tcl_AppendResult(interp,
"not an integer: ", argv[2],
NULL);
803 for (
size_t i = 0; i <
LIST_SIZE(&vgp->poly); i++) {
804 if (
LIST_GET(&vgp->poly, i).id == polyid) {
807 Tcl_AppendResult(interp,
"polygon ", argv[2],
" has fewer than 3 points "
808 "and thus cannot be triangulated",
NULL);
815 Tcl_AppendResult(interp,
" no such polygon: ", argv[2],
NULL);
817 }
else if (strcmp(argv[1],
"rotate") == 0) {
819 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
820 " ", argv[1],
" id alpha\"",
NULL);
823 if (sscanf(argv[2],
"%d", &polyid) != 1) {
824 Tcl_AppendResult(interp,
"not an integer: ", argv[2],
NULL);
827 if (sscanf(argv[3],
"%lg", &
alpha) != 1) {
828 Tcl_AppendResult(interp,
"not an angle in radians: ", argv[3],
NULL);
831 for (
size_t i = 0; i <
LIST_SIZE(&vgp->poly); i++) {
832 if (
LIST_GET(&vgp->poly, i).id == polyid) {
833 const size_t n =
LIST_GET(&vgp->poly, i).boundary.pn;
834 ps =
LIST_GET(&vgp->poly, i).boundary.ps;
836 for (
size_t j = 0; j < n; j++) {
842 Tcl_AppendResult(interp,
" no such polygon: ", argv[2],
NULL);
845 }
else if (strcmp(argv[1],
"scale") == 0) {
847 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
848 " ", argv[1],
" id gain\"",
NULL);
851 if (sscanf(argv[2],
"%d", &polyid) != 1) {
852 Tcl_AppendResult(interp,
"not an integer: ", argv[2],
NULL);
855 if (sscanf(argv[3],
"%lg", &gain) != 1) {
856 Tcl_AppendResult(interp,
"not a number: ", argv[3],
NULL);
859 for (
size_t i = 0; i <
LIST_SIZE(&vgp->poly); i++) {
860 if (
LIST_GET(&vgp->poly, i).id == polyid) {
861 const size_t n =
LIST_GET(&vgp->poly, i).boundary.pn;
862 ps =
LIST_GET(&vgp->poly, i).boundary.ps;
864 for (
size_t j = 0; j < n; j++) {
870 Tcl_AppendResult(interp,
" no such polygon: ", argv[2],
NULL);
873 }
else if (strcmp(argv[1],
"remove") == 0) {
875 Tcl_AppendResult(interp,
"wrong # args: should be \"", argv[0],
876 " ", argv[1],
" id\"",
NULL);
879 if (sscanf(argv[2],
"%d", &polyid) != 1) {
880 Tcl_AppendResult(interp,
"not an integer: ", argv[2],
NULL);
887 Tcl_AppendResult(interp,
" no such polygon: ", argv[2],
NULL);
891 Tcl_AppendResult(interp,
"bad method \"", argv[1],
892 "\" must be one of:",
893 "\n\tbbox, bind, bpath, center, coords, delete, find,",
894 "\n\tinsert, list, path, remove, rotate, scale, triangulate.",
NULL);
899vgpane(ClientData clientData, Tcl_Interp * interp,
int argc,
const char *argv[])
905 const vgpane_t vg = {.interp = interp};
908 vgp->index =
LIST_SIZE(&vgpaneTable) - 1;
913 const char *
const vbuf =
agxbuse(&buffer);
916 Tcl_AppendResult(interp, vbuf,
NULL);
928 if (Tcl_InitStubs(interp, TCL_VERSION, 0) ==
NULL) {
932 if (Tcl_PkgRequire(interp,
"Tcl", TCL_VERSION, 0) ==
NULL) {
938 char adjusted_version[
sizeof(PACKAGE_VERSION)] = PACKAGE_VERSION;
939 char *tilde_dev = strstr(adjusted_version,
"~dev.");
940 if (tilde_dev !=
NULL) {
942 memmove(tilde_dev + 1, tilde_dev + strlen(
"~dev."),
943 strlen(tilde_dev + strlen(
"~dev.")) + 1);
945 if (Tcl_PkgProvide(interp,
"Tclpathplan", adjusted_version) != TCL_OK) {
Dynamically expanding string buffers.
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)
type-generic dynamically expanding list
#define LIST_AT(list, index)
#define LIST_APPEND(list,...)
#define LIST_DROP_BACK(list)
#define LIST_SET(list, index, item)
#define LIST_IS_EMPTY(list)
#define LIST_GET(list, index)
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)
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 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)
TRI_API int Ptriangulate(Ppoly_t *polygon, void(*fn)(void *closure, const Ppoint_t tri[]), void *vc)