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