More stackup changes
[geda-pcb/pcjc2/v2.git] / src / teardrops.c
blob5fae90e3247903fd7823a06b1460bb234e7b0167
1 /*!
2 * \file src/teardrops.c
4 * \brief Functions for handling the teardrop property of pins and vias.
6 * <hr>
8 * <h1><b>Copyright.</b></h1>\n
10 * PCB, interactive printed circuit board design
12 * Copyright (C) 2006 DJ Delorie <dj@delorie.com>
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #include <stdio.h>
30 #include <math.h>
32 #include "config.h"
33 #include "global.h"
34 #include "data.h"
35 #include "hid.h"
36 #include "misc.h"
37 #include "create.h"
38 #include "rtree.h"
39 #include "undo.h"
41 #define MIN_LINE_LENGTH 700
42 #define MAX_DISTANCE 700
44 static PinType * pin;
45 static int layer;
46 static int px, py;
47 static LayerType * silk;
49 static int new_arcs = 0;
51 int
52 distance_between_points(int x1,int y1, int x2, int y2)
54 int a;
55 int b;
56 int distance;
57 a = (x1-x2);
58 b = (y1-y2);
59 distance = hypot (a, b);
60 return distance;
63 static int
64 check_line_callback (const BoxType * box, void *cl)
66 LayerType * lay = & PCB->Data->Layer[layer];
67 LineType * l = (LineType *) box;
68 int x1, x2, y1, y2;
69 double a, b, c, x, r, t;
70 double dx, dy, len;
71 double ax, ay, lx, ly, theta;
72 double ldist, adist, radius;
73 double vx, vy, vr, vl;
74 int delta, aoffset, count;
75 ArcType * arc;
77 /* if our line is to short ignore it */
78 if (distance_between_points(l->Point1.X,l->Point1.Y,l->Point2.X,l->Point2.Y) < MIN_LINE_LENGTH )
80 return 1;
83 if (distance_between_points(l->Point1.X,l->Point1.Y,px,py) < MAX_DISTANCE)
85 x1 = l->Point1.X;
86 y1 = l->Point1.Y;
87 x2 = l->Point2.X;
88 y2 = l->Point2.Y;
90 else if (distance_between_points(l->Point2.X,l->Point2.Y,px,py) < MAX_DISTANCE)
92 x1 = l->Point2.X;
93 y1 = l->Point2.Y;
94 x2 = l->Point1.X;
95 y2 = l->Point1.Y;
97 else
98 return 1;
100 r = pin->Thickness / 2.0;
101 t = l->Thickness / 2.0;
103 if (t > r)
104 return 1;
106 a = 1;
107 b = 4 * t - 2 * r;
108 c = 2 * t * t - r * r;
110 x = (-b + sqrt (b * b - 4 * a * c)) / (2 * a);
112 len = sqrt (((double)x2-x1)*(x2-x1) + ((double)y2-y1)*(y2-y1));
114 if (len > (x+t))
116 adist = ldist = x + t;
117 radius = x + t;
118 delta = 45;
120 if (radius < r || radius < t)
121 return 1;
123 else if (len > r + t)
125 /* special "short teardrop" code */
127 x = (len*len - r*r + t*t) / (2 * (r - t));
128 ldist = len;
129 adist = x + t;
130 radius = x + t;
131 delta = atan2 (len, x + t) * 180.0/M_PI;
133 else
134 return 1;
136 dx = ((double)x2 - x1) / len;
137 dy = ((double)y2 - y1) / len;
138 theta = atan2 (y2 - y1, x1 - x2) * 180.0/M_PI;
140 lx = px + dx * ldist;
141 ly = py + dy * ldist;
143 /* We need one up front to determine how many segments it will take
144 to fill. */
145 ax = lx - dy * adist;
146 ay = ly + dx * adist;
147 vl = sqrt (r*r - t*t);
148 vx = px + dx * vl;
149 vy = py + dy * vl;
150 vx -= dy * t;
151 vy += dx * t;
152 vr = sqrt ((ax-vx) * (ax-vx) + (ay-vy) * (ay-vy));
154 aoffset = 0;
155 count = 0;
156 do {
157 if (++count > 5)
159 printf("a %d,%d v %d,%d adist %g radius %g vr %g\n",
160 (int)ax, (int)ay, (int)vx, (int)vy, adist, radius, vr);
161 return 1;
164 ax = lx - dy * adist;
165 ay = ly + dx * adist;
167 arc = CreateNewArcOnLayer (lay, (int)ax, (int)ay, (int)radius, (int)radius,
168 (int)theta+90+aoffset, delta-aoffset,
169 l->Thickness, l->Clearance, l->Flags);
170 if (arc)
171 AddObjectToCreateUndoList (ARC_TYPE, lay, arc, arc);
173 ax = lx + dy * (x+t);
174 ay = ly - dx * (x+t);
176 arc = CreateNewArcOnLayer (lay, (int)ax, (int)ay, (int)radius, (int)radius,
177 (int)theta-90-aoffset, -delta+aoffset,
178 l->Thickness, l->Clearance, l->Flags);
179 if (arc)
180 AddObjectToCreateUndoList (ARC_TYPE, lay, arc, arc);
182 radius += t*1.9;
183 aoffset = acos ((double)adist / radius) * 180.0 / M_PI;
185 new_arcs ++;
186 } while (vr > radius - t);
188 return 1;
191 static void
192 check_pin (PinType * _pin)
194 BoxType spot;
196 pin = _pin;
198 px = pin->X;
199 py = pin->Y;
201 spot.X1 = px - 10;
202 spot.Y1 = py - 10;
203 spot.X2 = px + 10;
204 spot.Y2 = py + 10;
206 for (layer = 0; layer < max_copper_layer; layer ++)
208 LayerType * l = &(PCB->Data->Layer[layer]);
209 r_search (l->line_tree, &spot, NULL, check_line_callback, l);
213 /* %start-doc actions Teardrops
215 The @code{Teardrops()} action adds teardrops to the intersections
216 between traces and pins/vias.
218 This is a simplistic test, so there are cases where you'd think it would
219 add them but doesn't.
221 If the trace doesn't end at @emph{exactly} the same point as the pin/via, it
222 will be skipped.
224 This often happens with metric parts on an Imperial grid or visa-versa.
226 If a trace passes through a pin/via but doesn't end there, there won't
227 be any teardrops.
229 Use @code{:djopt(none)} to split those lines into two segments, each of which
230 ends at the pin/via.
232 Usage:
234 This action takes no parameters.
236 To invoke it, use the command window, usually by typing ":".
238 Example:
240 @code{:Teardrops()}
242 @center @image{td_ex1,,,Example of how Teardrops works,png}
244 With the lesstif HID you can add this action to your menu or a hotkey by
245 editing $HOME/.pcb/pcb-menu.res (grab a copy from the pcb source if you
246 haven't one there yet).
248 Known Bugs:
250 Square pins are teardropped too.
252 Refdes silk is no longer visible.
254 %end-doc */
255 static int
256 teardrops (int argc, char **argv, Coord x, Coord y)
258 silk = & PCB->Data->SILKLAYER;
260 new_arcs = 0;
262 VIA_LOOP (PCB->Data);
264 check_pin (via);
266 END_LOOP;
268 ALLPIN_LOOP (PCB->Data);
270 check_pin (pin);
272 ENDALL_LOOP;
274 gui->invalidate_all ();
276 if (new_arcs)
277 IncrementUndoSerialNumber ();
279 return 0;
282 static HID_Action teardrops_action_list[] = {
283 {"Teardrops", NULL, teardrops,
284 NULL, NULL}
287 REGISTER_ACTIONS (teardrops_action_list)
289 void
290 hid_teardrops_init()
292 register_teardrops_action_list();