pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 00043 #include <stdio.h> 00044 #include <math.h> 00045 00046 #include "config.h" 00047 #include "global.h" 00048 #include "data.h" 00049 #include "hid.h" 00050 #include "misc.h" 00051 #include "create.h" 00052 #include "rtree.h" 00053 #include "undo.h" 00054 #include "rats.h" 00055 #include "error.h" 00056 #include "move.h" 00057 #include "draw.h" 00058 #include "set.h" 00059 00060 #define GAP 10000 00061 static Coord minx; 00062 static Coord miny; 00063 static Coord maxx; 00064 static Coord maxy; 00065 00073 static void 00074 place (ElementType *element) 00075 { 00076 Coord dx, dy; 00077 00078 /* figure out how much to move the element */ 00079 dx = minx - element->BoundingBox.X1; 00080 dy = miny - element->BoundingBox.Y1; 00081 00082 /* snap to the grid */ 00083 dx -= (element->MarkX + dx) % (long) (PCB->Grid); 00084 dx += (long) (PCB->Grid); 00085 dy -= (element->MarkY + dy) % (long) (PCB->Grid); 00086 dy += (long) (PCB->Grid); 00087 00088 /* 00089 * and add one grid size so we make sure we always space by GAP or 00090 * more 00091 */ 00092 dx += (long) (PCB->Grid); 00093 00094 /* Figure out if this row has room. If not, start a new row */ 00095 if (minx != GAP && GAP + element->BoundingBox.X2 + dx > PCB->MaxWidth) 00096 { 00097 miny = maxy + GAP; 00098 minx = GAP; 00099 place(element); /* recurse can't loop, now minx==GAP */ 00100 return; 00101 } 00102 00103 /* move the element */ 00104 MoveElementLowLevel (PCB->Data, element, dx, dy); 00105 00106 /* and add to the undo list so we can undo this operation */ 00107 AddObjectToMoveUndoList (ELEMENT_TYPE, NULL, NULL, element, dx, dy); 00108 00109 /* keep track of how tall this row is */ 00110 minx += element->BoundingBox.X2 - element->BoundingBox.X1 + GAP; 00111 if (maxy < element->BoundingBox.Y2) 00112 { 00113 maxy = element->BoundingBox.Y2; 00114 } 00115 } 00116 00121 static Coord 00122 padDX (ConnectionType *conn) 00123 { 00124 ElementType *element = (ElementType *) conn->ptr1; 00125 AnyLineObjectType *line = (AnyLineObjectType *) conn->ptr2; 00126 00127 return line->BoundingBox.X1 - 00128 (element->BoundingBox.X1 + element->BoundingBox.X2) / 2; 00129 } 00130 00135 static int 00136 padorder (ConnectionType *conna, ConnectionType *connb) 00137 { 00138 Coord dxa, dxb; 00139 00140 dxa = padDX (conna); 00141 dxb = padDX (connb); 00142 /* there are other cases that merit rotation, ignore them for now */ 00143 if (dxa > 0 && dxb < 0) 00144 return 1; 00145 return 0; 00146 } 00147 00148 /* ewww, these are actually arrays */ 00149 #define ELEMENT_N(DATA,ELT) ((ELT) - (DATA)->Element) 00150 #define VISITED(ELT) (visited[ELEMENT_N(PCB->Data, (ELT))]) 00151 #define IS_ELEMENT(CONN) ((CONN)->type == PAD_TYPE || (CONN)->type == PIN_TYPE) 00152 00153 #define ARG(n) (argc > (n) ? argv[n] : 0) 00154 00155 static const char smartdisperse_syntax[] = "SmartDisperse([All|Selected])"; 00156 00157 /* %start-doc actions SmartDisperse 00158 00159 The @code{SmartDisperse([All|Selected])} action is a special-purpose 00160 optimization for dispersing elements. 00161 00162 Run with @code{:SmartDisperse()} or @code{:SmartDisperse(Selected)} 00163 (you can also say @code{:SmartDisperse(All)}, but that's the default). 00164 00165 %end-doc */ 00166 static int 00167 smartdisperse (int argc, char **argv, Coord x, Coord y) 00168 { 00169 char *function = ARG(0); 00170 NetListType *Nets; 00171 char *visited; 00172 // PointerListType stack = { 0, 0, NULL }; 00173 int all; 00174 // int changed = 0; 00175 // int i; 00176 00177 if (! function) 00178 { 00179 all = 1; 00180 } 00181 else if (strcmp(function, "All") == 0) 00182 { 00183 all = 1; 00184 } 00185 else if (strcmp(function, "Selected") == 0) 00186 { 00187 all = 0; 00188 } 00189 else 00190 { 00191 AFAIL (smartdisperse); 00192 } 00193 00194 Nets = ProcNetlist (&PCB->NetlistLib); 00195 if (! Nets) 00196 { 00197 Message (_("Can't use SmartDisperse because no netlist is loaded.\n")); 00198 return 0; 00199 } 00200 00201 /* remember which elements we finish with */ 00202 visited = calloc (PCB->Data->ElementN, sizeof(*visited)); 00203 00204 /* if we're not doing all, mark the unselected elements as "visited" */ 00205 ELEMENT_LOOP (PCB->Data); 00206 { 00207 if (! (all || TEST_FLAG (SELECTEDFLAG, element))) 00208 { 00209 visited[n] = 1; 00210 } 00211 } 00212 END_LOOP; 00213 00214 /* initialize variables for place() */ 00215 minx = GAP; 00216 miny = GAP; 00217 maxx = GAP; 00218 maxy = GAP; 00219 00220 /* 00221 * Pick nets with two connections. This is the start of a more 00222 * elaborate algorithm to walk serial nets, but the datastructures 00223 * are too gross so I'm going with the 80% solution. 00224 */ 00225 NET_LOOP (Nets); 00226 { 00227 ConnectionType *conna, *connb; 00228 ElementType *ea, *eb; 00229 // ElementType *epp; 00230 00231 if (net->ConnectionN != 2) 00232 continue; 00233 00234 conna = &net->Connection[0]; 00235 connb = &net->Connection[1]; 00236 if (!IS_ELEMENT(conna) || !IS_ELEMENT(conna)) 00237 continue; 00238 00239 ea = (ElementType *) conna->ptr1; 00240 eb = (ElementType *) connb->ptr1; 00241 00242 /* place this pair if possible */ 00243 if (VISITED((GList *)ea) || VISITED((GList *)eb)) 00244 continue; 00245 VISITED ((GList *)ea) = 1; 00246 VISITED ((GList *)eb) = 1; 00247 00248 /* a weak attempt to get the linked pads side-by-side */ 00249 if (padorder(conna, connb)) 00250 { 00251 place ((ElementType *) ea); 00252 place ((ElementType *) eb); 00253 } 00254 else 00255 { 00256 place (eb); 00257 place (ea); 00258 } 00259 } 00260 END_LOOP; 00261 00262 /* Place larger nets, still grouping by net */ 00263 NET_LOOP (Nets); 00264 { 00265 CONNECTION_LOOP (net); 00266 { 00267 ElementType *element; 00268 00269 if (! IS_ELEMENT(connection)) 00270 continue; 00271 00272 element = (ElementType *) connection->ptr1; 00273 00274 /* place this one if needed */ 00275 if (VISITED ((GList *) element)) 00276 continue; 00277 VISITED ((GList *) element) = 1; 00278 place (element); 00279 } 00280 END_LOOP; 00281 } 00282 END_LOOP; 00283 00284 /* Place up anything else */ 00285 ELEMENT_LOOP (PCB->Data); 00286 { 00287 if (! visited[n]) 00288 { 00289 place (element); 00290 } 00291 } 00292 END_LOOP; 00293 00294 free (visited); 00295 00296 IncrementUndoSerialNumber (); 00297 Redraw (); 00298 SetChangedFlag (1); 00299 00300 return 0; 00301 } 00302 00303 static HID_Action 00304 smartdisperse_action_list[] = 00305 { 00306 {"smartdisperse", NULL, smartdisperse, NULL, NULL} 00307 }; 00308 00309 REGISTER_ACTIONS (smartdisperse_action_list) 00310 00311 void 00312 hid_smartdisperse_init () 00313 { 00314 register_smartdisperse_action_list (); 00315 }