1 /* gEDA - GPL Electronic Design Automation
2 * libgeda - gEDA's library
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
5 *
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.
10 *
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.
15 *
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /*! \file o_arc_basic.c
22 * \brief functions for the arc object
23 */
24
25 #include <config.h>
26
27 #include <stdio.h>
28 #include <math.h>
29
30 #include "libgeda_priv.h"
31
32 #ifdef HAVE_LIBDMALLOC
33 #include <dmalloc.h>
34 #endif
35
36 /*! \brief
37 * \par Function Description
38 * The function creates a new OBJECT of type arc.
39 *
40 * The arc is defined by its center in parameters x and y.
41 * The radius parameter specifies the radius of the arc. The start
42 * angle is given by start_angle and the end angle by end_angle.
43 * The line and fill type of the created arc are set to default.
44 *
45 * All dimensions are in world unit, except start_angle and
46 * end_angle in degrees.
47 *
48 * A new object of type OBJECT is allocated. Its type and color
49 * are initilized. The description of the arc characteristics
50 * are stored in a new ARC structure.
51 *
52 * Now fixed for world coordinates.
53 *
54 * \param [in] toplevel The TOPLEVEL object.
55 * \param [in] type
56 * \param [in] color
57 * \param [in] x
58 * \param [in] y
59 * \param [in] radius
60 * \param [in] start_angle
61 * \param [in] end_angle
62 * \return
63 */
o_arc_new(TOPLEVEL * toplevel,char type,int color,int x,int y,int radius,int start_angle,int end_angle)64 OBJECT *o_arc_new(TOPLEVEL *toplevel,
65 char type, int color,
66 int x, int y, int radius, int start_angle, int end_angle)
67 {
68
69 OBJECT *new_node;
70
71 new_node = s_basic_new_object(type, "arc");
72
73 new_node->color = color;
74
75 new_node->arc = (ARC *) g_malloc(sizeof(ARC));
76
77 /*! \note
78 * The ARC structure is initialized with the parameters.
79 * A default initialization is performed for the line and
80 * fill type to avoid misunderstanding.
81 *
82 * The functions relative to the use of the object are sets.
83 */
84
85 /* World coordinates */
86 new_node->arc->x = x;
87 new_node->arc->y = y;
88 new_node->arc->width = 2 * radius;
89 new_node->arc->height = 2 * radius;
90
91 /* must check the sign of start_angle, end_angle ... */
92 if(end_angle < 0) {
93 start_angle = start_angle + end_angle;
94 end_angle = -end_angle;
95 }
96 if(start_angle < 0) start_angle = 360 + start_angle;
97
98 new_node->arc->start_angle = start_angle;
99 new_node->arc->end_angle = end_angle;
100
101 /* Default init */
102 o_set_line_options(toplevel, new_node,
103 END_NONE, TYPE_SOLID, 0, -1, -1);
104 o_set_fill_options(toplevel, new_node,
105 FILLING_HOLLOW, -1, -1, -1, -1, -1);
106
107 o_arc_recalc(toplevel, new_node);
108
109 /* new_node->graphical = arc; eventually */
110
111 return new_node;
112 }
113
114 /*! \brief
115 * \par Function Description
116 * This function creates a new object representing an arc.
117 *
118 * The values of the <B>o_current</B> pointed OBJECT are then copied to the new object.
119 *
120 * The arc, the line options are initialized whereas the fill options are
121 * initialized to passive values - as an arc can not be filled.
122 *
123 * \param [in] toplevel The TOPLEVEL object
124 * \param [in] o_current
125 * \return The new OBJECT
126 */
o_arc_copy(TOPLEVEL * toplevel,OBJECT * o_current)127 OBJECT *o_arc_copy(TOPLEVEL *toplevel, OBJECT *o_current)
128 {
129 OBJECT *new_obj;
130
131 new_obj = o_arc_new (toplevel, OBJ_ARC, o_current->color,
132 o_current->arc->x, o_current->arc->y,
133 o_current->arc->width / 2,
134 o_current->arc->start_angle,
135 o_current->arc->end_angle);
136 o_set_line_options(toplevel, new_obj,
137 o_current->line_end, o_current->line_type,
138 o_current->line_width,
139 o_current->line_length, o_current->line_space);
140 o_set_fill_options(toplevel, new_obj,
141 FILLING_HOLLOW, -1, -1, -1, -1, -1);
142
143 return new_obj;
144 }
145
146 /*! \brief
147 * \par Function Description
148 * This function modifies the internal values of the arc object
149 * *object according to the whichone parameter.
150 *
151 * The new values are given by <B>x</B> and/or <B>y</B>. Their meaning depends on the value of whichone.
152 *
153 * If <B>whichone</B> is equal to #ARC_CENTER, the (<B>x</B>,<B>y</B>) point is taken as the new center
154 * of the arc in world unit.
155 *
156 * If <B>whichone</B> is equal to #ARC_RADIUS, the <B>x</B> parameter is taken to be the radius
157 * of the arc in world unit. The <B>y</B> parameter is ignored.
158 *
159 * If <B>whichone</B> is equal to #ARC_START_ANGLE, the <B>x</B> parameter is the starting angle of the arc.
160 * <B>x</B> is in degrees. <B>y</B> is ignored.
161 *
162 * If <B>whichone</B> is equal to #ARC_END_ANGLE, the <B>x</B> parameter is the ending angle of the arc.
163 * <B>x</B> is in degrees. <B>y</B> is ignored.
164 *
165 * \param [in] toplevel The TOPLEVEL object.
166 * \param [in,out] object
167 * \param [in] x
168 * \param [in] y
169 * \param [in] whichone
170 */
o_arc_modify(TOPLEVEL * toplevel,OBJECT * object,int x,int y,int whichone)171 void o_arc_modify(TOPLEVEL *toplevel, OBJECT *object,
172 int x, int y, int whichone)
173 {
174
175 o_emit_pre_change_notify (toplevel, object);
176
177 switch(whichone) {
178 case ARC_CENTER:
179 /* modify the center of arc object */
180 object->arc->x = x;
181 object->arc->y = y;
182 break;
183
184 case ARC_RADIUS:
185 /* modify the radius of arc object */
186 object->arc->width = 2 * x;
187 object->arc->height = 2 * x;
188 break;
189
190 case ARC_START_ANGLE:
191 /* modify the start angle of the arc object */
192 object->arc->start_angle = x;
193 break;
194
195 case ARC_END_ANGLE:
196 /* modify the end angle of the arc object */
197 object->arc->end_angle = x;
198 break;
199
200 default:
201 break;
202 }
203
204 /* update the screen coords and the bounding box */
205 o_arc_recalc(toplevel, object);
206 o_emit_change_notify (toplevel, object);
207 }
208
209 /*! \brief
210 * \par Function Description
211 * This function reads a formatted text buffer describing an arc
212 * in the gEDA file format and initializes the corresponding object.
213 *
214 * Depending on the version of the file format the data extraction is
215 * performed differently : currently pre-20000704 and 20000704 on one
216 * hand and post-20000704 file format version on the other hand are supported.
217 * The version is specified in string pointed by <B>fileformat_ver</B>.
218 *
219 * To get information on the various file formats have a
220 * look to the fileformats.html document.
221 *
222 * The object is initialized with the functions #o_set_line_options() and #o_set_fill_options().
223 * The second one is only used to put initialize unused values for an arc as an arc can not be filled.
224 *
225 * The arc is allocated initialized with the function #o_arc_new().
226 *
227 * A negative or null radius is not allowed.
228 *
229 * \param [in] toplevel The TOPLEVEL object.
230 * \param [in] buf
231 * \param [in] release_ver
232 * \param [in] fileformat_ver
233 * \return The ARC OBJECT that was created, or NULL on error.
234 */
o_arc_read(TOPLEVEL * toplevel,const char buf[],unsigned int release_ver,unsigned int fileformat_ver,GError ** err)235 OBJECT *o_arc_read (TOPLEVEL *toplevel, const char buf[],
236 unsigned int release_ver, unsigned int fileformat_ver, GError **err)
237 {
238 OBJECT *new_obj;
239 char type;
240 int x1, y1;
241 int radius;
242 int start_angle, end_angle;
243 int color;
244 int arc_width, arc_length, arc_space;
245 int arc_type;
246 int arc_end;
247
248 /*! \note
249 * Depending on the version of the file format used to describe this arc,
250 * the buffer is parsed differently. The unknown parameters of the less
251 * restrictive - the oldest - file format are set to common values
252 */
253 if(release_ver <= VERSION_20000704) {
254 if (sscanf(buf, "%c %d %d %d %d %d %d", &type,
255 &x1, &y1, &radius, &start_angle, &end_angle, &color) != 7) {
256 g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse arc object"));
257 return NULL;
258 }
259
260 arc_width = 0;
261 arc_end = END_NONE;
262 arc_type = TYPE_SOLID;
263 arc_space = -1;
264 arc_length= -1;
265 } else {
266 if (sscanf(buf, "%c %d %d %d %d %d %d %d %d %d %d %d", &type,
267 &x1, &y1, &radius, &start_angle, &end_angle, &color,
268 &arc_width, &arc_end, &arc_type, &arc_length, &arc_space) != 12) {
269 g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse arc object"));
270 return NULL;
271 }
272 }
273
274 /* Error check */
275 if (radius <= 0) {
276 s_log_message (_("Found a zero radius arc [ %c %d, %d, %d, %d, %d, %d ]\n"),
277 type, x1, y1, radius, start_angle, end_angle, color);
278 radius = 0;
279 }
280
281 if (color < 0 || color > MAX_COLORS) {
282 s_log_message(_("Found an invalid color [ %s ]\n"), buf);
283 s_log_message(_("Setting color to default color\n"));
284 color = DEFAULT_COLOR;
285 }
286
287 /* Allocation and initialization */
288 new_obj = o_arc_new(toplevel, OBJ_ARC, color,
289 x1, y1, radius, start_angle, end_angle);
290 o_set_line_options(toplevel, new_obj,
291 arc_end, arc_type, arc_width, arc_length,
292 arc_space);
293 o_set_fill_options(toplevel, new_obj,
294 FILLING_HOLLOW, -1, -1, -1,
295 -1, -1);
296
297 return new_obj;
298 }
299
300 /*! \brief create the string representation of an arc object
301 * \par Function Description
302 * This function formats a string in the buffer <B>*buf</B> to describe
303 * the arc object <B>*object</B>.
304 * A pointer to the new allocated and formated string is returned.
305 * The string must be freed at some point.
306 *
307 * \param [in] toplevel
308 * \param [in] object
309 * \return the string representation of the arc object
310 */
o_arc_save(TOPLEVEL * toplevel,OBJECT * object)311 char *o_arc_save(TOPLEVEL *toplevel, OBJECT *object)
312 {
313 int x, y, radius, start_angle, end_angle;
314 int arc_width, arc_length, arc_space;
315 char *buf;
316 OBJECT_END arc_end;
317 OBJECT_TYPE arc_type;
318
319 /* radius, center and angles of the arc */
320 radius = object->arc->width / 2;
321 x = object->arc->x;
322 y = object->arc->y;
323 start_angle = object->arc->start_angle;
324 end_angle = object->arc->end_angle;
325
326 /* line type parameters */
327 arc_width = object->line_width;
328 arc_end = object->line_end;
329 arc_type = object->line_type;
330 arc_length = object->line_length;
331 arc_space = object->line_space;
332
333 /* Describe a circle with post-20000704 file format */
334 buf = g_strdup_printf("%c %d %d %d %d %d %d %d %d %d %d %d", object->type,
335 x, y, radius, start_angle, end_angle, object->color,
336 arc_width, arc_end, arc_type, arc_length, arc_space);
337
338 return(buf);
339 }
340
341 /*! \brief
342 * \par Function Description
343 * This function applies a translation of (<B>dx</B>,<B>dy</B>)
344 * to the arc described in <B>*object</B>. <B>dx</B> and <B>dy</B> are in world unit.
345 *
346 * \param [in] toplevel The TOPLEVEL object.
347 * \param [in] dx
348 * \param [in] dy
349 * \param [in] object
350 */
o_arc_translate_world(TOPLEVEL * toplevel,int dx,int dy,OBJECT * object)351 void o_arc_translate_world(TOPLEVEL *toplevel, int dx, int dy,
352 OBJECT *object)
353 {
354 if (object == NULL) {
355 return;
356 }
357
358 /* Do world coords */
359 object->arc->x = object->arc->x + dx;
360 object->arc->y = object->arc->y + dy;
361
362
363 /* Recalculate screen coords from new world coords */
364 o_arc_recalc(toplevel, object);
365 }
366
367 /*! \brief
368 * \par Function Description
369 * This function rotates the world coordinates of an arc of an angle
370 * specified by <B>angle</B>. The center of the rotation is given by
371 * (<B>world_centerx</B>,<B>world_centery</B>).
372 *
373 * The arc is translated in order to put the center of the rotation
374 * on the origin. The center of the arc is then rotated of the angle
375 * specified by <B>angle</B>. The start angle of the arc is incremented by <B>angle</B>.
376 *
377 * The arc is finally back translated to its previous location on the page.
378 *
379 * <B>world_centerx</B> and <B>world_centery</B> are in world units, <B>angle</B> is in degrees.
380 *
381 * \param [in] toplevel The TOPLEVEL object.
382 * \param [in] world_centerx
383 * \param [in] world_centery
384 * \param [in] angle
385 * \param [in] object
386 */
o_arc_rotate_world(TOPLEVEL * toplevel,int world_centerx,int world_centery,int angle,OBJECT * object)387 void o_arc_rotate_world(TOPLEVEL *toplevel,
388 int world_centerx, int world_centery, int angle,
389 OBJECT *object)
390 {
391 int x, y, newx, newy;
392
393 /* translate object to origin */
394 object->arc->x -= world_centerx;
395 object->arc->y -= world_centery;
396
397 /* get center, and rotate center */
398 x = object->arc->x;
399 y = object->arc->y;
400 if(angle % 90 == 0) {
401 rotate_point_90(x, y, angle % 360, &newx, &newy);
402 } else {
403 rotate_point(x, y, angle % 360, &newx, &newy);
404 }
405 object->arc->x = newx;
406 object->arc->y = newy;
407
408 /* apply rotation to angles */
409 object->arc->start_angle = (object->arc->start_angle + angle) % 360;
410 /* end_angle is unchanged as it is the sweep of the arc */
411 /* object->arc->end_angle = (object->arc->end_angle); */
412
413 /* translate object to its previous place */
414 object->arc->x += world_centerx;
415 object->arc->y += world_centery;
416
417 /* update the screen coords and the bounding box */
418 o_arc_recalc(toplevel, object);
419
420 }
421
422 /*! \brief Mirror the WORLD coordinates of an ARC.
423 * \par Function Description
424 * This function mirrors the world coordinates of an arc.
425 * The symetry axis is given by the vertical line going through the point (<B>world_centerx</B>,<B>world_centery</B>).
426 *
427 * The arc is translated in order to put the point (<B>world_centerx</B>,<B>world_centery</B>)
428 * on the origin. The center of the arc is then mirrored. The start angle of the arc
429 * and the sweep of the arc are also mirrored.
430 *
431 * The arc is finally back translated to its previous location on the page.
432 *
433 * \param [in] toplevel The TOPLEVEL object.
434 * \param [in] world_centerx
435 * \param [in] world_centery
436 * \param [in] object
437 */
o_arc_mirror_world(TOPLEVEL * toplevel,int world_centerx,int world_centery,OBJECT * object)438 void o_arc_mirror_world(TOPLEVEL *toplevel,
439 int world_centerx, int world_centery,
440 OBJECT *object)
441 {
442 /* translate object to origin */
443 object->arc->x -= world_centerx;
444 object->arc->y -= world_centery;
445
446 /* get center, and mirror it (vertical mirror) */
447 object->arc->x = -object->arc->x;
448 object->arc->y = object->arc->y;
449
450 /* apply mirror to angles (vertical mirror) */
451 object->arc->start_angle = (180 - object->arc->start_angle) % 360;
452 /* start_angle *MUST* be positive */
453 if(object->arc->start_angle < 0) object->arc->start_angle += 360;
454 object->arc->end_angle = -object->arc->end_angle;
455
456 /* translate object back to its previous position */
457 object->arc->x += world_centerx;
458 object->arc->y += world_centery;
459
460 /* update the screen coords and bounding box */
461 o_arc_recalc(toplevel, object);
462
463 }
464
465 /*! \brief
466 * \par Function Description
467 * This function recalculates internal parameters in screen units
468 * of an object containing an arc. The object is given as parameters <B>o_current</B>.
469 * The calculation is done according to the zoom factor detailed in the <B>toplevel</B>
470 * pointed structure.
471 * It also recalculates the <B>OBJECT</B> specific fields and the bounding box of the arc.
472 *
473 * The bounding box - in world units - is recalculated with the <B>world_get_arc_bounds()</B> function.
474 *
475 * \param [in] toplevel The TOPLEVEL object.
476 * \param [in] o_current
477 */
o_arc_recalc(TOPLEVEL * toplevel,OBJECT * o_current)478 void o_arc_recalc(TOPLEVEL *toplevel, OBJECT *o_current)
479 {
480 int left, right, top, bottom;
481
482 if (o_current->arc == NULL) {
483 return;
484 }
485
486 /* recalculates the bounding box */
487 world_get_arc_bounds(toplevel, o_current, &left, &top, &right, &bottom);
488 o_current->w_left = left;
489 o_current->w_top = top;
490 o_current->w_right = right;
491 o_current->w_bottom = bottom;
492 o_current->w_bounds_valid = TRUE;
493 }
494
495
496 /*! \brief
497 * \par Function Description
498 * This function calculates the smallest rectangle the arc can be drawn into.
499 * The <B>OBJECT</B> pointed by object is assumed to be an arc.
500 * The <B>left</B>, <B>top</B>, <B>right</B> and <B>bottom</B> pointed integers define
501 * this rectangle at the end of the function. It is expressed in world units.
502 * The process is divided into two steps : the first step is to calculate the
503 * coordinates of the two ends of the arc and the coordinates of the center.
504 * They forms a first rectangle but (depending on the start angle and the
505 * sweep of the arc) not the right.
506 *
507 * \param [in] toplevel The TOPLEVEL object.
508 * \param [in] object
509 * \param [out] left
510 * \param [out] top
511 * \param [out] right
512 * \param [out] bottom
513 */
world_get_arc_bounds(TOPLEVEL * toplevel,OBJECT * object,int * left,int * top,int * right,int * bottom)514 void world_get_arc_bounds(TOPLEVEL *toplevel, OBJECT *object, int *left,
515 int *top, int *right, int *bottom)
516 {
517 int x1, y1, x2, y2, x3, y3;
518 int radius, start_angle, end_angle;
519 int i, angle;
520 int halfwidth;
521
522 halfwidth = object->line_width / 2;
523
524 radius = object->arc->width / 2;
525 start_angle = object->arc->start_angle;
526 end_angle = object->arc->end_angle;
527
528 x1 = object->arc->x;
529 y1 = object->arc->y;
530 x2 = x1 + radius * cos(start_angle * M_PI / 180);
531 y2 = y1 + radius * sin(start_angle * M_PI / 180);
532 x3 = x1 + radius * cos((start_angle + end_angle) * M_PI / 180);
533 y3 = y1 + radius * sin((start_angle + end_angle) * M_PI / 180);
534
535 *left = (x1 < x2) ? ((x1 < x3) ? x1 : x3) : ((x2 < x3) ? x2 : x3);
536 *right = (x1 > x2) ? ((x1 > x3) ? x1 : x3) : ((x2 > x3) ? x2 : x3);
537 *bottom = (y1 > y2) ? ((y1 > y3) ? y1 : y3) : ((y2 > y3) ? y2 : y3);
538 *top = (y1 < y2) ? ((y1 < y3) ? y1 : y3) : ((y2 < y3) ? y2 : y3);
539
540 /*! \note
541 * The previous rectangle is extended to the final one
542 * by checking whether the arc is over a main axis (vertical or horizontal).
543 * If so, the rectangle is extended in these directions.
544 *
545 * In the mirror mode, the sweep angle is negativ. To get a
546 * CCW arc before this calculation we have to move the
547 * start angle to the end angle and reverse the sweep angle.
548 */
549 if (end_angle < 0) {
550 start_angle = (start_angle + end_angle + 360) % 360;
551 end_angle = -end_angle;
552 }
553 angle = ((int) (start_angle / 90)) * 90;
554 for(i = 0; i < 4; i++) {
555 angle = angle + 90;
556 if(angle < start_angle + end_angle) {
557 if(angle % 360 == 0) *right = x1 + radius;
558 if(angle % 360 == 90) *bottom = y1 + radius;
559 if(angle % 360 == 180) *left = x1 - radius;
560 if(angle % 360 == 270) *top = y1 - radius;
561 } else {
562 break;
563 }
564 }
565
566 /* This isn't strictly correct, but a 1st order approximation */
567 *left -= halfwidth;
568 *top -= halfwidth;
569 *right += halfwidth;
570 *bottom += halfwidth;
571
572 }
573
574 /*! \brief get the position of the center point
575 * \par Function Description
576 * This function gets the position of the center point of an arc object.
577 *
578 * \param [in] toplevel The toplevel environment.
579 * \param [out] x pointer to the x-position
580 * \param [out] y pointer to the y-position
581 * \param [in] object The object to get the position.
582 * \return TRUE if successfully determined the position, FALSE otherwise
583 */
o_arc_get_position(TOPLEVEL * toplevel,gint * x,gint * y,OBJECT * object)584 gboolean o_arc_get_position (TOPLEVEL *toplevel, gint *x, gint *y,
585 OBJECT *object)
586 {
587 *x = object->arc->x;
588 *y = object->arc->y;
589 return TRUE;
590 }
591
592 /*! \brief
593 * \par Function Description
594 * This function writes in a postscript file the arc described by
595 * the <B>o_current</B> pointed object.
596 * The postscript resulting file is described by the <B>fp</B> file pointer.
597 *
598 * Parameters of the arc are extracted from object pointed by <B>o_current</B>
599 * and formatted to suit future calls to specialized arc printing functions.
600 *
601 * \param [in] toplevel The TOPLEVEL object.
602 * \param [in] fp The postscript document to print to.
603 * \param [in] o_current
604 * \param [in] origin_x
605 * \param [in] origin_y
606 */
o_arc_print(TOPLEVEL * toplevel,FILE * fp,OBJECT * o_current,int origin_x,int origin_y)607 void o_arc_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current,
608 int origin_x, int origin_y)
609 {
610 int x, y, radius, start_angle, end_angle;
611 int color;
612 int arc_width, space, length;
613 void (*outl_func)() = NULL;
614
615 if (o_current == NULL) {
616 printf("got null in o_arc_print\n");
617 return;
618 }
619
620 x = o_current->arc->x;
621 y = o_current->arc->y;
622 radius = o_current->arc->width / 2;
623 start_angle = o_current->arc->start_angle;
624 end_angle = o_current->arc->end_angle;
625 color = o_current->color;
626
627 /*! \note
628 * Depending on the type of the line for this particular arc, the
629 * appropriate function is chosen among #o_arc_print_solid(),
630 * #o_arc_print_dotted(), #o_arc_print_dashed(), #o_arc_print_center() and #o_arc_print_phantom().
631 *
632 * The needed parameters for each of these types are extracted from the <B>o_current</B> object.
633 * Depending on the type, unused parameters are set to -1.
634 *
635 * In the eventuality of a length and/or space null, the arc is printed solid to avoid and
636 * endless loop produced by other functions.
637 */
638
639 #if 0 /* was causing arcs which are solid to be much thinner compared to */
640 /* lines, boxes, also of zero width */
641 if (o_current->line_width > 0) {
642 arc_width = o_current->line_width;
643 } else {
644 arc_width = 1;
645 }
646 #endif
647 arc_width = o_current->line_width; /* Added instead of above */
648 if(arc_width <=2) {
649 if(toplevel->line_style == THICK) {
650 arc_width=LINE_WIDTH;
651 } else {
652 arc_width=2;
653 }
654 }
655
656 length = o_current->line_length;
657 space = o_current->line_space;
658
659 switch(o_current->line_type) {
660 case(TYPE_SOLID):
661 length = -1; space = -1;
662 outl_func = o_arc_print_solid;
663 break;
664
665 case(TYPE_DOTTED):
666 length = -1;
667 outl_func = o_arc_print_dotted;
668 break;
669
670 case(TYPE_DASHED):
671 outl_func = o_arc_print_dashed;
672 break;
673
674 case(TYPE_CENTER):
675 outl_func = o_arc_print_center;
676 break;
677
678 case(TYPE_PHANTOM):
679 outl_func = o_arc_print_phantom;
680 break;
681
682 case(TYPE_ERASE):
683 /* Unused for now, print it solid */
684 length = -1; space = -1;
685 outl_func = o_arc_print_solid;
686 break;
687 }
688
689 if((space == 0) || (length == 0)) {
690 length = -1; space = -1;
691 outl_func = o_arc_print_solid;
692 }
693
694 (*outl_func)(toplevel, fp,
695 x - origin_x, y - origin_x, radius,
696 start_angle, end_angle,
697 color, arc_width, length, space, origin_x, origin_y);
698 }
699
700
701 /*! \brief
702 * \par Function Description
703 * This function prints an arc when a solid line type is required.
704 * The arc is defined by its center in <B>x</B> and <B>y</B>, its radius
705 * in <B>radius</B> and the start and end angles of the arc on the circle.
706 * The postscript file is defined by the file pointer <B>fp</B>.
707 *
708 * The parameters <B>length</B> and <B>space</B> are ignored
709 * whereas <B>arc_width</B> specifies the width of the printed line.
710 *
711 * All dimensions are in mils, except <B>angle1</B> and <B>angle2</B> in degrees.
712 *
713 * \param [in] toplevel The TOPLEVEL object.
714 * \param [in] fp FILE pointer to postscript document.
715 * \param [in] x
716 * \param [in] y
717 * \param [in] radius
718 * \param [in] angle1
719 * \param [in] angle2
720 * \param [in] color
721 * \param [in] arc_width
722 * \param [in] length
723 * \param [in] space
724 * \param [in] origin_x
725 * \param [in] origin_y
726 */
o_arc_print_solid(TOPLEVEL * toplevel,FILE * fp,int x,int y,int radius,int angle1,int angle2,int color,int arc_width,int length,int space,int origin_x,int origin_y)727 void o_arc_print_solid(TOPLEVEL *toplevel, FILE *fp,
728 int x, int y, int radius,
729 int angle1, int angle2,
730 int color,
731 int arc_width, int length, int space,
732 int origin_x, int origin_y)
733 {
734 f_print_set_color(toplevel, fp, color);
735
736 /* inverting angle2 if < 0 and changing angle1 accordingly */
737 if (angle2 < 0) {
738 angle1 = angle1 + angle2;
739 angle2 = -angle2;
740 }
741
742 fprintf(fp, "%d %d %d %d %d %d darc\n",
743 x,y, radius, angle1, angle1 + angle2,
744 arc_width);
745
746 }
747
748 /*! \brief
749 * \par Function Description
750 * This function prints an arc when a dotted line type is required.
751 * The arc is defined by its center in <B>x</B> and <B>y</B>, its
752 * radius in <B>radius</B> and the start and end angles of the arc on the circle.
753 * The postscript file is defined by the file pointer <B>fp</B>.
754 * The parameter <B>length</B> is ignored whereas <B>arc_width</B> specifies
755 * the diameter of the dots of the printed line and <B>space</B> the distance
756 * between two dots.
757 *
758 * A negative value for <B>space</B> leads to an endless loop.
759 *
760 * All dimensions are in mils, except <B>angle1</B> and <B>angle2</B> in degrees.
761 *
762 * The function sets the color the line will be printed with.
763 *
764 * \param [in] toplevel The TOPLEVEL object.
765 * \param [in] fp FILE pointer to postscript document.
766 * \param [in] x
767 * \param [in] y
768 * \param [in] radius
769 * \param [in] angle1
770 * \param [in] angle2
771 * \param [in] color
772 * \param [in] arc_width
773 * \param [in] length
774 * \param [in] space
775 * \param [in] origin_x
776 * \param [in] origin_y
777 */
o_arc_print_dotted(TOPLEVEL * toplevel,FILE * fp,int x,int y,int radius,int angle1,int angle2,int color,int arc_width,int length,int space,int origin_x,int origin_y)778 void o_arc_print_dotted(TOPLEVEL *toplevel, FILE *fp,
779 int x, int y, int radius,
780 int angle1, int angle2,
781 int color,
782 int arc_width, int length, int space,
783 int origin_x, int origin_y)
784 {
785 int da, d;
786
787 f_print_set_color(toplevel, fp, color);
788
789 /*! \note
790 * Depending on the radius of the arc, the <B>space</B> parameter is
791 * changed into a small angle <B>da</B>.
792 * Starting from <B>angle1</B> - the start angle - the dots are printed
793 * along the arc by increments of this new angle.
794 *
795 * As <B>da</B> is rounded as an integer, it can take a null value which
796 * will make the function enter an endless loop. In such a case, the arc
797 * is printed solid. The <B>da</B> variable should never be negative
798 * except if <B>space</B> is negative.
799 */
800
801 /* Inverting angle2 if < 0 and changing angle1 accordingly */
802 /* the loop test assume that da > 0 */
803 if (angle2 < 0) {
804 angle1 = angle1 + angle2;
805 angle2 = -angle2;
806 }
807 da = (int) ((space * 180) / (M_PI * ((double) radius)));
808
809 /* If da or db too small for arc to be displayed as dotted,
810 draw a solid arc */
811 if (da <= 0) {
812 o_arc_print_solid(toplevel, fp,
813 x, y, radius,
814 angle1, angle2,
815 color,
816 arc_width, length, space, origin_x, origin_y);
817 return;
818 }
819
820 fprintf(fp,"[");
821 d = angle1;
822 while (d < (angle2 + angle1)) {
823 /*xa = ((double) x) + ((double) radius) * cos(d * M_PI / 180);
824 ya = ((double) y) + ((double) radius) * sin(d * M_PI / 180);
825 */
826 fprintf(fp,"[%d] ",d);
827
828 d = d + da;
829 }
830 fprintf(fp,"] %d %d %d %d dashedarc %% dotted\n",
831 x,y, radius, arc_width);
832 }
833
834 /*! \brief
835 * \par Function Description
836 * This function prints an arc when a dashed line type is required.
837 * The arc is defined by its center in <B>x</B> and <B>y</B>, its radius
838 * in <B>radius</B> and the start and end angles of the arc on the circle.
839 * The postscript file is defined by the file pointer <B>fp</B>.
840 * The parameter <B>arc_width</B> specifies the diameter of the dots of the printed line.
841 *
842 * A negative value for <B>space</B> or <B>length</B> leads to an endless loop.
843 *
844 * All dimensions are in mils, except <B>angle1</B> and <B>angle2</B> in degrees.
845 *
846 * The function sets the color the line will be printed with.
847 *
848 * \param [in] toplevel The TOPLEVEL object.
849 * \param [in] fp FILE pointer to postscript document.
850 * \param [in] x
851 * \param [in] y
852 * \param [in] radius
853 * \param [in] angle1
854 * \param [in] angle2
855 * \param [in] color
856 * \param [in] arc_width
857 * \param [in] length
858 * \param [in] space
859 * \param [in] origin_x
860 * \param [in] origin_y
861 */
o_arc_print_dashed(TOPLEVEL * toplevel,FILE * fp,int x,int y,int radius,int angle1,int angle2,int color,int arc_width,int length,int space,int origin_x,int origin_y)862 void o_arc_print_dashed(TOPLEVEL *toplevel, FILE *fp,
863 int x, int y, int radius,
864 int angle1, int angle2,
865 int color,
866 int arc_width, int length, int space,
867 int origin_x, int origin_y)
868 {
869 int da, db, a1, d;
870
871 f_print_set_color(toplevel, fp, color);
872
873 /*! \note
874 * Depending on the radius of the arc, the <B>space</B> (resp. <B>length</B>)
875 * parameter is changed into a small angle <B>da</B> (resp. <B>db</B>).
876 * Starting from <B>angle1</B> - the start angle - the dashes are printed
877 * along the arc by increments of these new angles.
878 *
879 * As <B>da</B> (resp. <B>db</B>) is rounded as an integer, it can take a
880 * null value which will make the function enter an endless loop. In such a case,
881 * the arc is printed solid. The <B>da</B> (resp. <B>db</B>) variable should never
882 * be negative except if <B>space</B> (resp. <B>length</B>) is negative.
883 *
884 * It prints as many dashes of length <B>length</B> as possible.
885 */
886
887 /* Inverting angle2 if < 0 and changing angle1 accordingly */
888 /* the loop test assume that da > 0 */
889 if (angle2 < 0) {
890 angle1 = angle1 + angle2;
891 angle2 = -angle2;
892 }
893 da = (int) ((length * 180) / (M_PI * ((double) radius)));
894 db = (int) ((space * 180) / (M_PI * ((double) radius)));
895
896 /* If da or db too small for arc to be displayed as dotted,
897 draw a solid arc */
898 if ((da <= 0) || (db <= 0)) {
899 o_arc_print_solid(toplevel, fp,
900 x, y, radius,
901 angle1, angle2,
902 color,
903 arc_width, length, space, origin_x, origin_y);
904 return;
905 }
906
907 fprintf(fp,"[");
908 d = angle1;
909 while ((d + da + db) < (angle1 + angle2)) {
910 a1 = d;
911 d = d + da;
912
913 fprintf(fp,"[%d %d] ",
914 a1, a1+da);
915
916 d = d + db;
917 }
918 /*! \note
919 * When the above condition is no more satisfied, then it is not
920 * possible to print a dash of length <B>length</B> and the following <B>space</B>.
921 * However it may be possible to print the complete dash or a shorter one.
922 */
923
924 if ((d + da) < (angle1 + angle2)) {
925 a1 = d;
926 } else {
927 a1 = d;
928 }
929
930 fprintf(fp,"[%d %d] ",
931 a1, a1+da);
932
933
934 fprintf(fp,"] %d %d %d %d dashedarc %% dashed\n",
935 x,y, radius, arc_width);
936
937 }
938
939 /*! \brief
940 * \par Function Description
941 * This function prints an arc when a centered line type is required.
942 * The arc is defined by its center in <B>x</B> and <B>y</B>, its radius in
943 * <B>radius</B> and the start and end angles of the arc on the circle.
944 * The postscript file is defined by the file pointer <B>fp</B>.
945 * The parameter <B>arc_width</B> specifies the diameter of the dots and the width of the dashes of the printed line.
946 *
947 * A negative value for <B>space</B> or <B>length</B> leads to an endless loop.
948 *
949 * All dimensions are in mils, except <B>angle1</B> and <B>angle2</B> in degrees.
950 *
951 * The function sets the color in which the line will be printed with.
952 *
953 * \param [in] toplevel The TOPLEVEL object.
954 * \param [in] fp FILE pointer to postscript document.
955 * \param [in] x
956 * \param [in] y
957 * \param [in] radius
958 * \param [in] angle1
959 * \param [in] angle2
960 * \param [in] color
961 * \param [in] arc_width
962 * \param [in] length
963 * \param [in] space
964 * \param [in] origin_x
965 * \param [in] origin_y
966 */
o_arc_print_center(TOPLEVEL * toplevel,FILE * fp,int x,int y,int radius,int angle1,int angle2,int color,int arc_width,int length,int space,int origin_x,int origin_y)967 void o_arc_print_center(TOPLEVEL *toplevel, FILE *fp,
968 int x, int y, int radius,
969 int angle1, int angle2,
970 int color,
971 int arc_width, int length, int space,
972 int origin_x, int origin_y)
973 {
974 int da, db, a1, d;
975
976 f_print_set_color(toplevel, fp, color);
977
978 /*! \note
979 * Depending on the radius of the arc, the <B>space</B> (resp. <B>length</B>)
980 * parameter is changed into a small angle <B>da</B> (resp. <B>db</B>).
981 * Starting from <B>angle1</B> - the start angle - the dashes are printed
982 * along the arc by increments of these new angles.
983 *
984 * As <B>da</B> (resp. <B>db</B>) is rounded as an integer, it can take a null
985 * value which will make the function enter an endless loop. In such a case,
986 * the arc is printed solid. The <B>da</B> (resp. <B>db</B>) variable should never
987 * be negative except if <B>space</B> (resp. <B>length</B>) is negative.
988 *
989 * It prints as many sets of dash-dot as possible.
990 */
991
992 /* Inverting angle2 if < 0 and changing angle1 accordingly */
993 /* the loop test assume that da > 0 */
994 if (angle2 < 0) {
995 angle1 = angle1 + angle2;
996 angle2 = -angle2;
997 }
998
999 da = (int) ((length * 180) / (M_PI * ((double) radius)));
1000 db = (int) ((space * 180) / (M_PI * ((double) radius)));
1001
1002 /* If da or db too small to be displayed, draw an arc */
1003 if ((da <= 0) || (db <= 0)) {
1004 o_arc_print_solid(toplevel, fp,
1005 x, y, radius,
1006 angle1, angle2,
1007 color,
1008 arc_width, length, space, origin_x, origin_y);
1009 return;
1010 }
1011
1012 fprintf(fp, "[");
1013 d = angle1;
1014 while ((d + da + 2 * db) < (angle1 + angle2)) {
1015 a1 = d;
1016 d = d + da;
1017 fprintf(fp,"[%d %d] ",(int) a1, (int) a1 + da);
1018
1019 d = d + db;
1020 /*
1021 xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
1022 ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
1023 */
1024 fprintf(fp,"[%d] ",d);
1025 d = d + db;
1026 }
1027 /*! \note
1028 * When the above condition is no more satisfied, then it is not
1029 * possible to print a dash of length <B>length</B>. However two cases are possible :
1030 * <DL>
1031 * <DT>*</DT><DD>it is possible to print the dash and the dot
1032 * <DT>*</DT><DD>it is possible to print the dash or a part of the original dash
1033 * </DL>
1034 */
1035
1036 if ((d + da) < (angle1 + angle2)) {
1037 a1 = d;
1038
1039 d = d + da;
1040 } else {
1041 a1 = d;
1042
1043 d = d + da;
1044 }
1045
1046 fprintf(fp,"[%d %d] ",(int) a1, (int) a1 + da);
1047
1048
1049 if ((d + db) < (angle1 + angle2)) {
1050 /*
1051 xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
1052 ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
1053 */
1054 fprintf(fp,"[%d] ",d);
1055
1056 }
1057
1058 fprintf(fp,"] %d %d %d %d dashedarc %% center\n",
1059 x,y, radius, arc_width);
1060 }
1061
1062 /*! \note
1063 * A dot is represented by a filled circle. Position of the circle is (<B>xa</B>, <B>ya</B>)
1064 * and its radius is the <B>arc_width</B> parameter.
1065 */
1066
1067 /*! \brief
1068 * \par Function Description
1069 * This function prints an arc when a phantom line type is required.
1070 * The arc is defined by its center in <B>x</B> and <B>y</B>, its radius
1071 * in <B>radius</B> and the start and end angles of the arc on the circle.
1072 * The postscript file is defined by the file pointer <B>fp</B>.
1073 * The parameter <B>arc_width</B> specifies the diameter of the dots and the width of the dashes of the printed line.
1074 *
1075 * A negative value for <B>space</B> or <B>length</B> leads to an endless loop.
1076 *
1077 * All dimensions are in mils, except <B>angle1</B> and <B>angle2</B> in degrees.
1078 *
1079 * The function sets the color in which the line will be printed with.
1080 *
1081 * \param [in] toplevel The TOPLEVEL object.
1082 * \param [in] fp FILE pointer to postscript document.
1083 * \param [in] x
1084 * \param [in] y
1085 * \param [in] radius
1086 * \param [in] angle1
1087 * \param [in] angle2
1088 * \param [in] color
1089 * \param [in] arc_width
1090 * \param [in] length
1091 * \param [in] space
1092 * \param [in] origin_x
1093 * \param [in] origin_y
1094 */
o_arc_print_phantom(TOPLEVEL * toplevel,FILE * fp,int x,int y,int radius,int angle1,int angle2,int color,int arc_width,int length,int space,int origin_x,int origin_y)1095 void o_arc_print_phantom(TOPLEVEL *toplevel, FILE *fp,
1096 int x, int y, int radius,
1097 int angle1, int angle2,
1098 int color,
1099 int arc_width, int length, int space,
1100 int origin_x, int origin_y)
1101 {
1102 int da, db, a1, d;
1103
1104 f_print_set_color(toplevel, fp, color);
1105
1106 /*! \note
1107 * Depending on the radius of the arc, the <B>space</B> (resp. <B>length</B>)
1108 * parameter is changed into a small angle <B>da</B> (resp. <B>db</B>).
1109 * Starting from <B>angle1</B> - the start angle - the dashes are printed
1110 * along the arc by increments of these new angles.
1111 *
1112 * As <B>da</B> (resp. <B>db</B>) is rounded as an integer, it can take a
1113 * null value which will make the function enter an endless loop. In such
1114 * a case, the arc is printed solid. The <B>da</B> (resp. <B>db</B>) variable
1115 * should never be negative except if <B>space</B> (resp. <B>length</B>) is negative.
1116 *
1117 * It prints as many sets of dash-dot-dot as possible.
1118 */
1119
1120 /* Inverting angle2 if < 0 and changing angle1 accordingly */
1121 /* the loop test assume that da > 0 */
1122 if (angle2 < 0) {
1123 angle1 = angle1 + angle2;
1124 angle2 = -angle2;
1125 }
1126 da = (int) ((length * 180) / (((double) radius) * M_PI));
1127 db = (int) ((space * 180) / (((double) radius) * M_PI));
1128
1129 /* If da or db too small for arc to be displayed as dotted,
1130 draw a solid arc */
1131 if ((da <= 0) || (db <= 0)) {
1132 o_arc_print_solid(toplevel, fp,
1133 x, y, radius,
1134 angle1, angle2,
1135 color,
1136 arc_width, length, space, origin_x, origin_y);
1137 return;
1138 }
1139
1140 fprintf(fp,"[");
1141
1142 d = angle1;
1143 while ((d + da + 3 * db) < (angle1 + angle2)) {
1144 a1 = d;
1145 d = d + da;
1146
1147 fprintf(fp,"[%d %d] ",(int) a1, (int) a1 + da);
1148
1149 d = d + db;
1150 /*
1151 xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
1152 ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
1153 */
1154 fprintf(fp,"[%d] ",d);
1155
1156 d = d + db;
1157
1158 /*
1159 xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
1160 ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
1161 */
1162 fprintf(fp,"[%d] ",d);
1163
1164 d = d + db;
1165 }
1166
1167 /*! \note
1168 * When the above condition is no more satisfied, then it is not
1169 * possible to print a dash of length <B>length</B>.
1170 * However three cases are possible :
1171 * <DL>
1172 * <DT>*</DT><DD>it is possible to print a dash and a dot and a dot
1173 * <DT>*</DT><DD>it is possible to print a dash and a dot
1174 * <DT>*</DT><DD>it is possible to print the dash or a part of the original dash
1175 * </DL>
1176 */
1177
1178 if ((d + da) < (angle1 + angle2)) {
1179 a1 = d;
1180 d = d + da;
1181 } else {
1182 a1 = d;
1183 d = d + da;
1184 }
1185
1186 fprintf(fp,"[%d %d] ",(int) a1, (int) a1 + da);
1187
1188 if ((d + db) < (angle1 + angle2)) {
1189 d = d + db;
1190
1191 /*
1192 xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
1193 ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
1194 */
1195 fprintf(fp,"[%d] ",d);
1196
1197 }
1198
1199 if ((d + db) < (angle1 + angle2)) {
1200 d = d + db;
1201
1202 /*
1203 xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
1204 ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
1205 */
1206
1207 fprintf(fp,"[%d] ",d);
1208
1209
1210 }
1211
1212 fprintf(fp,"] %d %d %d %d dashedarc %% phantom\n",
1213 x,y, radius, arc_width);
1214 }
1215
1216 /*! \brief Calculates the distance between the given point and the closest
1217 * point on the perimeter of the arc.
1218 *
1219 * \param [in] object The arc OBJECT.
1220 * \param [in] x The x coordinate of the given point.
1221 * \param [in] y The y coordinate of the given point.
1222 * \param [in] force_solid If true, force treating the object as solid.
1223 * \return The shortest distance from the object to the point. With an
1224 * invalid parameter, this function returns G_MAXDOUBLE.
1225 */
o_arc_shortest_distance(OBJECT * object,int x,int y,int force_solid)1226 double o_arc_shortest_distance (OBJECT *object, int x, int y, int force_solid)
1227 {
1228 double shortest_distance;
1229 double radius;
1230
1231 g_return_val_if_fail (object->arc != NULL, G_MAXDOUBLE);
1232
1233 radius = ((double)object->arc->width) / 2.0;
1234
1235 if (o_arc_within_sweep (object->arc, x, y)) {
1236 double distance_to_center;
1237 double dx;
1238 double dy;
1239
1240 dx = ((double)x) - ((double)object->arc->x);
1241 dy = ((double)y) - ((double)object->arc->y);
1242
1243 distance_to_center = sqrt ((dx * dx) + (dy * dy));
1244
1245 shortest_distance = fabs (distance_to_center - radius);
1246
1247 } else {
1248 double angle;
1249 double distance_to_end0;
1250 double distance_to_end1;
1251 double dx, dy;
1252
1253 angle = G_PI * ((double)object->arc->start_angle) / 180;
1254
1255 dx = ((double)x) - radius * cos (angle) - ((double)object->arc->x);
1256 dy = ((double)y) - radius * sin (angle) - ((double)object->arc->y);
1257
1258 distance_to_end0 = sqrt ((dx * dx) + (dy * dy));
1259
1260 angle += G_PI * ((double)object->arc->end_angle) / 180;
1261
1262 dx = ((double)x) - radius * cos (angle) - ((double)object->arc->x);
1263 dy = ((double)y) - radius * sin (angle) - ((double)object->arc->y);
1264
1265 distance_to_end1 = sqrt ((dx * dx) + (dy * dy));
1266
1267 shortest_distance = min (distance_to_end0, distance_to_end1);
1268 }
1269
1270 return shortest_distance;
1271 }
1272
1273 /*! \brief Determines if a point lies within the sweep of the arc.
1274 *
1275 * \param [in] arc The arc of object
1276 * \param [in] x The x coordinate of the given point.
1277 * \param [in] y The y coordinate of the given point.
1278 * \return TRUE if the point lies within the sweep of the arc.
1279 * FALSE if the point lies outside the sweep of the arc. With an
1280 * invalid parameter, this function returns FALSE.
1281 */
o_arc_within_sweep(ARC * arc,gint x,gint y)1282 gboolean o_arc_within_sweep(ARC *arc, gint x, gint y)
1283 {
1284 gdouble a0;
1285 gdouble a1;
1286 gdouble angle;
1287 gdouble dx;
1288 gdouble dy;
1289
1290 if (arc == NULL) {
1291 g_critical("o_arc_within_sweep(): arc == NULL\n");
1292 return FALSE;
1293 }
1294
1295 dx = ((gdouble) x) - ((gdouble) arc->x);
1296 dy = ((gdouble) y) - ((gdouble) arc->y);
1297
1298 angle = 180 * atan2(dy, dx) / G_PI;
1299
1300 if (arc->end_angle > 0) {
1301 a0 = arc->start_angle;
1302 a1 = arc->start_angle + arc->end_angle;
1303 } else {
1304 a0 = arc->start_angle + arc->end_angle + 360;
1305 a1 = arc->start_angle + 360;
1306 }
1307
1308 while (angle < a0) {
1309 angle+=360;
1310 }
1311
1312 return (angle < a1);
1313 }
1314
1315