37 if (!p || p[0] ==
'\0')
40 long rv = strtol(p, &endp, 10);
41 if (p == endp || rv > INT_MAX)
53 if (!p || p[0] ==
'\0')
56 double rv = strtod(p, &endp);
86 if (!rv || (rv[0] ==
'\0'))
169 const int degree = 3;
174 for (j = 0; j <= degree; j++) {
179 for (i = 1; i <= degree; i++) {
180 for (j = 0; j <= degree - i; j++) {
182 (1.0 - t) * Vtemp[i - 1][j].x + t * Vtemp[i - 1][j + 1].x;
184 (1.0 - t) * Vtemp[i - 1][j].y + t * Vtemp[i - 1][j + 1].y;
189 for (j = 0; j <= degree; j++)
190 Left[j] = Vtemp[j][0];
192 for (j = 0; j <= degree; j++)
193 Right[j] = Vtemp[degree - j][j];
195 return Vtemp[degree][0];
247 static agxbuf safefilename;
251 char *filename =
agxbuse(&safefilename);
252 if (access(filename, R_OK) == 0)
261 static char *pathlist =
NULL;
264 if (!filename || !filename[0])
270 "file loading is disabled because the environment contains SERVER_NAME=\"%s\"\n",
278 if (pathlist ==
NULL) {
284 const char *
str = filename;
285 for (
const char *sep =
"/\\:"; *sep !=
'\0'; ++sep) {
286 const char *p = strrchr(
str, *sep);
299 if (pathlist && *pathlist)
303 if (*filename ==
DIRSEP[0] || !dirs)
313 for (; (q = name[i]) != 0; i++)
314 if (p &&
streq(p, q))
319bool mapBool(
const char *p,
bool defaultValue) {
320 if (!p || *p ==
'\0')
322 if (!strcasecmp(p,
"false"))
324 if (!strcasecmp(p,
"no"))
326 if (!strcasecmp(p,
"true"))
328 if (!strcasecmp(p,
"yes"))
342 double bestdist2, d2, dlow2, dhigh2;
350 for (
size_t i = 0; i < spl->
size; i++) {
352 for (
size_t j = 0; j < bz.
size; j++) {
358 if (bestj ==
SIZE_MAX || d2 < bestdist2) {
366 bz = spl->
list[besti];
371 if (bestj == bz.
size-1)
373 const size_t j = 3 * (bestj / 3);
374 for (
size_t k = 0; k < 4; k++) {
375 c[k].
x = bz.
list[j + k].
x;
376 c[k].
y = bz.
list[j + k].
y;
380 dlow2 =
DIST2(c[0], pt);
381 dhigh2 =
DIST2(c[3], pt);
383 t = (low + high) / 2.0;
385 if (fabs(dlow2 - dhigh2) < 1.0)
387 if (fabs(high - low) < .00001)
389 if (dlow2 < dhigh2) {
391 dhigh2 =
DIST2(pt2, pt);
394 dlow2 =
DIST2(pt2, pt);
566 double width, height;
578 min = p.
x - width / 2.;
579 max = p.
x + width / 2.;
585 min = p.
y - height / 2.;
586 max = p.
y + height / 2.;
601 const size_t sides =
poly->sides;
602 const size_t peris =
MAX(
poly->peripheries, 1ul);
603 pointf* verts =
poly->vertices + (peris-1)*sides;
606 bb.
LL = bb.
UR = verts[0];
607 for (
size_t i = 1; i < sides; i++) {
643 bb.
UR = (
pointf){-INT_MAX, -INT_MAX};
658 for (
size_t i = 0; i <
ED_spl(e)->size; i++) {
660 ptf =
ED_spl(e)->list[i].list[j];
692 return g == g->
root || !strncasecmp(
agnameof(g),
"cluster", 7) ||
755 const void **p1 = pp1;
756 const void **p2 = pp2;
773 newp->
p[0] = objp->
p[0];
774 newp->
p[1] = objp->
p[1];
783 .size =
sizeof(2 *
sizeof(
void *)),
784 .link = offsetof(
item, link),
880 agwarningf(
"tail cluster %s inside head cluster %s\n",
885 agwarningf(
"head cluster %s inside tail cluster %s\n",
895 agwarningf(
"tail node %s inside head cluster %s\n",
938 int num_cl_edges = 0;
948 clg =
agsubg(g,
"__clusternodes",1);
1013 ntail =
mapN(t, clg);
1014 nhead =
mapN(h, clg);
1045 clg =
agsubg(g,
"__clusternodes",1);
1055 for (i = 0; i < ecnt; i++)
1058 for (n =
agfstnode(clg); n; n = nextn) {
1073 a =
agattr(g, obj_kind, name, defaultValue);
1093 if (key.
data[key.
size] ==
'\0')
return t;
1099 return t + key.
size + 1;
1112 unsigned char*
str = *(
unsigned char**)
s;
1119 if (
byte ==
'x' ||
byte ==
'X') {
1120 for (i = 2; i < 8; i++) {
1122 if (
byte >=
'A' &&
byte <=
'F')
1123 byte =
byte -
'A' + 10;
1124 else if (
byte >=
'a' &&
byte <=
'f')
1125 byte =
byte -
'a' + 10;
1126 else if (
byte >=
'0' &&
byte <=
'9')
1130 n = n * 16 + (int)
byte;
1134 for (i = 1; i < 8; i++) {
1136 if (
byte >=
'0' &&
byte <=
'9')
1137 n = n * 10 + ((int)
byte -
'0');
1153 if (
byte ==
'\0')
break;
1180 size_t len = strlen(
s);
1209 while ((c = *(
unsigned char*)
s++)) {
1227 agwarningf(
"UTF8 codes > 4 bytes are not currently supported (graph %s) - treated as Latin-1. Perhaps \"-Gcharset=latin1\" is needed?\n",
agnameof(g));
1233 if (uc == 0 && c ==
'&') {
1240 else if (v < 0x07FF) {
1241 agxbputc(&xb, (
char)((v >> 6) | 0xC0));
1242 c = (v & 0x3F) | 0x80;
1245 agxbputc(&xb, (
char)((v >> 12) | 0xE0));
1246 agxbputc(&xb, (
char)(((v >> 6) & 0x3F) | 0x80));
1247 c = (v & 0x3F) | 0x80;
1252 for (ui = 0; ui < uc; ++ui)
1253 if ((*
s & 0xC0) == 0x80) {
1255 c = *(
unsigned char*)
s++;
1259 agwarningf(
"Invalid %d-byte UTF8 found in input of graph %s - treated as Latin-1. Perhaps \"-Gcharset=latin1\" is needed?\n", uc + 1,
agnameof(g));
1279 while ((v = *(
unsigned char*)
s++)) {
1286 else if (v < 0x07FF) {
1287 agxbputc(&xb, (
char)((v >> 6) | 0xC0));
1288 agxbputc(&xb, (
char)((v & 0x3F) | 0x80));
1291 agxbputc(&xb, (
char)((v >> 12) | 0xE0));
1292 agxbputc(&xb, (
char)(((v >> 6) & 0x3F) | 0x80));
1293 agxbputc(&xb, (
char)((v & 0x3F) | 0x80));
1309 while ((c = *(
unsigned char*)
s++)) {
1313 unsigned char outc = (c & 0x03) << 6;
1314 c = *(
unsigned char *)
s++;
1315 outc = outc | (c & 0x3F);
1331 return ND_shape(n)->fns->insidefn(&ictxt, p);
1350 for (
size_t i = 1; i < bz.
size; i++) {
1373 for (
size_t i = 0; i < spl->
size; i++)
1386 if (
s ==
NULL || strcmp(
s,
"") == 0) {
1387 return defaultValue;
1392 }
else if (*
s >=
'1' && *
s <=
'9') {
1394 }
else if (strcasecmp(
s,
"curved") == 0) {
1396 }
else if (strcasecmp(
s,
"compound") == 0) {
1398 }
else if (strcasecmp(
s,
"false") == 0) {
1400 }
else if (strcasecmp(
s,
"line") == 0) {
1402 }
else if (strcasecmp(
s,
"none") == 0) {
1404 }
else if (strcasecmp(
s,
"no") == 0) {
1406 }
else if (strcasecmp(
s,
"ortho") == 0) {
1408 }
else if (strcasecmp(
s,
"polyline") == 0) {
1410 }
else if (strcasecmp(
s,
"spline") == 0) {
1412 }
else if (strcasecmp(
s,
"true") == 0) {
1414 }
else if (strcasecmp(
s,
"yes") == 0) {
1418 agwarningf(
"Unknown \"splines\" value: \"%s\" - ignored\n",
s);
1419 return defaultValue;
1435 char*
s =
agget(g,
"splines");
1441 else if (*
s ==
'\0') {
1459 int isRadial =
flags & 1;
1460 int isRHS =
flags & 2;
1463 double rx =
A[1].
x -
A[0].x;
1464 double ry =
A[1].y -
A[0].y;
1465 min.
x =
A[0].x - rx;
1466 max.
x =
A[0].x + rx;
1467 min.
y =
A[0].y - ry;
1468 max.
y =
A[0].y + ry;
1471 min.
x = max.
x =
A[0].x;
1472 min.
y = max.
y =
A[0].y;
1473 for (
size_t i = 0; i < n; i++) {
1474 min.
x =
MIN(
A[i].x, min.
x);
1475 min.
y =
MIN(
A[i].y, min.
y);
1476 max.
x =
MAX(
A[i].x, max.
x);
1477 max.
y =
MAX(
A[i].y, max.
y);
1483 double inner_r, outer_r;
1485 inner_r = outer_r /4.;
1499 double sina = sin(angle);
1500 double cosa = cos(angle);
1516 for (
size_t i = 0; i <
ED_spl(e)->size; i++)
1578 .link = offsetof(
clust_t, link),
1588 agwarningf(
"Two clusters named %s - the second will be ignored\n",
s);
static void agxbfree(agxbuf *xb)
free any malloced resources
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
static WUR char * agxbuse(agxbuf *xb)
static int agxbputc(agxbuf *xb, char c)
add character to buffer
static char * agxbdisown(agxbuf *xb)
Memory allocation wrappers that exit on failure.
static void * gv_recalloc(void *ptr, size_t old_nmemb, size_t new_nmemb, size_t size)
static void * gv_calloc(size_t nmemb, size_t size)
static void * gv_alloc(size_t size)
boxf arrow_bb(pointf p, pointf u, double arrowsize)
CDT_API int dtclose(Dt_t *)
CDT_API Dtmethod_t * Dtoset
ordered set (self-adjusting tree)
CDT_API Dt_t * dtopen(Dtdisc_t *, Dtmethod_t *)
pointf Bezier(pointf *V, double t, pointf *Left, pointf *Right)
void processClusterEdges(graph_t *g)
void undoClusterEdges(graph_t *g)
char * late_nnstring(void *obj, attrsym_t *attr, char *defaultValue)
char * scanEntity(char *t, agxbuf *xb)
static edge_t * cloneEdge(edge_t *e, node_t *ct, node_t *ch)
Make a copy of e in e's graph but using ct and ch as nodes.
bool mapbool(const char *p)
node_t * UF_union(node_t *u, node_t *v)
node_t * UF_find(node_t *n)
static node_t * mapN(node_t *n, graph_t *clg)
Dt_t * mkClustMap(Agraph_t *g)
void UF_setname(node_t *u, node_t *v)
static void undoCompound(edge_t *e, graph_t *clg)
void setEdgeType(graph_t *g, int defaultValue)
static port chkPort(port(*pf)(node_t *, char *, char *), node_t *n, char *s)
char * late_string(void *obj, attrsym_t *attr, char *defaultValue)
void gv_free_splines(edge_t *e)
boxf polyBB(polygon_t *poly)
int late_int(void *obj, attrsym_t *attr, int defaultValue, int minimum)
void gv_cleanup_edge(edge_t *e)
static void insertEdge(Dt_t *map, void *t, void *h, edge_t *e)
void common_init_node(node_t *n)
bool overlap_label(textlabel_t *lp, boxf b)
int maptoken(char *p, char **name, int *val)
double late_double(void *obj, attrsym_t *attr, double defaultValue, double minimum)
static char * findPath(const strview_t *dirs, const char *str)
static void initFontLabelEdgeAttr(edge_t *e, struct fontinfo *fi, struct fontinfo *lfi)
bool overlap_node(node_t *n, boxf b)
static int comp_entities(const void *e1, const void *e2)
void common_init_edge(edge_t *e)
static bool noClip(edge_t *e, attrsym_t *sym)
Return true if head/tail end of edge should not be clipped to node.
const char * safefile(const char *filename)
pointf dotneato_closest(splines *spl, pointf pt)
static strview_t * mkDirlist(const char *list)
static bool overlap_bezier(bezier bz, boxf b)
static void * newItem(void *p, Dtdisc_t *disc)
attrsym_t * safe_dcl(graph_t *g, int obj_kind, char *name, char *defaultValue)
void UF_singleton(node_t *u)
static void initFontEdgeAttr(edge_t *e, struct fontinfo *fi)
char * utf8ToLatin1(char *s)
static int cmpItem(void *pp1, void *pp2)
char * latin1ToUTF8(char *s)
Converts string from Latin1 encoding to utf8. Also translates HTML entities.
double get_inputscale(graph_t *g)
static int edgeType(const char *s, int defaultValue)
Convert string to edge type.
static boxf addLabelBB(boxf bb, textlabel_t *lp, bool flipxy)
void updateBB(graph_t *g, textlabel_t *lp)
static bool overlap_arrow(pointf p, pointf u, double scale, boxf b)
static int checkCompound(edge_t *e, graph_t *clg, agxbuf *xb, Dt_t *map, Dt_t *cmap)
bool overlap_edge(edge_t *e, boxf b)
static unsigned char cvtAndAppend(unsigned char c, agxbuf *xb)
void compute_bb(graph_t *g)
static void fillMap(Agraph_t *g, Dt_t *map)
static node_t * clustNode(node_t *n, graph_t *cg, agxbuf *xb, graph_t *clg)
void gv_cleanup_node(node_t *n)
bool mapBool(const char *p, bool defaultValue)
char * htmlEntityUTF8(char *s, graph_t *g)
static int num_clust_edges(graph_t *g)
void get_gradient_points(pointf *A, pointf *G, size_t n, double angle, int flags)
void gv_nodesize(node_t *n, bool flip)
static item * mapEdge(Dt_t *map, edge_t *e)
Check if we already have cluster edge corresponding to t->h, and return it.
static int htmlEntity(char **s)
bool is_a_cluster(Agraph_t *g)
static graph_t * mapc(Dt_t *cmap, node_t *n)
bool late_bool(void *obj, attrsym_t *attr, bool defaultValue)
Agraph_t * findCluster(Dt_t *map, char *name)
Agsym_t * setAttr(graph_t *g, void *obj, char *name, char *value, Agsym_t *ap)
#define DEFAULT_NODEHEIGHT
#define DEFAULT_NODEWIDTH
#define EDGETYPE_COMPOUND
#define DEFAULT_NODESHAPE
#define ENTITY_NAME_LENGTH_MAX
static const struct entities_s entities[]
int lineToBox(pointf p, pointf q, boxf b)
#define INCH2PS(a_inches)
static pointf mid_pointf(pointf p, pointf q)
static pointf add_pointf(pointf p, pointf q)
static pointf sub_pointf(pointf p, pointf q)
static pointf scale(double c, pointf p)
static bool boxf_overlap(boxf b0, boxf b1)
Agsym_t * E_labelfontsize
Agsym_t * E_labelfontname
Agsym_t * E_labelfontcolor
static double len(glCompPoint p)
static int cnt(Dict_t *d, Dtlink_t **set)
int agnnodes(Agraph_t *g)
Agsym_t * agattr(Agraph_t *g, int kind, char *name, const char *value)
creates or looks up attributes of a graph
Agsym_t * agnxtattr(Agraph_t *g, int kind, Agsym_t *attr)
permits traversing the list of attributes of a given type
int agxset(void *obj, Agsym_t *sym, const char *value)
char * agget(void *obj, char *name)
char * agxget(void *obj, Agsym_t *sym)
int agcopyattr(void *oldobj, void *newobj)
copies all of the attributes from one object to another
Agedge_t * agedge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *name, int createflag)
#define ED_label_ontop(e)
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
#define agfindedge(g, t, h)
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
void agwarningf(const char *fmt,...)
#define agfindgraphattr(g, a)
int agclose(Agraph_t *g)
deletes a graph, freeing its associated storage
Agnode_t * agnode(Agraph_t *g, char *name, int createflag)
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Agnode_t * agfstnode(Agraph_t *g)
Agnode_t * agsubnode(Agraph_t *g, Agnode_t *n, int createflag)
Agraph_t * agraphof(void *obj)
#define AGDATA(obj)
returns Agrec_t
char * agnameof(void *)
returns a string descriptor for the object.
int agdelete(Agraph_t *g, void *obj)
deletes object. Equivalent to agclose, agdelnode, and agdeledge for obj being a graph,...
int agcontains(Agraph_t *, void *obj)
returns non-zero if obj is a member of (sub)graph
Agraph_t * agroot(void *obj)
void * agbindrec(void *obj, const char *name, unsigned int recsize, int move_to_front)
attaches a new record of the given size to the object
int agdelrec(void *obj, const char *name)
deletes a named record from one object
int aghtmlstr(const char *)
Agraph_t * agsubg(Agraph_t *g, char *name, int cflag)
replacements for ctype.h functions
static bool gv_isdigit(int c)
Arithmetic helper functions.
static bool is_exactly_zero(double v)
is a value precisely 0.0?
static int imin(int a, int b)
minimum of two integers
Graphviz context library.
textitem scanner parser str
textlabel_t * make_label(void *obj, char *str, int kind, double fontsize, char *fontname, char *fontcolor)
void free_label(textlabel_t *p)
#define SET_CLUST_NODE(n)
#define HAS_CLUST_EDGE(g)
NEATOPROCS_API void s1(graph_t *, node_t *)
shape_kind shapeOf(node_t *)
shape_desc * bind_shape(char *name, node_t *)
static double cg(SparseMatrix A, const double *precond, int n, int dim, double *x0, double *rhs, double tol, double maxit)
static bool startswith(const char *s, const char *prefix)
does the string s begin with the string prefix?
platform abstraction for case-insensitive string functions
static bool streq(const char *a, const char *b)
are a and b equal?
Agraph_t * root
subgraphs - ancestors
implementation of Agrec_t
size_t size
number of characters in the buffer
a non-owning string reference
const char * data
start of the pointed to string
size_t size
extent of the string in bytes
state for an in-progress string tokenization
Non-owning string references.
static int strview_cmp(strview_t a, strview_t b)
compare two string references
static strview_t strview(const char *referent, char terminator)
create a string reference
static point center(point vertex[], size_t n)
static strview_t tok_get(const tok_t *t)
get the current token
static tok_t tok(const char *input, const char *separators)
begin tokenization of a new string
static bool tok_end(const tok_t *t)
is this tokenizer exhausted?
static void tok_next(tok_t *t)
advance to the next token in the string being scanned
int(* pf)(void *, char *,...)