libgeda

o_circle_basic.c

Go to the documentation of this file.
00001 /* gEDA - GPL Electronic Design Automation
00002  * libgeda - gEDA's library
00003  * Copyright (C) 1998-2010 Ales Hvezda
00004  * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00019  */
00020 
00025 #include <config.h>
00026 #include <stdio.h>
00027 #include <math.h>
00028 
00029 #include "libgeda_priv.h"
00030 
00031 #ifdef HAVE_LIBDMALLOC
00032 #include <dmalloc.h>
00033 #endif
00034 
00047 int dist(int x1, int y1, int x2, int y2)
00048 {
00049   return sqrt(pow(x1-x2,2)+pow(y1-y2,2));
00050 }
00051 
00077 OBJECT *o_circle_new(TOPLEVEL *toplevel,
00078              char type, int color,
00079              int x, int y, int radius)
00080 {
00081   OBJECT *new_node; 
00082 
00083   /* create the object */
00084   new_node = s_basic_new_object(type, "circle");
00085   new_node->color  = color;
00086   
00087   new_node->circle = (CIRCLE *) g_malloc(sizeof(CIRCLE));
00088   
00089   /* describe the circle with its center and radius */
00090   new_node->circle->center_x = x;
00091   new_node->circle->center_y = y;
00092   new_node->circle->radius   = radius;
00093   
00094   /* line type and filling initialized to default */
00095   o_set_line_options(toplevel, new_node,
00096              END_NONE, TYPE_SOLID, 0, -1, -1);
00097   o_set_fill_options(toplevel, new_node,
00098              FILLING_HOLLOW, -1, -1, -1, -1, -1);
00099 
00100   /* compute the bounding box coords */
00101   o_circle_recalc(toplevel, new_node);
00102 
00103   return new_node;
00104 }
00105 
00115 OBJECT *o_circle_copy(TOPLEVEL *toplevel, OBJECT *o_current)
00116 {
00117   OBJECT *new_obj;
00118 
00119   /* A new circle object is created with #o_circle_new().
00120    * Values for its fields are default and need to be modified. */
00121   new_obj = o_circle_new (toplevel, OBJ_CIRCLE, o_current->color, 0, 0, 0);
00122 
00123   /*
00124    * The parameters of the new circle are set with the ones of the original
00125    * circle. The two circle have the same line type and the same filling
00126    * options.
00127    *
00128    * The bounding box coordinates are computed with
00129    * #o_circle_recalc().
00130    */
00131   /* modify */
00132   new_obj->circle->center_x = o_current->circle->center_x;
00133   new_obj->circle->center_y = o_current->circle->center_y;
00134   new_obj->circle->radius   = o_current->circle->radius;
00135   
00136   o_set_line_options(toplevel, new_obj, o_current->line_end,
00137              o_current->line_type, o_current->line_width,
00138              o_current->line_length, o_current->line_space);
00139   o_set_fill_options(toplevel, new_obj,
00140              o_current->fill_type, o_current->fill_width,
00141              o_current->fill_pitch1, o_current->fill_angle1,
00142              o_current->fill_pitch2, o_current->fill_angle2);
00143   
00144   o_circle_recalc(toplevel, new_obj);
00145 
00146   /*    new_obj->attribute = 0;*/
00147 
00148   return new_obj;
00149 }
00150 
00179 void o_circle_modify(TOPLEVEL *toplevel, OBJECT *object,
00180              int x, int y, int whichone)
00181 {
00182   o_emit_pre_change_notify (toplevel, object);
00183 
00184   switch(whichone) {
00185     case CIRCLE_CENTER:
00186       /* modify the center of the circle */
00187       object->circle->center_x = x;
00188       object->circle->center_y = y;
00189       break;
00190     case CIRCLE_RADIUS:
00191       /* modify the radius of the circle */
00192       if (x == 0) {
00193     s_log_message(_("Null radius circles are not allowed\n"));
00194     return;
00195       }
00196       object->circle->radius = x;
00197       break;
00198     default:
00199       break;
00200   }
00201 
00202   /* recalculate the boundings */
00203   o_circle_recalc(toplevel, object);
00204   o_emit_change_notify (toplevel, object);
00205 }
00206 
00225 OBJECT *o_circle_read (TOPLEVEL *toplevel, const char buf[],
00226               unsigned int release_ver, unsigned int fileformat_ver, GError ** err)
00227 {
00228   OBJECT *new_obj;
00229   char type; 
00230   int x1, y1;
00231   int radius;
00232   int color;
00233   int circle_width, circle_space, circle_length;
00234   int fill_width, angle1, pitch1, angle2, pitch2;
00235   int circle_end;
00236   int circle_type;
00237   int circle_fill;
00238 
00239   if(release_ver <= VERSION_20000704) {
00240     /*
00241      * The old geda file format, i.e. releases 20000704 and older, does not
00242      * handle the line type and the filling of the box object. They are set
00243      * to default.
00244      */
00245     if (sscanf(buf, "%c %d %d %d %d\n", &type, &x1, &y1, &radius, &color) != 5) {
00246       g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse circle object"));
00247       return NULL;
00248     }
00249 
00250     circle_width = 0;
00251     circle_end   = END_NONE;
00252     circle_type  = TYPE_SOLID;
00253     circle_length= -1;
00254     circle_space = -1;
00255     
00256     circle_fill  = FILLING_HOLLOW;
00257     fill_width  = 0;
00258     angle1      = -1;
00259     pitch1      = -1;
00260     angle2      = -1;
00261     pitch2      = -1;
00262             
00263   } else {
00264     
00265     /*
00266      * The current line format to describe a circle is a space separated
00267      * list of characters and numbers in plain ASCII on a single line. The
00268      * meaning of each item is described in the file format documentation.
00269      */  
00270     if (sscanf(buf, "%c %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
00271            &type, &x1, &y1, &radius, &color,
00272            &circle_width, &circle_end, &circle_type,
00273            &circle_length, &circle_space, &circle_fill,
00274            &fill_width, &angle1, &pitch1, &angle2, &pitch2) != 16) {
00275       g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse circle object"));
00276       return NULL;
00277     }
00278   }
00279 
00280 
00281   if (radius <= 0) {
00282     s_log_message(_("Found a zero or negative radius circle [ %c %d %d %d %d ]\n"),
00283                   type, x1, y1, radius, color);
00284     s_log_message (_("Setting radius to 0\n"));
00285     radius = 0;
00286   }
00287   
00288   if (color < 0 || color > MAX_COLORS) {
00289     s_log_message(_("Found an invalid color [ %s ]\n"), buf);
00290     s_log_message(_("Setting color to default color\n"));
00291     color = DEFAULT_COLOR;
00292   }
00293 
00294   /* 
00295    * A circle is internally described by its center and its radius.
00296    *
00297    * A new object is allocated, initialized and added to the object list.
00298    * Its filling and line type are set according to the values of the field
00299    * on the line.
00300    */
00301   new_obj = o_circle_new(toplevel, type, color, x1, y1, radius);
00302   o_set_line_options(toplevel, new_obj,
00303              circle_end, circle_type, circle_width, 
00304              circle_length, circle_space);
00305   o_set_fill_options(toplevel, new_obj,
00306              circle_fill, fill_width, pitch1, angle1, pitch2, angle2);
00307 
00308   return new_obj;
00309 }
00310 
00326 char *o_circle_save(TOPLEVEL *toplevel, OBJECT *object)
00327 {
00328   int x,y;
00329   int radius;
00330   int circle_width, circle_space, circle_length;
00331   int fill_width, angle1, pitch1, angle2, pitch2;
00332   char *buf;
00333   OBJECT_END circle_end;
00334   OBJECT_TYPE circle_type;
00335   OBJECT_FILLING circle_fill;
00336 
00337   /* circle center and radius */
00338   x = object->circle->center_x;
00339   y = object->circle->center_y;
00340   radius = object->circle->radius;
00341   
00342   /* line type parameters */
00343   circle_width = object->line_width;
00344   circle_end   = object->line_end;
00345   circle_type  = object->line_type;
00346   circle_length= object->line_length;
00347   circle_space = object->line_space;
00348   
00349   /* filling parameters */
00350   circle_fill  = object->fill_type;
00351   fill_width   = object->fill_width;
00352   angle1       = object->fill_angle1;
00353   pitch1       = object->fill_pitch1;
00354   angle2       = object->fill_angle2;
00355   pitch2       = object->fill_pitch2;
00356   
00357   buf = g_strdup_printf("%c %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d", 
00358             object->type, x, y, radius, object->color,
00359             circle_width, circle_end, circle_type, circle_length, 
00360             circle_space, circle_fill,
00361             fill_width, angle1, pitch1, angle2, pitch2);
00362   return(buf);
00363 }
00364            
00375 void o_circle_translate_world(TOPLEVEL *toplevel,
00376                   int dx, int dy, OBJECT *object)
00377 {
00378   /* Do world coords */
00379   object->circle->center_x = object->circle->center_x + dx;
00380   object->circle->center_y = object->circle->center_y + dy;
00381   
00382   /* recalc the screen coords and the bounding box */
00383   o_circle_recalc(toplevel, object);
00384   
00385 }
00386 
00400 void o_circle_rotate_world(TOPLEVEL *toplevel,
00401                int world_centerx, int world_centery, int angle,
00402                OBJECT *object)
00403 {
00404   int newx, newy;
00405   int x, y;
00406 
00407   /* Only 90 degree multiple and positive angles are allowed. */
00408   /* angle must be positive */
00409   if(angle < 0) angle = -angle;
00410   /* angle must be a 90 multiple or no rotation performed */
00411   if((angle % 90) != 0) return;
00412   
00413   /*
00414    * The center of rotation (<B>world_centerx</B>,<B>world_centery</B>) is
00415    * translated to the origin. The rotation of the center around the origin
00416    * is then performed. Finally, the rotated circle is translated back to
00417    * its previous location.
00418    */
00419 
00420   /* translate object to origin */
00421   object->circle->center_x -= world_centerx;
00422   object->circle->center_y -= world_centery;
00423   
00424   /* rotate the center of the circle around the origin */
00425   x = object->circle->center_x;
00426   y = object->circle->center_y;
00427   rotate_point_90(x, y, angle, &newx, &newy);
00428   object->circle->center_x = newx;
00429   object->circle->center_y = newy;
00430   
00431   /* translate back in position */
00432   object->circle->center_x += world_centerx;
00433   object->circle->center_y += world_centery;
00434 
00435   o_circle_recalc(toplevel, object);
00436   
00437 }
00438 
00452 void o_circle_mirror_world(TOPLEVEL *toplevel,
00453                int world_centerx, int world_centery,
00454                OBJECT *object)
00455 {
00456   /* translate object to origin */
00457   object->circle->center_x -= world_centerx;
00458   object->circle->center_y -= world_centery;
00459 
00460   /* mirror the center of the circle */
00461   object->circle->center_x = -object->circle->center_x;
00462   object->circle->center_y =  object->circle->center_y;
00463 
00464   /* translate back in position */
00465   object->circle->center_x += world_centerx;
00466   object->circle->center_y += world_centery;
00467 
00468   /* recalc boundings and screen coords */
00469   o_circle_recalc(toplevel, object);
00470   
00471 }
00472 
00484 void o_circle_recalc(TOPLEVEL *toplevel, OBJECT *o_current)
00485 {
00486   int left, right, top, bottom;
00487 
00488   if (o_current->circle == NULL) {
00489     return;
00490   }
00491   
00492   /* update the bounding box - world unit */
00493   world_get_circle_bounds(toplevel, o_current,
00494             &left, &top, &right, &bottom);
00495   o_current->w_left   = left;
00496   o_current->w_top    = top;
00497   o_current->w_right  = right;
00498   o_current->w_bottom = bottom;
00499   o_current->w_bounds_valid = TRUE;
00500 }
00501 
00515 void world_get_circle_bounds(TOPLEVEL *toplevel, OBJECT *object, int *left,
00516                              int *top, int *right, int *bottom)
00517 {
00518   int halfwidth;
00519 
00520   halfwidth = object->line_width / 2;
00521 
00522   *left   = object->circle->center_x - object->circle->radius;
00523   *top    = object->circle->center_y - object->circle->radius;
00524   *right  = object->circle->center_x + object->circle->radius;
00525   *bottom = object->circle->center_y + object->circle->radius;
00526 
00527   /* This isn't strictly correct, but a 1st order approximation */
00528   *left   -= halfwidth;
00529   *top    -= halfwidth;
00530   *right  += halfwidth;
00531   *bottom += halfwidth;
00532 
00533 }
00534 
00545 gboolean o_circle_get_position (TOPLEVEL *toplevel, gint *x, gint *y,
00546                               OBJECT *object)
00547 {
00548   *x = object->circle->center_x;
00549   *y = object->circle->center_y;
00550   return TRUE;
00551 }
00552 
00576 void o_circle_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current,
00577             int origin_x, int origin_y)
00578 {
00579   int x, y, radius;
00580   int color;
00581   int circle_width, length, space;
00582   int fill_width, angle1, pitch1, angle2, pitch2;
00583   void (*outl_func)() = NULL;
00584   void (*fill_func)() = NULL;
00585 
00586   if (o_current == NULL) {
00587     printf("got null in o_circle_print\n");
00588     return;
00589   }
00590 
00591   x      = o_current->circle->center_x; 
00592   y      = o_current->circle->center_y;
00593   radius = o_current->circle->radius;
00594 
00595   color  = o_current->color;
00596 
00597   /*
00598    * Depending on the type of the line for this particular circle, the
00599    * appropriate function is chosen among #o_circle_print_solid(),
00600    * #o_circle_print_dotted(), #o_circle_print_dashed(),
00601    * #o_circle_print_center() and #o_circle_print_phantom().
00602    *
00603    * The needed parameters for each of these type is extracted from the
00604    * <B>o_current</B> object. Depending on the type, unused parameters are
00605    * set to -1.
00606    *
00607    * In the eventuality of a length and/or space null, the line is
00608    * printed solid to avoid and endless loop produced by other functions
00609    * in such a case.
00610    */
00611   circle_width = o_current->line_width;
00612   if(circle_width <=2) {
00613     if(toplevel->line_style == THICK) {
00614       circle_width=LINE_WIDTH;
00615     } else {
00616       circle_width=2;
00617     }
00618   }
00619   length       = o_current->line_length;
00620   space        = o_current->line_space;
00621 
00622   switch(o_current->line_type) {
00623     case(TYPE_SOLID):
00624       length = -1; space  = -1;
00625       outl_func = o_circle_print_solid;
00626       break;
00627 
00628     case(TYPE_DOTTED):
00629       length = -1;
00630       outl_func = o_circle_print_dotted;
00631       break;
00632 
00633     case(TYPE_DASHED):
00634       outl_func = o_circle_print_dashed;
00635       break;
00636 
00637     case(TYPE_CENTER):
00638       outl_func = o_circle_print_center;
00639       break;
00640 
00641     case(TYPE_PHANTOM):
00642       outl_func = o_circle_print_phantom;
00643       break;
00644 
00645     case(TYPE_ERASE):
00646       /* Unused for now print it solid */
00647       length = -1; space  = -1;
00648       outl_func = o_circle_print_solid;
00649       break;
00650   }
00651 
00652   if((length == 0) || (space == 0)) {
00653     length = -1; space  = -1;
00654     outl_func = o_circle_print_solid;
00655   }
00656 
00657   (*outl_func)(toplevel, fp,
00658                x - origin_x, y - origin_y,
00659                radius,
00660                color,
00661                circle_width, length, space,
00662                origin_x, origin_y);
00663 
00664   /*
00665    * If the filling type of the circle is not <B>HOLLOW</B>, the appropriate
00666    * function is chosen among #o_circle_print_filled(), #o_circle_print_mesh()
00667    * and #o_circle_print_hatch(). The corresponding parameters are extracted
00668    * from the <B>o_current</B> object and corrected afterward.
00669    *
00670    * The case where <B>pitch1</B> and <B>pitch2</B> are null or negative is
00671    * avoided as it leads to an endless loop in most of the called functions.
00672    * In such a case, the circle is printed filled. Unused parameters for
00673    * each of these functions are set to -1 or any passive value.
00674    */
00675   if(o_current->fill_type != FILLING_HOLLOW) {
00676     fill_width = o_current->fill_width;
00677     angle1     = o_current->fill_angle1;
00678     pitch1     = o_current->fill_pitch1;
00679     angle2     = o_current->fill_angle2;
00680     pitch2     = o_current->fill_pitch2;
00681         
00682     switch(o_current->fill_type) {
00683       case(FILLING_FILL):
00684         angle1 = -1; pitch1 = 1;
00685         angle2 = -1; pitch2 = 1;
00686         fill_width = -1;
00687         fill_func = o_circle_print_filled;
00688         break;
00689             
00690       case(FILLING_MESH):
00691         fill_func = o_circle_print_mesh;
00692         break;
00693                 
00694       case(FILLING_HATCH):
00695         angle2 = -1; pitch2 = 1;
00696         fill_func = o_circle_print_hatch;
00697         break;
00698                 
00699       case(FILLING_VOID):
00700                 /* Unused for now, print it filled */
00701         angle1 = -1; pitch1 = 1;
00702         angle2 = -1; pitch2 = 1;
00703         fill_width = -1;
00704         fill_func = o_circle_print_filled;
00705         break;
00706         
00707       case(FILLING_HOLLOW):
00708         /* nop */
00709         break;
00710     }
00711 
00712     if((pitch1 <= 0) || (pitch2 <= 0)) {
00713       angle1 = -1; pitch1 = 1;
00714       angle2 = -1; pitch2 = 1;
00715       fill_func = o_circle_print_filled;
00716     }
00717         
00718     (*fill_func)(toplevel, fp,
00719                  x, y, radius,
00720                  color,
00721                  fill_width,
00722                  angle1, pitch1, angle2, pitch2,
00723                  origin_x, origin_y);
00724   }
00725 }
00726 
00753 void o_circle_print_solid(TOPLEVEL *toplevel, FILE *fp,
00754               int x, int y, int radius,
00755               int color,
00756               int circle_width, int length, int space,
00757               int origin_x, int origin_y)
00758 {
00759 
00760   o_arc_print_solid(toplevel, fp,
00761                     x, y, radius,
00762                     0, FULL_CIRCLE / 64,
00763                     color,
00764                     circle_width, -1, -1,
00765                     origin_x, origin_y);
00766 
00767 }
00768 
00769 
00796 void o_circle_print_dotted(TOPLEVEL *toplevel, FILE *fp,
00797                int x, int y, int radius,
00798                int color,
00799                int circle_width, int length, int space,
00800                int origin_x, int origin_y)
00801 {
00802 
00803   o_arc_print_dotted(toplevel, fp,
00804                      x, y, radius,
00805                      0, FULL_CIRCLE / 64,
00806                      color,
00807                      circle_width, -1, space,
00808                      origin_x, origin_y);
00809 
00810 }
00811 
00837 void o_circle_print_dashed(TOPLEVEL *toplevel, FILE *fp,
00838                int x, int y,
00839                int radius,
00840                int color,
00841                int circle_width, int length, int space,
00842                int origin_x, int origin_y)
00843 {
00844 
00845   o_arc_print_dashed(toplevel, fp,
00846                      x, y, radius,
00847                      0, FULL_CIRCLE / 64,
00848                      color,
00849                      circle_width, length, space,
00850                      origin_x, origin_y);
00851 
00852 }
00853 
00879 void o_circle_print_center(TOPLEVEL *toplevel, FILE *fp,
00880                int x, int y,
00881                int radius,
00882                int color,
00883                int circle_width, int length, int space,
00884                int origin_x, int origin_y)
00885 {
00886     
00887   o_arc_print_center(toplevel, fp,
00888                      x, y, radius,
00889                      0, FULL_CIRCLE / 64,
00890                      color,
00891                      circle_width, length, space,
00892                      origin_x, origin_y);
00893 
00894 }
00895 
00921 void o_circle_print_phantom(TOPLEVEL *toplevel, FILE *fp,
00922                 int x, int y,
00923                 int radius,
00924                 int color,
00925                 int circle_width, int length, int space,
00926                 int origin_x, int origin_y)
00927 {
00928 
00929   o_arc_print_phantom(toplevel, fp,
00930                       x, y, radius,
00931                       0, FULL_CIRCLE / 64,
00932                       color,
00933                       circle_width, length, space,
00934                       origin_x, origin_y);
00935 
00936 }
00937 
00965 void o_circle_print_filled(TOPLEVEL *toplevel, FILE *fp,
00966                int x, int y, int radius,
00967                int color,
00968                int fill_width,
00969                int angle1, int pitch1,
00970                int angle2, int pitch2,
00971                int origin_x, int origin_y)
00972 {
00973   f_print_set_color(toplevel, fp, color);
00974 
00975   fprintf(fp, "%d %d %d dot\n",
00976       x-origin_x, y-origin_y,
00977       radius);
00978     
00979 }
00980 
01011 void o_circle_print_mesh(TOPLEVEL *toplevel, FILE *fp,
01012              int x, int y, int radius,
01013              int color,
01014              int fill_width,
01015              int angle1, int pitch1,
01016              int angle2, int pitch2,
01017              int origin_x, int origin_y)
01018 {
01019   o_circle_print_hatch(toplevel, fp,
01020                        x, y, radius,
01021                        color,
01022                        fill_width,
01023                        angle1, pitch1,
01024                        -1, -1,
01025                        origin_x, origin_y);
01026   o_circle_print_hatch(toplevel, fp,
01027                        x, y, radius,
01028                        color,
01029                        fill_width,
01030                        angle2, pitch2,
01031                        -1, -1,
01032                        origin_x, origin_y);
01033     
01034 }
01035 
01066 void o_circle_print_hatch(TOPLEVEL *toplevel, FILE *fp,
01067               int x, int y, int radius,
01068               int color,
01069               int fill_width,
01070               int angle1, int pitch1,
01071               int angle2, int pitch2,
01072               int origin_x, int origin_y)
01073 {
01074   CIRCLE circle;
01075   gint index;
01076   GArray *lines;
01077 
01078   g_return_if_fail(toplevel != NULL);
01079   g_return_if_fail(fp != NULL);
01080 
01081   f_print_set_color(toplevel, fp, color);
01082 
01083   /* Avoid printing line widths too small */
01084   if (fill_width <= 1) fill_width = 2;
01085 
01086   lines = g_array_new(FALSE, FALSE, sizeof(LINE));
01087 
01088   circle.center_x = x;
01089   circle.center_y = y;
01090   circle.radius   = radius;
01091 
01092   m_hatch_circle(&circle, angle1, pitch1, lines);
01093 
01094   for(index=0; index<lines->len; index++) {
01095     LINE *line = &g_array_index(lines, LINE, index);
01096 
01097     fprintf(fp,"%d %d %d %d %d line\n",
01098             line->x[0], line->y[0],
01099             line->x[1], line->y[1],
01100             fill_width);
01101   }
01102 
01103   g_array_free(lines, TRUE);
01104 }
01105 
01116 double o_circle_shortest_distance (OBJECT *object, int x, int y,
01117                                    int force_solid)
01118 {
01119   int solid;
01120 
01121   g_return_val_if_fail (object->circle != NULL, G_MAXDOUBLE);
01122 
01123   solid = force_solid || object->fill_type != FILLING_HOLLOW;
01124 
01125   return m_circle_shortest_distance (object->circle, x, y, solid);
01126 }
01127 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines