utilities.c

00001 /*
00002  * utilities
00003  *
00004  * Copyright 2008 Dean Ferreyra <dferreyra@igc.org>, All rights reserved
00005  *
00006  * This file is part of Footprint-Update.
00007  * 
00008  * Footprint-Update is free software: you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation, either version 3 of the License, or
00011  * (at your option) any later version.
00012  * 
00013  * Footprint-Update is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  * 
00018  * You should have received a copy of the GNU General Public License
00019  * along with Footprint-Update.  If not, see <http://www.gnu.org/licenses/>.
00020  *
00021  * $Id: utilities.c,v 1.22 2008-05-22 04:52:13 dean Exp $
00022  * Dean Ferreyra
00023  */
00024 
00025 #include "utilities.h"
00026 
00027 static Boolean have_two_corresponding_aux(ElementTypePtr old_element,
00028                                           ElementTypePtr new_element,
00029                                           Boolean unique,
00030                                           Boolean non_coincident,
00031                                           PadOrPinType* old1_pp_ptr,
00032                                           PadOrPinType* old2_pp_ptr,
00033                                           PadOrPinType* new1_pp_ptr,
00034                                           PadOrPinType* new2_pp_ptr);
00035 /*
00036  * Pad/pin type
00037  */
00038 
00039 PadOrPinType
00040 make_pad_or_pin(PadTypePtr pad, PinTypePtr pin)
00041 {
00042   PadOrPinType pp = { pad, pin };
00043   return pp;
00044 }
00045 
00046 Boolean
00047 is_pad_or_pin(const PadOrPinType* pp)
00048 {
00049   return pp->pad || pp->pin;
00050 }
00051 
00052 const char*
00053 pad_or_pin_number(const PadOrPinType* pp)
00054 {
00055   if (pp->pad) {
00056     return pp->pad->Number;
00057   } else if (pp->pin) {
00058     return pp->pin->Number;
00059   } else {
00060     return NULL;
00061   }
00062 }
00063 
00064 const char*
00065 pad_or_pin_name(const PadOrPinType* pp)
00066 {
00067   if (pp->pad) {
00068     return pp->pad->Name;
00069   } else if (pp->pin) {
00070     return pp->pin->Name;
00071   } else {
00072     return NULL;
00073   }
00074 }
00075 
00076 int
00077 number_cmp(const char* number_a, const char* number_b)
00078 {
00079   if (! number_a && ! number_b) {
00080     return 0;
00081   } else if (! number_a) {
00082     return -1;
00083   } else if (! number_b) {
00084     return 1;
00085   } else {
00086     return strcmp(number_a, number_b);
00087   }
00088 }
00089 
00090 Boolean
00091 pad_or_pin_test_flag(const PadOrPinType* pp, unsigned long flag)
00092 {
00093   if (pp->pad) {
00094     return TEST_FLAG(flag, pp->pad);
00095   } else if (pp->pin) {
00096     return TEST_FLAG(flag, pp->pin);
00097   } else {
00098     return False;
00099   }
00100 }
00101 void
00102 pad_or_pin_set_flag(PadOrPinType* pp, unsigned long flag)
00103 {
00104   if (pp->pad) {
00105     SET_FLAG(flag, pp->pad);
00106   } else if (pp->pin) {
00107     SET_FLAG(flag, pp->pin);
00108   }
00109 }
00110 
00111 int
00112 pad_or_pin_number_cmp(const PadOrPinType* ppa, const PadOrPinType* ppb)
00113 {
00114   return number_cmp(pad_or_pin_number(ppa), pad_or_pin_number(ppb));
00115 }
00116 
00117 CheapPointType
00118 pad_or_pin_center(PadOrPinType* pp)
00119 {
00120   if (pp->pad) {
00121     return pad_center(pp->pad);
00122   } else if (pp->pin) {
00123     return pin_center(pp->pin);
00124   } else {
00125     base_log("Error: pad_or_pin_center() got an empty PadOrPinType.\n");
00126     return make_point(0, 0);
00127   }
00128 }
00129 
00130 CheapPointType
00131 pad_center(PadTypePtr pad)
00132 {
00133   return make_point((pad->Point1.X + pad->Point2.X) / 2,
00134                     (pad->Point1.Y + pad->Point2.Y) / 2);
00135 }
00136 
00137 CheapPointType
00138 pin_center(PinTypePtr pin)
00139 {
00140   return MAKE_PT(*pin);
00141 }
00142 
00143 Boolean
00144 find_pad_or_pin(ElementTypePtr element, const char* number,
00145                 PadOrPinType* pp_ptr)
00146 {
00147   PadOrPinType pp = make_pad_or_pin(NULL, NULL);
00148   if (number &&
00149       ((pp.pad = find_pad(element, number))
00150        || (pp.pin = find_pin(element, number)))) {
00151     *pp_ptr = pp;
00152     return True;
00153   } else {
00154     return False;
00155   }
00156 }
00157 
00158 PadTypePtr
00159 find_pad(ElementTypePtr element, const char* number)
00160 {
00161   PAD_LOOP(element);
00162   {
00163     if (pad->Number && number_cmp(pad->Number, number) == 0) {
00164       return pad;
00165     }
00166   }
00167   END_LOOP;
00168   return NULL;
00169 }
00170 
00171 PinTypePtr
00172 find_pin(ElementTypePtr element, const char* number)
00173 {
00174   PIN_LOOP(element);
00175   {
00176     if (pin->Number && number_cmp(pin->Number, number) == 0) {
00177       return pin;
00178     }
00179   }
00180   END_LOOP;
00181   return NULL;
00182 }
00183 
00184 Boolean
00185 is_number_unique(ElementTypePtr element, const char* number)
00186 {
00187   int count = 0;
00188   PAD_OR_PIN_LOOP(element);
00189   {
00190     const char* pp_number = pad_or_pin_number(&pp);
00191     if (pp_number && number_cmp(pp_number, number) == 0) {
00192       if (++count > 1) {
00193         return False;
00194       }
00195     }
00196   }
00197   END_LOOP;
00198   return True;
00199 }
00200 
00201 Boolean
00202 have_two_corresponding_non_coincident(ElementTypePtr old_element,
00203                                       ElementTypePtr new_element,
00204                                       PadOrPinType* old1_pp_ptr,
00205                                       PadOrPinType* old2_pp_ptr,
00206                                       PadOrPinType* new1_pp_ptr,
00207                                       PadOrPinType* new2_pp_ptr)
00208 {
00209   return have_two_corresponding_aux(old_element, new_element,
00210                                     False, True,
00211                                     old1_pp_ptr, old2_pp_ptr,
00212                                     new1_pp_ptr, new2_pp_ptr);
00213 }
00214 
00215 Boolean
00216 have_two_corresponding_unique_non_coincident(ElementTypePtr old_element,
00217                                              ElementTypePtr new_element,
00218                                              PadOrPinType* old1_pp_ptr,
00219                                              PadOrPinType* old2_pp_ptr,
00220                                              PadOrPinType* new1_pp_ptr,
00221                                              PadOrPinType* new2_pp_ptr)
00222 {
00223   return have_two_corresponding_aux(old_element, new_element,
00224                                     True, True,
00225                                     old1_pp_ptr, old2_pp_ptr,
00226                                     new1_pp_ptr, new2_pp_ptr);
00227 }
00228 
00229 static Boolean
00230 have_two_corresponding_aux(ElementTypePtr old_element,
00231                            ElementTypePtr new_element,
00232                            Boolean unique,
00233                            Boolean non_coincident,
00234                            PadOrPinType* old1_pp_ptr,
00235                            PadOrPinType* old2_pp_ptr,
00236                            PadOrPinType* new1_pp_ptr,
00237                            PadOrPinType* new2_pp_ptr)
00238 {
00239   PadOrPinType old1_pp = make_pad_or_pin(NULL, NULL);
00240   PadOrPinType new1_pp = make_pad_or_pin(NULL, NULL);
00241   Boolean first_found = False;
00242 
00243   PAD_OR_PIN_LOOP_HYG(old_element, _old);
00244   {
00245     if (! unique
00246         || is_number_unique(old_element,
00247                             pad_or_pin_number(&pp_old))) {
00248       CheapPointType old_pt = pad_or_pin_center(&pp_old);
00249       PAD_OR_PIN_LOOP_HYG(new_element, _new);
00250       {
00251         if (pad_or_pin_number_cmp(&pp_old, &pp_new) == 0
00252             && (! unique
00253                 || is_number_unique(new_element,
00254                                     pad_or_pin_number(&pp_new)))) {
00255           CheapPointType new_pt = pad_or_pin_center(&pp_new);
00256           if (! non_coincident || point_distance2(old_pt, new_pt)) {
00257             if (! first_found) {
00258               old1_pp = pp_old;
00259               new1_pp = pp_new;
00260               first_found = True;
00261             } else {
00262               if (old1_pp_ptr) {
00263                 *old1_pp_ptr = old1_pp;
00264               }
00265               if (new1_pp_ptr) {
00266                 *new1_pp_ptr = new1_pp;
00267               }
00268               if (old2_pp_ptr) {
00269                 *old2_pp_ptr = pp_old;
00270               }
00271               if (new2_pp_ptr) {
00272                 *new2_pp_ptr = pp_new;
00273               }
00274               return True;
00275             }
00276           }
00277         }
00278       }
00279       END_LOOP;
00280     }
00281   }
00282   END_LOOP;
00283   return False;
00284 }
00285 
00286 Boolean
00287 have_any_corresponding_pad_or_pin(ElementTypePtr old_element,
00288                                   ElementTypePtr new_element,
00289                                   PadOrPinType* old_pp,
00290                                   PadOrPinType* new_pp)
00291 {
00292   PAD_OR_PIN_LOOP_HYG(old_element, _old);
00293   {
00294     PAD_OR_PIN_LOOP_HYG(new_element, _new);
00295     {
00296       if (pad_or_pin_number_cmp(&pp_old, &pp_new) == 0) {
00297         if (old_pp) {
00298           *old_pp = pp_old;
00299         }
00300         if (new_pp) {
00301           *new_pp = pp_new;
00302         }
00303         return True;
00304       }
00305     }
00306     END_LOOP;
00307   }
00308   END_LOOP;
00309   return False;
00310 }
00311 
00312 /*
00313  * CheapPointType helpers.
00314  */
00315 
00316 CheapPointType
00317 make_point(LocationType x, LocationType y)
00318 {
00319   CheapPointType pt = { x, y };
00320   return pt;
00321 }
00322 
00323 CheapPointType
00324 point_subtract(CheapPointType pt1, CheapPointType pt2)
00325 {
00326   return make_point(pt1.X - pt2.X, pt1.Y - pt2.Y);
00327 }
00328 
00329 /* Distance squared */
00330 double
00331 point_distance2(CheapPointType pt1, CheapPointType pt2)
00332 {
00333   CheapPointType diff = point_subtract(pt1, pt2);
00334   return (double)diff.X * (double)diff.X + (double)diff.Y * (double)diff.Y;
00335 }
00336 
00337 /*
00338  * Miscellaneous
00339  */
00340 
00341 double
00342 round(double v)
00343 {
00344   if (v < 0) {
00345     return ceil(v - 0.5);
00346   } else {
00347     return floor(v + 0.5);
00348   }
00349 }
00350 
00351 double
00352 multiple_of_90(double rad)
00353 {
00354   return (M_PI / 2) * round(rad / (M_PI / 2));
00355 }
00356 
00357 #define ANGLE_EPSILON 0.01
00358 #define ANGLE_NEAR(a1, a2) (fabs((a1) - (a2)) < ANGLE_EPSILON)
00359 
00360 BYTE
00361 angle_to_rotation_steps(double rad)
00362 {
00363   double rad90 = multiple_of_90(rad);
00364 
00365   if (ANGLE_NEAR(rad90, M_PI / 2)) {
00366     return 3;
00367   } else if (ANGLE_NEAR(fabs(rad90), M_PI)) {
00368     return 2;
00369   } else if (ANGLE_NEAR(rad90, -M_PI / 2)) {
00370     return 1;
00371   } else if (ANGLE_NEAR(rad90, 0)) {
00372     return 0;
00373   } else {
00374     base_log("Error: angle_to_rotation_steps() got "
00375              "an unhandled angle: %lf\n",
00376              rad * RAD_TO_DEG);
00377     return 0;
00378   }
00379 }
00380 
00381 /*
00382  * Logging
00383  */
00384 
00385 void
00386 log_point(CheapPointType pt)
00387 {
00388   base_log("Point\n");
00389   base_log("%8d %8d\n", pt.X, pt.Y);
00390 }
00391 
00392 void
00393 log_pad_or_pin(const PadOrPinType* pp)
00394 {
00395   if (pp->pad) {
00396     log_pad(pp->pad);
00397   } else {
00398     log_pin(pp->pin);
00399   }
00400 }
00401 
00402 void
00403 log_pad(PadTypePtr p)
00404 {
00405   base_log("Pad\n");
00406   base_log("Name: \"%s\"\n", p->Name);
00407   base_log("Number: \"%s\"\n", p->Number);
00408   base_log("Point 1: (%d, %d)\n", p->Point1.X, p->Point1.Y);
00409   base_log("Point 2: (%d, %d)\n", p->Point2.X, p->Point2.Y);
00410 }
00411 
00412 void
00413 log_pin(PinTypePtr p)
00414 {
00415   base_log("Pin\n");
00416   base_log("Name: \"%s\"\n", p->Name);
00417   base_log("Number: \"%s\"\n", p->Number);
00418   base_log("Point: (%d, %d)\n", p->X, p->Y);
00419 }
00420 
00421 void
00422 log_element(ElementTypePtr e)
00423 {
00424   base_log("Element\n");
00425   base_log("Description: %s\n", DESCRIPTION_NAME(e));
00426   base_log("Name on PCB: %s\n", NAMEONPCB_NAME(e));
00427   base_log("Value: %s\n", VALUE_NAME(e));
00428   base_log("Flags: %04x\n", FLAG_VALUE(e->Flags));
00429   base_log("MarkX, MarkY: %d, %d\n", e->MarkX, e->MarkY);
00430   base_log("PinN: %d\n", e->PinN);
00431   base_log("PadN: %d\n", e->PadN);
00432   base_log("LineN: %d\n", e->LineN);
00433   base_log("ArcN: %d\n", e->ArcN);
00434   base_log("Attributes number: %d\n", e->Attributes.Number);
00435 
00436   int i = 0;
00437   PAD_LOOP(e);
00438   {
00439     base_log("Pad %d\n", i++);
00440     log_pad(pad);
00441   }
00442   END_LOOP;
00443 
00444   i = 0;
00445   PIN_LOOP(e);
00446   {
00447     base_log("Pin %d\n", i++);
00448     log_pin(pin);
00449   }
00450   END_LOOP;
00451 }
00452 
00453 void base_log(const char *fmt, ...)
00454 {
00455   va_list args;
00456   va_start(args, fmt);
00457   gui->log(TITLE);
00458   gui->log(": ");
00459   gui->logv(fmt, args);
00460 #if DEBUG
00461   /* In debug mode, output logs to stderr. */
00462   vfprintf(stderr, fmt, args);
00463 #endif
00464   va_end(args);
00465 }
00466 
00467 void debug_log(const char *fmt, ...)
00468 {
00469   va_list args;
00470   va_start(args, fmt);
00471 #if DEBUG
00472   gui->log(TITLE);
00473   gui->log(": ");
00474   gui->logv(fmt, args);
00475   /* In debug mode, output logs to stderr. */
00476   vfprintf(stderr, fmt, args);
00477 #endif
00478   va_end(args);
00479 }

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