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
26 #ifdef HAVE_LIBDMALLOC
31 /*! \brief Draw an arc on the screen.
32 * \par Function Description
33 * This function is used to draw an arc on screen. The arc is described
34 * in the object which is referred by <B>o_current</B>. The arc is displayed
35 * according to the current state, described in the GSCHEM_TOPLEVEL object
36 * pointed by <B>w_current</B>.
38 * It first checkes if the object is valid or not. If not it returns
39 * and do not output anything. That should never happen though.
41 * \param [in] w_current The GSCHEM_TOPLEVEL object.
42 * \param [in] o_current The arc OBJECT to draw.
44 void o_arc_draw(GSCHEM_TOPLEVEL
*w_current
, OBJECT
*o_current
)
46 TOPLEVEL
*toplevel
= w_current
->toplevel
;
48 if (o_current
->arc
== NULL
) {
52 if (toplevel
->DONT_REDRAW
== 1)
55 gschem_cairo_arc (w_current
, o_current
->line_width
,
58 o_current
->arc
->width
/ 2,
59 o_current
->arc
->start_angle
,
60 o_current
->arc
->end_angle
);
62 gschem_cairo_set_source_color (w_current
,
63 o_drawing_color (w_current
, o_current
));
64 gschem_cairo_stroke (w_current
, o_current
->line_type
,
66 o_current
->line_width
,
67 o_current
->line_length
,
68 o_current
->line_space
);
70 if (o_current
->selected
&& w_current
->draw_grips
== TRUE
) {
71 o_arc_draw_grips (w_current
, o_current
);
75 /*! \todo Finish function documentation!!!
77 * \par Function Description
80 void o_arc_invalidate_rubber (GSCHEM_TOPLEVEL
*w_current
)
84 WORLDtoSCREEN (w_current
, w_current
->first_wx
, w_current
->first_wy
, &cx
, &cy
);
85 radius
= SCREENabs (w_current
, w_current
->distance
);
87 /* FIXME: This isn't a tight bounding box */
88 o_invalidate_rect (w_current
, cx
- radius
, cy
- radius
,
89 cx
+ radius
, cy
+ radius
);
92 /*! \brief Draw an arc described by OBJECT with translation
93 * \par Function Description
94 * This function draws the arc object described by <B>*o_current</B>
95 * translated by the vector (<B>dx</B>,<B>dy</B>).
96 * The translation vector is in screen unit.
98 * The arc is displayed with the color of the object.
100 * \param [in] w_current The GSCHEM_TOPLEVEL object.
101 * \param [in] dx Delta x coordinate for arc.
102 * \param [in] dy Delta y coordinate for arc.
103 * \param [in] o_current Arc OBJECT to draw.
105 void o_arc_draw_place (GSCHEM_TOPLEVEL
*w_current
, int dx
, int dy
, OBJECT
*o_current
)
107 g_return_if_fail (o_current
->arc
!= NULL
);
109 gschem_cairo_arc (w_current
, 0, o_current
->arc
->x
+ dx
,
110 o_current
->arc
->y
+ dy
,
111 o_current
->arc
->width
/ 2,
112 o_current
->arc
->start_angle
,
113 o_current
->arc
->end_angle
);
115 gschem_cairo_set_source_color (w_current
,
116 x_color_lookup_dark (o_current
->color
));
117 gschem_cairo_stroke (w_current
, TYPE_SOLID
, END_NONE
, 0, -1, -1);
120 /*! \brief Start process to input a new arc.
121 * \par Function Description
122 * This function starts the process to input a new arc. Parameters for
123 * this arc are put into/extracted from the <B>w_current</B> toplevel structure.
124 * <B>w_x</B> and <B>w_y</B> are current coordinates of the pointer in screen unit.
126 * First step of the arc input is to set the radius of the arc. The center
127 * of the arc is kept in (<B>w_current->first_wx</B>,<B>w_current->first_wy</B>).
128 * The radius of the arc is in <B>w_current->distance</B>.
130 * \param [in] w_current The GSCHEM_TOPLEVEL object.
131 * \param [in] w_x Current x coordinate of pointer in world units.
132 * \param [in] w_y Current y coordinate of pointer in world units.
134 void o_arc_start(GSCHEM_TOPLEVEL
*w_current
, int w_x
, int w_y
)
136 /* set the center of the arc */
137 w_current
->first_wx
= w_x
;
138 w_current
->first_wy
= w_y
;
141 w_current
->distance
= 0;
143 /* set the start and end angles */
144 w_current
->second_wx
= w_current
->second_wy
= 0;
146 /* start the rubberbanding process of the radius */
147 o_arc_invalidate_rubber (w_current
);
148 w_current
->rubber_visible
= 1;
151 /*! \brief End the input of an arc.
152 * \par Function Description
153 * This function ends the input of the radius of the arc.
154 * The (<B>w_x</B>,<B>w_y</B>) point is taken as the other end of the radius segment.
155 * The distance between this point and the center is the radius of the arc.
156 * <B>w_x</B> and <B>w_y</B> are in world coords.
158 * At the end of this function, the center of the arc is at
159 * (<B>w_current->first_wx</B>,<B>w_current->first_wy</B>) and its radius is
160 * <B>w_current->distance</B>.
162 * The two angles needs to be input to fully define the arc.
164 * \param [in] w_current The GSCHEM_TOPLEVEL object.
165 * \param [in] w_x (unused)
166 * \param [in] w_y (unused)
168 void o_arc_end1(GSCHEM_TOPLEVEL
*w_current
, int w_x
, int w_y
)
170 g_assert( w_current
->inside_action
!= 0 );
172 /* erases the previous temporary radius segment */
173 /* o_arc_invalidate_rubber (w_current); */
174 w_current
->rubber_visible
= 0;
176 /* ack! zero length radius */
177 if (w_current
->distance
== 0) {
182 printf("DIST: %d\n", w_current
->distance
);
185 /* open a dialog to input the start and end angle */
186 arc_angle_dialog(w_current
, NULL
);
189 /*! \brief Ends the process of arc input.
190 * \par Function Description
191 * The #o_arc_end4() function ends the process of the input of an arc.
192 * <B>start_angle</B> and <B>end_angle</B> are the start and end angle of the
193 * arc in degrees. The partial internal representation of the arc, i.e.
194 * the center and the radius of the arc, are converted in world units.
195 * A new object is created and linked to the object list.
197 * \param [in] w_current The GSCHEM_TOPLEVEL object.
198 * \param [in] radius Radius of the arc
199 * \param [in] start_angle Start of angle in degrees.
200 * \param [in] end_angle End of angle in degrees.
202 void o_arc_end4(GSCHEM_TOPLEVEL
*w_current
, int radius
,
203 int start_angle
, int end_angle
)
205 TOPLEVEL
*toplevel
= w_current
->toplevel
;
208 /* create, initialize and link the new arc object */
209 new_obj
= o_arc_new (toplevel
, OBJ_ARC
, GRAPHIC_COLOR
,
210 w_current
->first_wx
, w_current
->first_wy
,
211 radius
, start_angle
, end_angle
);
212 s_page_append (toplevel
, toplevel
->page_current
, new_obj
);
214 /* draw the new object */
215 o_invalidate (w_current
, new_obj
);
217 w_current
->first_wx
= -1;
218 w_current
->first_wy
= -1;
219 w_current
->distance
= 0;
221 toplevel
->page_current
->CHANGED
= 1;
223 o_undo_savestate(w_current
, UNDO_ALL
);
226 /*! \brief Draw an arc using one angle modification.
227 * \par Function Description
228 * This function draws an arc according to its internal representation
229 * and allows the modification of one of its angle. The start or end
230 * angle of the arc is updated according to <B>whichone</B> with the angle
231 * that the current pointer and the arc center are making with the horizontal.
233 * The previous temporary arc is erased, the angle is then computed
234 * and updated and finally a new temporary arc with the new angle is drawn.
236 * The arc is internally described by :
238 * <DT>*</DT><DD>(<B>w_current->first_wx</B>,<B>w_current->first_wy</B>) as
240 * <DT>*</DT><DD><B>w_current->distance</B> as its radius.
241 * <DT>*</DT><DD><B>w_current->second_wx</B> and <B>w_current->second_wx</B> as its
242 * start and end angle respectively.
245 * \param [in] w_current The GSCHEM_TOPLEVEL object.
246 * \param [in] w_x Current x coordinate of pointer in world units.
247 * \param [in] w_y Current y coordinate of pointer in world units.
248 * \param [in] whichone Which angle to change.
250 * <B>whichone</B> can have one of the following values:
252 * <DT>ARC_RADIUS</DT>
253 * <DD>at the center of the arc. This grip is used to modify
254 * the radius of the arc.
255 * <DT>ARC_START_ANGLE</DT>
256 * <DD>at one end of the arc. It corresponds to the starting
258 * <DT>ARC_END_ANGLE</DT>
259 * <DD>at the other end of the arc. It corresponds to the
260 * ending angle of the arc.
263 void o_arc_motion (GSCHEM_TOPLEVEL
*w_current
, int w_x
, int w_y
, int whichone
)
265 int diff_x
, diff_y
, angle_deg
;
267 /* erase the previous temporary arc */
268 if (w_current
->rubber_visible
)
269 o_arc_invalidate_rubber (w_current
);
271 if(whichone
== ARC_RADIUS
) {
273 * The radius is taken as the biggest distance on the x and y
274 * axis between the center of the arc and the mouse position.
276 diff_x
= abs(w_current
->first_wx
- snap_grid (w_current
, w_x
));
277 diff_y
= abs(w_current
->first_wy
- snap_grid (w_current
, w_y
));
278 w_current
->distance
= max(diff_x
, diff_y
);
280 else if((whichone
== ARC_START_ANGLE
) || (whichone
== ARC_END_ANGLE
)) {
281 /* compute the angle */
282 diff_x
= w_x
- w_current
->first_wx
;
283 diff_y
= w_y
- w_current
->first_wy
;
284 angle_deg
= atan2 (diff_y
, diff_x
) * 180 / M_PI
;
286 /* set the start or end angle with this angle */
288 case ARC_START_ANGLE
:
289 w_current
->second_wx
= (angle_deg
+ 360) % 360;
293 w_current
->second_wy
= (((angle_deg
+ 360) % 360) -
294 w_current
->second_wx
+ 360) % 360;
295 if (w_current
->which_object
->arc
->end_angle
< 0)
296 w_current
->second_wy
= w_current
->second_wy
- 360;
297 if (w_current
->second_wy
== 0)
298 w_current
->second_wy
= 360;
307 /* draw the new temporary arc */
308 o_arc_invalidate_rubber (w_current
);
309 w_current
->rubber_visible
= 1;
312 /*! \brief Draw arc from GSCHEM_TOPLEVEL object.
313 * \par Function Description
314 * This function draws the arc from the variables in the GSCHEM_TOPLEVEL
315 * structure <B>*w_current</B>.
316 * The center of the arc is at (<B>w_current->first_wx</B>,
317 * <B>w_current->first_wy</B>), its radius equal to <B>w_current->distance</B>,
318 * and the start and end angle are given by <B>w_current->second_wx</B> and
319 * <B>w_current->second_wy</B>.
321 * \param [in] w_current The GSCHEM_TOPLEVEL object.
323 void o_arc_draw_rubber (GSCHEM_TOPLEVEL
*w_current
)
328 gschem_cairo_arc (w_current
, 0, w_current
->first_wx
,
331 w_current
->second_wx
,
332 w_current
->second_wy
);
334 gschem_cairo_set_source_color (w_current
,
335 x_color_lookup_dark (SELECT_COLOR
));
337 /* draw the radius line */
338 rad_angle
= ((double) w_current
->second_wx
) * M_PI
/ 180;
339 rdx
= (double) w_current
->distance
* cos (rad_angle
);
340 rdy
= (double) w_current
->distance
* sin (rad_angle
);
342 gschem_cairo_line (w_current
, END_NONE
, 0, w_current
->first_wx
,
344 w_current
->first_wx
+ rdx
,
345 w_current
->first_wy
+ rdy
);
347 gschem_cairo_stroke (w_current
, TYPE_SOLID
, END_NONE
, 0, -1, -1);
350 /*! \brief Draw grip marks on arc.
351 * \par Function Description
352 * This function draws three grips on the center and on the ends of
353 * the arc object described by <B>*o_current</B>.
355 * \param [in] w_current The GSCHE_TOPLEVEL object.
356 * \param [in] o_current Arc OBJECT to draw grip points on.
358 void o_arc_draw_grips(GSCHEM_TOPLEVEL
*w_current
, OBJECT
*o_current
)
360 double radius
, start_angle
, end_angle
;
361 int x1
, y1
, x2
, y2
, x3
, y3
;
363 if (w_current
->draw_grips
== FALSE
)
367 * An arc has three grips:
369 * <DT>*</DT><DD>one at the center that allows changes on the
370 * radius - at (<B>x</B>,<B>y</B>).
371 * <DT>*</DT><DD>one at the start of the arc - at (<B>x1</B>,<B>y1</B>).
372 * <DT>*</DT><DD>one at the end of the arc - at (<B>x2</B>,<B>y2</B>).
375 x1
= o_current
->arc
->x
;
376 y1
= o_current
->arc
->y
;
378 radius
= o_current
->arc
->width
/ 2.;
379 start_angle
= o_current
->arc
->start_angle
;
380 end_angle
= o_current
->arc
->end_angle
;
382 x2
= x1
+ radius
* cos ( start_angle
* M_PI
/ 180);
383 y2
= y1
+ radius
* sin ( start_angle
* M_PI
/ 180);
384 x3
= x1
+ radius
* cos ((start_angle
+ end_angle
) * M_PI
/ 180);
385 y3
= y1
+ radius
* sin ((start_angle
+ end_angle
) * M_PI
/ 180);
387 /* draw the grip at the center */
388 o_grips_draw (w_current
, x1
, y1
);
390 /* draw the grip at the start_angle end of the arc */
391 o_grips_draw (w_current
, x2
, y2
);
393 /* draw the grip at the end_angle end of the arc */
394 o_grips_draw (w_current
, x3
, y3
);