A[3].x = A[0].x;
A[3].y = A[2].y;
- gvrender_usershape(job, cp->src, A, 4, TRUE);
+ gvrender_usershape(job, cp->src, A, 4, TRUE, 0);
}
static void
else {
imagesize.x = imagesize.y = 0;
}
- dimen.x = MAX(dimen.x, imagesize.x);
- dimen.y = MAX(dimen.y, imagesize.y);
+ dimen.x = MAX(dimen.x, imagesize.x+2);
+ dimen.y = MAX(dimen.y, imagesize.y+2);
}
}
pencolor(job, n); /* emit pen color */
}
+ /* if no boundary but filled, set boundary color to fill color */
+ if ((peripheries == 0) && filled) {
+ char *color;
+ peripheries = 1;
+ color = findFill(n);
+ if (color[0])
+ gvrender_set_pencolor(job, color);
+ }
if (ND_shape(n)->usershape) {
+ int shapefilled = filled;
+ if (filled) {
+ for (i = 0; i < sides; i++) {
+ P = vertices[i];
+ AF[i].x = P.x * xsize;
+ AF[i].y = P.y * ysize;
+ if (sides > 2) {
+ AF[i].x += (double)ND_coord_i(n).x;
+ AF[i].y += (double)ND_coord_i(n).y;
+ }
+ }
+ if (sides <= 2) {
+ pointf PF;
+
+ P2PF(ND_coord_i(n), PF);
+ gvrender_ellipse(job, PF, AF[0].x, AF[0].y, filled);
+ if (style & DIAGONALS) {
+ Mcircle_hack(job, n);
+ }
+ } else if (style & (ROUNDED | DIAGONALS)) {
+ node_round_corners(job, n, AF, sides, style);
+ } else {
+ gvrender_polygon(job, AF, sides, filled);
+ }
+ filled = FALSE;
+ }
for (i = 0; i < sides; i++) {
P = vertices[i];
AF[i].x = P.x * xsize;
name = ND_shape(n)->name;
if (streq(name, "custom"))
name = agget(n, "shapefile");
- gvrender_usershape(job, name, AF, sides, filled);
- filled = FALSE;
- }
- /* if no boundary but filled, set boundary color to fill color */
- if ((peripheries == 0) && filled) {
- char *color;
- peripheries = 1;
- color = findFill(n);
- if (color[0])
- gvrender_set_pencolor(job, color);
+ gvrender_usershape(job, name, AF, sides, shapefilled, FALSE);
}
+
for (j = 0; j < peripheries; j++) {
for (i = 0; i < sides; i++) {
P = vertices[i + j * sides];
extern void gvloadimage(GVJ_t *job, usershape_t *us, boxf b, boolean filled, char *target);
/* usershapes */
+ extern point gvusershape_size_dpi(usershape_t*, pointf);
extern point gvusershape_size(graph_t *g, char *name);
extern usershape_t *gvusershape_find(char *name);
int arrow_at_start, int arrow_at_end, boolean filled);
extern void gvrender_polyline(GVJ_t * job, pointf * AF, int n);
extern void gvrender_comment(GVJ_t * job, char *str);
- extern void gvrender_usershape(GVJ_t * job, char *name, pointf * AF, int n, boolean filled);
+ extern void gvrender_usershape(GVJ_t * job, char *name, pointf * AF, int n, boolean filled, boolean expand);
/* layout */
#endif
}
-void gvrender_usershape(GVJ_t * job, char *name, pointf * a, int n, boolean filled)
+/* gvrender_usershape:
+ * If expand is true, if necessary expand user image to fill polygon a,
+ * maintaining aspect ratio.
+ */
+void gvrender_usershape(GVJ_t * job, char *name, pointf * a, int n,
+ boolean filled, boolean expand)
{
gvrender_engine_t *gvre = job->render.engine;
usershape_t *us;
- double iw, ih, pw, ph, tw, th;
+ double iw, ih, pw, ph;
double scalex, scaley; /* scale factors */
boxf b; /* target box */
int i;
- pointf *af;
+ point isz;
if (! (us = gvusershape_find(name))) {
if (find_user_shape(name)) {
return;
}
- if (job->flags & GVRENDER_DOES_TRANSFORM)
- af = a;
- else {
- if (sizeAF < n) {
- sizeAF = n+10;
- AF = grealloc(AF, sizeAF * sizeof(pointf));
- }
- gvrender_ptf_A(job, a, AF, n);
- af = AF;
- }
+ isz = gvusershape_size_dpi (us, job->dpi);
+ if ((isz.x <= 0) && (isz.y <= 0)) return;
/* compute bb of polygon */
- b.LL = b.UR = af[0];
+ b.LL = b.UR = a[0];
for (i = 1; i < n; i++) {
- EXPANDBP(b, af[i]);
+ EXPANDBP(b, a[i]);
}
- ih = (double)us->h;
- iw = (double)us->w;
pw = b.UR.x - b.LL.x;
ph = b.UR.y - b.LL.y;
- scalex = pw / iw;
- scaley = ph / ih;
-
+ ih = (double)isz.y;
+ iw = (double)isz.x;
+ if (expand) {
+ scalex = pw / iw;
+ scaley = ph / ih;
/* keep aspect ratio fixed by just using the smaller scale */
- if (scalex < scaley) {
- tw = iw * scalex;
- th = ih * scalex;
- } else {
- tw = iw * scaley;
- th = ih * scaley;
+ if (scalex < scaley) {
+ iw *= scalex;
+ ih *= scalex;
+ } else {
+ iw *= scaley;
+ ih *= scaley;
+ }
}
+
/* if image is smaller than target area then center it */
- if (tw < pw) {
- b.LL.x += (pw - tw) / 2.0;
- b.UR.x -= (pw - tw) / 2.0;
+ if (iw < pw) {
+ b.LL.x += (pw - iw) / 2.0;
+ b.UR.x -= (pw - iw) / 2.0;
+ }
+ if (ih < ph) {
+ b.LL.y += (ph - ih) / 2.0;
+ b.UR.y -= (ph - ih) / 2.0;
}
- if (th < ph) {
- b.LL.y += (ph - th) / 2.0;
- b.UR.y -= (ph - th) / 2.0;
+
+ /* convert from graph to device coordinates */
+ if (!(job->flags & GVRENDER_DOES_TRANSFORM)) {
+ b.LL = gvrender_ptf(job, b.LL);
+ b.UR = gvrender_ptf(job, b.UR);
}
+ if (b.LL.x > b.UR.x) {
+ double d = b.LL.x;
+ b.LL.x = b.UR.x;
+ b.UR.x = d;
+ }
+ if (b.LL.y > b.UR.y) {
+ double d = b.LL.y;
+ b.LL.y = b.UR.y;
+ b.UR.y = d;
+ }
if (gvre) {
if (job->render.features->loadimage_target)
gvloadimage(job, us, b, filled, job->render.features->loadimage_target);
{
unsigned int w, h;
- us->dpi = DEFAULT_DPI;
+ us->dpi = 0;
fseek(us->f, 16, SEEK_SET);
if (get_int_msb_first(us->f, 4, &w) && get_int_msb_first(us->f, 4, &h)) {
us->w = w;
{
unsigned int w, h;
- us->dpi = DEFAULT_DPI;
+ us->dpi = 0;
fseek(us->f, 6, SEEK_SET);
if (get_int_lsb_first(us->f, 2, &w) && get_int_lsb_first(us->f, 2, &h)) {
us->w = w;
static void bmp_size (usershape_t *us) {
unsigned int size_x_msw, size_x_lsw, size_y_msw, size_y_lsw;
- us->dpi = DEFAULT_DPI;
+ us->dpi = 0;
fseek (us->f, 16, SEEK_SET);
if ( get_int_lsb_first (us->f, 2, &size_x_msw) &&
get_int_lsb_first (us->f, 2, &size_x_lsw) &&
0
};
- us->dpi = DEFAULT_DPI;
+ us->dpi = 0;
while (TRUE) {
/* Now we must be at a 0xff or at a series of 0xff's.
* If that is not the case, or if we're at EOF, then there's
return us;
}
-point gvusershape_size(graph_t * g, char *name)
+/* gvusershape_size_dpi:
+ * Return image size in points.
+ */
+point
+gvusershape_size_dpi (usershape_t* us, pointf dpi)
{
point rv;
- usershape_t *us;
- double dpi;
- dpi = GD_drawing(g)->dpi;
- if (dpi < 1.0)
- dpi = POINTS_PER_INCH;
-
- /* no shape file, no shape size */
- if (!name || (*name == '\0') || !(us = gvusershape_open (name))) {
+ if (!us) {
rv.x = rv.y = -1;
}
else {
- rv.x = us->w * dpi / us->dpi;
- rv.y = us->h * dpi / us->dpi;
+ if (us->dpi != 0) {
+ dpi.x = dpi.y = us->dpi;
+ }
+ rv.x = us->w * POINTS_PER_INCH / dpi.x;
+ rv.y = us->h * POINTS_PER_INCH / dpi.y;
}
return rv;
}
+
+/* gvusershape_size:
+ * Loads user image from file name if not already loaded.
+ * Return image size in points.
+ */
+point gvusershape_size(graph_t * g, char *name)
+{
+ point rv;
+ pointf dpi;
+
+ /* no shape file, no shape size */
+ if (!name || (*name == '\0')) {
+ rv.x = rv.y = -1;
+ return rv;
+ }
+
+ if ((dpi.y = GD_drawing(g)->dpi) >= 1.0)
+ dpi.x = dpi.y;
+ else
+ dpi.x = dpi.y = (double)DEFAULT_DPI;
+
+ return gvusershape_size_dpi (gvusershape_open (name), dpi);
+}
extern void core_fputs(GVJ_t * job, char *s);
extern void core_printf(GVJ_t * job, const char *format, ...);
+extern void core_loadimage_xdot(GVJ_t*, usershape_t*, boxf, boolean);
extern void epsf_emit_body(usershape_t *us, FILE *of);
extern shape_desc *find_user_shape(char *name);
typedef enum {
FORMAT_PNG_SVG, FORMAT_GIF_SVG, FORMAT_JPEG_SVG,
+ FORMAT_PNG_XDOT, FORMAT_GIF_XDOT, FORMAT_JPEG_XDOT,
FORMAT_PNG_FIG, FORMAT_GIF_FIG, FORMAT_JPEG_FIG,
FORMAT_PNG_VRML, FORMAT_GIF_VRML, FORMAT_JPEG_VRML,
FORMAT_PS_PS, FORMAT__PS,
core_loadimage_pslib
};
+static gvloadimage_engine_t engine_xdot = {
+ core_loadimage_xdot
+};
+
gvplugin_installed_t gvloadimage_core_types[] = {
{FORMAT_PNG_SVG, "png2svg", 1, &engine_svg, NULL},
{FORMAT_GIF_SVG, "gif2svg", 1, &engine_svg, NULL},
{FORMAT_JPEG_VRML, "jpeg2vrml", 1, &engine_vrml, NULL},
{FORMAT_PS_PS, "ps2ps", 1, &engine_ps, NULL},
{FORMAT__PS, "2ps", 1, &engine_pslib, NULL},
+ {FORMAT_PNG_XDOT, "png2xdot", 1, &engine_xdot, NULL},
+ {FORMAT_GIF_XDOT, "gif2xdot", 1, &engine_xdot, NULL},
+ {FORMAT_JPEG_XDOT, "jpeg2xdot", 1, &engine_xdot, NULL},
{0, NULL, 0, NULL, NULL}
};
typedef enum { FORMAT_DOT, FORMAT_CANON, FORMAT_PLAIN, FORMAT_PLAIN_EXT, FORMAT_XDOT } format_type;
-#define XDOTVERSION "1.1"
+#define XDOTVERSION "1.2"
#define NUMXBUFS (EMIT_HLABEL+1)
/* There are as many xbufs as there are values of emit_state_t.
xdot_points(job, 'L', A, n);
}
+void core_loadimage_xdot(GVJ_t * job, usershape_t *us, boxf b, boolean filled)
+{
+ emit_state_t emit_state = job->obj->emit_state;
+ char buf[BUFSIZ];
+
+ agxbput(xbufs[emit_state], "I ");
+ output_point(xbufs[emit_state], b.LL);
+ sprintf(buf, "%d %d ", ROUND(b.UR.x - b.LL.x), ROUND(b.UR.y - b.LL.y));
+ agxbput(xbufs[emit_state], buf);
+ xdot_str (job, "", us->name);
+}
+
gvrender_engine_t dot_engine = {
0, /* dot_begin_job */
0, /* dot_end_job */
NULL, /* gvloadimage target for usershapes */
};
+gvrender_features_t xdot_features = {
+ GVRENDER_DOES_TRANSFORM, /* not really - uses raw graph coords */
+ 0., /* default margin - points */
+ 0., /* default pad - graph units */
+ {0.,0.}, /* default page width, height - points */
+ {72.,72.}, /* default dpi */
+ NULL, /* knowncolors */
+ 0, /* sizeof knowncolors */
+ COLOR_STRING, /* color_type */
+ NULL, /* device */
+ "xdot", /* gvloadimage target for usershapes */
+};
+
gvplugin_installed_t gvrender_core_dot_types[] = {
{FORMAT_DOT, "dot", 1, &dot_engine, &dot_features},
{FORMAT_CANON, "canon", 1, &dot_engine, &canon_features},
{FORMAT_PLAIN, "plain", 1, &dot_engine, &dot_features},
{FORMAT_PLAIN_EXT, "plain-ext", 1, &dot_engine, &dot_features},
- {FORMAT_XDOT, "xdot", 1, &xdot_engine, &dot_features},
+ {FORMAT_XDOT, "xdot", 1, &xdot_engine, &xdot_features},
{0, NULL, 0, NULL, NULL}
};