Updated copyright text/header in most source files.
[geda-gaf/peter-b.git] / gschem / src / o_circle.c
blob0c5cdb4ee20fd4976640beb2a23976c7f80f96da
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
20 #include <config.h>
21 #include <stdio.h>
22 #include <math.h>
24 #include "gschem.h"
26 #ifdef HAVE_LIBDMALLOC
27 #include <dmalloc.h>
28 #endif
31 typedef void (*FILL_FUNC)( GdkDrawable *w, GdkGC *gc, COLOR *color,
32 GSCHEM_TOPLEVEL *w_current, CIRCLE *circle,
33 gint fill_width, gint angle1, gint pitch1,
34 gint angle2, gint pitch2 );
37 /*! \brief Draw a circle on the screen.
38 * \par Function Description
39 * This function is used to draw a circle on screen. The circle is described
40 * by the OBJECT which is referred by <B>o_current</B>. The display is done
41 * according to the current state, given by the GSCHEM_TOPLEVEL object pointed by
42 * <B>w_current</B>.
44 * It first checks if the OBJECT pointed is valid or not. If not it
45 * returns and do not output anything. That should never happen though.
47 * \param [in] w_current The GSCHEM_TOPLEVEL object.
48 * \param [in] o_current Circle OBJECT to draw.
50 void o_circle_draw(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current)
52 TOPLEVEL *toplevel = w_current->toplevel;
53 int angle1, pitch1, angle2, pitch2;
54 FILL_FUNC fill_func;
56 if (o_current->circle == NULL) {
57 return;
60 if (toplevel->DONT_REDRAW == 1)
61 return;
63 #if DEBUG
64 printf("drawing circle\n\n");
65 #endif
68 * The draw of the circle is divided in two steps : first step is to draw
69 * the outline, the second is to draw the filling pattern inside (if any).
71 * Finally the function takes care of the grips.
75 * The values needed for the fill operation are taken from the
76 * <B>o_current</B> pointed OBJECT. It include the type of fill required, the
77 * width of the lines (if the fill use line) and angles and pitchs for hatch
78 * based filling.
80 * Once again the width of the line is important as if it is equal to 0 it
81 * may not be displayed. That is definetely not what we are looking for.
83 * Depending on the type of fill that has to be used inside the circle the
84 * right function is called. Values of <B>angle1</B>, <B>angle2</B>,
85 * <B>pitch1</B> and <B>pitch2</B> are adapted to the type of filling. The
86 * possible functions are the following : #o_circle_fill_hollow(),
87 * #o_circle_fill_fill(), #o_circle_fill_mesh() and #o_circle_fill_hatch().
89 * The combination <B>pitch1</B> <= 0 and <B>pitch2</B> <= 0 is avoided as it
90 * lead to an endless loop in function called after. It happens when the
91 * zoom factor is too small for two lines separated by the pitch to be
92 * distinct. If such a case is encountered the circle is filled hollow
93 * (e.q. not filled).
96 angle1 = o_current->fill_angle1;
97 pitch1 = o_current->fill_pitch1;
98 angle2 = o_current->fill_angle2;
99 pitch2 = o_current->fill_pitch2;
101 switch(o_current->fill_type) {
102 case FILLING_HOLLOW:
103 angle1 = -1; angle2 = -1;
104 pitch1 = 1; pitch2 = 1;
106 * this function is empty ! however if it do not use it we have to add
107 * a test before the call. Simply putting a return here instead is not
108 * possible as it would prevent any hollow circle from having its grips
110 fill_func = o_circle_fill_hollow;
111 break;
113 case FILLING_FILL:
114 angle1 = -1; angle2 = -1;
115 pitch1 = 1; pitch2 = 1;
116 fill_func = o_circle_fill_fill;
117 break;
119 case FILLING_MESH:
120 fill_func = o_circle_fill_mesh;
121 break;
123 case FILLING_HATCH:
124 angle2 = -1;
125 pitch2 = 1;
126 fill_func = o_circle_fill_hatch;
127 break;
129 case FILLING_VOID:
130 default:
131 angle1 = -1; angle2 = -1;
132 pitch1 = 1; pitch2 = 1;
133 fill_func = o_circle_fill_hollow;
134 fprintf(stderr, _("Unknown type for circle (fill)!\n"));
137 if((pitch1 <= 0) || (pitch2 <= 0)) {
138 fill_func = o_circle_fill_fill;
141 (*fill_func) (w_current->drawable, w_current->gc,
142 o_drawing_color (w_current, o_current),
143 w_current, o_current->circle,
144 o_current->fill_width, angle1, pitch1, angle2, pitch2);
146 gschem_cairo_arc (w_current, o_current->line_width,
147 o_current->circle->center_x,
148 o_current->circle->center_y,
149 o_current->circle->radius, 0, 360);
151 gschem_cairo_set_source_color (w_current,
152 o_drawing_color (w_current, o_current));
153 if (o_current->fill_type == FILLING_FILL)
154 cairo_fill_preserve (w_current->cr);
155 gschem_cairo_stroke (w_current, o_current->line_type,
156 o_current->line_end,
157 o_current->line_width,
158 o_current->line_length,
159 o_current->line_space);
161 if (o_current->selected && w_current->draw_grips) {
162 o_circle_draw_grips (w_current, o_current);
166 /*! \brief Placeholder filling function.
167 * \par Function Description
168 * This function does nothing. It has the same prototype as all the filling
169 * functions. It prevent from making a difference between filling in function
170 * #o_circle_draw().
172 * The unit for <B>width</B>, <B>pitch1</B> and <B>pitch2</B> is pixel and unit
173 * for <B>angle1</B> and <B>angle2</B> is degree.
175 * \param [in] w GdkDrawable to draw in.
176 * \param [in] gc GdkGC graphics context to draw on.
177 * \param [in] color Circle fill color.
178 * \param [in] x Center x coordinate of Circle.
179 * \param [in] y Center y coordinate of Circle.
180 * \param [in] radius Radius of Circle.
181 * \param [in] width Circle pattern fill width.
182 * \param [in] angle1 1st angle for pattern.
183 * \param [in] pitch1 1st pitch for pattern.
184 * \param [in] angle2 2nd angle for pattern.
185 * \param [in] pitch2 2nd pitch for pattern.
187 void o_circle_fill_hollow (GdkDrawable *w, GdkGC *gc, COLOR *color,
188 GSCHEM_TOPLEVEL *w_current, CIRCLE *circle,
189 gint fill_width,
190 gint angle1, gint pitch1,
191 gint angle2, gint pitch2)
195 /*! \brief Fill inside of circle with a solid pattern.
196 * \par Function Description
197 * This function fills the inside of the circle with a solid pattern.
198 * Parameters <B>angle1</B>, <B>pitch1</B> and <B>angle2</B>, <B>pitch2</B>
199 * and <B>width</B> are unused here but kept for compatibility with other
200 * circle filling functions.
202 * The circle is described by the coordinates of its center and its radius.
203 * Please not that it is not the way GDK take it. Translation is made
204 * afterward.
206 * The unit for <B>width</B>, <B>pitch1</B> and <B>pitch2</B> is pixel and unit
207 * for <B>angle1</B> and <B>angle2</B> is degree.
209 * \param [in] w GdkDrawable to draw in.
210 * \param [in] gc GdkGC graphics context to draw on.
211 * \param [in] color Circle fill color.
212 * \param [in] x Center x coordinate of Circle.
213 * \param [in] y Center y coordinate of Circle.
214 * \param [in] radius Radius of Circle.
215 * \param [in] width (unused)
216 * \param [in] angle1 (unused)
217 * \param [in] pitch1 (unused)
218 * \param [in] angle2 (unused)
219 * \param [in] pitch2 (unused)
221 void o_circle_fill_fill (GdkDrawable *w, GdkGC *gc, COLOR *color,
222 GSCHEM_TOPLEVEL *w_current, CIRCLE *circle,
223 gint fill_width,
224 gint angle1, gint pitch1,
225 gint angle2, gint pitch2)
227 /* NOP: We'll fill it when we do the stroking */
230 /*! \brief Fill inside of circle with single line pattern.
231 * \par Function Description
232 * This function fills the inside of the circle with a pattern made of lines.
233 * The lines are drawn inside the circle with an angle <B>angle1</B> from the
234 * horizontal. The distance between two of these lines is given by
235 * <B>pitch1</B> and their width by <B>width</B>.
236 * Parameters <B>angle2</B>, <B>pitch2</B> are unused here but kept for
237 * compatibility with other circle filling functions.
239 * The circle is described by the coordinates of its center and its radius.
240 * Please not that it is not the way GDK take it. Translation is made
241 * afterward.
243 * The unit for <B>width</B>, <B>pitch1</B> and <B>pitch2</B> is pixel and unit
244 * for <B>angle1</B> and <B>angle2</B> is degree.
246 * The only attribute of line here is its width from the parameter <B>width</B>.
248 * Negative or null values for <B>pitch1</B> are not allowed as it leads to
249 * an endless loop.
251 * \param [in] w GdkDrawable to draw in.
252 * \param [in] gc GdkGC graphics context to draw on.
253 * \param [in] color Circle fill color.
254 * \param [in] x Center x coordinate of Circle.
255 * \param [in] y Center y coordinate of Circle.
256 * \param [in] radius Radius of Circle.
257 * \param [in] width Circle pattern fill width.
258 * \param [in] angle1 1st angle for pattern.
259 * \param [in] pitch1 1st pitch for pattern.
260 * \param [in] angle2 (unused)
261 * \param [in] pitch2 (unused)
263 void o_circle_fill_hatch (GdkDrawable *w, GdkGC *gc, COLOR *color,
264 GSCHEM_TOPLEVEL *w_current, CIRCLE *circle,
265 gint fill_width,
266 gint angle1, gint pitch1,
267 gint angle2, gint pitch2)
269 int i;
270 GArray *lines;
272 gschem_cairo_set_source_color (w_current, color);
274 lines = g_array_new (FALSE, FALSE, sizeof (LINE));
275 m_hatch_circle (circle, angle1, pitch1, lines);
277 for (i=0; i < lines->len; i++) {
278 LINE *line = &g_array_index (lines, LINE, i);
280 gschem_cairo_line (w_current, END_NONE, fill_width, line->x[0], line->y[0],
281 line->x[1], line->y[1]);
283 gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, fill_width, -1, -1);
285 g_array_free (lines, TRUE);
288 /*! \brief Fill inside of circle with mesh pattern.
289 * \par Function Description
290 * This function fills the inside of the circle with a pattern made of set
291 * of parallel lines in two directions. The first set is drawn inside the
292 * circle with an angle <B>angle1</B> from the horizontal. The distance between
293 * two of these lines is given by <B>pitch1</B>.
294 * The second set is drawn inside the circle with an angle <B>angle2</B> from
295 * the horizontal. The distance between two of these lines is given by
296 * <B>pitch2</B>.
297 * Every lines have the same width given by <B>width</B>.
299 * The unit for <B>width</B>, <B>pitch1</B> and <B>pitch2</B> is pixel and unit
300 * for <B>angle1</B> and <B>angle2</B> is degree.
302 * This function simply makes two successive calls to the function
303 * #o_circle_fill_hatch() respectively with <B>angle1</B>, <B>pitch1</B> and
304 * <B>angle2</B>, <B>pitch2</B> for parameters.
306 * \param [in] w GdkDrawable to draw in.
307 * \param [in] gc GdkGC graphics context to draw on.
308 * \param [in] color Circle fill color.
309 * \param [in] x Center x coordinate of Circle.
310 * \param [in] y Center y coordinate of Circle.
311 * \param [in] radius Radius of Circle.
312 * \param [in] width Circle pattern fill width.
313 * \param [in] angle1 1st angle for pattern.
314 * \param [in] pitch1 1st pitch for pattern.
315 * \param [in] angle2 2nd angle for pattern.
316 * \param [in] pitch2 2nd pitch for pattern.
318 void o_circle_fill_mesh (GdkDrawable *w, GdkGC *gc, COLOR *color,
319 GSCHEM_TOPLEVEL *w_current, CIRCLE *circle,
320 gint fill_width,
321 gint angle1, gint pitch1,
322 gint angle2, gint pitch2)
324 o_circle_fill_hatch (w, gc, color, w_current, circle,
325 fill_width, angle1, pitch1, -1, -1);
326 o_circle_fill_hatch (w, gc, color, w_current, circle,
327 fill_width, angle2, pitch2, -1, -1);
332 /*! \todo Finish function documentation!!!
333 * \brief
334 * \par Function Description
337 void o_circle_invalidate_rubber (GSCHEM_TOPLEVEL *w_current)
339 int cx, cy, radius;
341 WORLDtoSCREEN (w_current, w_current->first_wx, w_current->first_wy, &cx, &cy);
342 radius = SCREENabs (w_current, w_current->distance);
344 o_invalidate_rect (w_current, cx - radius, cy - radius,
345 cx + radius, cy + radius);
348 /*! \brief Draw a circle described by OBJECT with translation
349 * \par Function Description
350 * This function draws the circle object described by <B>*o_current</B>
351 * translated by the vector (<B>dx</B>,<B>dy</B>).
352 * The translation vector is in world unit.
354 * The circle is displayed with the color of the object.
356 * \param [in] w_current The GSCHEM_TOPLEVEL object.
357 * \param [in] dx Delta x coordinate for circle.
358 * \param [in] dy Delta y coordinate for circle.
359 * \param [in] o_current Circle OBJECT to draw.
361 * \todo
362 * add in offsets, get rid of global diffs_x,y
364 void o_circle_draw_place (GSCHEM_TOPLEVEL *w_current, int dx, int dy, OBJECT *o_current)
366 g_return_if_fail (o_current->circle != NULL);
368 gschem_cairo_arc (w_current, 0, o_current->circle->center_x + dx,
369 o_current->circle->center_y + dy,
370 o_current->circle->radius, 0, 360);
372 gschem_cairo_set_source_color (w_current,
373 x_color_lookup_dark (o_current->color));
374 gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 0, -1, -1);
377 /*! \brief Start process to input a new circle.
378 * \par Function Description
379 * This function starts the process to input a new circle. Parameters for
380 * this circle are pu into/extracted from the <B>w_current</B> toplevel
381 * structure.
382 * <B>w_x</B> and <B>w_y</B> are current coordinates of the mouse pointer in
383 * world units.
385 * The first step of the circle input is to set the center of the arc.
386 * This center is kept in (<B>w_current->first_wx</B>,<B>w_current->first_wy</B>).
388 * \param [in] w_current The GSCHEM_TOPLEVEL object.
389 * \param [in] w_x Current x coordinate of pointer in world units.
390 * \param [in] w_y Current y coordinate of pointer in world units.
392 void o_circle_start(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
394 /* center of circle */
395 w_current->first_wx = w_x;
396 w_current->first_wy = w_y;
398 /* radius */
399 w_current->distance = 0;
401 /* first temporary circle */
402 o_circle_invalidate_rubber (w_current);
403 w_current->rubber_visible = 1;
406 /*! \brief End the input of a circle.
407 * \par Function Description
408 * This function ends the input of the radius of the circle.
409 * The (<B>w_x</B>,<B>w_y</B>) point is taken as the other end of the radius
410 * segment, i.e. on the circle. The distance between this point and the
411 * center is the radius of the circle.
412 * <B>w_x</B> and <B>w_y</B> are in world coords.
414 * The center has previously been input and saved as
415 * (<B>w_current->first_wx</B>,<B>w_current->first_wy</B>).
417 * The temporary circle drawn during the input of the radius is erased.
418 * A new object is allocated, initialized and linked in the object list.
419 * This new object is finally drawn.
421 * \param [in] w_current The GSCHEM_TOPLEVEL object.
422 * \param [in] w_x (unused)
423 * \param [in] w_y (unused)
425 void o_circle_end(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
427 TOPLEVEL *toplevel = w_current->toplevel;
428 OBJECT *new_obj;
430 g_assert( w_current->inside_action != 0 );
432 /* erase the temporary circle */
433 /* o_circle_invalidate_rubber (w_current); */
434 w_current->rubber_visible = 0;
436 /* circle with null radius are not allowed */
437 if (w_current->distance == 0) {
438 /* cancel the object creation */
439 return;
442 /* create the object */
443 new_obj = o_circle_new (toplevel, OBJ_CIRCLE, GRAPHIC_COLOR,
444 w_current->first_wx, w_current->first_wy,
445 w_current->distance);
446 s_page_append (toplevel, toplevel->page_current, new_obj);
448 /* draw it */
449 o_invalidate (w_current, new_obj);
451 toplevel->page_current->CHANGED = 1;
452 o_undo_savestate(w_current, UNDO_ALL);
455 /*! \brief Draw temporary circle while dragging edge.
456 * \par Function Description
457 * This function draws a circle according to its internal representation and
458 * allows the modification of its radius. The radius is updated according to
459 * the current mouse position in <B>w_x</B> and <B>w_y</B>.
460 * It draws a full circle and the horizontal segment of the radius in the
461 * right half of the circle.
463 * The previous temporary circle is erased, the radius is then computed and
464 * updated and finally a new temporary circle is drawn.
466 * The arc is internally described by :
467 * <DL>
468 * <DT>*</DT><DD>(<B>w_current->first_wx</B>,<B>w_current->first_wy</B>) as its
469 * center ;
470 * <DT>*</DT><DD><B>w_current->distance</B> as its radius.
471 * </DL>
473 * \param [in] w_current The GSCHEM_TOPLEVEL object.
474 * \param [in] w_x Current x coordinate of pointer in world units.
475 * \param [in] w_y Current y coordinate of pointer in world units.
477 void o_circle_motion (GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
479 int diff_x, diff_y;
481 g_assert( w_current->inside_action != 0 );
483 /* erase the previous temporary circle if it is visible */
484 if (w_current->rubber_visible)
485 o_circle_invalidate_rubber (w_current);
488 * The radius is taken as the biggest distance on the x and y axis between
489 * the center of the circle and the mouse position.
491 diff_x = abs(w_current->first_wx - w_x);
492 diff_y = abs(w_current->first_wy - w_y);
493 w_current->distance = max(diff_x, diff_y);
495 /* draw the new temporary circle */
496 o_circle_invalidate_rubber (w_current);
497 w_current->rubber_visible =1;
500 /*! \brief Draw circle from GSCHEM_TOPLEVEL object.
501 * \par Function Description
502 * This function draws the circle from the variables in the GSCHEM_TOPLEVEL
503 * structure <B>*w_current</B>.
504 * The center of the circle is at (<B>w_current->first_wx</B>,
505 * <B>w_current->first_wy</B>) and its radius is in <B>w_current->distance</B>.
507 * It draws a horizontal radius segment on the right half of the circle and
508 * the circle with the selection color.
510 * \param [in] w_current The GSCHEM_TOPLEVEL object.
512 void o_circle_draw_rubber (GSCHEM_TOPLEVEL *w_current)
514 gschem_cairo_arc (w_current, 0, w_current->first_wx,
515 w_current->first_wy,
516 w_current->distance, 0, 360);
518 gschem_cairo_line (w_current, END_NONE, 0,
519 w_current->first_wx,
520 w_current->first_wy,
521 w_current->first_wx + w_current->distance,
522 w_current->first_wy);
524 gschem_cairo_set_source_color (w_current,
525 x_color_lookup_dark (SELECT_COLOR));
526 gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 0, -1, -1);
529 /*! \brief Draw grip marks on circle.
530 * \par Function Description
531 * This function draws the grip that match the circle object <B>*o_current</B>.
533 * \param [in] w_current The GSCHEM_TOPLEVEL object.
534 * \param [in] o_current Circle OBJECT to draw grip points on.
536 void o_circle_draw_grips(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current)
538 if (w_current->draw_grips == FALSE)
539 return;
541 /* grip on lower right corner of the square */
542 o_grips_draw (w_current,
543 o_current->circle->center_x + o_current->circle->radius,
544 o_current->circle->center_y - o_current->circle->radius);