add support for dynamic versions of xdot output.
</TD><TD>E</TD><TD>int<BR>double</TD><TD ALIGN="CENTER">1</TD><TD>0(dot)<BR>1(neato,fdp)</TD><TD></TD> </TR>
<TR><TD><A NAME=a:width HREF=#d:width>width</A>
</TD><TD>N</TD><TD>double</TD><TD ALIGN="CENTER">0.75</TD><TD>0.01</TD><TD></TD> </TR>
+ <TR><TD><A NAME=a:xdotversion HREF=#d:xdotversion>xdotversion</A>
+</TD><TD>G</TD><TD>string</TD><TD ALIGN="CENTER"></TD><TD></TD><TD>xdot only</TD> </TR>
<TR><TD><A NAME=a:xlabel HREF=#d:xlabel>xlabel</A>
</TD><TD>EN</TD><TD><A HREF=#k:lblString>lblString</A>
</TD><TD ALIGN="CENTER">""</TD><TD></TD><TD></TD> </TR>
If neither is set explicitly, the minimum of the two default values
is used.
+<DT><A NAME=d:xdotversion HREF=#a:xdotversion><STRONG>xdotversion</STRONG></A>
+<DD> For xdot output, if this attribute is set, this determines the version of xdot used in output.
+ If not set, the attribute will be set to the xdot version used for output.
+
<DT><A NAME=d:xlabel HREF=#a:xlabel><STRONG>xlabel</STRONG></A>
<DD> External label for a node or edge. For nodes, the label will be placed outside of the
node but near it. For edges, the label will be placed near the center of the edge.
an edge or node is invisible, no drawing operations are attached to it.
<P>
Version info:
-<TABLE border >
-<TR><TH>Xdot version</TH><TH>Graphviz version</TH></TR>
-<TR><TD>1.0</TD><TD>1.9</TD></TR>
-<TR><TD>1.1</TD><TD>2.8</TD></TR>
-<TR><TD>1.2</TD><TD>2.13</TD></TR>
-<TR><TD>1.3</TD><TD>2.31</TD></TR>
-<TR><TD>1.4</TD><TD>2.32</TD></TR>
+<TABLE border="1" >
+<TR><TH>Xdot version</TH><TH>Graphviz version</TH><TH>Modification</TH></TR>
+<TR><TD>1.0</TD> <TD>1.9</TD><TD> </TD></TR>
+<TR><TD>1.1</TD> <TD>2.8</TD><TD>First plug-in version</TD></TR>
+<TR><TD>1.2</TD><TD>2.13</TD><TD>Support image operator <b>I</b></TD></TR>
+<TR><TD>1.3</TD><TD>2.31</TD><TD>Add numerical precision</TD</TR>
+<TR><TD>1.4</TD><TD>2.32</TD><TD>Add gradient colors</TD</TR>
+<TR><TD>1.5</TD><TD>2.34</TD><TD>Fix text layout problem; fix inverted vector in gradient; support version-specific output</TD</TR>
</TABLE>
<DT><A NAME=d:cmap HREF=#a:cmap><STRONG>cmap</STRONG></A>
a color palette, font
antialiasing can show up as a fuzzy white area around characters.
Using <B>truecolor</B>=true avoids this problem.
+:xdotversion:G:string:; xdot
+For xdot output, if this attribute is set, this determines the version of xdot used in output.
+If not set, the attribute will be set to the xdot version used for output.
:vertices:N:pointList; write
If the input graph defines this attribute, the node is polygonal,
and output is dot or xdot, this attribute provides the
an edge or node is invisible, no drawing operations are attached to it.
<P>
Version info:
-<TABLE border >
-<TR><TH>Xdot version</TH><TH>Graphviz version</TH></TR>
-<TR><TD>1.0</TD><TD>1.9</TD></TR>
-<TR><TD>1.1</TD><TD>2.8</TD></TR>
-<TR><TD>1.2</TD><TD>2.13</TD></TR>
-<TR><TD>1.3</TD><TD>2.31</TD></TR>
-<TR><TD>1.4</TD><TD>2.32</TD></TR>
+<TABLE border="1" >
+<TR><TH>Xdot version</TH><TH>Graphviz version</TH><TH>Modification</TH></TR>
+<TR><TD>1.0</TD> <TD>1.9</TD><TD> </TD></TR>
+<TR><TD>1.1</TD> <TD>2.8</TD><TD>First plug-in version</TD></TR>
+<TR><TD>1.2</TD><TD>2.13</TD><TD>Support image operator <b>I</b></TD></TR>
+<TR><TD>1.3</TD><TD>2.31</TD><TD>Add numerical precision</TD</TR>
+<TR><TD>1.4</TD><TD>2.32</TD><TD>Add gradient colors</TD</TR>
+<TR><TD>1.5</TD><TD>2.34</TD><TD>Fix text layout problem; fix inverted vector in gradient; support version-specific output</TD</TR>
</TABLE>
:plain/plain-ext:Simple text format
The plain and plain-ext formats produce output using
* If isRadial is true,sets the inner radius to half the distance to the min point;
* else uses the angle parameter to identify two points on a line that defines the
* gradient direction
+ * By default, this assumes a left-hand coordinate system (for svg); if RHS = 2 flag
+ * is set, use standard coordinate system.
*/
-void get_gradient_points(pointf * A, pointf * G, int n, float angle, boolean isRadial)
+void get_gradient_points(pointf * A, pointf * G, int n, float angle, int flags)
{
int i;
double rx, ry;
pointf min,max,center;
+ int isRadial = flags & 1;
+ int isRHS = flags & 2;
if (n == 2) {
rx = A[1].x - A[0].x;
center.y = min.y + (max.y - min.y)/2;
if (isRadial) {
double inner_r, outer_r;
- outer_r = sqrt((center.x - min.x)*(center.x - min.x) +
+ outer_r = sqrt((center.x - min.x)*(center.x - min.x) +
(center.y - min.y)*(center.y - min.y));
- inner_r = outer_r /4.;
- G[0].x = center.x;
- G[0].y = -center.y;
- G[1].x = inner_r;
- G[1].y = outer_r;
+ inner_r = outer_r /4.;
+ if (isRHS) {
+ G[0].y = center.y;
+ }
+ else {
+ G[0].y = -center.y;
+ }
+ G[0].x = center.x;
+ G[1].x = inner_r;
+ G[1].y = outer_r;
}
else {
- G[0].x = center.x - (max.x - center.x) * cos(angle);
- G[0].y = -center.y + (max.y - center.y) * sin(angle);
- G[1].x = center.x + (center.x - min.x) * cos(angle);
- G[1].y = -center.y - (center.y - min.y) * sin(angle);
+ double half_x = max.x - center.x;
+ double half_y = max.y - center.y;
+ double sina = sin(angle);
+ double cosa = cos(angle);
+ if (isRHS) {
+ G[0].y = center.y - half_y * sina;
+ G[1].y = center.y + half_y * sina;
+ }
+ else {
+ G[0].y = -center.y + (max.y - center.y) * sin(angle);
+ G[1].y = -center.y - (center.y - min.y) * sin(angle);
+ }
+ G[0].x = center.x - half_x * cosa;
+ G[1].x = center.x + half_x * cosa;
}
}
extern boolean overlap_label(textlabel_t *lp, boxf b);
extern boolean overlap_edge(edge_t *e, boxf b);
- extern void get_gradient_points(pointf * A, pointf * G, int n, float angle, boolean isRadial);
+ extern void get_gradient_points(pointf * A, pointf * G, int n, float angle, int flags);
extern int processClusterEdges(graph_t * g);
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#include "macros.h"
#include "const.h"
FORMAT_CANON,
FORMAT_PLAIN,
FORMAT_PLAIN_EXT,
- FORMAT_XDOT
+ FORMAT_XDOT,
+ FORMAT_XDOT12,
+ FORMAT_XDOT14,
} format_type;
#ifdef WIN32 /*dependencies*/
attrsym_t *hl_draw;
attrsym_t *tl_draw;
unsigned char buf[NUMXBUFS][BUFSIZ];
+ unsigned short version;
+ char* version_s;
} xdot_state_t;
static xdot_state_t* xd;
penwidth[EMIT_CLABEL] = 1;
}
+static unsigned short
+versionStr2Version (char* str)
+{
+ char c, buf[BUFSIZ];
+ int n = 0;
+ char* s = str;
+ unsigned short us;
+
+ while ((c = *s++)) {
+ if (isdigit(c)) {
+ if (n < BUFSIZ-1) buf[n++] = c;
+ else {
+ agerr(AGWARN, "xdot version \"%s\" too long", str);
+ break;
+ }
+ }
+ }
+ buf[n] = '\0';
+
+ us = atoi(buf);
+ return us;
+}
+
/*
* John M. suggests:
* You might want to add four more:
* output with them, it could break what we have.
*/
static void
-xdot_begin_graph (graph_t *g, int s_arrows, int e_arrows)
+xdot_begin_graph (graph_t *g, int s_arrows, int e_arrows, format_type id)
{
- int i;
+ int i, us;
+ char* s;
xd = GNEW(xdot_state_t);
+ if (id == FORMAT_XDOT14) {
+ xd->version = 14;
+ xd->version_s = "1.4";
+ }
+ else if (id == FORMAT_XDOT12) {
+ xd->version = 12;
+ xd->version_s = "1.2";
+ }
+ else if ((s = agget(g, "xdotversion")) && s[0] && ((us = versionStr2Version(s)) > 10)) {
+ xd->version = us;
+ xd->version_s = s;
+ }
+ else {
+ xd->version = versionStr2Version(XDOTVERSION);
+ xd->version_s = XDOTVERSION;
+ }
+
if (GD_n_cluster(g))
#ifndef WITH_CGRAPH
xd->g_draw = safe_dcl(g, g, "_draw_", "", agraphattr);
case FORMAT_PLAIN_EXT:
break;
case FORMAT_XDOT:
+ case FORMAT_XDOT12:
+ case FORMAT_XDOT14:
attach_attrs_and_arrows(g, &s_arrows, &e_arrows);
- xdot_begin_graph(g, s_arrows, e_arrows);
+ xdot_begin_graph(g, s_arrows, e_arrows, job->render.id);
+ break;
}
}
#else /* WITH_CGRAPH */
agxset(g, xd->g_l_draw, agxbuse(xbufs[EMIT_GLABEL]));
#endif /* WITH_CGRAPH */
- agsafeset (g, "xdotversion", XDOTVERSION, "");
+ agsafeset (g, "xdotversion", xd->version_s, "");
for (i = 0; i < NUMXBUFS; i++)
agxbfree(xbuf+i);
agwrite(g, (FILE*)job);
break;
case FORMAT_XDOT:
+ case FORMAT_XDOT12:
+ case FORMAT_XDOT14:
xdot_end_graph(g);
if (!(job->flags & OUTPUT_NOT_REQUIRED))
agwrite(g, (FILE*)job);
float r1,r2;
pointf G[2],c1,c2;
+ if (xd->version < 14) {
+ xdot_fillcolor (job);
+ return;
+ }
+
agxbinit(&xbuf, BUFSIZ, buf0);
if (filled == GRADIENT) {
- get_gradient_points(A, G, n, angle, 0);
+ get_gradient_points(A, G, n, angle, 2);
agxbputc (&xbuf, '[');
xdot_point (&xbuf, G[0]);
xdot_point (&xbuf, G[1]);
}
else {
- get_gradient_points(A, G, n, 0, 1);
+ get_gradient_points(A, G, n, 0, 3);
//r1 is inner radius, r2 is outer radius
r1 = G[1].x;
r2 = G[1].y;
{FORMAT_PLAIN, "plain:dot", 1, NULL, &device_features_dot},
{FORMAT_PLAIN_EXT, "plain-ext:dot", 1, NULL, &device_features_dot},
{FORMAT_XDOT, "xdot:xdot", 1, NULL, &device_features_dot},
+ {FORMAT_XDOT12, "xdot1.2:xdot", 1, NULL, &device_features_dot},
+ {FORMAT_XDOT14, "xdot1.4:xdot", 1, NULL, &device_features_dot},
{0, NULL, 0, NULL, NULL}
};