pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 00029 #include <stdio.h> 00030 #include <math.h> 00031 00032 #include "config.h" 00033 #include "global.h" 00034 #include "data.h" 00035 #include "hid.h" 00036 #include "misc.h" 00037 #include "create.h" 00038 #include "rtree.h" 00039 #include "undo.h" 00040 00041 #define MIN_LINE_LENGTH 700 00042 #define MAX_DISTANCE 700 00043 00044 static PinType * pin; 00045 static int layer; 00046 static int px, py; 00047 static LayerType * silk; 00048 00049 static int new_arcs = 0; 00050 00051 int 00052 distance_between_points(int x1,int y1, int x2, int y2) 00053 { 00054 int a; 00055 int b; 00056 int distance; 00057 a = (x1-x2); 00058 b = (y1-y2); 00059 distance = hypot (a, b); 00060 return distance; 00061 } 00062 00063 static int 00064 check_line_callback (const BoxType * box, void *cl) 00065 { 00066 LayerType * lay = & PCB->Data->Layer[layer]; 00067 LineType * l = (LineType *) box; 00068 int x1, x2, y1, y2; 00069 double a, b, c, x, r, t; 00070 double dx, dy, len; 00071 double ax, ay, lx, ly, theta; 00072 double ldist, adist, radius; 00073 double vx, vy, vr, vl; 00074 int delta, aoffset, count; 00075 ArcType * arc; 00076 00077 /* if our line is to short ignore it */ 00078 if (distance_between_points(l->Point1.X,l->Point1.Y,l->Point2.X,l->Point2.Y) < MIN_LINE_LENGTH ) 00079 { 00080 return 1; 00081 } 00082 00083 if (distance_between_points(l->Point1.X,l->Point1.Y,px,py) < MAX_DISTANCE) 00084 { 00085 x1 = l->Point1.X; 00086 y1 = l->Point1.Y; 00087 x2 = l->Point2.X; 00088 y2 = l->Point2.Y; 00089 } 00090 else if (distance_between_points(l->Point2.X,l->Point2.Y,px,py) < MAX_DISTANCE) 00091 { 00092 x1 = l->Point2.X; 00093 y1 = l->Point2.Y; 00094 x2 = l->Point1.X; 00095 y2 = l->Point1.Y; 00096 } 00097 else 00098 return 1; 00099 00100 r = pin->Thickness / 2.0; 00101 t = l->Thickness / 2.0; 00102 00103 if (t > r) 00104 return 1; 00105 00106 a = 1; 00107 b = 4 * t - 2 * r; 00108 c = 2 * t * t - r * r; 00109 00110 x = (-b + sqrt (b * b - 4 * a * c)) / (2 * a); 00111 00112 len = sqrt (((double)x2-x1)*(x2-x1) + ((double)y2-y1)*(y2-y1)); 00113 00114 if (len > (x+t)) 00115 { 00116 adist = ldist = x + t; 00117 radius = x + t; 00118 delta = 45; 00119 00120 if (radius < r || radius < t) 00121 return 1; 00122 } 00123 else if (len > r + t) 00124 { 00125 /* special "short teardrop" code */ 00126 00127 x = (len*len - r*r + t*t) / (2 * (r - t)); 00128 ldist = len; 00129 adist = x + t; 00130 radius = x + t; 00131 delta = atan2 (len, x + t) * 180.0/M_PI; 00132 } 00133 else 00134 return 1; 00135 00136 dx = ((double)x2 - x1) / len; 00137 dy = ((double)y2 - y1) / len; 00138 theta = atan2 (y2 - y1, x1 - x2) * 180.0/M_PI; 00139 00140 lx = px + dx * ldist; 00141 ly = py + dy * ldist; 00142 00143 /* We need one up front to determine how many segments it will take 00144 to fill. */ 00145 ax = lx - dy * adist; 00146 ay = ly + dx * adist; 00147 vl = sqrt (r*r - t*t); 00148 vx = px + dx * vl; 00149 vy = py + dy * vl; 00150 vx -= dy * t; 00151 vy += dx * t; 00152 vr = sqrt ((ax-vx) * (ax-vx) + (ay-vy) * (ay-vy)); 00153 00154 aoffset = 0; 00155 count = 0; 00156 do { 00157 if (++count > 5) 00158 { 00159 printf("a %d,%d v %d,%d adist %g radius %g vr %g\n", 00160 (int)ax, (int)ay, (int)vx, (int)vy, adist, radius, vr); 00161 return 1; 00162 } 00163 00164 ax = lx - dy * adist; 00165 ay = ly + dx * adist; 00166 00167 arc = CreateNewArcOnLayer (lay, (int)ax, (int)ay, (int)radius, (int)radius, 00168 (int)theta+90+aoffset, delta-aoffset, 00169 l->Thickness, l->Clearance, l->Flags); 00170 if (arc) 00171 AddObjectToCreateUndoList (ARC_TYPE, lay, arc, arc); 00172 00173 ax = lx + dy * (x+t); 00174 ay = ly - dx * (x+t); 00175 00176 arc = CreateNewArcOnLayer (lay, (int)ax, (int)ay, (int)radius, (int)radius, 00177 (int)theta-90-aoffset, -delta+aoffset, 00178 l->Thickness, l->Clearance, l->Flags); 00179 if (arc) 00180 AddObjectToCreateUndoList (ARC_TYPE, lay, arc, arc); 00181 00182 radius += t*1.9; 00183 aoffset = acos ((double)adist / radius) * 180.0 / M_PI; 00184 00185 new_arcs ++; 00186 } while (vr > radius - t); 00187 00188 return 1; 00189 } 00190 00191 static void 00192 check_pin (PinType * _pin) 00193 { 00194 BoxType spot; 00195 00196 pin = _pin; 00197 00198 px = pin->X; 00199 py = pin->Y; 00200 00201 spot.X1 = px - 10; 00202 spot.Y1 = py - 10; 00203 spot.X2 = px + 10; 00204 spot.Y2 = py + 10; 00205 00206 for (layer = 0; layer < max_copper_layer; layer ++) 00207 { 00208 LayerType * l = &(PCB->Data->Layer[layer]); 00209 r_search (l->line_tree, &spot, NULL, check_line_callback, l); 00210 } 00211 } 00212 00213 /* %start-doc actions Teardrops 00214 00215 The @code{Teardrops()} action adds teardrops to the intersections 00216 between traces and pins/vias. 00217 00218 This is a simplistic test, so there are cases where you'd think it would 00219 add them but doesn't. 00220 00221 If the trace doesn't end at @emph{exactly} the same point as the pin/via, it 00222 will be skipped. 00223 00224 This often happens with metric parts on an Imperial grid or visa-versa. 00225 00226 If a trace passes through a pin/via but doesn't end there, there won't 00227 be any teardrops. 00228 00229 Use @code{:djopt(none)} to split those lines into two segments, each of which 00230 ends at the pin/via. 00231 00232 Usage: 00233 00234 This action takes no parameters. 00235 00236 To invoke it, use the command window, usually by typing ":". 00237 00238 Example: 00239 00240 @code{:Teardrops()} 00241 00242 @center @image{td_ex1,,,Example of how Teardrops works,png} 00243 00244 With the lesstif HID you can add this action to your menu or a hotkey by 00245 editing $HOME/.pcb/pcb-menu.res (grab a copy from the pcb source if you 00246 haven't one there yet). 00247 00248 Known Bugs: 00249 00250 Square pins are teardropped too. 00251 00252 Refdes silk is no longer visible. 00253 00254 %end-doc */ 00255 static int 00256 teardrops (int argc, char **argv, Coord x, Coord y) 00257 { 00258 silk = & PCB->Data->SILKLAYER; 00259 00260 new_arcs = 0; 00261 00262 VIA_LOOP (PCB->Data); 00263 { 00264 check_pin (via); 00265 } 00266 END_LOOP; 00267 00268 ALLPIN_LOOP (PCB->Data); 00269 { 00270 check_pin (pin); 00271 } 00272 ENDALL_LOOP; 00273 00274 gui->invalidate_all (); 00275 00276 if (new_arcs) 00277 IncrementUndoSerialNumber (); 00278 00279 return 0; 00280 } 00281 00282 static HID_Action teardrops_action_list[] = { 00283 {"Teardrops", NULL, teardrops, 00284 NULL, NULL} 00285 }; 00286 00287 REGISTER_ACTIONS (teardrops_action_list) 00288 00289 void 00290 hid_teardrops_init() 00291 { 00292 register_teardrops_action_list(); 00293 }