1 /* Dia -- an diagram creation/manipulation program
2  * Copyright (C) 1998 Alexander Larsson
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18 
19 #include <config.h>
20 
21 #define _BSD_SOURCE 1 /* to get finite */
22 #include <math.h>
23 #include <stdio.h>
24 #include <string.h>
25 
26 #include <glib.h>
27 #include "message.h"
28 #include "boundingbox.h"
29 
30 #ifdef G_OS_WIN32
31 #include <float.h>
32 #define finite(d) _finite(d)
33 #endif
34 
35 #ifdef __EMX__
36 #define finite(d) isfinite(d)
37 #endif
38 
39 #include "arrows.h"
40 #include "diarenderer.h"
41 #include "attributes.h"
42 #include "widgets.h"
43 #include "intl.h"
44 
45 /**** prototypes ****/
46 static void
47 draw_empty_ellipse(DiaRenderer *renderer, Point *to, Point *from,
48 		  real length, real width, real linewidth,
49 		   Color *fg_color);
50 static void
51 calculate_double_arrow(Point *second_to, Point *second_from,
52                        const Point *to, const Point *from, real length);
53 
54 static void
55 draw_crow_foot(DiaRenderer *renderer, Point *to, Point *from,
56 	       real length, real width, real linewidth,
57 	       Color *fg_color,Color *bg_color);
58 static int
59 calculate_diamond(Point *poly/*[4]*/, const Point *to, const Point *from,
60 		  real length, real width);
61 
62 /** The function calculate_arrow_point adjusts the placement of the line and
63  * the arrow, so that the arrow doesn't overshoot the connectionpoint and the
64  * line doesn't stick out the other end of the arrow.
65  * @param arrow An arrow to calculate adjustments for.  The arrow type
66  *              determins what adjustments are done..
67  * @param to Where the arrow points to (e.g. connection point)
68  * @param from Where the arrow points from (e.g. bezier control line end)
69  * @param move_arrow A place to return the new end point of the arrow head
70  *                   (i.e. where 'to' should be to render the arrow head well)
71  * @param move_line A place to return the new end point of the line (i.e.
72  *                  where 'to' should be to render the connecting line without
73  *                  leaving bits of its linewidth outside the arrow).
74  * @param linewidth The linewidth used for drawing both arrow and line.
75  */
76 void
calculate_arrow_point(const Arrow * arrow,const Point * to,const Point * from,Point * move_arrow,Point * move_line,real linewidth)77 calculate_arrow_point(const Arrow *arrow, const Point *to, const Point *from,
78 		      Point *move_arrow, Point *move_line,
79 		      real linewidth)
80 {
81   real add_len;
82   real angle;
83   Point tmp;
84   ArrowType arrow_type = arrow->type;
85   /* Otherwise line is drawn through arrow
86    * head for some hollow arrow heads
87    * */
88   if (linewidth == 0.0)
89     linewidth = 0.0001;
90 
91   /** Since some of the calculations are sensitive to small values,
92    * ignore small arrowheads.  They won't be visible anyway.
93    */
94   if (arrow->length < MIN_ARROW_DIMENSION ||
95       arrow->width < MIN_ARROW_DIMENSION) {
96     arrow_type = ARROW_NONE;
97   }
98 
99   /* First, we move the arrow head backwards.
100    * This in most cases just accounts for the linewidth of the arrow.
101    * In pointy arrows, this means we must look at the angle of the
102    * arrowhead.
103    * */
104   switch (arrow_type) {
105   case ARROW_LINES:
106   case ARROW_HOLLOW_TRIANGLE:
107   case ARROW_UNFILLED_TRIANGLE:
108   case ARROW_FILLED_CONCAVE:
109   case ARROW_BLANKED_CONCAVE:
110   case ARROW_DOUBLE_HOLLOW_TRIANGLE:
111     if (arrow->width < 0.0000001) return;
112     angle = atan(arrow->length/(arrow->width/2));
113     if (angle < 75*2*G_PI/360.0) {
114       add_len = .5*linewidth/cos(angle);
115     } else {
116       add_len = 0;
117     }
118 
119     *move_arrow = *to;
120     point_sub(move_arrow, from);
121     point_normalize(move_arrow);
122     point_scale(move_arrow, add_len);
123     break;
124   case ARROW_HALF_HEAD:
125     if (arrow->width < 0.0000001) return;
126     angle = atan(arrow->length/(arrow->width/2));
127     if (angle < 60*2*G_PI/360.0) {
128       add_len = linewidth/cos(angle);
129     } else {
130       add_len = 0;
131     }
132 
133     *move_arrow = *to;
134     point_sub(move_arrow, from);
135     point_normalize(move_arrow);
136     point_scale(move_arrow, add_len);
137     break;
138   case ARROW_FILLED_TRIANGLE:
139   case ARROW_HOLLOW_ELLIPSE:
140   case ARROW_ROUNDED:
141   case ARROW_DIMENSION_ORIGIN:
142   case ARROW_BLANKED_DOT:
143   case ARROW_BLANKED_BOX:
144     add_len = .5*linewidth;
145 
146     *move_arrow = *to;
147     point_sub(move_arrow, from);
148     point_normalize(move_arrow);
149     point_scale(move_arrow, add_len);
150     break;
151   case ARROW_ONE_EXACTLY:
152   case ARROW_ONE_OR_NONE:
153   case ARROW_ONE_OR_MANY:
154   case ARROW_NONE_OR_MANY:
155   default:
156     move_arrow->x = 0.0;
157     move_arrow->y = 0.0;
158     break;
159   }
160 
161   /* Now move the line to be behind the arrowhead. */
162   switch (arrow_type) {
163   case ARROW_LINES:
164   case ARROW_HALF_HEAD:
165     *move_line = *move_arrow;
166     point_scale(move_line, 2.0);
167     return;
168   case ARROW_HOLLOW_TRIANGLE:
169   case ARROW_UNFILLED_TRIANGLE:
170   case ARROW_FILLED_TRIANGLE:
171   case ARROW_FILLED_ELLIPSE:
172   case ARROW_HOLLOW_ELLIPSE:
173   case ARROW_ROUNDED:
174     *move_line = *move_arrow;
175     point_normalize(move_line);
176     point_scale(move_line, arrow->length);
177     point_add(move_line, move_arrow);
178     return;
179   case ARROW_HALF_DIAMOND:
180   case ARROW_OPEN_ROUNDED:
181     /* These don't move the arrow, so *move_arrow can't be used. */
182     *move_line = *to;
183     point_sub(move_line, from);
184     point_normalize(move_line);
185     point_scale(move_line, arrow->length);
186     point_add(move_line, move_arrow);
187     return;
188   case ARROW_HOLLOW_DIAMOND:
189   case ARROW_FILLED_DIAMOND:
190     /* Make move_line be a unit vector in direction of line */
191     *move_line = *to;
192     point_sub(move_line, from);
193     point_normalize(move_line);
194 
195     /* Set the length to arrow_length - \/2*linewidth */
196     tmp = *move_line;
197     point_scale(move_line, arrow->length);
198     point_scale(&tmp, G_SQRT2*linewidth);
199     point_sub(move_line, &tmp);
200     return;
201   case ARROW_DIMENSION_ORIGIN:
202   case ARROW_BLANKED_DOT:
203   case ARROW_BLANKED_BOX:
204     *move_line = *move_arrow;
205     point_normalize(move_line);
206     point_scale(move_line, .5*arrow->length);
207     return;
208   case ARROW_FILLED_DOT:
209   case ARROW_FILLED_BOX:
210     *move_line = *to;
211     point_sub(move_line, from);
212     point_normalize(move_line);
213     point_scale(move_line, .5*arrow->length);
214     return;
215   case ARROW_FILLED_CONCAVE:
216   case ARROW_BLANKED_CONCAVE:
217     *move_line = *move_arrow;
218     point_normalize(move_line);
219     point_scale(move_line, .75*arrow->length);
220     point_add(move_line, move_arrow);
221     return;
222   case ARROW_DOUBLE_HOLLOW_TRIANGLE:
223     *move_line = *move_arrow;
224     point_normalize(move_line);
225     tmp = *move_line;
226     point_scale(move_line, 2.0*arrow->length);
227     point_add(move_line, move_arrow);
228     point_scale(&tmp, linewidth);
229     point_add(move_line, &tmp);
230     return;
231   case ARROW_DOUBLE_FILLED_TRIANGLE:
232     *move_line = *to;
233     point_sub(move_line, from);
234     point_normalize(move_line);
235     point_scale(move_line, 2*arrow->length);
236     return;
237   case ARROW_FILLED_DOT_N_TRIANGLE:
238     *move_line = *to;
239     point_sub(move_line, from);
240     point_normalize(move_line);
241     point_scale(move_line, arrow->length + arrow->width);
242     return;
243   case ARROW_THREE_DOTS:
244     *move_line = *to;
245     point_sub(move_line, from);
246     add_len = point_len(move_line);
247     point_normalize(move_line);
248     if (add_len > 4*arrow->length)
249       point_scale(move_line, 2*arrow->length);
250     else
251       point_scale(move_line, arrow->length);
252     return;
253   case ARROW_SLASH_ARROW:
254   case ARROW_INTEGRAL_SYMBOL:
255     *move_line = *to;
256     point_sub(move_line, from);
257     add_len = point_len(move_line);
258     point_normalize(move_line);
259     point_scale(move_line, arrow->length / 2);
260     return;
261   case ARROW_ONE_EXACTLY:
262   case ARROW_ONE_OR_NONE:
263   case ARROW_ONE_OR_MANY:
264   case ARROW_NONE_OR_MANY:
265   default:
266     move_arrow->x = 0.0;
267     move_arrow->y = 0.0;
268     move_line->x = 0.0;
269     move_line->y = 0.0;
270     return;
271   }
272 }
273 
274 /** Calculate the corners of a normal arrow.
275  * @param poly A three-element array in which to return the three points
276  *             involved in making a simple arrow: poly[0] is the right-
277  *             hand point, poly[1] is the tip, and poly[2] is the left-hand
278  *             point.
279  * @param to Where the arrow is pointing to
280  * @param from Where the arrow is pointing from (e.g. the end of the stem)
281  * @param length How long the arrowhead should be.
282  * @param width How wide the arrowhead should be.
283  */
284 static int
calculate_arrow(Point * poly,const Point * to,const Point * from,real length,real width)285 calculate_arrow(Point *poly, const Point *to, const Point *from,
286 		real length, real width)
287 {
288   Point delta;
289   Point orth_delta;
290   real len;
291 
292   delta = *to;
293   point_sub(&delta, from);
294   len = point_len(&delta);
295   if (len <= 0.0001) {
296     delta.x=1.0;
297     delta.y=0.0;
298   } else {
299     delta.x/=len;
300     delta.y/=len;
301   }
302 
303   orth_delta.x = delta.y;
304   orth_delta.y = -delta.x;
305 
306   point_scale(&delta, length);
307   point_scale(&orth_delta, width/2.0);
308 
309   poly[0] = *to;
310   point_sub(&poly[0], &delta);
311   point_sub(&poly[0], &orth_delta);
312   poly[1] = *to;
313   poly[2] = *to;
314   point_sub(&poly[2], &delta);
315   point_add(&poly[2], &orth_delta);
316 
317   return 3;
318 }
319 
320 /** Calculate the actual point of a crows-foot arrow.
321  * @param poly A three-element array in which to return the three points
322  *             involved in making a simple arrow: poly[0] is the tip, poly[1]
323  *             is the right-hand point, and poly[2] is the left-hand point.
324  * @param to Where the arrow is pointing to
325  * @param from Where the arrow is pointing from (e.g. the end of the stem)
326  * @param length How long the arrowhead should be.
327  * @param width How wide the arrowhead should be.
328  */
329 static int
calculate_crow(Point * poly,const Point * to,const Point * from,real length,real width)330 calculate_crow(Point *poly, const Point *to, const Point *from,
331 	       real length, real width)
332 {
333   Point delta;
334   Point orth_delta;
335   real len;
336 
337   delta = *to;
338   point_sub(&delta, from);
339   len = point_len(&delta);
340   if (len <= 0.0001) {
341     delta.x=1.0;
342     delta.y=0.0;
343   } else {
344     delta.x/=len;
345     delta.y/=len;
346   }
347 
348   orth_delta.x = delta.y;
349   orth_delta.y = -delta.x;
350 
351   point_scale(&delta, length);
352   point_scale(&orth_delta, width/2.0);
353 
354   poly[0] = *to;
355   point_sub(&poly[0], &delta);
356   poly[1] = *to;
357   point_sub(&poly[1], &orth_delta);
358   poly[2] = *to;
359   point_add(&poly[2], &orth_delta);
360 
361   return 3;
362 }
363 
364 /** Draw ER arrow for 0..N according to Modern database management,
365  *  McFadden/Hoffer/Prescott, Addison-Wessley, 1999
366  * @param renderer A renderer instance to draw into
367  * @param to The point that the arrow points to.
368  * @param from Where the arrow points from (e.g. end of stem)
369  * @param length The length of the arrow
370  * @param width The width of the arrow
371  * @param linewidth The thickness of the lines used to draw the arrow.
372  * @param fg_color The color used for drawing the arrow lines.
373  * @param bg_color Ignored.
374  * @todo The ER-drawing methods are ripe for some refactoring.
375  */
376 static void
draw_none_or_many(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)377 draw_none_or_many(DiaRenderer *renderer, Point *to, Point *from,
378 		  real length, real width, real linewidth,
379 		  Color *fg_color,Color *bg_color)
380 {
381   Point second_from, second_to;
382 
383   draw_crow_foot(renderer, to, from, length, width,
384 		 linewidth, fg_color, bg_color);
385 
386   calculate_double_arrow(&second_to, &second_from, to, from, length);
387   /* use the middle of the arrow */
388 
389   DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer, linewidth);
390   DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
391   DIA_RENDERER_GET_CLASS(renderer)->set_linejoin(renderer, LINEJOIN_MITER);
392   DIA_RENDERER_GET_CLASS(renderer)->set_linecaps(renderer, LINECAPS_BUTT);
393 
394   draw_empty_ellipse(renderer, &second_to, &second_from, length/2,
395 		     width, linewidth, fg_color);
396 }
397 
398 /** ER arrow for exactly-one relations according to Modern database management,
399  *  McFadden/Hoffer/Prescott, Addison-Wessley, 1999
400  * @param renderer A renderer instance to draw into
401  * @param to The point that the arrow points to.
402  * @param from Where the arrow points from (e.g. end of stem)
403  * @param length The length of the arrow
404  * @param width The width of the arrow
405  * @param linewidth The thickness of the lines used to draw the arrow.
406  * @param fg_color The color used for drawing the arrow lines.
407  * @param bg_color Ignored.
408  */
409 static void
draw_one_exactly(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)410 draw_one_exactly(DiaRenderer *renderer, Point *to, Point *from,
411 		  real length, real width, real linewidth,
412 		  Color *fg_color,Color *bg_color)
413 {
414   Point vl,vt;
415   Point bs,be;
416 
417   /* the first line */
418   point_copy(&vl,from); point_sub(&vl,to);
419   if (point_len(&vl) > 0)
420     point_normalize(&vl);
421   else {
422     vl.x = 1.0; vl.y = 0.0;
423   }
424   if (!finite(vl.x)) {
425     vl.x = 1.0; vl.y = 0.0;
426   }
427   point_get_perp(&vt,&vl);
428   point_copy_add_scaled(&bs,to,&vl,length/2);
429   point_copy_add_scaled(&be,&bs,&vt,-width/2.0);
430   point_add_scaled(&bs,&vt,width/2.0);
431 
432   DIA_RENDERER_GET_CLASS(renderer)->draw_line(renderer,&bs,&be,fg_color);
433 
434   point_copy_add_scaled(&bs,to,&vl,length);
435 
436   point_copy_add_scaled(&be,&bs,&vt,-width/2.0);
437   point_add_scaled(&bs,&vt,width/2.0);
438 
439   DIA_RENDERER_GET_CLASS(renderer)->draw_line(renderer,&bs,&be,fg_color);
440 }
441 
442 /* ER arrow for 1..N according to Modern database management,
443  * McFadden/Hoffer/Prescott, Addison-Wessley, 1999
444  * @param renderer A renderer instance to draw into
445  * @param to The point that the arrow points to.
446  * @param from Where the arrow points from (e.g. end of stem)
447  * @param length The length of the arrow
448  * @param width The width of the arrow
449  * @param linewidth The thickness of the lines used to draw the arrow.
450  * @param fg_color The color used for drawing the arrow lines.
451  * @param bg_color Ignored.
452  */
453 static void
draw_one_or_many(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)454 draw_one_or_many(DiaRenderer *renderer, Point *to, Point *from,
455 		 real length, real width, real linewidth,
456 		 Color *fg_color,Color *bg_color)
457 {
458 
459   Point poly[6];
460 
461   draw_crow_foot(renderer, to, from, length, width,
462 		 linewidth, fg_color, bg_color);
463 
464   calculate_arrow(poly, to, from, length, width);
465 
466   DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer, linewidth);
467   DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
468   DIA_RENDERER_GET_CLASS(renderer)->set_linejoin(renderer, LINEJOIN_MITER);
469   DIA_RENDERER_GET_CLASS(renderer)->set_linecaps(renderer, LINECAPS_BUTT);
470 
471   DIA_RENDERER_GET_CLASS(renderer)->draw_line(renderer, &poly[0],&poly[2], fg_color);
472 }
473 
474 /* ER arrow for 0,1 according to Modern database management,
475  * McFadden/Hoffer/Prescott, Addison-Wessley, 1999
476  * @param renderer A renderer instance to draw into
477  * @param to The point that the arrow points to.
478  * @param from Where the arrow points from (e.g. end of stem)
479  * @param length The length of the arrow
480  * @param width The width of the arrow
481  * @param linewidth The thickness of the lines used to draw the arrow.
482  * @param fg_color The color used for drawing the arrow lines.
483  * @param bg_color Ignored.
484  */
485 static void
draw_one_or_none(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)486 draw_one_or_none(DiaRenderer *renderer, Point *to, Point *from,
487 		  real length, real width, real linewidth,
488 		  Color *fg_color,Color *bg_color)
489 {
490   Point vl,vt;
491   Point bs,be;
492   Point second_from, second_to;
493 
494   /* the  line */
495   point_copy(&vl,from); point_sub(&vl,to);
496   if (point_len(&vl) > 0)
497     point_normalize(&vl);
498   else {
499     vl.x = 1.0; vl.y = 0.0;
500   }
501   if (!finite(vl.x)) {
502     vl.x = 1.0; vl.y = 0.0;
503   }
504   point_get_perp(&vt,&vl);
505   point_copy_add_scaled(&bs,to,&vl,length/2);
506   point_copy_add_scaled(&be,&bs,&vt,-width/2.0);
507   point_add_scaled(&bs,&vt,width/2.0);
508 
509   DIA_RENDERER_GET_CLASS(renderer)->draw_line(renderer,&bs,&be,fg_color);
510   /* the ellipse */
511   calculate_double_arrow(&second_to, &second_from, to, from, length);
512   draw_empty_ellipse(renderer, &second_to, &second_from, length/2, width, linewidth, fg_color);
513 }
514 
515 /** Draw a crow's foot arrowhead.
516  * @param renderer A renderer instance to draw into
517  * @param to The point that the arrow points to.
518  * @param from Where the arrow points from (e.g. end of stem)
519  * @param length The length of the arrow
520  * @param width The width of the arrow
521  * @param linewidth The thickness of the lines used to draw the arrow.
522  * @param fg_color The color used for drawing the arrow lines.
523  * @param bg_color Ignored.
524  */
525 static void
draw_crow_foot(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)526 draw_crow_foot(DiaRenderer *renderer, Point *to, Point *from,
527 	       real length, real width, real linewidth,
528 	       Color *fg_color,Color *bg_color)
529 {
530 
531   Point poly[3];
532 
533   calculate_crow(poly, to, from, length, width);
534 
535   DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer, linewidth);
536   DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
537   DIA_RENDERER_GET_CLASS(renderer)->set_linejoin(renderer, LINEJOIN_MITER);
538 
539   DIA_RENDERER_GET_CLASS(renderer)->draw_line(renderer,&poly[0],&poly[1],fg_color);
540   DIA_RENDERER_GET_CLASS(renderer)->draw_line(renderer,&poly[0],&poly[2],fg_color);
541 }
542 
543 /** Draw a simple open line arrow.
544  * @param renderer A renderer instance to draw into
545  * @param to The point that the arrow points to.
546  * @param from Where the arrow points from (e.g. end of stem)
547  * @param length The length of the arrow
548  * @param width The width of the arrow
549  * @param linewidth The thickness of the lines used to draw the arrow.
550  * @param fg_color The color used for drawing the arrow lines.
551  */
552 static void
draw_lines(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)553 draw_lines(DiaRenderer *renderer, Point *to, Point *from,
554 	   real length, real width, real linewidth,
555 	   Color *fg_color, Color *bg_color)
556 {
557   Point poly[3];
558 
559   calculate_arrow(poly, to, from, length, width);
560 
561   DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer, linewidth);
562   DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
563   DIA_RENDERER_GET_CLASS(renderer)->set_linejoin(renderer, LINEJOIN_MITER);
564   DIA_RENDERER_GET_CLASS(renderer)->set_linecaps(renderer, LINECAPS_BUTT);
565 
566   DIA_RENDERER_GET_CLASS(renderer)->draw_polyline(renderer, poly, 3, fg_color);
567 }
568 
569 static int
calculate_ellipse(Point * poly,const Point * to,const Point * from,real length,real width)570 calculate_ellipse (Point *poly, const Point *to, const Point *from,
571 		   real length, real width)
572 {
573   return calculate_diamond (poly, to, from, length, width);
574 }
575 
576 /** Draw an arrowhead that is a filled ellipse.
577  * @param renderer A renderer instance to draw into
578  * @param to The point that the arrow points to.
579  * @param from Where the arrow points from (e.g. end of stem)
580  * @param length The length of the arrow
581  * @param width The width of the arrow
582  * @param linewidth The thickness of the lines used to draw the arrow.
583  * @param fg_color The color used for drawing the arrow lines.
584  * @param bg_color Used to fill the ellipse, usually white and non-settable.
585  *                 If null, the ellipse is filled with fg_color and slightly
586  *                 smaller (by linewidth/2).
587  */
588 static void
draw_fill_ellipse(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)589 draw_fill_ellipse(DiaRenderer *renderer, Point *to, Point *from,
590 		  real length, real width, real linewidth,
591 		  Color *fg_color,Color *bg_color)
592 {
593   BezPoint bp[5];
594   Point vl,vt;
595 
596   DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer, linewidth);
597   DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
598   DIA_RENDERER_GET_CLASS(renderer)->set_linejoin(renderer, LINEJOIN_MITER);
599   DIA_RENDERER_GET_CLASS(renderer)->set_linecaps(renderer, LINECAPS_BUTT);
600 
601   if (!bg_color) {
602     /* no bg_color means filled ellipse ; we then compensate for the line width
603      */
604     length += linewidth;
605     width += linewidth;
606   }
607   point_copy(&vl,from); point_sub(&vl,to);
608   if (point_len(&vl) > 0)
609     point_normalize(&vl);
610   else {
611     vl.x = 1.0; vl.y = 0.0;
612   }
613   if (!finite(vl.x)) {
614     vl.x = 1.0; vl.y = 0.0;
615   }
616   point_get_perp(&vt,&vl);
617 
618 
619   /* This pile of crap is quite well handled by gcc. */
620   bp[0].type = BEZ_MOVE_TO;
621   point_copy(&bp[0].p1,to);
622   bp[1].type = bp[2].type = bp[3].type = bp[4].type = BEZ_CURVE_TO;
623   point_copy(&bp[4].p3,&bp[0].p1);
624 
625   point_copy_add_scaled(&bp[2].p3,&bp[0].p1,&vl,length);
626   point_copy_add_scaled(&bp[2].p2,&bp[2].p3,&vt,-width / 4.0);
627   point_copy_add_scaled(&bp[3].p1,&bp[2].p3,&vt,width / 4.0);
628   point_copy_add_scaled(&bp[1].p1,&bp[0].p1,&vt,-width / 4.0);
629   point_copy_add_scaled(&bp[4].p2,&bp[0].p1,&vt,width / 4.0);
630   point_copy_add_scaled(&bp[1].p3,&bp[0].p1,&vl,length / 2.0); /* temp */
631   point_copy_add_scaled(&bp[3].p3,&bp[1].p3,&vt,width / 2.0);
632   point_add_scaled(&bp[1].p3,&vt,-width / 2.0);
633   point_copy_add_scaled(&bp[1].p2,&bp[1].p3,&vl,-length / 4.0);
634   point_copy_add_scaled(&bp[4].p1,&bp[3].p3,&vl,-length / 4.0);
635   point_copy_add_scaled(&bp[2].p1,&bp[1].p3,&vl,length / 4.0);
636   point_copy_add_scaled(&bp[3].p2,&bp[3].p3,&vl,length / 4.0);
637   if (bg_color) {
638     DIA_RENDERER_GET_CLASS(renderer)->fill_bezier(renderer,bp,sizeof(bp)/sizeof(bp[0]),bg_color);
639     DIA_RENDERER_GET_CLASS(renderer)->draw_bezier(renderer,bp,sizeof(bp)/sizeof(bp[0]),fg_color);
640   } else {
641     DIA_RENDERER_GET_CLASS(renderer)->fill_bezier(renderer,bp,sizeof(bp)/sizeof(bp[0]),fg_color);
642   }
643 }
644 
645 /** Draw an arrowhead that is an ellipse with empty interior.
646  * @param renderer A renderer instance to draw into
647  * @param to The point that the arrow points to.
648  * @param from Where the arrow points from (e.g. end of stem)
649  * @param length The length of the arrow
650  * @param width The width of the arrow
651  * @param linewidth The thickness of the lines used to draw the arrow.
652  * @param fg_color The color used for drawing the arrow lines.
653  */
654 static void
draw_empty_ellipse(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color)655 draw_empty_ellipse(DiaRenderer *renderer, Point *to, Point *from,
656 		  real length, real width, real linewidth,
657 		  Color *fg_color)
658 {
659   BezPoint bp[5];
660   Point vl,vt;
661   Point disp;
662 
663   DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer, linewidth);
664   DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
665   DIA_RENDERER_GET_CLASS(renderer)->set_linejoin(renderer, LINEJOIN_MITER);
666   DIA_RENDERER_GET_CLASS(renderer)->set_linecaps(renderer, LINECAPS_BUTT);
667 
668   point_copy(&vl,from);
669   point_sub(&vl,to);
670   if (point_len(&vl) > 0)
671     point_normalize(&vl);
672   else {
673     vl.x = 1.0; vl.y = 0.0;
674   }
675   if (!finite(vl.x)) {
676     vl.x = 1.0; vl.y = 0.0;
677   }
678 
679   point_get_perp(&vt,&vl);
680 
681   point_copy(&disp, &vl);
682   disp.x *= length/2;
683   disp.y *= length/2;
684 
685   /* This pile of crap is quite well handled by gcc. */
686   bp[0].type = BEZ_MOVE_TO;
687   point_copy(&bp[0].p1,to);
688   point_add(&bp[0].p1,&disp);
689   bp[1].type = bp[2].type = bp[3].type = bp[4].type = BEZ_CURVE_TO;
690   point_copy(&bp[4].p3,&bp[0].p1);
691 
692   point_copy_add_scaled(&bp[2].p3,&bp[0].p1,&vl,length);
693   point_copy_add_scaled(&bp[2].p2,&bp[2].p3,&vt,-width / 4.0);
694   point_copy_add_scaled(&bp[3].p1,&bp[2].p3,&vt,width / 4.0);
695   point_copy_add_scaled(&bp[1].p1,&bp[0].p1,&vt,-width / 4.0);
696   point_copy_add_scaled(&bp[4].p2,&bp[0].p1,&vt,width / 4.0);
697   point_copy_add_scaled(&bp[1].p3,&bp[0].p1,&vl,length / 2.0); /* temp */
698   point_copy_add_scaled(&bp[3].p3,&bp[1].p3,&vt,width / 2.0);
699   point_add_scaled(&bp[1].p3,&vt,-width / 2.0);
700   point_copy_add_scaled(&bp[1].p2,&bp[1].p3,&vl,-length / 4.0);
701   point_copy_add_scaled(&bp[4].p1,&bp[3].p3,&vl,-length / 4.0);
702   point_copy_add_scaled(&bp[2].p1,&bp[1].p3,&vl,length / 4.0);
703   point_copy_add_scaled(&bp[3].p2,&bp[3].p3,&vl,length / 4.0);
704 
705   DIA_RENDERER_GET_CLASS(renderer)->draw_bezier(renderer,bp,sizeof(bp)/sizeof(bp[0]),fg_color);
706 }
707 
708 static int
calculate_box(Point * poly,const Point * to,const Point * from,real length,real width)709 calculate_box (Point *poly, const Point *to, const Point *from,
710 	       real length, real width)
711 {
712   Point vl, vt;
713   Point bs, be;
714 
715   point_copy(&vl,from); point_sub(&vl,to);
716   if (point_len(&vl) > 0)
717     point_normalize(&vl);
718   else {
719     vl.x = 1.0; vl.y = 0.0;
720   }
721   if (!finite(vl.x)) {
722     vl.x = 1.0; vl.y = 0.0;
723   }
724   point_get_perp(&vt,&vl);
725 
726   point_copy_add_scaled(&bs,to,&vl,length/4);
727   point_copy_add_scaled(&be,&bs,&vt,-width/2.0);
728   point_add_scaled(&bs,&vt,width/2.0);
729 
730   point_copy(&poly[0],to);
731   point_copy(&poly[1],&poly[0]);
732   point_add_scaled(&poly[0],&vt,width/4.0);
733   point_add_scaled(&poly[1],&vt,-width/4.0);
734   point_copy_add_scaled(&poly[2],&poly[1],&vl,length/2.0);
735   point_copy_add_scaled(&poly[3],&poly[0],&vl,length/2.0);
736 
737   poly[4] = bs;
738   poly[5] = be;
739 
740   return 6;
741 }
742 
743 /** Draw an arrow head that is an (optionall) filled box.
744  * @param renderer A renderer instance to draw into
745  * @param to The point that the arrow points to.
746  * @param from Where the arrow points from (e.g. end of stem)
747  * @param length The length of the arrow
748  * @param width The width of the arrow
749  * @param linewidth The thickness of the lines used to draw the arrow.
750  * @param fg_color The color used for drawing the arrow lines.
751  * @param bg_color The color used for the interior of the box.  If
752  *                 fg_color == bg_color, the box is rendered slightly smaller.
753  */
754 static void
draw_fill_box(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)755 draw_fill_box(DiaRenderer *renderer, Point *to, Point *from,
756 	      real length, real width, real linewidth,
757 	      Color *fg_color,Color *bg_color)
758 {
759   Point poly[6];
760   real lw_factor,clength,cwidth;
761 
762   DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer, linewidth);
763   DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
764   DIA_RENDERER_GET_CLASS(renderer)->set_linejoin(renderer, LINEJOIN_MITER);
765   DIA_RENDERER_GET_CLASS(renderer)->set_linecaps(renderer, LINECAPS_BUTT);
766 
767   if (fg_color == bg_color) {
768     /* Filled dot */
769     lw_factor = linewidth;
770   } else {
771     /* Hollow dot or dimension origin */
772     lw_factor = 0.0;
773   }
774   clength = length + lw_factor;
775   cwidth = width + lw_factor;
776 
777   calculate_box (poly, to, from, clength, cwidth);
778 
779   if (fg_color == bg_color) {
780     DIA_RENDERER_GET_CLASS(renderer)->fill_polygon(renderer, poly, 4, fg_color);
781   } else {
782     DIA_RENDERER_GET_CLASS(renderer)->fill_polygon(renderer, poly, 4, bg_color);
783     DIA_RENDERER_GET_CLASS(renderer)->draw_polygon(renderer, poly, 4, fg_color);
784   }
785   DIA_RENDERER_GET_CLASS(renderer)->draw_line(renderer,&poly[4],&poly[5],fg_color);
786 }
787 static int
calculate_dot(Point * poly,const Point * to,const Point * from,real length,real width)788 calculate_dot (Point *poly, const Point *to, const Point *from,
789 	       real length, real width)
790 {
791   return calculate_diamond (poly, to, from, length, width);
792 }
793 /** Draw a "filled dot" arrow.
794  * @param renderer A renderer instance to draw into
795  * @param to The point that the arrow points to.
796  * @param from Where the arrow points from (e.g. end of stem)
797  * @param length The length of the arrow
798  * @param width The width of the arrow
799  * @param linewidth The thickness of the lines used to draw the arrow.
800  * @param fg_color The color used for drawing the arrow lines.
801  * @param bg_color The collor used for the interior of the dot.
802  * @bug Need to describe the diff between this and ellipse arrow.
803  */
804 static void
draw_fill_dot(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)805 draw_fill_dot(DiaRenderer *renderer, Point *to, Point *from,
806 	      real length, real width, real linewidth,
807 	      Color *fg_color, Color *bg_color)
808 {
809   BezPoint bp[5];
810   Point vl,vt;
811   Point bs,be;
812   real lw_factor,clength,cwidth;
813 
814   DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer, linewidth);
815   DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
816   DIA_RENDERER_GET_CLASS(renderer)->set_linejoin(renderer, LINEJOIN_MITER);
817   DIA_RENDERER_GET_CLASS(renderer)->set_linecaps(renderer, LINECAPS_BUTT);
818 
819   if (fg_color == bg_color) {
820     /* Filled dot */
821     lw_factor = linewidth;
822   } else {
823     /* Hollow dot or dimension origin */
824     lw_factor = 0.0;
825   }
826   clength = length + lw_factor;
827   cwidth = width + lw_factor;
828 
829   point_copy(&vl,from); point_sub(&vl,to);
830   if (point_len(&vl) > 0)
831     point_normalize(&vl);
832   else {
833     vl.x = 1.0; vl.y = 0.0;
834   }
835   if (!finite(vl.x)) {
836     vl.x = 1.0; vl.y = 0.0;
837   }
838   point_get_perp(&vt,&vl);
839 
840   point_copy_add_scaled(&bs,to,&vl,length/4);
841   point_copy_add_scaled(&be,&bs,&vt,-width/2.0);
842   point_add_scaled(&bs,&vt,width/2.0);
843 
844   /* This pile of crap is quite well handled by gcc. */
845   bp[0].type = BEZ_MOVE_TO;
846   point_copy(&bp[0].p1,to);
847   bp[1].type = bp[2].type = bp[3].type = bp[4].type = BEZ_CURVE_TO;
848   point_copy(&bp[4].p3,&bp[0].p1);
849 
850   point_copy_add_scaled(&bp[2].p3,&bp[0].p1,&vl,clength/2);
851   point_copy_add_scaled(&bp[2].p2,&bp[2].p3,&vt,-cwidth / 8.0);
852   point_copy_add_scaled(&bp[3].p1,&bp[2].p3,&vt,cwidth / 8.0);
853   point_copy_add_scaled(&bp[1].p1,&bp[0].p1,&vt,-cwidth / 8.0);
854   point_copy_add_scaled(&bp[4].p2,&bp[0].p1,&vt,cwidth / 8.0);
855   point_copy_add_scaled(&bp[1].p3,&bp[0].p1,&vl,clength / 4.0); /* temp */
856   point_copy_add_scaled(&bp[3].p3,&bp[1].p3,&vt,cwidth / 4.0);
857   point_add_scaled(&bp[1].p3,&vt,-cwidth / 4.0);
858   point_copy_add_scaled(&bp[1].p2,&bp[1].p3,&vl,-clength / 8.0);
859   point_copy_add_scaled(&bp[4].p1,&bp[3].p3,&vl,-clength / 8.0);
860   point_copy_add_scaled(&bp[2].p1,&bp[1].p3,&vl,clength / 8.0);
861   point_copy_add_scaled(&bp[3].p2,&bp[3].p3,&vl,clength / 8.0);
862 
863   if (!bg_color) {
864     /* Means dimension origin */
865     Point dos,doe;
866 
867     point_copy_add_scaled(&doe,to,&vl,length);
868     point_copy_add_scaled(&dos,to,&vl,length/2);
869 
870     DIA_RENDERER_GET_CLASS(renderer)->draw_line(renderer,&dos,&doe,fg_color);
871   } else {
872     DIA_RENDERER_GET_CLASS(renderer)->fill_bezier(renderer,bp,sizeof(bp)/sizeof(bp[0]),bg_color);
873   }
874   if (fg_color != bg_color) {
875     DIA_RENDERER_GET_CLASS(renderer)->draw_bezier(renderer,bp,sizeof(bp)/sizeof(bp[0]),fg_color);
876   }
877   DIA_RENDERER_GET_CLASS(renderer)->draw_line(renderer,&bs,&be,fg_color);
878 }
879 
880 /** Draw the integral-sign arrow head.
881  * @param renderer A renderer instance to draw into
882  * @param to The point that the arrow points to.
883  * @param from Where the arrow points from (e.g. end of stem)
884  * @param length The length of the arrow
885  * @param width The width of the arrow
886  * @param linewidth The thickness of the lines used to draw the arrow.
887  * @param fg_color The color used for drawing the arrow lines.
888  * @param bg_color The color used to kludge around the longer stem of this
889  *                 arrow.
890  * @bug The bg_color kludge should not be necessary, arrow pos is adjustable.
891  */
892 static void
draw_integral(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color)893 draw_integral(DiaRenderer *renderer, Point *to, Point *from,
894 	      real length, real width, real linewidth,
895 	      Color *fg_color)
896 {
897   BezPoint bp[2];
898   Point vl,vt;
899   Point bs,be, bs2,be2;
900   DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer, linewidth);
901   DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
902   DIA_RENDERER_GET_CLASS(renderer)->set_linejoin(renderer, LINEJOIN_MITER);
903   DIA_RENDERER_GET_CLASS(renderer)->set_linecaps(renderer, LINECAPS_BUTT);
904 
905   point_copy(&vl,from); point_sub(&vl,to);
906   if (point_len(&vl) > 0)
907     point_normalize(&vl);
908   else {
909     vl.x = 1.0; vl.y = 0.0;
910   }
911   if (!finite(vl.x)) {
912     vl.x = 1.0; vl.y = 0.0;
913   }
914   point_get_perp(&vt,&vl);
915 
916   point_copy_add_scaled(&bs,to,&vl,length/2);
917   point_copy_add_scaled(&be,&bs,&vt,-width/2.0);
918   point_add_scaled(&bs,&vt,width/2.0);
919 
920   point_copy_add_scaled(&bs2,to,&vl,length/2);
921   point_copy_add_scaled(&be2,&bs2,&vl,length/2);
922 
923   bp[0].type = BEZ_MOVE_TO;
924   bp[1].type = BEZ_CURVE_TO;
925   point_copy_add_scaled(&bp[0].p1,to,&vl,.1*length);
926   point_add_scaled(&bp[0].p1,&vt,.4*width);
927   point_copy_add_scaled(&bp[1].p3,to,&vl,.9*length);
928   point_add_scaled(&bp[1].p3,&vt,-.4*width);
929   point_copy_add_scaled(&bp[1].p1,&bp[0].p1,&vl,.35*length);
930   point_copy_add_scaled(&bp[1].p2,&bp[1].p3,&vl,-.35*length);
931 
932   DIA_RENDERER_GET_CLASS(renderer)->draw_line(renderer, &bs2, &be2, fg_color);
933   DIA_RENDERER_GET_CLASS(renderer)->draw_line(renderer, &bs, &be, fg_color);
934   DIA_RENDERER_GET_CLASS(renderer)->draw_bezier(renderer,bp,sizeof(bp)/sizeof(bp[0]),fg_color);
935 }
936 static int
calculate_slashed(Point * poly,const Point * to,const Point * from,real length,real width)937 calculate_slashed (Point *poly, const Point *to, const Point *from,
938                    real length, real width)
939 {
940   Point vl,vt;
941 
942   point_copy(&vl,from);
943   point_sub(&vl,to);
944   if (point_len(&vl) > 0)
945     point_normalize(&vl);
946   else {
947     vl.x = 1.0; vl.y = 0.0;
948   }
949   if (!finite(vl.x)) {
950     vl.x = 1.0; vl.y = 0.0;
951   }
952   point_get_perp(&vt,&vl);
953 
954   point_copy_add_scaled(&poly[2],to,&vl,length/2);
955   point_copy_add_scaled(&poly[3],&poly[2],&vt,-width/2.0);
956   point_add_scaled(&poly[2],&vt,width/2.0);
957 
958   point_copy_add_scaled(&poly[0],to,&vl,length/2);
959   point_copy_add_scaled(&poly[1],&poly[0],&vl,length/2);
960 
961   point_copy_add_scaled(&poly[4],to,&vl,.1*length);
962   point_add_scaled(&poly[4],&vt,.4*width);
963   point_copy_add_scaled(&poly[5],to,&vl,.9*length);
964   point_add_scaled(&poly[5],&vt,-.4*width);
965 
966   return 6;
967 }
968 
969 /** Draw the arrowhead that is a line with a slash through it.
970  * @param renderer A renderer instance to draw into
971  * @param to The point that the arrow points to.
972  * @param from Where the arrow points from (e.g. end of stem)
973  * @param length The length of the arrow
974  * @param width The width of the arrow
975  * @param linewidth The thickness of the lines used to draw the arrow.
976  * @param fg_color The color used for drawing the arrow lines.
977  * @param bg_color Used for a kludge of "erasing" the line tip instead of
978  *                 figuring out the correct way to do this.
979  * @bug Figure out the right way to do this, avoid kludge.
980  */
981 static void
draw_slashed(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)982 draw_slashed(DiaRenderer *renderer, Point *to, Point *from,
983 	     real length, real width, real linewidth,
984 	     Color *fg_color, Color *bg_color)
985 {
986   Point poly[6];
987 
988   calculate_slashed (poly, to, from, length, width);
989 
990   DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer, linewidth);
991   DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
992   DIA_RENDERER_GET_CLASS(renderer)->set_linejoin(renderer, LINEJOIN_MITER);
993   DIA_RENDERER_GET_CLASS(renderer)->set_linecaps(renderer, LINECAPS_BUTT);
994 
995   DIA_RENDERER_GET_CLASS(renderer)->draw_line(renderer, &poly[0], &poly[1], fg_color);
996   DIA_RENDERER_GET_CLASS(renderer)->draw_line(renderer, &poly[2], &poly[3], fg_color);
997   DIA_RENDERER_GET_CLASS(renderer)->draw_line(renderer, &poly[4], &poly[5], fg_color);
998 }
999 
1000 /** Calculate positions for the half-head arrow (only left-hand(?) line drawn)
1001  * @param poly The three-element array to store the result in.
1002  * @param to Where the arrow points to
1003  * @param from Where the arrow points from (e.g. end of stem)
1004  * @param length The length of the arrowhead
1005  * @param width The width of the arrowhead
1006  * @param linewidth The width of the lines used to draw the arrow
1007  * @bug Describe better what is put into poly.
1008  */
1009 static int
calculate_halfhead(Point * poly,const Point * to,const Point * from,real length,real width)1010 calculate_halfhead(Point *poly, const Point *to, const Point *from,
1011 		   real length, real width)
1012 {
1013   Point delta;
1014   Point orth_delta;
1015   real len;
1016   real angle;
1017 
1018   if (width > 0.0000001) {
1019     angle = atan(length/(width/2));
1020   } else {
1021     angle = 0;
1022   }
1023 
1024   delta = *to;
1025   point_sub(&delta, from);
1026   len = point_len(&delta);
1027   if (len <= 0.0001) {
1028     delta.x=1.0;
1029     delta.y=0.0;
1030   } else {
1031     delta.x/=len;
1032     delta.y/=len;
1033   }
1034 
1035   orth_delta.x = delta.y;
1036   orth_delta.y = -delta.x;
1037 
1038   point_scale(&delta, length);
1039   point_scale(&orth_delta, width/2.0);
1040 
1041   poly[0] = *to;
1042   point_sub(&poly[0], &delta);
1043   point_sub(&poly[0], &orth_delta);
1044   poly[1] = *to;
1045   poly[2] = *to;
1046   point_normalize(&delta);
1047   point_scale(&delta, 0);
1048   point_sub(&poly[2], &delta);
1049   /*  point_add(&poly[2], &orth_delta);*/
1050   return 3;
1051 }
1052 
1053 /** Draw a halfhead arrow.
1054  * @param renderer A renderer instance to draw into
1055  * @param to The point that the arrow points to.
1056  * @param from Where the arrow points from (e.g. end of stem)
1057  * @param length The length of the arrow
1058  * @param width The width of the arrow
1059  * @param linewidth The thickness of the lines used to draw the arrow.
1060  * @param color The color used for drawing the arrow lines.
1061  */
1062 static void
draw_halfhead(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)1063 draw_halfhead(DiaRenderer *renderer, Point *to, Point *from,
1064 	      real length, real width, real linewidth,
1065 	      Color *fg_color, Color *bg_color)
1066 {
1067   Point poly[3];
1068 
1069   calculate_halfhead(poly, to, from, length, width);
1070 
1071   DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer, linewidth);
1072   DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
1073   DIA_RENDERER_GET_CLASS(renderer)->set_linejoin(renderer, LINEJOIN_MITER);
1074   DIA_RENDERER_GET_CLASS(renderer)->set_linecaps(renderer, LINECAPS_BUTT);
1075 
1076   DIA_RENDERER_GET_CLASS(renderer)->draw_polyline(renderer, poly, 3, fg_color);
1077 }
1078 
1079 /** Draw a basic triangular arrow.
1080  * @param renderer A renderer instance to draw into
1081  * @param to The point that the arrow points to.
1082  * @param from Where the arrow points from (e.g. end of stem)
1083  * @param length The length of the arrow
1084  * @param width The width of the arrow
1085  * @param linewidth The thickness of the lines used to draw the arrow.
1086  * @param color The color used for drawing the arrow lines.
1087  */
1088 static void
draw_triangle(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)1089 draw_triangle(DiaRenderer *renderer, Point *to, Point *from,
1090 	      real length, real width, real linewidth,
1091 	      Color *fg_color, Color *bg_color)
1092 {
1093   Point poly[3];
1094 
1095   calculate_arrow(poly, to, from, length, width);
1096 
1097   DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer, linewidth);
1098   DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
1099   DIA_RENDERER_GET_CLASS(renderer)->set_linejoin(renderer, LINEJOIN_MITER);
1100 
1101   DIA_RENDERER_GET_CLASS(renderer)->draw_polygon(renderer, poly, 3, fg_color);
1102 }
1103 
1104 /** Draw a simple triangular arrow, with filled head.
1105  * @param renderer A renderer instance to draw into
1106  * @param to The point that the arrow points to.
1107  * @param from Where the arrow points from (e.g. end of stem)
1108  * @param length The length of the arrow
1109  * @param width The width of the arrow
1110  * @param linewidth The thickness of the lines used to draw the arrow.
1111  * @param color The color used for drawing the arrowhead.
1112  */
1113 static void
fill_triangle(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)1114 fill_triangle(DiaRenderer *renderer, Point *to, Point *from,
1115 	      real length, real width, real linewidth,
1116 	      Color *fg_color, Color *bg_color)
1117 {
1118   Point poly[3];
1119 
1120   calculate_arrow(poly, to, from, length, width);
1121 
1122   DIA_RENDERER_GET_CLASS(renderer)->set_fillstyle(renderer, FILLSTYLE_SOLID);
1123   DIA_RENDERER_GET_CLASS(renderer)->set_linejoin(renderer, LINEJOIN_MITER);
1124 
1125   DIA_RENDERER_GET_CLASS(renderer)->fill_polygon(renderer, poly, 3, bg_color);
1126 }
1127 
1128 /** Calculate the points needed to draw a diamon arrowhead.
1129  * @param poly A 4-element arrow to hold the return values:
1130  *             poly[0] holds the tip of the diamond.
1131  *             poly[1] holds the right-side tip of the diamond.
1132  *             poly[2] holds the back end of the diamond.
1133  *             poly[3] holds the left-side tip of the diamond.
1134  * @param to The point the arrow points to.
1135  * @param from The point the arrow points away from (e.g. bezier control line)
1136  * @param length The length of the arrowhead
1137  * @param width The width of the arrowhead
1138  */
1139 static int
calculate_diamond(Point * poly,const Point * to,const Point * from,real length,real width)1140 calculate_diamond(Point *poly, const Point *to, const Point *from,
1141 		  real length, real width)
1142 {
1143   Point delta;
1144   Point orth_delta;
1145   real len;
1146 
1147   delta = *to;
1148   point_sub(&delta, from);
1149   len = sqrt(point_dot(&delta, &delta));
1150   if (len <= 0.0001) {
1151     delta.x=1.0;
1152     delta.y=0.0;
1153   } else {
1154     delta.x/=len;
1155     delta.y/=len;
1156   }
1157 
1158   orth_delta.x = delta.y;
1159   orth_delta.y = -delta.x;
1160 
1161   point_scale(&delta, length/2.0);
1162   point_scale(&orth_delta, width/2.0);
1163 
1164   poly[0] = *to;
1165   poly[1] = *to;
1166   point_sub(&poly[1], &delta);
1167   point_sub(&poly[1], &orth_delta);
1168   poly[2] = *to;
1169   point_sub(&poly[2], &delta);
1170   point_sub(&poly[2], &delta);
1171   poly[3] = *to;
1172   point_sub(&poly[3], &delta);
1173   point_add(&poly[3], &orth_delta);
1174 
1175   return 4;
1176 }
1177 
1178 /** Draw a diamond-shaped arrow head.
1179  * @param renderer A renderer instance to draw into
1180  * @param to The point that the arrow points to.
1181  * @param from Where the arrow points from (e.g. end of stem)
1182  * @param length The length of the arrow
1183  * @param width The width of the arrow
1184  * @param linewidth The thickness of the lines used to draw the arrow.
1185  * @param color The color used for drawing the arrowhead.
1186  */
1187 static void
draw_diamond(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * color)1188 draw_diamond(DiaRenderer *renderer, Point *to, Point *from,
1189 	     real length, real width, real linewidth,
1190 	     Color *color)
1191 {
1192   Point poly[4];
1193 
1194   calculate_diamond(poly, to, from, length, width);
1195 
1196   DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer, linewidth);
1197   DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
1198   DIA_RENDERER_GET_CLASS(renderer)->set_linejoin(renderer, LINEJOIN_MITER);
1199   DIA_RENDERER_GET_CLASS(renderer)->set_linecaps(renderer, LINECAPS_BUTT);
1200 
1201   DIA_RENDERER_GET_CLASS(renderer)->draw_polygon(renderer, poly, 4, color);
1202 }
1203 
1204 /** Draw a right-hand part of a diamond arrowhead.
1205  * @param renderer A renderer instance to draw into
1206  * @param to The point that the arrow points to.
1207  * @param from Where the arrow points from (e.g. end of stem)
1208  * @param length The length of the arrow
1209  * @param width The width of the arrow
1210  * @param linewidth The thickness of the lines used to draw the arrow.
1211  * @param color The color used for drawing the arrowhead.
1212 */
1213 static void
draw_half_diamond(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)1214 draw_half_diamond(DiaRenderer *renderer, Point *to, Point *from,
1215 		  real length, real width, real linewidth,
1216 		  Color *fg_color, Color *bg_color)
1217 {
1218   Point poly[4];
1219 
1220   calculate_diamond(poly, to, from, length, width);
1221 
1222   DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer, linewidth);
1223   DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
1224   DIA_RENDERER_GET_CLASS(renderer)->set_linejoin(renderer, LINEJOIN_MITER);
1225   DIA_RENDERER_GET_CLASS(renderer)->set_linecaps(renderer, LINECAPS_BUTT);
1226 
1227   DIA_RENDERER_GET_CLASS(renderer)->draw_polyline(renderer, poly+1, 3, fg_color);
1228 }
1229 
1230 /** Draw a filled diamond arrow head.
1231  * @param renderer A renderer instance to draw into
1232  * @param to The point that the arrow points to.
1233  * @param from Where the arrow points from (e.g. end of stem)
1234  * @param length The length of the arrow
1235  * @param width The width of the arrow
1236  * @param color The color used for drawing the arrowhead.
1237  */
1238 static void
fill_diamond(DiaRenderer * renderer,Point * to,Point * from,real length,real width,Color * color)1239 fill_diamond(DiaRenderer *renderer, Point *to, Point *from,
1240 	     real length, real width,
1241 	     Color *color)
1242 {
1243   Point poly[4];
1244 
1245   calculate_diamond(poly, to, from, length, width);
1246 
1247   DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
1248   DIA_RENDERER_GET_CLASS(renderer)->set_linejoin(renderer, LINEJOIN_MITER);
1249   DIA_RENDERER_GET_CLASS(renderer)->set_linecaps(renderer, LINECAPS_BUTT);
1250 
1251   DIA_RENDERER_GET_CLASS(renderer)->fill_polygon(renderer, poly, 4, color);
1252 }
1253 
1254 /** Calculate the points needed to draw a slashed-cross arrowhead.
1255  * @param poly A 6-element array to hold the points calculated:
1256  * @param to Where the arrow points to.
1257  * @param from Where the arrow points from (e.g. other end of stem).
1258  * @param length The length of the arrowhead.
1259  * @param width The width of the arrowhead.
1260  * @bug Describe what is where in the poly array.
1261  */
1262 static int
calculate_slashed_cross(Point * poly,const Point * to,const Point * from,real length,real width)1263 calculate_slashed_cross(Point *poly, const Point *to, const Point *from,
1264 			real length, real width)
1265 {
1266   Point delta;
1267   Point orth_delta;
1268   real len;
1269   int i;
1270 
1271   delta = *to;
1272   point_sub(&delta, from);
1273   len = sqrt(point_dot(&delta, &delta));
1274   if (len <= 0.0001) {
1275     delta.x=1.0;
1276     delta.y=0.0;
1277   } else {
1278     delta.x/=len;
1279     delta.y/=len;
1280   }
1281 
1282   orth_delta.x = delta.y;
1283   orth_delta.y = -delta.x;
1284 
1285   point_scale(&delta, length/2.0);
1286   point_scale(&orth_delta, width/2.0);
1287 
1288   for(i=0; i<6;i++)poly[i] = *to;
1289 
1290   point_add(&poly[1], &delta);
1291 
1292   point_add(&poly[2], &delta);
1293   point_add(&poly[2], &orth_delta);
1294 
1295   point_sub(&poly[3], &delta);
1296   point_sub(&poly[3], &orth_delta);
1297 
1298   point_add(&poly[4], &orth_delta);
1299   point_sub(&poly[5], &orth_delta);
1300 
1301   return 6;
1302 }
1303 
1304 /** Draw a slashed cross arrowhead.
1305  * @param renderer A renderer instance to draw into
1306  * @param to The point that the arrow points to.
1307  * @param from Where the arrow points from (e.g. end of stem)
1308  * @param length The length of the arrow
1309  * @param width The width of the arrow
1310  * @param linewidth The thickness of the lines used to draw the arrow.
1311  * @param color The color used for drawing the arrowhead.
1312  */
1313 static void
draw_slashed_cross(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)1314 draw_slashed_cross(DiaRenderer *renderer, Point *to, Point *from,
1315 		   real length, real width, real linewidth,
1316 		   Color *fg_color, Color *bg_color)
1317 {
1318   Point poly[6];
1319 
1320   calculate_slashed_cross(poly, to, from, length, width);
1321 
1322   DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer, linewidth);
1323   DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
1324   DIA_RENDERER_GET_CLASS(renderer)->set_linejoin(renderer, LINEJOIN_MITER);
1325   DIA_RENDERER_GET_CLASS(renderer)->set_linecaps(renderer, LINECAPS_BUTT);
1326 
1327   DIA_RENDERER_GET_CLASS(renderer)->draw_line(renderer, &poly[0],&poly[1], fg_color);
1328   DIA_RENDERER_GET_CLASS(renderer)->draw_line(renderer, &poly[2],&poly[3], fg_color);
1329   DIA_RENDERER_GET_CLASS(renderer)->draw_line(renderer, &poly[4],&poly[5], fg_color);
1330 }
1331 static int
calculate_backslash(Point * poly,const Point * to,const Point * from,real length,real width)1332 calculate_backslash (Point *poly, const Point *to, const Point *from,
1333 		     real length, real width)
1334 {
1335   Point delta;
1336   Point orth_delta;
1337   real len;
1338 
1339   delta = *to;
1340   point_sub(&delta, from);
1341   len = sqrt(point_dot(&delta, &delta));
1342   if (len <= 0.0001) {
1343     delta.x=1.0;
1344     delta.y=0.0;
1345   } else {
1346     delta.x/=len;
1347     delta.y/=len;
1348   }
1349 
1350   orth_delta.x = delta.y;
1351   orth_delta.y = -delta.x;
1352 
1353   point_scale(&delta, length/2.0);
1354   point_scale(&orth_delta, width/2.0);
1355 
1356   poly[0] = *to;
1357   point_sub(&poly[0], &delta);
1358   point_sub(&poly[0], &delta);
1359   point_sub(&poly[0], &delta);
1360   point_add(&poly[0], &orth_delta);
1361 
1362   poly[1] = *to;
1363   point_sub(&poly[1], &delta);
1364   point_sub(&poly[1], &orth_delta);
1365 
1366   return 2;
1367 }
1368 /** Draw a backslash arrowhead.
1369  * @param renderer A renderer instance to draw into
1370  * @param to The point that the arrow points to.
1371  * @param from Where the arrow points from (e.g. end of stem)
1372  * @param length The length of the arrow
1373  * @param width The width of the arrow
1374  * @param linewidth The thickness of the lines used to draw the arrow.
1375  * @param color The color used for drawing the arrowhead.
1376  */
1377 static void
draw_backslash(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)1378 draw_backslash(DiaRenderer *renderer, Point *to, Point *from,
1379                real length, real width, real linewidth,
1380 	       Color *fg_color, Color *bg_color)
1381 {
1382   Point poly[2];
1383 
1384   calculate_backslash (poly, to, from, length, width);
1385 
1386   DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer, linewidth);
1387   DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
1388   DIA_RENDERER_GET_CLASS(renderer)->set_linejoin(renderer, LINEJOIN_MITER);
1389   DIA_RENDERER_GET_CLASS(renderer)->set_linecaps(renderer, LINECAPS_BUTT);
1390 
1391   DIA_RENDERER_GET_CLASS(renderer)->draw_line(renderer, &poly[0], &poly[1], fg_color);
1392 }
1393 
1394 /** Draw a cross-like arrowhead.
1395  * @param renderer A renderer instance to draw into
1396  * @param to The point that the arrow points to.
1397  * @param from Where the arrow points from (e.g. end of stem)
1398  * @param length The length of the arrow
1399  * @param width The width of the arrow
1400  * @param linewidth The thickness of the lines used to draw the arrow.
1401  * @param color The color used for drawing the arrowhead.
1402  */
1403 static void
draw_cross(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)1404 draw_cross(DiaRenderer *renderer, Point *to, Point *from,
1405 	   real length, real width, real linewidth,
1406 	   Color *fg_color, Color *bg_color)
1407 {
1408   Point poly[6];
1409 
1410   calculate_arrow(poly, to, from, length, width);
1411 
1412   DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer, linewidth);
1413   DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
1414   DIA_RENDERER_GET_CLASS(renderer)->set_linejoin(renderer, LINEJOIN_MITER);
1415   DIA_RENDERER_GET_CLASS(renderer)->set_linecaps(renderer, LINECAPS_BUTT);
1416 
1417   DIA_RENDERER_GET_CLASS(renderer)->draw_line(renderer, &poly[0],&poly[2], fg_color);
1418   /*DIA_RENDERER_GET_CLASS(renderer)->draw_line(renderer, &poly[4],&poly[5], color); */
1419 }
1420 
1421 /** Calculate where to put the second arrowhead of a double arrow
1422  * @param second_to Return value for the point where the second arrowhead
1423  *                  should point to.
1424  * @param second_from Return value for the point where the second arrowhead
1425  *                  should point from.
1426  * @param to Where the first arrowhead should point to.
1427  * @param from Where the whole arrow points from (e.g. end of stem)
1428  * @param length The length of each arrowhead.
1429  */
1430 static void
calculate_double_arrow(Point * second_to,Point * second_from,const Point * to,const Point * from,real length)1431 calculate_double_arrow(Point *second_to, Point *second_from,
1432                        const Point *to, const Point *from, real length)
1433 {
1434   Point delta;
1435   real len;
1436 
1437   delta = *to;
1438   point_sub(&delta, from);
1439   len = sqrt(point_dot(&delta, &delta));
1440   if (len <= 0.0001) {
1441     delta.x=1.0;
1442     delta.y=0.0;
1443   } else {
1444     delta.x/=len;
1445     delta.y/=len;
1446   }
1447 
1448   point_scale(&delta, length/2);
1449 
1450   *second_to = *to;
1451   point_sub(second_to, &delta);
1452   point_sub(second_to, &delta);
1453   *second_from = *from;
1454   point_add(second_from, &delta);
1455   point_add(second_from, &delta);
1456 }
1457 
1458 /** Draw a double-triangle arrowhead.
1459  * @param renderer A renderer instance to draw into
1460  * @param to The point that the arrow points to.
1461  * @param from Where the arrow points from (e.g. end of stem)
1462  * @param length The length of the arrow
1463  * @param width The width of the arrow
1464  * @param linewidth The thickness of the lines used to draw the arrow.
1465  * @param color The color used for drawing the arrowhead.
1466  */
1467 static void
draw_double_triangle(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)1468 draw_double_triangle(DiaRenderer *renderer, Point *to, Point *from,
1469 		     real length, real width, real linewidth,
1470 		     Color *fg_color, Color *bg_color)
1471 {
1472   Point second_from, second_to;
1473 
1474   draw_triangle(renderer, to, from, length, width, linewidth, fg_color, bg_color);
1475   calculate_double_arrow(&second_to, &second_from, to, from, length+linewidth);
1476   draw_triangle(renderer, &second_to, &second_from, length, width, linewidth, fg_color, bg_color);
1477 }
1478 
1479 /** Draw a filled double-triangle arrowhead.
1480  * @param renderer A renderer instance to draw into
1481  * @param to The point that the arrow points to.
1482  * @param from Where the arrow points from (e.g. end of stem)
1483  * @param length The length of the arrow
1484  * @param width The width of the arrow
1485  * @param linewidth The thickness of the lines used to draw the arrow.
1486  * @param color The color used for drawing the arrowhead.
1487  */
1488 static void
fill_double_triangle(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)1489 fill_double_triangle(DiaRenderer *renderer, Point *to, Point *from,
1490 		     real length, real width, real linewidth,
1491 		     Color *fg_color, Color *bg_color)
1492 {
1493   Point second_from, second_to;
1494 
1495   fill_triangle(renderer, to, from, length, width, linewidth, NULL, bg_color);
1496   calculate_double_arrow(&second_to, &second_from, to, from, length);
1497   fill_triangle(renderer, &second_to, &second_from, length, width, linewidth, NULL, bg_color);
1498 }
1499 
1500 /** Calculate the points needed to draw a concave arrowhead.
1501  * @param poly A 4-element array of return points:
1502  *             poly[0] is the tip of the arrow.
1503  *             poly[1] is the right-hand point of the arrow.
1504  *             poly[2] is the rear indent point of the arrow.
1505  *             poly[3] is the left-hand point of the arrow.
1506  * @param to Where the arrow points to.
1507  * @param from Where the arrow points from (e.g. bezier control point)
1508  * @param length The length of the arrow.
1509  * @param width The width of the arrow.
1510  */
1511 static int
calculate_concave(Point * poly,const Point * to,const Point * from,real length,real width)1512 calculate_concave(Point *poly, const Point *to, const Point *from,
1513 		  real length, real width)
1514 {
1515   Point delta;
1516   Point orth_delta;
1517   real len;
1518 
1519   delta = *to;
1520   point_sub(&delta, from);
1521   len = sqrt(point_dot(&delta, &delta));
1522   if (len <= 0.0001) {
1523     delta.x=1.0;
1524     delta.y=0.0;
1525   } else {
1526     delta.x/=len;
1527     delta.y/=len;
1528   }
1529 
1530   orth_delta.x = delta.y;
1531   orth_delta.y = -delta.x;
1532 
1533   point_scale(&delta, length/4.0);
1534   point_scale(&orth_delta, width/2.0);
1535 
1536   poly[0] = *to;
1537   poly[1] = *to;
1538   point_sub(&poly[1], &delta);
1539   point_sub(&poly[1], &delta);
1540   point_sub(&poly[1], &delta);
1541   point_sub(&poly[1], &delta);
1542   point_sub(&poly[1], &orth_delta);
1543   poly[2] = *to;
1544   point_sub(&poly[2], &delta);
1545   point_sub(&poly[2], &delta);
1546   point_sub(&poly[2], &delta);
1547   poly[3] = *to;
1548   point_add(&poly[3], &orth_delta);
1549   point_sub(&poly[3], &delta);
1550   point_sub(&poly[3], &delta);
1551   point_sub(&poly[3], &delta);
1552   point_sub(&poly[3], &delta);
1553 
1554   return 4;
1555 }
1556 
1557 /** Draw a concave triangle arrowhead.
1558  * @param renderer A renderer instance to draw into
1559  * @param to The point that the arrow points to.
1560  * @param from Where the arrow points from (e.g. end of stem)
1561  * @param length The length of the arrow
1562  * @param width The width of the arrow
1563  * @param linewidth The thickness of the lines used to draw the arrow.
1564  * @param fg_color The color used for drawing the arrowhead lines
1565  * @param bg_color The color used for drawing the arrowhead interior.
1566  */
1567 static void
draw_concave_triangle(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)1568 draw_concave_triangle(DiaRenderer *renderer, Point *to, Point *from,
1569 		      real length, real width, real linewidth,
1570 		      Color *fg_color, Color *bg_color)
1571 {
1572   Point poly[4];
1573 
1574   calculate_concave(poly, to, from, length, width);
1575 
1576   DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
1577   DIA_RENDERER_GET_CLASS(renderer)->set_linejoin(renderer, LINEJOIN_MITER);
1578   DIA_RENDERER_GET_CLASS(renderer)->set_linecaps(renderer, LINECAPS_BUTT);
1579 
1580   if (fg_color == bg_color)
1581     DIA_RENDERER_GET_CLASS(renderer)->fill_polygon(renderer, poly, 4, bg_color);
1582   DIA_RENDERER_GET_CLASS(renderer)->draw_polygon(renderer, poly, 4, fg_color);
1583 }
1584 
1585 /** Draw a rounded (half-circle) arrowhead.
1586  * @param renderer A renderer instance to draw into
1587  * @param to The point that the arrow points to.
1588  * @param from Where the arrow points from (e.g. end of stem)
1589  * @param length The length of the arrow
1590  * @param width The width of the arrow
1591  * @param linewidth The thickness of the lines used to draw the arrow.
1592  * @param fg_color The color used for drawing the arrowhead lines
1593  * @param bg_color Ignored.
1594  */
1595 static void
draw_rounded(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)1596 draw_rounded(DiaRenderer *renderer, Point *to, Point *from,
1597 	     real length, real width, real linewidth,
1598 	     Color *fg_color, Color *bg_color)
1599 {
1600   Point p = *to;
1601   Point delta;
1602   real len, rayon;
1603   real rapport;
1604   real angle_start;
1605 
1606   DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer, linewidth);
1607   DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
1608   DIA_RENDERER_GET_CLASS(renderer)->set_linejoin(renderer, LINEJOIN_MITER);
1609   DIA_RENDERER_GET_CLASS(renderer)->set_linecaps(renderer, LINECAPS_BUTT);
1610 
1611   delta = *from;
1612 
1613   point_sub(&delta, to);
1614 
1615   len = sqrt(point_dot(&delta, &delta)); /* line length */
1616   rayon = (length / 2.0);
1617   if (len > 0.0) {
1618     /* no length, no direction - but invalid coords */
1619     rapport = rayon / len;
1620 
1621     p.x += delta.x * rapport;
1622     p.y += delta.y * rapport;
1623   }
1624   angle_start = 90.0 - dia_asin((p.y - to->y) / rayon) * (180.0 / 3.14);
1625   if (p.x - to->x < 0) { angle_start = 360.0 - angle_start;  }
1626 
1627   DIA_RENDERER_GET_CLASS(renderer)->draw_arc(renderer, &p, width, length, angle_start, angle_start - 180.0, fg_color);
1628 
1629   if (len > 0.0) {
1630     p.x += delta.x * rapport;
1631     p.y += delta.y * rapport;
1632   }
1633   DIA_RENDERER_GET_CLASS(renderer)->draw_line(renderer, &p, to, fg_color);
1634 }
1635 
1636 /** Draw an open rounded arrowhead.
1637  * @param renderer A renderer instance to draw into
1638  * @param to The point that the arrow points to.
1639  * @param from Where the arrow points from (e.g. end of stem)
1640  * @param length The length of the arrow
1641  * @param width The width of the arrow
1642  * @param linewidth The thickness of the lines used to draw the arrow.
1643  * @param fg_color The color used for drawing the arrowhead lines
1644  * @param bg_color Ignored.
1645  * @todo Describe the arrowhead better.
1646  */
1647 static void
draw_open_rounded(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)1648 draw_open_rounded(DiaRenderer *renderer, Point *to, Point *from,
1649 		  real length, real width, real linewidth,
1650 		  Color *fg_color, Color *bg_color)
1651 {
1652   Point p = *to;
1653   Point delta;
1654   real len, rayon;
1655   real rapport;
1656   real angle_start;
1657   Point p_line;
1658 
1659   DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
1660   DIA_RENDERER_GET_CLASS(renderer)->set_linejoin(renderer, LINEJOIN_MITER);
1661   DIA_RENDERER_GET_CLASS(renderer)->set_linecaps(renderer, LINECAPS_BUTT);
1662 
1663   delta = *from;
1664 
1665   point_sub(&delta, to);
1666 
1667   len = sqrt(point_dot(&delta, &delta)); /* line length */
1668   rayon = (length / 2.0);
1669   if (len > 0.0) {
1670     /* no length, no direction - but invalid coords */
1671     rapport = rayon / len;
1672 
1673     p.x += delta.x * rapport;
1674     p.y += delta.y * rapport;
1675   }
1676   angle_start = 90.0 - dia_asin((p.y - to->y) / rayon) * (180.0 / 3.14);
1677   if (p.x - to->x < 0) { angle_start = 360.0 - angle_start;  }
1678 
1679   p_line = p;
1680   if (len > 0.0) {
1681     p_line.x += delta.x * rapport;
1682     p_line.y += delta.y * rapport;
1683   }
1684   /*
1685   DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer, linewidth * 2.0);
1686   DIA_RENDERER_GET_CLASS(renderer)->draw_line(renderer, &p_line, to, bg_color);
1687   */
1688   DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer, linewidth);
1689   DIA_RENDERER_GET_CLASS(renderer)->draw_arc(renderer, &p, width, length, angle_start - 180.0, angle_start, fg_color);
1690 }
1691 
1692 /** Draw an arrowhead with a circle in front of a triangle, filled.
1693  * @param renderer A renderer instance to draw into
1694  * @param to The point that the arrow points to.
1695  * @param from Where the arrow points from (e.g. end of stem)
1696  * @param length The length of the arrow
1697  * @param width The width of the arrow
1698  * @param linewidth The thickness of the lines used to draw the arrow.
1699  * @param fg_color The color used for drawing the arrowhead lines
1700  * @param bg_color Ignored.
1701  */
1702 static void
draw_filled_dot_n_triangle(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)1703 draw_filled_dot_n_triangle(DiaRenderer *renderer, Point *to, Point *from,
1704 			   real length, real width, real linewidth,
1705 			   Color *fg_color, Color *bg_color)
1706 {
1707   Point p_dot = *to, p_tri = *to, delta;
1708   real len, rayon;
1709   real rapport;
1710   Point poly[3];
1711 
1712   DIA_RENDERER_GET_CLASS(renderer)->set_linecaps(renderer, LINECAPS_BUTT);
1713   DIA_RENDERER_GET_CLASS(renderer)->set_linejoin(renderer, LINEJOIN_MITER);
1714   DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
1715   DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer, linewidth);
1716 
1717   delta = *from;
1718 
1719   point_sub(&delta, to);
1720 
1721   len = sqrt(point_dot(&delta, &delta)); /* line length */
1722 
1723   /* dot */
1724   rayon = (width / 2.0);
1725 
1726   if (len > 0.0) {
1727     /* no length, no direction - but invalid coords */
1728     rapport = rayon / len;
1729     p_dot.x += delta.x * rapport;
1730     p_dot.y += delta.y * rapport;
1731   }
1732   DIA_RENDERER_GET_CLASS(renderer)->fill_ellipse(renderer, &p_dot,
1733 						 width, width, fg_color);
1734   /* triangle */
1735   if (len > 0.0) {
1736     rapport = width / len;
1737     p_tri.x += delta.x * rapport;
1738     p_tri.y += delta.y * rapport;
1739   }
1740   calculate_arrow(poly, &p_tri, from, length, width);
1741   DIA_RENDERER_GET_CLASS(renderer)->fill_polygon(renderer, poly, 3, fg_color);
1742 }
1743 
1744 /** Draw an arrowhead that is simply three dots (ellipsis)
1745  * @param renderer A renderer instance to draw into
1746  * @param to The point that the arrow points to.
1747  * @param from Where the arrow points from (e.g. end of stem)
1748  * @param length The length of the arrow
1749  * @param width The width of the arrow
1750  * @param linewidth The thickness of the lines used to draw the arrow.
1751  * @param fg_color The color used for drawing the arrowhead lines
1752  */
1753 static void
draw_three_dots(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color)1754 draw_three_dots(DiaRenderer *renderer, Point *to, Point *from,
1755                real length, real width, real linewidth, Color *fg_color)
1756 {
1757 
1758   gdouble dot_width;
1759   gdouble hole_width;
1760   gdouble len;
1761   gint i;
1762   Point delta, dot_from, dot_to;
1763 
1764   delta = *to;
1765   point_sub(&delta, from);
1766   len = point_len(&delta);
1767   point_normalize(&delta);
1768 
1769   if (len > 4 * width)
1770     width *= 2;
1771   dot_width = width * 0.2;
1772   hole_width = width / 3 - dot_width;
1773 
1774   DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer, linewidth);
1775   DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID);
1776 
1777   for (i = 0; i < 3; i++) {
1778     dot_from.x = to->x - i  * (dot_width + hole_width) * delta.x;
1779     dot_from.y = to->y - i  * (dot_width + hole_width) * delta.y;
1780     dot_to.x = to->x - ((i + 1) * dot_width + i * hole_width) * delta.x;
1781     dot_to.y = to->y - ((i + 1) * dot_width + i * hole_width) * delta.y;
1782     DIA_RENDERER_GET_CLASS(renderer)->draw_line(renderer, &dot_from, &dot_to, fg_color);
1783   }
1784 }
1785 
1786 static void
draw_hollow_triangle(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)1787 draw_hollow_triangle (DiaRenderer *renderer, Point *to, Point *from,
1788 		      real length, real width, real linewidth,
1789 		      Color *fg_color, Color *bg_color)
1790 {
1791   fill_triangle(renderer, to, from, length, width, linewidth, NULL, bg_color);
1792   draw_triangle(renderer, to, from, length, width, linewidth, fg_color, NULL);
1793 }
1794 static void
draw_filled_triangle(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)1795 draw_filled_triangle (DiaRenderer *renderer, Point *to, Point *from,
1796 		      real length, real width, real linewidth,
1797 		      Color *fg_color, Color *bg_color)
1798 {
1799   fill_triangle(renderer, to, from, length, width, linewidth, NULL, fg_color);
1800   draw_triangle(renderer, to, from, length, width, linewidth, fg_color, NULL);
1801 }
1802 static void
draw_unfilled_triangle(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)1803 draw_unfilled_triangle (DiaRenderer *renderer, Point *to, Point *from,
1804 		        real length, real width, real linewidth,
1805 		        Color *fg_color, Color *bg_color)
1806 {
1807   draw_triangle(renderer, to, from, length, width, linewidth, fg_color, bg_color);
1808 }
1809 static void
draw_hollow_diamond(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)1810 draw_hollow_diamond (DiaRenderer *renderer, Point *to, Point *from,
1811 		     real length, real width, real linewidth,
1812 		     Color *fg_color, Color *bg_color)
1813 {
1814   fill_diamond(renderer, to, from, length, width, bg_color);
1815   draw_diamond(renderer, to, from, length, width, linewidth, fg_color);
1816 }
1817 static void
draw_filled_diamond(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)1818 draw_filled_diamond (DiaRenderer *renderer, Point *to, Point *from,
1819 		     real length, real width, real linewidth,
1820 		     Color *fg_color, Color *bg_color)
1821 {
1822   fill_diamond(renderer, to, from, length, width, fg_color);
1823   draw_diamond(renderer, to, from, length, width, linewidth, fg_color);
1824 }
1825 static void
draw_filled_ellipse(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)1826 draw_filled_ellipse (DiaRenderer *renderer, Point *to, Point *from,
1827 		     real length, real width, real linewidth,
1828 		     Color *fg_color, Color *bg_color)
1829 {
1830   draw_fill_ellipse(renderer,to,from,length,width,linewidth,fg_color,fg_color);
1831 }
1832 static void
draw_filled_dot(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)1833 draw_filled_dot (DiaRenderer *renderer, Point *to, Point *from,
1834 		 real length, real width, real linewidth,
1835 		 Color *fg_color, Color *bg_color)
1836 {
1837   draw_fill_dot(renderer,to,from,length,width,linewidth,fg_color,fg_color);
1838 }
1839 static void
draw_filled_box(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)1840 draw_filled_box (DiaRenderer *renderer, Point *to, Point *from,
1841 		 real length, real width, real linewidth,
1842 		 Color *fg_color, Color *bg_color)
1843 {
1844   draw_fill_box(renderer,to,from,length,width,linewidth,fg_color,fg_color);
1845 }
1846 static void
draw_filled_concave(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)1847 draw_filled_concave (DiaRenderer *renderer, Point *to, Point *from,
1848 		     real length, real width, real linewidth,
1849 		     Color *fg_color, Color *bg_color)
1850 {
1851   draw_concave_triangle(renderer, to, from, length, width, linewidth, fg_color, fg_color);
1852 }
1853 static int
calculate_double_triangle(Point * poly,const Point * to,const Point * from,real length,real width)1854 calculate_double_triangle (Point *poly, const Point *to, const Point *from,
1855                            real length, real width)
1856 {
1857   Point second_from, second_to;
1858 
1859   calculate_arrow (poly, to, from, length, width);
1860   calculate_double_arrow(&second_to, &second_from, to, from, length);
1861   calculate_arrow (poly+3, &second_to, &second_from, length, width);
1862   return 6;
1863 }
1864 static void
draw_double_hollow_triangle(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)1865 draw_double_hollow_triangle (DiaRenderer *renderer, Point *to, Point *from,
1866 		             real length, real width, real linewidth,
1867 		             Color *fg_color, Color *bg_color)
1868 {
1869   fill_double_triangle(renderer, to, from, length+(linewidth/2), width, linewidth, fg_color, bg_color);
1870   draw_double_triangle(renderer, to, from, length, width, linewidth, fg_color, bg_color);
1871 }
1872 static void
draw_double_filled_triangle(DiaRenderer * renderer,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)1873 draw_double_filled_triangle (DiaRenderer *renderer, Point *to, Point *from,
1874 		             real length, real width, real linewidth,
1875 		             Color *fg_color, Color *bg_color)
1876 {
1877   fill_double_triangle(renderer, to, from, length, width, linewidth, fg_color, fg_color);
1878 }
1879 struct ArrowDesc {
1880   const char *name;
1881   ArrowType enum_value;
1882   /* calculates the points for the arrow, their number is returned */
1883   int (*calculate) (Point *poly, /* variable size poly */
1884                     const Point *to, /* pointing to */
1885 		    const Point *from, /* coming from */
1886 		    real length, /* the arrows length */
1887 		    real width); /* the arrows width */
1888   /* draw the arrow, internally calculated with the respective calculate */
1889   void (*draw) (DiaRenderer *renderer,
1890                 Point *to,
1891 	        Point *from,
1892 	        real length,
1893 	        real width,
1894 	        real linewidth, /* the lines width also used in many arrows */
1895 	        Color *fg_color, /* the main drawin color */
1896 	        Color *bg_color); /* not always used */
1897 } arrow_types[] =
1898   {{N_("None"),ARROW_NONE},
1899    {N_("Lines"),ARROW_LINES, calculate_arrow, draw_lines},
1900    {N_("Hollow Triangle"), ARROW_HOLLOW_TRIANGLE, calculate_arrow, draw_hollow_triangle},
1901    {N_("Filled Triangle"), ARROW_FILLED_TRIANGLE, calculate_arrow, draw_filled_triangle},
1902    {N_("Unfilled Triangle"), ARROW_UNFILLED_TRIANGLE, calculate_arrow, draw_unfilled_triangle},
1903    {N_("Hollow Diamond"),ARROW_HOLLOW_DIAMOND, calculate_diamond, draw_hollow_diamond},
1904    {N_("Filled Diamond"),ARROW_FILLED_DIAMOND, calculate_diamond, draw_filled_diamond},
1905    {N_("Half Diamond"), ARROW_HALF_DIAMOND, calculate_diamond, draw_half_diamond},
1906    {N_("Half Head"), ARROW_HALF_HEAD, calculate_halfhead, draw_halfhead},
1907    {N_("Slashed Cross"), ARROW_SLASHED_CROSS, calculate_slashed_cross, draw_slashed_cross},
1908    {N_("Filled Ellipse"), ARROW_FILLED_ELLIPSE, calculate_ellipse, draw_filled_ellipse},
1909    {N_("Hollow Ellipse"), ARROW_HOLLOW_ELLIPSE, calculate_ellipse, draw_fill_ellipse},
1910    {N_("Filled Dot"), ARROW_FILLED_DOT, calculate_dot, draw_filled_dot},
1911    {N_("Dimension Origin"),ARROW_DIMENSION_ORIGIN},
1912    {N_("Blanked Dot"),ARROW_BLANKED_DOT, calculate_dot, draw_fill_dot},
1913    {N_("Double Hollow Triangle"),ARROW_DOUBLE_HOLLOW_TRIANGLE, calculate_double_triangle, draw_double_hollow_triangle},
1914    {N_("Double Filled Triangle"),ARROW_DOUBLE_FILLED_TRIANGLE, calculate_double_triangle, draw_double_filled_triangle},
1915    {N_("Filled Dot and Triangle"), ARROW_FILLED_DOT_N_TRIANGLE},
1916    {N_("Filled Box"), ARROW_FILLED_BOX, calculate_box, draw_filled_box},
1917    {N_("Blanked Box"),ARROW_BLANKED_BOX, calculate_box, draw_fill_box},
1918    {N_("Slashed"), ARROW_SLASH_ARROW, calculate_slashed, draw_slashed},
1919    {N_("Integral Symbol"),ARROW_INTEGRAL_SYMBOL},
1920    {N_("Crow Foot"), ARROW_CROW_FOOT, calculate_crow, draw_crow_foot},
1921    {N_("Cross"),ARROW_CROSS, calculate_arrow, draw_cross},
1922    {N_("1-or-many"),ARROW_ONE_OR_MANY},
1923    {N_("0-or-many"),ARROW_NONE_OR_MANY},
1924    {N_("1-or-0"),ARROW_ONE_OR_NONE},
1925    {N_("1 exactly"),ARROW_ONE_EXACTLY},
1926    {N_("Filled Concave"),ARROW_FILLED_CONCAVE, calculate_concave, draw_filled_concave},
1927    {N_("Blanked Concave"),ARROW_BLANKED_CONCAVE, calculate_concave, draw_concave_triangle},
1928    {N_("Round"), ARROW_ROUNDED},
1929    {N_("Open Round"), ARROW_OPEN_ROUNDED},
1930    {N_("Backslash"), ARROW_BACKSLASH, calculate_backslash, draw_backslash},
1931    {N_("Infinite Line"),ARROW_THREE_DOTS},
1932    {NULL,0}
1933 };
1934 
1935 /** following the signature pattern of lib/boundingbox.h
1936  * the arrow bounding box is added to the given rect
1937  * @param arrow the arrow
1938  * @param linewidth arrows use the same line width
1939  * @param to The point that the arrow points to.
1940  * @param from Where the arrow points from (e.g. end of stem)
1941  * @param rect the preintialized bounding box
1942  */
1943 void
arrow_bbox(const Arrow * arrow,real line_width,const Point * to,const Point * from,Rectangle * rect)1944 arrow_bbox (const Arrow *arrow, real line_width, const Point *to, const Point *from,
1945             Rectangle *rect)
1946 {
1947   Point poly[6]; /* Attention: nust be the maximum used! */
1948   PolyBBExtras pextra;
1949   int n_points = 0;
1950   int idx = arrow_index_from_type(arrow->type);
1951 
1952   if (ARROW_NONE == arrow->type)
1953     return; /* bbox not growing */
1954 
1955   /* some extra steps necessary for e.g circle shapes? */
1956   if (arrow_types[idx].calculate)
1957     n_points = arrow_types[idx].calculate (poly, to, from, arrow->length, arrow->width);
1958   else /* fallback, should vanish */
1959     n_points = calculate_arrow(poly, to, from, arrow->length, arrow->width);
1960   g_assert (n_points > 0 && n_points <= sizeof(poly)/sizeof(Point));
1961 
1962   pextra.start_trans = pextra.end_trans =
1963   pextra.start_long = pextra.end_long =
1964   pextra.middle_trans = line_width/2.0;
1965 
1966   polyline_bbox (poly, n_points, &pextra, TRUE, rect);
1967 }
1968 
1969 /** Draw any arrowhead.
1970  * @param renderer A renderer instance to draw into
1971  * @param type Which kind of arrowhead to draw.
1972  * @param to The point that the arrow points to.
1973  * @param from Where the arrow points from (e.g. end of stem)
1974  * @param length The length of the arrow
1975  * @param width The width of the arrow
1976  * @param linewidth The thickness of the lines used to draw the arrow.
1977  * @param fg_color The color used for drawing the arrowhead lines
1978  * @param bg_color The color used for drawing the arrowhead interior.
1979  */
1980 void
arrow_draw(DiaRenderer * renderer,ArrowType type,Point * to,Point * from,real length,real width,real linewidth,Color * fg_color,Color * bg_color)1981 arrow_draw(DiaRenderer *renderer, ArrowType type,
1982 	   Point *to, Point *from,
1983 	   real length, real width, real linewidth,
1984 	   Color *fg_color, Color *bg_color)
1985 {
1986   switch(type) {
1987   case ARROW_NONE:
1988     break;
1989   case ARROW_DIMENSION_ORIGIN:
1990     draw_fill_dot(renderer,to,from,length,width,linewidth,fg_color,NULL);
1991     break;
1992   case ARROW_INTEGRAL_SYMBOL:
1993     draw_integral(renderer,to,from,length,width,linewidth,fg_color);
1994     break;
1995   case ARROW_ONE_OR_MANY:
1996     draw_one_or_many(renderer,to,from,length,width,linewidth,fg_color,bg_color);
1997     break;
1998   case ARROW_NONE_OR_MANY:
1999     draw_none_or_many(renderer,to,from,length,width,linewidth,fg_color,bg_color);
2000     break;
2001   case ARROW_ONE_EXACTLY:
2002     draw_one_exactly(renderer,to,from,length,width,linewidth,fg_color,bg_color);
2003     break;
2004   case ARROW_ONE_OR_NONE:
2005     draw_one_or_none(renderer,to,from,length,width,linewidth,fg_color,bg_color);
2006     break;
2007   case ARROW_ROUNDED:
2008     draw_rounded(renderer, to, from, length, width, linewidth, fg_color, bg_color);
2009     break;
2010   case ARROW_OPEN_ROUNDED:
2011     draw_open_rounded(renderer, to, from, length, width, linewidth,
2012 		      fg_color, bg_color);
2013     break;
2014   case ARROW_FILLED_DOT_N_TRIANGLE:
2015     draw_filled_dot_n_triangle(renderer, to, from, length, width, linewidth,
2016 			       fg_color, bg_color);
2017     break;
2018   case ARROW_THREE_DOTS:
2019     draw_three_dots(renderer,to,from,length,width,linewidth,fg_color);
2020     break;
2021   case MAX_ARROW_TYPE:
2022     break;
2023   default :
2024     {
2025       int idx = arrow_index_from_type(type);
2026       g_return_if_fail (arrow_types[idx].draw != NULL);
2027       arrow_types[idx].draw (renderer,to,from,length,width,linewidth,fg_color,bg_color);
2028       break;
2029     }
2030   }
2031   if ((type != ARROW_NONE) && (render_bounding_boxes) && (renderer->is_interactive)) {
2032     Arrow arrow = {type, length, width};
2033     Rectangle bbox = {0, };
2034     Point p1, p2;
2035     Color col = {1.0, 0.0, 1.0};
2036 
2037     arrow_bbox (&arrow, linewidth, to, from, &bbox);
2038 
2039     p1.x = bbox.left;
2040     p1.y = bbox.top;
2041     p2.x = bbox.right;
2042     p2.y = bbox.bottom;
2043 
2044     DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer,0.01);
2045     DIA_RENDERER_GET_CLASS(renderer)->draw_rect(renderer, &p1, &p2, &col);
2046   }
2047 }
2048 
2049 /* *** Loading and saving arrows. *** */
2050 /** Makes sure an arrow object is within reasonable limits
2051  * @param arrow An arrow object.  This object may be modified to comply with
2052  * restrictions of MIN_ARROW_DIMENSION on its length and width and to have a
2053  * legal head type.
2054  */
2055 static void
sanitize_arrow(Arrow * arrow)2056 sanitize_arrow(Arrow *arrow)
2057 {
2058   if (arrow->type < 0 || arrow->type > MAX_ARROW_TYPE) {
2059     message_warning(_("Arrow head of unknown type"));
2060     arrow->type = ARROW_NONE;
2061     arrow->width = DEFAULT_ARROW_WIDTH;
2062     arrow->length = DEFAULT_ARROW_LENGTH;
2063   }
2064 
2065   if (arrow->length < MIN_ARROW_DIMENSION ||
2066       arrow->width < MIN_ARROW_DIMENSION) {
2067     message_warning(_("Arrow head of type %s has too small dimensions, removing.\n"),
2068 		    arrow_get_name_from_type(arrow->type));
2069     arrow->type = ARROW_NONE;
2070     arrow->width = DEFAULT_ARROW_WIDTH;
2071     arrow->length = DEFAULT_ARROW_LENGTH;
2072   }
2073 }
2074 
2075 /** Save the arrow information into three attributes.
2076  * @param obj_node The XML node to save to.
2077  * @param arrow the arrow to save.
2078  * @param type_attribute the name of the attribute of the arrow type.
2079  * @param length_attribute the name of the attribute of the arrow length.
2080  * @param width_attribute the name of the attribte of the arrow width.
2081  */
2082 void
save_arrow(ObjectNode obj_node,Arrow * arrow,gchar * type_attribute,gchar * length_attribute,gchar * width_attribute)2083 save_arrow(ObjectNode obj_node, Arrow *arrow, gchar *type_attribute,
2084 	   gchar *length_attribute, gchar *width_attribute)
2085 {
2086   data_add_enum(new_attribute(obj_node, type_attribute),
2087 		arrow->type);
2088   data_add_real(new_attribute(obj_node, length_attribute),
2089 		arrow->length);
2090   data_add_real(new_attribute(obj_node, width_attribute),
2091 		arrow->width);
2092 }
2093 
2094 /** Load arrow information from three attributes.
2095  * @param obj_node The XML node to load from.
2096  * @param arrow the arrow to store the data info.
2097  * @param type_attribute the name of the attribute of the arrow type.
2098  * @param length_attribute the name of the attribute of the arrow length.
2099  * @param width_attribute the name of the attribte of the arrow width.
2100  */
2101 void
load_arrow(ObjectNode obj_node,Arrow * arrow,gchar * type_attribute,gchar * length_attribute,gchar * width_attribute)2102 load_arrow(ObjectNode obj_node, Arrow *arrow, gchar *type_attribute,
2103 	   gchar *length_attribute, gchar *width_attribute)
2104 {
2105   AttributeNode attr;
2106 
2107   arrow->type = ARROW_NONE;
2108   arrow->length = DEFAULT_ARROW_LENGTH;
2109   arrow->width = DEFAULT_ARROW_WIDTH;
2110   attr = object_find_attribute(obj_node, type_attribute);
2111   if (attr != NULL)
2112     arrow->type = data_enum(attribute_first_data(attr));
2113   attr = object_find_attribute(obj_node, length_attribute);
2114   if (attr != NULL)
2115     arrow->length = data_real(attribute_first_data(attr));
2116   attr = object_find_attribute(obj_node, width_attribute);
2117   if (attr != NULL)
2118     arrow->width = data_real(attribute_first_data(attr));
2119 
2120   sanitize_arrow(arrow);
2121 }
2122 
2123 /** Returns the arrow type that corresponds to a given name.
2124  * @param name The name of an arrow type (case sensitive)
2125  * @returns The arrow type (@see ArrowType enum in arrows.h).  Returns
2126  *          ARROW_NONE if the name doesn't match any known arrow head type.
2127  */
2128 ArrowType
arrow_type_from_name(const gchar * name)2129 arrow_type_from_name(const gchar *name)
2130 {
2131   int i;
2132   for (i = 0; arrow_types[i].name != NULL; i++) {
2133     if (!strcmp(arrow_types[i].name, name)) {
2134       return arrow_types[i].enum_value;
2135     }
2136   }
2137   printf("Unknown arrow type %s\n", name);
2138   return 0;
2139 }
2140 
2141 /** Return the index into the arrow_types array (which is sorted by an
2142  * arbitrary order that we like) for a given arrow type.
2143  * @param atype An arrow type as defined in arrows.h
2144  * @returns An index into the arrow_types array.
2145  */
2146 gint
arrow_index_from_type(ArrowType atype)2147 arrow_index_from_type(ArrowType atype)
2148 {
2149   int i = 0;
2150 
2151   for (i = 0; arrow_types[i].name != NULL; i++) {
2152     if (arrow_types[i].enum_value == atype) {
2153       return i;
2154     }
2155   }
2156   printf("Can't find arrow index for type %d\n", atype);
2157   return 0;
2158 }
2159 
2160 /**
2161  * Return the arrow type for a given arrow index (preferred sorting)
2162  */
2163 ArrowType
arrow_type_from_index(gint index)2164 arrow_type_from_index (gint index)
2165 {
2166   if (index >= 0 && index < MAX_ARROW_TYPE) {
2167     return arrow_types[index].enum_value;
2168   }
2169   return MAX_ARROW_TYPE;
2170 }
2171 
2172 /** Get a list of all known arrow head names, in arrow_types order.
2173  * @returns A newly allocated list of the names.  The list should be
2174  *          freed after use, but the strings are owned by arrow_types.
2175  */
2176 GList *
get_arrow_names(void)2177 get_arrow_names(void)
2178 {
2179   int i = 0;
2180   GList *arrows = NULL;
2181 
2182   for (i = 0; arrow_types[i].name != NULL; i++) {
2183     arrows = g_list_append(arrows, (char*)arrow_types[i].name);
2184   }
2185   return arrows;
2186 }
2187 
2188 /** Get the name of an arrow from its type.
2189  * @param type A type of arrow.
2190  * @returns The name of the type, if any such arrow type is defined,
2191  * or else "unknown arrow".  This is a static string and should not be
2192  * freed or modified.
2193  */
2194 const gchar *
arrow_get_name_from_type(ArrowType type)2195 arrow_get_name_from_type(ArrowType type)
2196 {
2197   if (type >= 0 && type < MAX_ARROW_TYPE) {
2198     return arrow_types[arrow_index_from_type(type)].name;
2199   }
2200   return _("unknown arrow");
2201 }
2202