|
|
researchv10 Norman
/*
* emit PostScript.
*
*/
#include "draw_dag.h"
#include "dag.h"
#include "parsedag.h"
#include "paths.h"
static double PS_scalefactor;
static dag_ink_t Current_PS_ink;
static Point Page_min,Page_max;
static Point PS_page_size,PS_Margin;
static int Pages_across, Pages_up;
static int Page_number = 0;
static char* escape(char *s) {
static char buf[BUFSIZ];
char *p = buf;
while (*s) {
if ((*s == '(') || (*s == ')')) *p++ = '\\';
*p++ = *s++;
}
*p = '\0';
return buf;
}
void emit_ps_setink(dag_ink_t ink) {
char *inkstr;
switch(ink) {
case solid_ink:
inkstr = "[] 0"; break;
case dashed_ink:
inkstr = "[9 9 idtransform abs ceiling exch abs ceiling exch] 0"; break;
case dotted_ink:
inkstr = "[1 6 idtransform abs ceiling exch abs ceiling exch] 0"; break;
case invis_ink:
inkstr = "[0 1] 1"; break;
}
printf("%s setdash\n",inkstr);
Current_PS_ink = ink;
}
void emit_ps_header() {
if (!Page_number) {
printf("%%! PostScript\n%%%%EndComments\n");
printf("/Reset_Node_Pointsize %d def\n",Reset_node.pointsize);
printf("/Reset_Edge_Pointsize %d def\n",Reset_edge.pointsize);
printf("/coordfont /Times-Roman findfont 6 scalefont def\n");
cat_libfile(DAGLIB_PS);
}
PS_scalefactor = 1.;
if (User.width > 0) {
PS_scalefactor = min((User.width*Resolution)/Xmax,1.);
if (User.height <= 0) User.height = (double)Ymax/Resolution;
else PS_scalefactor = min((User.height*Resolution)/Ymax,PS_scalefactor);
}
if ((Page_size.x == 0) && (Page_size.y == 0) && (User.width != 0)) {
PS_page_size.x = round(User.width * Resolution / PS_scalefactor);
PS_page_size.y = round(User.height * Resolution / PS_scalefactor);
}
else {
if (Page_size.x) {
PS_page_size.x = round(Page_size.x / PS_scalefactor);
PS_page_size.y = round(Page_size.y / PS_scalefactor);
}
else {
PS_page_size.x = Xmax;
PS_page_size.y = Ymax;
}
}
PS_Margin.x = (int)(Margin.x/PS_scalefactor);
PS_Margin.y = (int)(Margin.x/PS_scalefactor);
printf("save\n");
if (Default_node.pointsize != Reset_node.pointsize)
printf("/dagnodefont dagnodefont %.3f scalefont def\n",
Default_node.pointsize/(double)Reset_node.pointsize);
if (Default_edge.pointsize != Reset_edge.pointsize)
printf("/dagedgefont dagedgefont %.3f scalefont def\n",
Default_edge.pointsize/(double)Reset_edge.pointsize);
printf("/coordfont /Times-Roman findfont %d scalefont def\n",(int)(6/PS_scalefactor));
if (PS_scalefactor != 1.) printf("%.3f %.3f scale\n",PS_scalefactor,PS_scalefactor);
printf("/arrowlength %d def\n",Default_node.ysize/5);
printf("/arrowwidth arrowlength 2 div def\n");
unsquirrel(); // inside save region, so will not affect global defs
printf("%%%%EndProlog\n");
}
void emit_ps_node_header() {
printf("dagnodefont setfont\n");
}
void emit_ps_edge_header() {
emit_ps_setink(Default_edge.ink);
Current_PS_ink = Default_edge.ink;
printf("dagedgefont setfont\n");
}
/* emit drawing code for an edge label */
void emit_ps_edgelabel(DAG_edge_t *e) {
if (!e->label.type) return; // no label
if (e->pointsize != Default_edge.pointsize)
printf("dagedgefont %.3f scalefont setfont\n",
PS_scalefactor * e->pointsize / Default_edge.pointsize);
Point midpoint = find_edge_midpoint(e);
printf("%d %d moveto\n",midpoint.x,midpoint.y);
switch (e->label.type) {
case DESC:
printf("gsave\n%s\ngrestore\n",e->label.value);
break;
case STRING:
printf("(%s) show\n",escape(e->label.value));
}
if (e->pointsize != Default_edge.pointsize)
printf("dagedgefront setfont\n");
}
void emit_ps_node(int node) {
char *printname;
if (Node[node]->label.type == STRING)
printname = Node[node]->label.value;
else if (Node[node]->label.type == DESC)
printname = "";
else printname = Node[node]->name;
printf("%d %d moveto\n",Node[node]->pos.x,Node[node]->pos.y);
if (Node[node]->color)
printf("gsave %s setdagcolor\n",Node[node]->color);
if (Node[node]->pointsize != Default_node.pointsize)
printf("dagnodefont %.3f scalefont setfont\n",
(PS_scalefactor*Node[node]->pointsize)/Default_node.pointsize);
if (Node[node]->shape.type == STRING)
printf("(%s) %d %d %s\n",escape(printname),Node[node]->xsize,Node[node]->ysize,Node[node]->shape.value);
else printf("%s\n",Node[node]->shape.value);
if (Node[node]->label.type == DESC) {
printf("%d %d moveto\n",Node[node]->pos.x,Node[node]->pos.y);
printf("%s\n",Node[node]->label.value);
}
if (Node[node]->pointsize != Default_node.pointsize)
printf("dagnodefont setfont\n");
if (Node[node]->color)
printf("grestore\n");
}
/*
* generate PS code to place node intersection on stack.
* intersection is the ray from rayorg through rayinter
*/
void emit_ps_nodeport(int node,Point rayorg, Point rayinter) {
printf(" %d %d %d %d %d %d ",Node[node]->xsize,Node[node]->ysize,rayorg.x - Node[node]->pos.x,rayorg.y - Node[node]->pos.y,rayinter.x - Node[node]->pos.x,rayinter.y - Node[node]->pos.y);
printf("%s_clip\n",Node[node]->shape.type == STRING? Node[node]->shape.value : Default_node.shape.value);
printf("%d add exch %d add exch\n",Node[node]->pos.y,Node[node]->pos.x);
}
Point find_seg_midpoint(Point p0, Point p1) {
Point rv;
rv.x = (p0.x + p1.x) / 2;
rv.y = (p0.y + p1.y) / 2;
return rv;
}
void emit_ps_edge(int node, DAG_edge_t *e) {
if (e->ink == invis_ink) return;
int fromnode = node, tonode = e->node;
if (e->ink != Current_PS_ink) emit_ps_setink(e->ink);
printf("%% %s %s edge\n",Node[fromnode]->name,Node[tonode]->name);
if (e->color != 0) {printf("gsave %s setdagcolor\n",e->color);}
printf("newpath ");
emit_ps_nodeport(fromnode,e->top,e->splinept[0]); printf("moveto\n");
Point mp = find_seg_midpoint(e->splinept[0],e->splinept[1]);
if (e->flipped)
printf("%d %d makearrow\n",e->top.x,e->top.y);
printf(" %d %d lineto\n",mp.x,mp.y);
for (int i = 1; e->splinept[i + 1].x >= 0; i++) {
Point mp = find_seg_midpoint(e->splinept[i],e->splinept[i+1]);
printf("%d %d 2 copy %d %d curveto\n",
e->splinept[i].x,e->splinept[i].y,mp.x,mp.y);
}
emit_ps_nodeport(tonode,e->bottom,e->splinept[i]);
printf("lineto currentpoint stroke moveto\n");
if (!e->flipped)
printf("%d %d makearrow\n",e->bottom.x,e->bottom.y);
printf("stroke\n");
if (e->color != 0) {printf("grestore\n");}
emit_ps_edgelabel(e);
}
void emit_ps_trailer() {
printf("restore\n");
}
void emit_ps_page() {
printf("showpage\ngrestore\n");
}
int n_ps_pages() {
int rv;
Pages_across = Xmax / PS_page_size.x;
if (Pages_across != (double)Xmax/PS_page_size.x) Pages_across++;
Pages_up = Ymax / PS_page_size.y;
if (Pages_up != (double)Ymax/PS_page_size.y) Pages_up++;
rv = Pages_across * Pages_up;
return rv;
}
void emit_ps_set_page(int page) {
int row = page % Pages_up;
int col = (page - row) / Pages_up;
Page_min.x = col * PS_page_size.x;
Page_min.y = row * PS_page_size.y;
Page_max.x = Page_min.x + PS_page_size.x;
Page_max.y = Page_min.y + PS_page_size.y;
printf("%%%%Page: %s %d\n",Current_file.name,++Page_number);
printf("%%%%BoundingBox: %d %d %d %d\n",
PS_Margin.x-1,PS_Margin.y-1,PS_Margin.x+PS_page_size.x+1,PS_Margin.y+PS_page_size.y+1);
printf("gsave\n");
/* page coord before clip so it can be in the margin if ever change this */
if ((Pages_up > 1) || (Pages_across > 1))
printf("coordfont setfont %d %d moveto (%d,%d) show\n",
PS_Margin.x,PS_Margin.y,col,row);
printf("%d %d moveto %d 0 rlineto 0 %d rlineto %d 0 rlineto closepath clip newpath\n",
PS_Margin.x-1,PS_Margin.y-1,PS_page_size.x+2,PS_page_size.y+2,-PS_page_size.x-2); // off by one pixel?
printf("%d %d translate\n",PS_Margin.x - Page_min.x,PS_Margin.y - Page_min.y);
}
int node_in_page(int node) {
int halfx = Node[node]->xsize / 2;
int halfy = Node[node]->ysize / 2;
for (int xcorner = Node[node]->pos.x - halfx; xcorner <= Node[node]->pos.x + halfx; xcorner += halfx) {
for (int ycorner = Node[node]->pos.y - halfy; ycorner <= Node[node]->pos.y + halfy; ycorner += halfy) {
if ((ycorner >= Page_min.y) && (ycorner <= Page_max.y)
&& (xcorner >= Page_min.x) && (xcorner <= Page_max.x))
return 1;
}
}
return 0;
}
int edge_in_page(DAG_edge_t* e) {
for (int i = 0; e->splinept[i+1].x >= 0; i++) {
Point pt0 = e->splinept[i];
Point pt1 = e->splinept[i+1];
if (!(((pt0.x < Page_min.x) && (pt1.x < Page_min.x)) ||
((pt0.x > Page_max.x) && (pt1.x > Page_max.x)) ||
((pt0.y < Page_min.y) && (pt1.y < Page_min.y)) ||
((pt0.y > Page_max.y) && (pt1.y > Page_max.y)))) return 1;
}
return 0;
}
void emit_ps() {
int node;
DAG_edge_t *e;
int maxpage;
emit_ps_header();
maxpage = n_ps_pages();
for (int page = 0; page < maxpage; page++) {
emit_ps_set_page(page);
emit_ps_node_header();
for (node = 0; node < N; node++)
if (node_in_page(node)) emit_ps_node(node);
emit_ps_edge_header();
for (node = 0; node < N; node++)
for (e = Edge[node]; e; e = e->nextof())
if (edge_in_page(e)) emit_ps_edge(node,e);
emit_ps_page();
}
emit_ps_trailer();
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.