teardrops.c

00001 /* Teardrops plug-in for PCB
00002    http://www.delorie.com/pcb/teardrops/
00003 
00004    Copyright (C) 2006 DJ Delorie <dj@delorie.com>
00005 
00006    Licensed under the terms of the GNU General Public License, version
00007    2 or later.
00008 */
00009 
00010 #include <stdio.h>
00011 #include <math.h>
00012 
00013 #include "global.h"
00014 #include "data.h"
00015 #include "hid.h"
00016 #include "misc.h"
00017 #include "create.h"
00018 #include "rtree.h"
00019 #include "undo.h"
00020 
00021 static PinTypePtr pin;
00022 static int layer;
00023 static int px, py;
00024 static LayerTypePtr silk;
00025 
00026 static int new_arcs = 0;
00027 
00028 static int
00029 check_line_callback (const BoxType * box, void *cl)
00030 {
00031   LayerTypePtr lay = & PCB->Data->Layer[layer];
00032   LineTypePtr l = (LineTypePtr) box;
00033   int x1, x2, y1, y2;
00034   double a, b, c, x, r, t;
00035   double dx, dy, len;
00036   double ax, ay, lx, ly, theta;
00037   double ldist, adist, radius;
00038   double vx, vy, vr, vl;
00039   int delta, aoffset, count;
00040   ArcTypePtr arc;
00041 
00042   if (l->Point1.X == px && l->Point1.Y == py)
00043     {
00044       x1 = l->Point1.X;
00045       y1 = l->Point1.Y;
00046       x2 = l->Point2.X;
00047       y2 = l->Point2.Y;
00048     }
00049   else if (l->Point2.X == px && l->Point2.Y == py)
00050     {
00051       x1 = l->Point2.X;
00052       y1 = l->Point2.Y;
00053       x2 = l->Point1.X;
00054       y2 = l->Point1.Y;
00055     }
00056   else
00057     return 1;
00058 
00059   r = pin->Thickness / 2.0;
00060   t = l->Thickness / 2.0;
00061 
00062   if (t > r)
00063     return 1;
00064 
00065   a = 1;
00066   b = 4 * t - 2 * r;
00067   c = 2 * t * t - r * r;
00068 
00069   x = (-b + sqrt (b * b - 4 * a * c)) / (2 * a);
00070 
00071   len = sqrt (((double)x2-x1)*(x2-x1) + ((double)y2-y1)*(y2-y1));
00072 
00073   if (len > (x+t))
00074     {
00075       adist = ldist = x + t;
00076       radius = x + t;
00077       delta = 45;
00078 
00079       if (radius < r || radius < t)
00080         return 1;
00081     }
00082   else if (len > r + t)
00083     {
00084       /* special "short teardrop" code */
00085 
00086       x = (len*len - r*r + t*t) / (2 * (r - t));
00087       ldist = len;
00088       adist = x + t;
00089       radius = x + t;
00090       delta = atan2 (len, x + t) * 180.0/M_PI;
00091     }
00092   else
00093     return 1;
00094 
00095   dx = ((double)x2 - x1) / len;
00096   dy = ((double)y2 - y1) / len;
00097   theta = atan2 (y2 - y1, x1 - x2) * 180.0/M_PI;
00098 
00099   lx = px + dx * ldist;
00100   ly = py + dy * ldist;
00101 
00102   /* We need one up front to determine how many segments it will take
00103      to fill.  */
00104   ax = lx - dy * adist;
00105   ay = ly + dx * adist;
00106   vl = sqrt (r*r - t*t);
00107   vx = px + dx * vl;
00108   vy = py + dy * vl;
00109   vx -= dy * t;
00110   vy += dx * t;
00111   vr = sqrt ((ax-vx) * (ax-vx) + (ay-vy) * (ay-vy));
00112 
00113   aoffset = 0;
00114   count = 0;
00115   do {
00116     if (++count > 5)
00117       {
00118         printf("a %d,%d v %d,%d adist %g radius %g vr %g\n",
00119                (int)ax, (int)ay, (int)vx, (int)vy, adist, radius, vr);
00120         return 1;
00121       }
00122 
00123     ax = lx - dy * adist;
00124     ay = ly + dx * adist;
00125 
00126     arc = CreateNewArcOnLayer (lay, (int)ax, (int)ay, (int)radius, (int)radius,
00127                                (int)theta+90+aoffset, delta-aoffset,
00128                                l->Thickness, l->Clearance, l->Flags);
00129     if (arc)
00130       AddObjectToCreateUndoList (ARC_TYPE, lay, arc, arc);
00131 
00132     ax = lx + dy * (x+t);
00133     ay = ly - dx * (x+t);
00134 
00135     arc = CreateNewArcOnLayer (lay, (int)ax, (int)ay, (int)radius, (int)radius,
00136                                (int)theta-90-aoffset, -delta+aoffset,
00137                                l->Thickness, l->Clearance, l->Flags);
00138     if (arc)
00139       AddObjectToCreateUndoList (ARC_TYPE, lay, arc, arc);
00140 
00141     radius += t*1.9;
00142     aoffset = acos ((double)adist / radius) * 180.0 / M_PI;
00143 
00144     new_arcs ++;
00145   } while (vr > radius - t);
00146 
00147   return 1;
00148 }
00149 
00150 static void
00151 check_pin (PinTypePtr _pin)
00152 {
00153   BoxType spot;
00154 
00155   pin = _pin;
00156 
00157   px = pin->X;
00158   py = pin->Y;
00159 
00160   spot.X1 = px - 1;
00161   spot.Y1 = py - 1;
00162   spot.X2 = px + 1;
00163   spot.Y2 = py + 1;
00164 
00165   for (layer = 0; layer < max_layer; layer ++)
00166     {
00167       LayerTypePtr l = &(PCB->Data->Layer[layer]);
00168       r_search (l->line_tree, &spot, NULL, check_line_callback, l);
00169     }
00170 }
00171 
00172 static int
00173 teardrops (int argc, char **argv, int x, int y)
00174 {
00175   silk = & PCB->Data->SILKLAYER;
00176 
00177   new_arcs = 0;
00178 
00179   VIA_LOOP (PCB->Data);
00180   {
00181     check_pin (via);
00182   }
00183   END_LOOP;
00184 
00185   ALLPIN_LOOP (PCB->Data);
00186   {
00187     check_pin (pin);
00188   }
00189   ENDALL_LOOP;
00190 
00191   gui->invalidate_all ();
00192 
00193   if (new_arcs)
00194     IncrementUndoSerialNumber ();
00195 
00196   return 0;
00197 }
00198 
00199 static HID_Action teardrops_action_list[] = {
00200   {"Teardrops", NULL, teardrops,
00201    NULL, NULL}
00202 };
00203 
00204 REGISTER_ACTIONS (teardrops_action_list)
00205 
00206 void
00207 hid_teardrops_init()
00208 {
00209   register_teardrops_action_list();
00210 }

Generated on Tue Aug 17 15:28:04 2010 for pcb-plugins by  doxygen 1.4.6-NO