home *** CD-ROM | disk | FTP | other *** search
- /**
- GRAB Graph Layout and Browser System
-
- Copyright (c) 1986, 1988 Regents of the University of California
- Copyright (c) 1989, Tera Computer Company
- **/
-
- /* output.c contains procedures to draw a layed out digraph. */
-
- #include "malloc.h"
- #include <math.h>
-
- #include "attribute.h"
- #include "digraph.h"
- #include "screen.h"
- #include "scrdep.h"
- #include "globals.h"
- #include "interf.h"
- #include "tedge.h"
- #include "cursor.h"
- #include "clip.h"
-
- BOOL on_screen(), edge_on_screen();
- NODE *get_prev_node(), *get_next_node();
- char *get_edge_label();
- OUTEDGE *get_edge();
- void NewFont();
-
- void DoGraph()
- /**
- draw the graph. First set up the font. Then make sure the screen
- variable is et correctly. Then add the nodes to the graph.
- Then draw it.
- **/
- {
- NODE *node;
-
- if (digraph == NULL)
- {
- IChangeStatusLine("No digraph to display", FALSE);
- return;
- }
-
- ISetCursor(waitC);
-
- if (digraph->lastnode != -1)
- /* there is something to display */
- {
- IChangeStatusLine("Drawing Graph", TRUE);
- }
-
- IEraseGraph();
- NewFont();
-
- ReCalcScreen();
-
- /* foreach node on the current node list, print out node and edges */
- each_node(digraph, node)
- loop
- draw_node(digraph, node, &screen, FALSE);
- draw_out_edges(digraph, node, &screen, FALSE);
- endloop
-
- IUpdateG();
- IUnsetCursor();
- } /* DoGraph */
-
- void NewFont()
- {
- int sizex, sizey;
- int a, b, c, d, e, f;
- int width, height;
-
- /* find size of font to use */
- IGetBounds (&a, &b, &width, &height, &c, &d, &e, &f);
-
- sizex = width /
- ((float)(screen.absview.max_x - screen.absview.min_x) /
- (float)(HALF_CHAR * 2));
- sizey = get_height(digraph) * ((float) height /
- (float)(screen.absview.max_y - screen.absview.min_y));
- ISetFont(sizex, sizey);
- }
-
- double GetHeight()
- /* returns the height of a node in relation to the height of the digraph */
- {
- return (double) get_height(digraph) /
- (double) (screen.absview.max_y - screen.absview.min_y);
- }
-
- get_height(digraph)
- DIGRAPH *digraph;
- /* returns the height of one node */
- {
- NODE *node;
-
- each_node(digraph, node)
- loop
- if (Half_height(node) != 0)
- {
- return (Half_height(node) + Half_height(node));
- }
- endloop
-
- /* if no nodes, return what height a node would have */
- return ((NODE_HALF_HEIGHT + 2) * 2);
- }
-
- draw_node(digraph, node, screen, draw)
- DIGRAPH *digraph;
- NODE *node; /* node to draw */
- SCREEN *screen; /* window information */
- BOOL draw; /* draw it now, or wait? */
- /**
- draw_node draws a node, including its name, outgoing edges, and
- barycenters (optional).
- **/
- {
- char *text;
- char upbc[20]; /* up bc */
- char downbc[20]; /* down bc */
-
- if (on_screen(node)) /* shortcut. Saves mucho time */
- {
- if (!(Is_dummy(node)))
- {
- text = Text(node);
- }
- else
- {
- strsave(text, NULL_STRING);
- }
-
- if (Has_bc(node, UP))
- {
- sprintf(upbc, "%d/%3.1f", Priority(node, UP), Bc(node, UP));
- }
- else
- {
- strcpy(upbc, NULL_STRING);
- }
-
- if (Has_bc(node, DOWN))
- {
- sprintf(downbc, "%d/%3.1f", Priority(node, DOWN), Bc(node, DOWN));
- }
- else
- {
- strcpy(downbc, NULL_STRING);
- }
-
- if (Is_dummy(node))
- /**
- dummies actually represent many small subnodes in the case
- of multigraphs, one for each edge that goes through it
- **/
- {
- int i;
-
- for (i = max_edges(node, node); i > 0; i--)
- {
- if (get_edge(digraph, node, node, i) != NULL)
- /* edge for this subnode could have been deleted */
- {
- int shift;
-
- shift = ORD_TO_SHIFT(i);
-
- if (markDummyNodes)
- {
- IAddNode ((int) ABSX_TO_SCRX(screen, X_position(node) +
- shift),
- (int) ABSY_TO_SCRY(screen, Y_position(node)),
- 1, 1,
- RECTANGLE, text, Is_dummy(node),
- (char *) node, upbc, downbc,
- Brush(node), Color(node), draw, i);
- }
- else
- {
- IAddNode ((int) ABSX_TO_SCRX(screen, X_position(node) +
- shift),
- (int) ABSY_TO_SCRY(screen, Y_position(node)),
- 0, 0,
- POINT, text, Is_dummy(node),
- (char *) node, upbc, downbc,
- Brush(node), Color(node), draw, i);
- }
- }
- }
- }
- else
- {
- IAddNode ((int) ABSX_TO_SCRX(screen, X_position(node)),
- (int) ABSY_TO_SCRY(screen, Y_position(node)),
- (int) SCALE_X(screen, Half_width(node)),
- (int) SCALE_Y(screen, Half_height(node)),
- Shape(node), text, Is_dummy(node), (char *) node,
- upbc, downbc, Brush(node), Color(node), draw, -1);
- }
- }
- } /* draw_node */
-
- draw_edge(digraph, e, fromnode, tonode, ord, screen, draw)
- DIGRAPH *digraph;
- OUTEDGE *e;
- NODE *fromnode, *tonode;
- int ord;
- SCREEN *screen;
- BOOL draw;
- /**
- draw the edge from fromnode to tonode of ord ord.
- most of the time a get_edge was done just before this was called,
- so I decided to make the caller pass the result of that call (e). And
- if it wasn't done, he can do it. Saves time
- **/
- {
- double from_x; /* x-coordinate of start of edge */
- double from_y; /* y-coordinates of start of edge */
- double to_x; /* x-coordinate of end of edge */
- double to_y; /* y-coordinates of end of edge */
- NODE *prevnode;
- TEDGE *edge;
- BOOL parrow, reversed;
- BRUSH brush;
- COLOR color;
-
- if (edge_on_screen(fromnode, tonode)) /* time-saver */
- {
- parrow = FALSE;
- reversed = FALSE;
-
- /**
- We don't switch tonode and fromnode if the edge is
- reversed, which makes it very compatible with most
- of the rest of the code
- **/
- edge = (TEDGE *) malloc(sizeof(TEDGE));
- edge->label = Is_dummy(fromnode) ? NULL_STRING : Label(e);
- edge->tonode = (char *) tonode;
- edge->fromnode = (char *) fromnode;
- edge->ord = ord;
-
- /* clip in both directions */
- Clip(fromnode, tonode, ord, &from_x, &from_y, &to_x, &to_y, screen);
-
- if (!Is_dummy(fromnode) && Edge_reversed(e))
- {
- parrow = TRUE;
- reversed = TRUE;
- }
- else if (!Is_dummy(tonode) && !Edge_reversed(e))
- {
- parrow = TRUE;
- }
-
- brush = Brush(e);
- color = Color(e);
-
- if (reversed)
- {
- IAddEdge(
- (int) ABSX_TO_SCRX(screen, to_x),
- (int) ABSY_TO_SCRY(screen, to_y),
- (int) ABSX_TO_SCRX(screen, from_x),
- (int) ABSY_TO_SCRY(screen, from_y),
- parrow, (char *) edge, edge->label, Brush(e), Color(e),
- draw, ord);
- }
- else
- {
- IAddEdge(
- (int) ABSX_TO_SCRX(screen, from_x),
- (int) ABSY_TO_SCRY(screen, from_y),
- (int) ABSX_TO_SCRX(screen, to_x),
- (int) ABSY_TO_SCRY(screen, to_y),
- parrow, (char *) edge, edge->label, Brush(e), Color(e),
- draw, ord);
- }
- }
- }
-
- draw_out_edges(digraph, node, screen, draw)
- DIGRAPH *digraph;
- NODE *node; /* node with edges */
- SCREEN *screen;
- BOOL draw;
- /**
- draw_out_edges draws the out-going edges of node.
- **/
- {
- VNO to_vno; /* each succedent node */
- NODE *tonode;
- OUTEDGE *e;
- int i;
-
- each_element(Succ_set(node), to_vno)
- loop
- tonode = Node(digraph, to_vno);
-
- for (i = max_edges(node, tonode); i > 0; i--)
- {
- if ((e = get_edge(digraph, node, tonode, i)) != NULL)
- {
- draw_edge(digraph, e, node, tonode, i, screen, draw);
- }
- }
- endloop
- } /* draw_out_edges */
-
- /**
- We should find all references to these next two routines
- and delete them. This information is derivable with a call to
- get_edge
- **/
- outedge_reversed(digraph, node, tonode, ord)
- DIGRAPH *digraph;
- NODE *node, *tonode;
- int ord;
- {
- OUTEDGE *outedge;
- NODE *get_next_node();
-
- /* node at end of reverse edge is a dummy - can't be ... */
- if (Is_dummy(node))
- {
- return FALSE;
- }
-
- if (Is_dummy(tonode))
- {
- tonode = get_next_node(digraph, tonode);
- }
-
- if ((outedge = get_edge(digraph, node, tonode, ord)) != NULL)
- {
- return Edge_reversed(outedge);
- }
- else
- {
- return FALSE;
- }
- }
-
- char *get_edge_label(digraph, node, tonode, ord)
- register DIGRAPH *digraph;
- register NODE *node, *tonode;
- int ord;
- {
- register OUTEDGE *outedge;
-
- if (Is_dummy(node))
- {
- return (NULL_STRING);
- }
- else
- {
- if (Is_dummy(tonode))
- {
- tonode = get_next_node(digraph, tonode);
- }
-
- if ((outedge = get_edge(digraph, node, tonode, ord)) != NULL)
- {
- return Label(outedge);
- }
- else
- {
- fprintf(stderr,
- "get_edge_label: node=%s, tonode=%s, ord=%d, outedge not found\n",
- Text(node), Text(tonode), ord);
- return NULL_STRING;
- }
- }
- }
-
- /* the all argument may be useless here; it's only called in one place */
- draw_in_edges(digraph, node, screen, draw, all)
- DIGRAPH *digraph;
- NODE *node; /* node with edges */
- SCREEN *screen;
- BOOL draw;
- BOOL all; /* draw the edges no matter what */
- {
- VNO from_vno; /* each antecedent node */
- NODE *fromnode;
- OUTEDGE *e;
- int i;
-
- each_element(Ante_set(node), from_vno)
- loop
- fromnode = Node(digraph, from_vno);
-
- if ((!on_screen(fromnode) && on_screen(node)) || all)
- {
- for (i = max_edges(fromnode, node); i > 0; i--)
- {
- if ((e = get_edge(digraph, fromnode, node, i)) != NULL)
- {
- draw_edge(digraph, e, fromnode, node, i, screen, draw);
- }
- }
- }
- endloop
- } /* draw_in_edges */
-
- BOOL on_screen(node)
- NODE *node;
- {
- return (X_right(node) >= screen.bound.min_x &&
- X_left(node) <= screen.bound.max_x &&
- Y_top(node) >= screen.bound.min_y &&
- Y_bottom(node) <= screen.bound.max_y);
- }
-
- BOOL edge_on_screen(fromnode, tonode)
- NODE *fromnode, *tonode;
- {
- return (! ((Y_position(fromnode) > screen.bound.max_y &&
- Y_position(tonode) > screen.bound.max_y) ||
- (Y_position(fromnode) < screen.bound.min_y &&
- Y_position(tonode) < screen.bound.min_y) ||
- (X_position(fromnode) > screen.bound.max_x &&
- X_position(tonode) > screen.bound.max_x) ||
- (X_position(fromnode) < screen.bound.min_x &&
- X_position(tonode) < screen.bound.min_x)));
- /**
- well, it's _not_ on screen if both endpoints are above, below,
- to the right of, or to the left of the screen
- **/
- }
-