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