1 /****************************************************************************
2 Copyright (C) 1987-2015 by Jeffery P. Hansen
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 ****************************************************************************/
18 /*
19 One of four main modules pertaining to wires. Containes functions for moving
20 and drawing wires. Basic routines to maintain horizontal and vertical wires
21 being moved are defined here.
22 */
23 #include "tkgate.h"
24
25 #include <assert.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28
29 #define isgatenode(_n) ((_n)->end && (_n)->end->gate)
30
31 /*
32 * Straighten out nodes
33 */
wire_netstraight(GWireNode * n,int wt,int ox,int oy,int nx,int ny)34 int wire_netstraight(GWireNode *n,int wt,int ox,int oy,int nx,int ny)
35 {
36 int x,y;
37 GWireNode *next;
38
39 if (!n) return OK;
40
41 next = (wt == DRIVER ? n->out : n->in);
42 x = n->x;
43 y = n->y;
44 if (isgatenode(n)) {
45 if ((ox == nx) && (oy == ny)) return OK;
46 if (next && (ox == nx) && next->y == n->y) return OK;
47 if (next && (oy == ny) && next->x == n->x) return OK;
48
49 return IMMOBILE;
50 }
51
52 ob_touch(n);
53
54 switch (wire_netstraight(next,wt,x,y,x+nx-ox,y+ny-oy)) {
55 case OK :
56 n->x += nx - ox;
57 n->y += ny - oy;
58 if ((nx != ox) || (ny != oy)) n->mark = 1;
59 return OK;
60 case IMMOBILE :
61 if ((next->end->orient % 2) == 0) {
62 n->y = next->y;
63 n->x += nx - ox;
64 if (nx - ox) n->mark = 1;
65 } else {
66 n->x = next->x;
67 n->y += ny - oy;
68 if (ny - oy) n->mark = 1;
69 }
70 return OK;
71 }
72 logError(ERL_FATAL,"Unknown case in wire_newstraight.");
73 return IMMOBILE;
74 }
75
76 /*
77 Splits a node if we can't find a way around it
78 */
wire_splitnode(GWireNode * n,int dir)79 GWireNode *wire_splitnode(GWireNode *n,int dir)
80 {
81 GWireNode *newnode;
82
83 newnode = new_GWireNode();
84
85 ob_touch(newnode);
86 newnode->mark = 1;
87 switch (dir) {
88 case OUT_DIR :
89 newnode->out = n->out;
90 newnode->in = n;
91 newnode->end = NULL;
92 if (n->out) {
93 ob_touch(n->out);
94 n->out->in = newnode;
95 newnode->x = (n->x + n->out->x) / 2;
96 newnode->y = (n->y + n->out->y) / 2;
97 } else {
98 newnode->x = n->x;
99 newnode->y = n->y;
100 }
101 ob_touch(n);
102 n->out = newnode;
103 break;
104 case IN_DIR :
105 newnode->in = n->in;
106 newnode->out = n;
107 newnode->end = NULL;
108 if (n->in) {
109 ob_touch(n->in);
110 n->in->out = newnode;
111 newnode->x = (n->x + n->in->x) / 2;
112 newnode->y = (n->y + n->in->y) / 2;
113 } else {
114 newnode->x = n->x;
115 newnode->y = n->y;
116 }
117 ob_touch(n);
118 n->in = newnode;
119 break;
120 }
121 return newnode;
122 }
123
124 /* Auxilliary function for makestraight */
wire_makestraightaux(GWireNode * n,int wt,int ox,int oy,int nx,int ny)125 void wire_makestraightaux(GWireNode *n,int wt,int ox,int oy,int nx,int ny)
126 {
127 GWireNode *n1,*n2;
128
129 if (!n) return;
130
131 if (wire_netstraight(n,wt,ox,oy,nx,ny) == IMMOBILE) {
132 if (wt == DRIVEE && (n->out->out || isgatenode(n->out))) {
133 n1 = wire_splitnode(n,OUT_DIR);
134 n2 = wire_splitnode(n1,OUT_DIR);
135 ob_touch(n1);
136 ob_touch(n2);
137 n2->x = n1->x = (n->x + ox) / 2;
138 n2->y = n1->y = (n->y + oy) / 2;
139 } else if (wt != DRIVEE && (n->in->in || isgatenode(n->in))) {
140 n1 = wire_splitnode(n,IN_DIR);
141 n2 = wire_splitnode(n1,IN_DIR);
142 ob_touch(n1);
143 ob_touch(n2);
144 n2->x = n1->x = (n->x + ox) / 2;
145 n2->y = n1->y = (n->y + oy) / 2;
146 } else {
147 n2 = wire_splitnode(n,wt == DRIVEE ? OUT_DIR : IN_DIR);
148 ob_touch(n2);
149 if (n->x == ox)
150 n2->y = oy;
151 else
152 n2->x = ox;
153 }
154 if (wire_netstraight(n2,wt,ox,oy,nx,ny) == IMMOBILE)
155 fprintf(stderr,"Huh? split node didn't help\n");
156 }
157 }
158
159 /* Takes a moved node and it's old position to figure out how to move the rest of the
160 network to keep the rep. invarient */
wire_makestraight(GWireNode * n,int ox,int oy)161 void wire_makestraight(GWireNode *n,int ox,int oy)
162 {
163 if (n->stype == FULL) {
164 wire_makestraightaux(n->out,DRIVER,ox,oy,n->x,n->y);
165 wire_makestraightaux(n->in,DRIVEE,ox,oy,n->x,n->y);
166 } else {
167 if (n->stype & HORIZONTAL) {
168 ob_touch(n->out);
169 n->out->x += n->x - ox;
170 if (n->x - ox) {
171 ob_touch(n);
172 n->mark = 1;
173 }
174 }
175 if (n->stype & VERTICAL) {
176 ob_touch(n->out);
177 n->out->y += n->y - oy;
178 if (n->y - oy) {
179 ob_touch(n);
180 n->mark = 1;
181 }
182 }
183 }
184 }
185
186 /******************************************************************************
187 *
188 * Moves a wire
189 *
190 * Parameters:
191 * n Wire node to be moved
192 * dx,dy Vector for movement of node
193 * type Type of movement (affects movement of connected nodes)
194 *
195 *****************************************************************************/
wire_move(GWireNode * n,int dx,int dy,WireSelectMode_t type)196 void wire_move(GWireNode *n,int dx,int dy,WireSelectMode_t type)
197 {
198 int x,y;
199
200 ob_touch(n);
201 n->stype = type;
202 x = n->x;
203 y = n->y;
204
205 if ((type & VERTICAL)) n->y += dy;
206 if ((type & HORIZONTAL)) n->x += dx;
207
208 if (n->x == x && n->y == y) return; /* Didn't move */
209
210 SetModified(MF_NET);
211
212 if ((type & NOSTRAIGHTEN)) return;
213 wire_makestraight(n,x,y);
214 }
215
wire_moveto(GWireNode * n,int x,int y)216 void wire_moveto(GWireNode *n,int x,int y)
217 {
218 wire_move(n,x-n->x,y-n->y,FULL);
219 }
220
221
222
wire_hitanynode(int x,int y,GWireList * wires)223 GWireNode *wire_hitanynode(int x,int y,GWireList *wires)
224 {
225 struct wirenode *N,*Close;
226 int CloseD,D;
227
228 if (!wires) return NULL;
229
230 CloseD = distance(x,y,wires->wl_wire->nodes->x,wires->wl_wire->nodes->y);
231 Close = wires->wl_wire->nodes;
232
233 for (;wires;wires = wires->wl_next)
234 if (wires->wl_wire->nodes->out)
235 for (N = wires->wl_wire->nodes;N;N = N->out) {
236 D = distance(x,y,N->x,N->y);
237 if (D < CloseD) {
238 CloseD = D;
239 Close = N;
240 }
241 }
242
243 if (CloseD < MAXWIRERANGE)
244 return Close;
245 else
246 return NULL;
247 }
248
249 /* Test an individual wire's node list */
wire_nodehit(int x,int y,GWireNode * n,int includeend,int range,int corneronly)250 GWireNode *wire_nodehit(int x,int y,GWireNode *n,int includeend,int range,int corneronly)
251 {
252 int testrange;
253 GWireNode *test;
254
255 if (!n)
256 return NULL;
257
258 if (includeend || !anchoredp(n))
259 if ((testrange = distance(x,y,n->x,n->y))
260 < (corneronly ? range : MAXWIRERANGE)) {
261 if ((test = wire_nodehit(x,y,n->out,includeend,testrange,1)))
262 return test;
263 else {
264 ob_touch(n);
265 n->stype = FULL;
266 return n;
267 }
268 }
269
270 if ((n->out ? includeend || (!anchoredp(n) && !anchoredp(n->out)) : 0) &&
271 !corneronly) {
272 if ((n->y == n->out->y) &&
273 (midpointp(x,n->x,n->out->x) && ((testrange = sqr(y - n->y)) < range))) {
274
275
276 if ((test = wire_nodehit(x,y,n->out,includeend,testrange,0)))
277 return test;
278 else {
279 ob_touch(n);
280 n->stype = VERTICAL;
281 return n;
282 }
283 }
284 if ((n->x == n->out->x) &&
285 (midpointp(y,n->y,n->out->y) && ((testrange = sqr(x - n->x)) < range))) {
286
287 if ((test = wire_nodehit(x,y,n->out,includeend,testrange,0)))
288 return test;
289 else {
290 ob_touch(n);
291 n->stype = HORIZONTAL;
292 return n;
293 }
294 }
295 }
296 return wire_nodehit(x,y,n->out,includeend,range,corneronly);
297 }
298
wire_hitall(int x,int y,GWireList * wires)299 GWireNode *wire_hitall(int x,int y,GWireList *wires)
300 {
301 GWireNode *test;
302
303 if (!wires)
304 return NULL;
305
306 if ((wires->wl_wire->nodes->out ? (test =
307 wire_nodehit(x,y,wires->wl_wire->nodes,1,MAXWIRERANGE,0)):NULL))
308 return test;
309 else
310 return wire_hitall(x,y,wires->wl_next);
311 }
312
313
314
315 /* Search for a wire other than 'w' */
wire_hit_other(GWire * w,GWireList * wires)316 GWireNode *wire_hit_other(GWire *w,GWireList *wires)
317 {
318 GWireNode *test;
319
320 if ((!wires) || (!w))
321 return NULL;
322
323 if ((wires->wl_wire->nodes->out && (wires->wl_wire->driver != w->driver)) ?
324 (test = wire_nodehit(w->nodes->x,w->nodes->y,wires->wl_wire->nodes,
325 1,MAXWIRERANGE,0)):NULL)
326 return test;
327 else
328 return wire_hit_other(w,wires->wl_next);
329 }
330
331 /* Test to see if theres a wire here */
wire_hit(int x,int y,GWireList * wires)332 GWireNode *wire_hit(int x,int y,GWireList *wires)
333 {
334 GWireNode *test;
335
336 if (!wires)
337 return NULL;
338
339 if ((wires->wl_wire->nodes->out ? (test =
340 wire_nodehit(x,y,wires->wl_wire->nodes,0,MAXWIRERANGE,0)):NULL))
341 return test;
342 else
343 return wire_hit(x,y,wires->wl_next);
344 }
345
wire_iohit(int x,int y,GWireList * wires)346 GWireNode *wire_iohit(int x,int y,GWireList *wires)
347 {
348 GWireNode *test;
349
350 if (!wires)
351 return NULL;
352
353 #ifdef DEBUGHIT
354 printf("Wire is: %d\n",wires->wl_wire->wtype);
355 #endif
356 /* Range was 5*5+1 */
357 if ((test = wire_nodehit(x,y,wires->wl_wire->nodes,1,MAXWIRERANGE,0)))
358 /* Danger */
359 return test;
360 else
361 return wire_iohit(x,y,wires->wl_next);
362 }
363
364 /* Test only at endpoints of a wire. */
wire_endhit(GWire * w,GWireList * wl)365 GWire *wire_endhit(GWire *w,GWireList *wl)
366 {
367 GWire *best_w = 0;
368 int best_d2 = 0;
369
370 for (;wl;wl = wl->wl_next) {
371 int dx = wl->wl_wire->nodes->x - w->nodes->x;
372 int dy = wl->wl_wire->nodes->y - w->nodes->y;
373 int d2 = dx*dx + dy*dy;
374
375 if (wl->wl_wire == w || anchoredp(wl->wl_wire->nodes))
376 continue;
377
378 if (!best_w || d2 < best_d2) {
379 best_w = wl->wl_wire;
380 best_d2 = d2;
381 }
382 }
383
384 if (best_w && best_d2 < 25)
385 return best_w;
386 else
387 return 0;
388
389 #if 0
390 if (!wl)
391 return NULL;
392 if ((abs(wl->wl_wire->nodes->x - w->nodes->x) < 5) &&
393 (abs(wl->wl_wire->nodes->y - w->nodes->y) < 5) &&
394 (wl->wl_wire != w) && !anchoredp(wl->wl_wire->nodes))
395 return wl->wl_wire;
396 else
397 return wire_endhit(w,wl->wl_next);
398 #endif
399 }
400
wire_drivinggate(GWire * w)401 GCElement *wire_drivinggate(GWire *w)
402 {
403 if (!w)
404 return NULL;
405 else
406 return w->driver->gate;
407 }
408
409 /* Returns the driver of a wire network */
wirenode_driver(GWireNode * n)410 GWire *wirenode_driver(GWireNode *n)
411 {
412 if (!n)
413 return NULL;
414 if (!n->in)
415 return n->end;
416 else
417 return wirenode_driver(n->in);
418 }
419
420 /* Returns the drivee of a wire network */
wirenode_drivee(GWireNode * n)421 GWire *wirenode_drivee(GWireNode *n)
422 {
423 if (!n)
424 return NULL;
425 if (!n->out) {
426 return n->end;
427 } else
428 return wirenode_drivee(n->out);
429 }
430
wire_driver(GWire * w)431 GWire *wire_driver(GWire *w)
432 {
433 return wirenode_driver(w->nodes);
434 }
435
wire_drivee(GWire * w)436 GWire *wire_drivee(GWire *w)
437 {
438 return wirenode_drivee(w->nodes);
439 }
440
441
wire_other(GWire * w)442 GWire *wire_other(GWire *w)
443 {
444 if (w->driver != w)
445 return w->driver;
446 else
447 return wire_drivee(w);
448 }
449
posongate(GWire * w,GCElement * g,int * p,int * n)450 int posongate(GWire *w,GCElement *g,int *p,int *n)
451 {
452 int i;
453 int N = GCElement_numPads(g);
454
455 for (i = 0;i < N;i++)
456 if ((*n = findwirepos(w,g->wires[i]))) {
457 *p = i;
458 return 0;
459 }
460
461 return -1;
462 }
463
464 /* Searches an i/o wire list for the number of the target wire */
findwirepos(GWire * w,GWire * l)465 int findwirepos(GWire *w,GWire *l)
466 {
467 int p;
468
469 if (!l)
470 return 0;
471 else {
472 assert(l != l->next);
473 if (w == l)
474 return 1;
475 else
476 if ((p = findwirepos(w,l->next)) != 0)
477 return p + 1;
478 else
479 return 0;
480 }
481 }
482
GetPadPosition(GCElement * g,const char * name)483 int GetPadPosition(GCElement *g,const char *name)
484 {
485 int N = GCElement_numPads(g);
486 int i;
487
488 for (i = 0;i < N;i++)
489 if (!strcmp(GCElement_getPadName(g,i),name))
490 return i;
491 return -1;
492 }
493
wire_rePort(GWire * w,int wx,int wy,int dir)494 void wire_rePort(GWire *w,int wx,int wy,int dir)
495 {
496 GWire *ow = wire_other(w);
497
498 ob_touch(w);
499 wire_move(w->nodes,wx-w->nodes->x,wy-w->nodes->y,VERTICAL|HORIZONTAL);
500
501 /*
502 * If wire end is not attached, compute mirror image. Otherwise use brute force
503 * to fix the wire.
504 */
505 if (w->orient != dir) {
506 w->orient = dir;
507 if (!ow->gate) {
508 int cx = w->nodes->x;
509 int cy = w->nodes->y;
510 GWireNode *n;
511
512
513 for (n = w->driver->nodes;n;n = n->out) {
514 ob_touch(n);
515 // if (g->orient == 0 || g->orient == 2)
516 if (dir == D_LEFT || dir == D_RIGHT)
517 n->x = cx - (n->x - cx);
518 else
519 n->y = cy - (n->y - cy);
520 }
521 } else
522 GWire_snap(w->driver);
523 }
524 }
525