gschem

o_circle.c

Go to the documentation of this file.
00001 /* gEDA - GPL Electronic Design Automation
00002  * gschem - gEDA Schematic Capture
00003  * Copyright (C) 1998-2010 Ales Hvezda
00004  * Copyright (C) 1998-2011 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 #include <config.h>
00021 #include <stdio.h>
00022 #include <math.h>
00023 
00024 #include "gschem.h"
00025 
00026 #ifdef HAVE_LIBDMALLOC
00027 #include <dmalloc.h>
00028 #endif
00029 
00030 
00031 typedef void (*FILL_FUNC) (GSCHEM_TOPLEVEL *w_current,
00032                            COLOR *color, CIRCLE *circle,
00033                            gint fill_width, gint angle1, gint pitch1,
00034                            gint angle2, gint pitch2);
00035 
00036 
00055 static void
00056 o_circle_fill_hollow (GSCHEM_TOPLEVEL *w_current,
00057                       COLOR *color, CIRCLE *circle,
00058                       gint fill_width,
00059                       gint angle1, gint pitch1,
00060                       gint angle2, gint pitch2)
00061 {
00062 }
00063 
00087 static void
00088 o_circle_fill_fill (GSCHEM_TOPLEVEL *w_current,
00089                     COLOR *color, CIRCLE *circle,
00090                     gint fill_width,
00091                     gint angle1, gint pitch1,
00092                     gint angle2, gint pitch2)
00093 {
00094   /* NOP: We'll fill it when we do the stroking */
00095 }
00096 
00127 static void
00128 o_circle_fill_hatch (GSCHEM_TOPLEVEL *w_current,
00129                      COLOR *color, CIRCLE *circle,
00130                      gint fill_width,
00131                      gint angle1, gint pitch1,
00132                      gint angle2, gint pitch2)
00133 {
00134   int i;
00135   GArray *lines;
00136 
00137   gschem_cairo_set_source_color (w_current, color);
00138 
00139   lines = g_array_new (FALSE, FALSE, sizeof (LINE));
00140   m_hatch_circle (circle, angle1, pitch1, lines);
00141 
00142   for (i=0; i < lines->len; i++) {
00143     LINE *line = &g_array_index (lines, LINE, i);
00144 
00145     gschem_cairo_line (w_current, END_NONE, fill_width, line->x[0], line->y[0],
00146                                                         line->x[1], line->y[1]);
00147   }
00148   gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, fill_width, -1, -1);
00149 
00150   g_array_free (lines, TRUE);
00151 }
00152 
00180 static void
00181 o_circle_fill_mesh (GSCHEM_TOPLEVEL *w_current,
00182                     COLOR *color, CIRCLE *circle,
00183                     gint fill_width,
00184                     gint angle1, gint pitch1,
00185                     gint angle2, gint pitch2)
00186 {
00187   o_circle_fill_hatch (w_current, color, circle,
00188                        fill_width, angle1, pitch1, -1, -1);
00189   o_circle_fill_hatch (w_current, color, circle,
00190                        fill_width, angle2, pitch2, -1, -1);
00191     
00192 }
00193 
00194 
00208 void o_circle_draw(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current)
00209 {
00210   int angle1, pitch1, angle2, pitch2;
00211   FILL_FUNC fill_func;
00212 
00213   if (o_current->circle == NULL) {
00214     return;
00215   }
00216 
00217   /*
00218    * The draw of the circle is divided in two steps : first step is to draw
00219    * the outline, the second is to draw the filling pattern inside (if any).
00220    *
00221    * Finally the function takes care of the grips.
00222    */
00223 
00224   /*
00225    * The values needed for the fill operation are taken from the
00226    * <B>o_current</B> pointed OBJECT. It include the type of fill required, the
00227    * width of the lines (if the fill use line) and angles and pitchs for hatch
00228    * based filling.
00229    *
00230    * Once again the width of the line is important as if it is equal to 0 it
00231    * may not be displayed. That is definetely not what we are looking for.
00232    *
00233    * Depending on the type of fill that has to be used inside the circle the
00234    * right function is called. Values of <B>angle1</B>, <B>angle2</B>,
00235    * <B>pitch1</B> and <B>pitch2</B> are adapted to the type of filling. The
00236    * possible functions are the following : #o_circle_fill_hollow(),
00237    * #o_circle_fill_fill(), #o_circle_fill_mesh() and #o_circle_fill_hatch().
00238    *
00239    * The combination <B>pitch1</B> <= 0 and <B>pitch2</B> <= 0 is avoided as it
00240    * lead to an endless loop in function called after. It happens when the
00241    * zoom factor is too small for two lines separated by the pitch to be
00242    * distinct. If such a case is encountered the circle is filled hollow
00243    * (e.q. not filled).
00244    */
00245 
00246   angle1 = o_current->fill_angle1;
00247   pitch1 = o_current->fill_pitch1;
00248   angle2 = o_current->fill_angle2;
00249   pitch2 = o_current->fill_pitch2;
00250 
00251   switch(o_current->fill_type) {
00252     case FILLING_HOLLOW:
00253       angle1 = -1; angle2 = -1;
00254       pitch1 = 1; pitch2 = 1;
00255       /*
00256        * this function is empty ! however if it do not use it we have to add
00257        * a test before the call. Simply putting a return here instead is not
00258        * possible as it would prevent any hollow circle from having its grips
00259        */
00260       fill_func = o_circle_fill_hollow;
00261       break;
00262 
00263     case FILLING_FILL:
00264       angle1 = -1; angle2 = -1;
00265       pitch1 = 1; pitch2 = 1;
00266       fill_func = o_circle_fill_fill;
00267       break;
00268 
00269     case FILLING_MESH:
00270       fill_func = o_circle_fill_mesh;
00271       break;
00272 
00273     case FILLING_HATCH:
00274       angle2 = -1;
00275       pitch2 = 1;
00276       fill_func = o_circle_fill_hatch;
00277       break;
00278 
00279     case FILLING_VOID:
00280     default:
00281       angle1 = -1; angle2 = -1;
00282       pitch1 = 1; pitch2 = 1;
00283       fill_func = o_circle_fill_hollow;
00284       fprintf (stderr, _("Unknown type for circle (fill)!\n"));
00285   }
00286 
00287   if ((pitch1 <= 0) || (pitch2 <= 0))
00288     fill_func = o_circle_fill_fill;
00289 
00290   (*fill_func) (w_current, o_drawing_color (w_current, o_current),
00291                 o_current->circle, o_current->fill_width,
00292                 angle1, pitch1, angle2, pitch2);
00293 
00294   gschem_cairo_arc (w_current, o_current->line_width,
00295                                o_current->circle->center_x,
00296                                o_current->circle->center_y,
00297                                o_current->circle->radius, 0, 360);
00298 
00299   gschem_cairo_set_source_color (w_current,
00300                                  o_drawing_color (w_current, o_current));
00301   if (o_current->fill_type == FILLING_FILL)
00302     cairo_fill_preserve (w_current->cr);
00303   gschem_cairo_stroke (w_current, o_current->line_type,
00304                                   o_current->line_end,
00305                                   o_current->line_width,
00306                                   o_current->line_length,
00307                                   o_current->line_space);
00308 
00309   if (o_current->selected && w_current->draw_grips)
00310     o_circle_draw_grips (w_current, o_current);
00311 }
00312 
00313 
00319 void o_circle_invalidate_rubber (GSCHEM_TOPLEVEL *w_current)
00320 {
00321   int cx, cy, radius;
00322 
00323   WORLDtoSCREEN (w_current, w_current->first_wx, w_current->first_wy, &cx, &cy);
00324   radius = SCREENabs (w_current, w_current->distance);
00325 
00326   o_invalidate_rect (w_current, cx - radius, cy - radius,
00327                                 cx + radius, cy + radius);
00328 }
00329 
00346 void o_circle_draw_place (GSCHEM_TOPLEVEL *w_current, int dx, int dy, OBJECT *o_current)
00347 {
00348   g_return_if_fail (o_current->circle != NULL);
00349 
00350   gschem_cairo_arc (w_current, 0, o_current->circle->center_x + dx,
00351                                   o_current->circle->center_y + dy,
00352                                   o_current->circle->radius, 0, 360);
00353 
00354   gschem_cairo_set_source_color (w_current,
00355                                  x_color_lookup_dark (o_current->color));
00356   gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 0, -1, -1);
00357 }
00358 
00374 void o_circle_start(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
00375 {
00376   /* center of circle */
00377   w_current->first_wx = w_x;
00378   w_current->first_wy = w_y;
00379 
00380   /* radius */
00381   w_current->distance = 0;
00382 
00383   /* first temporary circle */
00384   o_circle_invalidate_rubber (w_current);
00385   w_current->rubber_visible = 1;
00386 }
00387 
00407 void o_circle_end(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
00408 {
00409   TOPLEVEL *toplevel = w_current->toplevel;
00410   OBJECT *new_obj;
00411 
00412   g_assert( w_current->inside_action != 0 );
00413 
00414   /* erase the temporary circle */
00415   /* o_circle_invalidate_rubber (w_current); */
00416   w_current->rubber_visible = 0;
00417   
00418   /* circle with null radius are not allowed */
00419   if (w_current->distance == 0) {
00420     /* cancel the object creation */
00421     return;
00422   }
00423 
00424   /* create the object */
00425   new_obj = o_circle_new (toplevel, OBJ_CIRCLE, GRAPHIC_COLOR,
00426                           w_current->first_wx, w_current->first_wy,
00427                           w_current->distance);
00428   s_page_append (toplevel, toplevel->page_current, new_obj);
00429 
00430   /* Call add-objects-hook */
00431   g_run_hook_object (w_current, "%add-objects-hook", new_obj);
00432 
00433   toplevel->page_current->CHANGED = 1;
00434   o_undo_savestate(w_current, UNDO_ALL);
00435 }
00436 
00459 void o_circle_motion (GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
00460 {
00461   int diff_x, diff_y;
00462 
00463   g_assert( w_current->inside_action != 0 );
00464 
00465   /* erase the previous temporary circle if it is visible */
00466   if (w_current->rubber_visible)
00467     o_circle_invalidate_rubber (w_current);
00468 
00469   /*
00470    * The radius is taken as the biggest distance on the x and y axis between
00471    * the center of the circle and the mouse position.
00472    */
00473   diff_x = abs(w_current->first_wx - w_x);
00474   diff_y = abs(w_current->first_wy - w_y);
00475   w_current->distance = max(diff_x, diff_y);
00476 
00477   /* draw the new temporary circle */
00478   o_circle_invalidate_rubber (w_current);
00479   w_current->rubber_visible =1;
00480 }
00481 
00494 void o_circle_draw_rubber (GSCHEM_TOPLEVEL *w_current)
00495 {
00496   gschem_cairo_arc (w_current, 0, w_current->first_wx,
00497                                   w_current->first_wy,
00498                                   w_current->distance, 0, 360);
00499 
00500   gschem_cairo_line (w_current, END_NONE, 0,
00501                      w_current->first_wx,
00502                      w_current->first_wy,
00503                      w_current->first_wx + w_current->distance,
00504                      w_current->first_wy);
00505 
00506   gschem_cairo_set_source_color (w_current,
00507                                  x_color_lookup_dark (SELECT_COLOR));
00508   gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 0, -1, -1);
00509 }
00510 
00518 void o_circle_draw_grips(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current)
00519 {
00520   if (w_current->draw_grips == FALSE)
00521     return;
00522 
00523   /* grip on lower right corner of the square */
00524   o_grips_draw (w_current,
00525                 o_current->circle->center_x + o_current->circle->radius,
00526                 o_current->circle->center_y - o_current->circle->radius);
00527 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines