/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/lib/fdpgen/grid.c

Go to the documentation of this file.
00001 /* $Id: grid.c,v 1.1.1.1 2004/12/23 04:05:07 ellson Exp $ $Revision: 1.1.1.1 $ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /**********************************************************
00005 *      This software is part of the graphviz package      *
00006 *                http://www.graphviz.org/                 *
00007 *                                                         *
00008 *            Copyright (c) 1994-2004 AT&T Corp.           *
00009 *                and is licensed under the                *
00010 *            Common Public License, Version 1.0           *
00011 *                      by AT&T Corp.                      *
00012 *                                                         *
00013 *        Information and Software Systems Research        *
00014 *              AT&T Research, Florham Park NJ             *
00015 **********************************************************/
00016 
00017 
00018 /*
00019  * grid.c
00020  * Written by Emden R. Gansner
00021  *
00022  * Support for grid to speed up layout. On each pass, nodes are
00023  * put into grid cells. Given a node, repulsion is only computed 
00024  * for nodes in one of that nodes 9 adjacent grids.
00025  */
00026 
00027 /* uses PRIVATE interface for NOTUSED */
00028 #define FDP_PRIVATE 1
00029 
00030 #include <fdp.h>
00031 #include <grid.h>
00032 #include <macros.h>
00033 
00034   /* structure for maintaining a free list of cells */
00035 typedef struct _block {
00036     cell *mem;                  /* block of cells */
00037     cell *cur;                  /* next available cell */
00038     cell *endp;                 /* after last cell */
00039     struct _block *next;        /* next memory block */
00040 } block_t;
00041 
00042 /* newBlock:
00043  * Create new block of size cells
00044  */
00045 static block_t *newBlock(int size)
00046 {
00047     block_t *newb;
00048 
00049     newb = GNEW(block_t);
00050     newb->next = 0;
00051     newb->mem = N_GNEW(size, cell);
00052     newb->endp = newb->mem + size;
00053     newb->cur = newb->mem;
00054 
00055     return newb;
00056 }
00057 
00058 /* freeBlock:
00059  * Free malloc'ed memory and block.
00060  * Recurse to next block
00061  */
00062 static void freeBlock(block_t * b)
00063 {
00064     if (b) {
00065         block_t *next = b->next;
00066         free(b->mem);
00067         free(b);
00068         freeBlock(next);
00069     }
00070 }
00071 
00072 struct _grid {
00073     Dt_t *data;                 /* cells indexed by (i,j) */
00074     block_t *cellMem;           /* list of memory blocks for cells */
00075     block_t *cellCur;           /* current block */
00076     int listSize;               /* memory of nodes */
00077     node_list *listMem;         /* list of memory for node items */
00078     node_list *listCur;         /* next node item */
00079 };
00080 
00081 /* getCell:
00082  * Create a new cell using memory blocks.
00083  */
00084 static cell *getCell(Grid * g)
00085 {
00086     cell *cp;
00087     block_t *bp = g->cellCur;   /* current block */
00088 
00089     if (bp->cur == bp->endp) {  /* current block is full */
00090         if (bp->next == 0) {
00091             bp->next = newBlock(2 * (bp->endp - bp->mem));
00092         }
00093         bp = g->cellCur = bp->next;
00094         bp->cur = bp->mem;
00095     }
00096     cp = bp->cur++;
00097     return cp;
00098 }
00099 
00100 #ifndef offsetof
00101 #define offsetof(typ,fld)  ((int)(&(((typ*)0)->fld)))
00102 #endif
00103 
00104 
00105 static int ijcmpf(Dt_t * d, gridpt * p1, gridpt * p2, Dtdisc_t * disc)
00106 {
00107     int diff;
00108 
00109     NOTUSED(d);
00110     NOTUSED(disc);
00111     if ((diff = (p1->i - p2->i)))
00112         return diff;
00113     else
00114         return (p1->j - p2->j);
00115 }
00116 
00117 static Grid *_grid;             /* hack because can't attach info. to Dt_t */
00118 
00119 /* newCell:
00120  * Allocate a new cell from free store and initialize its indices
00121  * This is used by the grid discipline to create cells.
00122  */
00123 static void *newCell(Dt_t * d, void *obj, Dtdisc_t * disc)
00124 {
00125     cell *cellp = (cell *) obj;
00126     cell *newp;
00127 
00128     NOTUSED(disc);
00129     newp = getCell(_grid);
00130     newp->p.i = cellp->p.i;
00131     newp->p.j = cellp->p.j;
00132     newp->nodes = 0;
00133 
00134     return newp;
00135 }
00136 
00137 /* newNode:
00138  * Allocate a new node item from free store. 
00139  * Set node value and hook into list.
00140  * A grid assumes the memory allocated in adjustGrid
00141  * will be enough more all nodes added.
00142  */
00143 static node_list *newNode(Grid * g, Agnode_t * n, node_list * nxt)
00144 {
00145     node_list *newp;
00146 
00147     newp = g->listCur++;
00148     newp->node = n;
00149     newp->next = nxt;
00150 
00151     return newp;
00152 }
00153 
00154 static Dtdisc_t gridDisc = {
00155     offsetof(cell, p),
00156     sizeof(gridpt),
00157     offsetof(cell, link),
00158     (Dtmake_f) newCell,
00159     NIL(Dtfree_f),
00160     (Dtcompar_f) ijcmpf,
00161     NIL(Dthash_f),
00162     NIL(Dtmemory_f),
00163     NIL(Dtevent_f)
00164 };
00165 
00166 /* mkGrid:
00167  * Create grid data structure.
00168  * cellHint provides rough idea of how many cells
00169  * may be needed.
00170  */
00171 Grid *mkGrid(int cellHint)
00172 {
00173     Grid *g;
00174 
00175     g = GNEW(Grid);
00176     _grid = g;                  /* see comment above */
00177     g->data = dtopen(&gridDisc, Dtoset);
00178     g->listMem = 0;
00179     g->listSize = 0;
00180     g->cellMem = newBlock(cellHint);
00181     return g;
00182 }
00183 
00184 /* adjustGrid:
00185  * Set up node list for grid. Make sure the list
00186  * can handle nnodes nodes.
00187  * It is assumed no more than nnodes will be added
00188  * to the grid.
00189  */
00190 void adjustGrid(Grid * g, int nnodes)
00191 {
00192     int nsize;
00193 
00194     if (nnodes > g->listSize) {
00195         nsize = MAX(nnodes, 2 * (g->listSize));
00196         if (g->listMem)
00197             free(g->listMem);
00198         g->listMem = N_GNEW(nsize, node_list);
00199         g->listSize = nsize;
00200     }
00201 }
00202 
00203 /* clearGrid:
00204  * Reset grid. This clears the dictionary,
00205  * and reuses available memory.
00206  */
00207 void clearGrid(Grid * g)
00208 {
00209     dtclear(g->data);
00210     g->listCur = g->listMem;
00211     g->cellCur = g->cellMem;
00212     g->cellCur->cur = g->cellCur->mem;
00213 }
00214 
00215 /* delGrid:
00216  * Close and free all grid resources.
00217  */
00218 void delGrid(Grid * g)
00219 {
00220     dtclose(g->data);
00221     freeBlock(g->cellMem);
00222     free(g->listMem);
00223     free(g);
00224 }
00225 
00226 /* addGrid:
00227  * Add node n to cell (i,j) in grid g.
00228  */
00229 void addGrid(Grid * g, int i, int j, Agnode_t * n)
00230 {
00231     cell *cellp;
00232     cell key;
00233 
00234     key.p.i = i;
00235     key.p.j = j;
00236     cellp = dtinsert(g->data, &key);
00237     cellp->nodes = newNode(g, n, cellp->nodes);
00238     if (Verbose >= 3) {
00239         fprintf(stderr, "grid(%d,%d): %s\n", i, j, n->name);
00240     }
00241 }
00242 
00243 typedef int (*walkfn_t) (Dt_t *, Void_t *, Void_t *);
00244 
00245 /* walkGrid:
00246  * Apply function walkf to each cell in the grid.
00247  * The second argument to walkf is the cell; the
00248  * third argument is the grid. (The first argument
00249  * is the dictionary.) walkf must return 0.
00250  */
00251 void walkGrid(Grid * g, int (*walkf) (Dt_t *, cell *, Grid *))
00252 {
00253     dtwalk(g->data, (walkfn_t) walkf, g);
00254 }
00255 
00256 /* findGrid;
00257  * Return the cell, if any, corresponding to
00258  * indices i,j
00259  */
00260 cell *findGrid(Grid * g, int i, int j)
00261 {
00262     cell key;
00263 
00264     key.p.i = i;
00265     key.p.j = j;
00266     return ((cell *) dtsearch(g->data, &key));
00267 }
00268 
00269 /* gLength:
00270  * Return the number of nodes in a cell.
00271  */
00272 int gLength(cell * p)
00273 {
00274     int len = 0;
00275     node_list *nodes = p->nodes;
00276 
00277     while (nodes) {
00278         len++;
00279         nodes = nodes->next;
00280     }
00281     return len;
00282 }

Generated on Mon Mar 31 19:03:26 2008 for Graphviz by  doxygen 1.5.1