UML class fix bigtime.
[dia.git] / lib / render.c
blobf93d1c722ed59371203c388cf5a6d827fc8dae9f
1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 2002 Lars Clausen
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.
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.
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.
19 /* This file defines the abstract superclass for renderers. It defines
20 * a bunch of functions to render higher-level structures with lower-level
21 * primitives.
24 #include "config.h"
26 #include "render.h"
28 static void begin_render(Renderer *renderer);
29 static void end_render(Renderer *renderer);
30 static void set_linewidth(Renderer *renderer, real linewidth);
31 static void set_linecaps(Renderer *renderer, LineCaps mode);
32 static void set_linejoin(Renderer *renderer, LineJoin mode);
33 static void set_linestyle(Renderer *renderer, LineStyle mode);
34 static void set_dashlength(Renderer *renderer, real length);
35 static void set_fillstyle(Renderer *renderer, FillStyle mode);
36 static void set_font(Renderer *renderer, DiaFont *font, real height);
37 static void draw_line(Renderer *renderer,
38 Point *start, Point *end,
39 Color *line_color);
40 static void draw_polyline(Renderer *renderer,
41 Point *points, int num_points,
42 Color *line_color);
43 static void draw_polygon(Renderer *renderer,
44 Point *points, int num_points,
45 Color *line_color);
46 static void fill_polygon(Renderer *renderer,
47 Point *points, int num_points,
48 Color *line_color);
49 static void draw_rect(Renderer *renderer,
50 Point *ul_corner, Point *lr_corner,
51 Color *color);
52 static void fill_rect(Renderer *renderer,
53 Point *ul_corner, Point *lr_corner,
54 Color *color);
55 static void draw_arc(Renderer *renderer,
56 Point *center,
57 real width, real height,
58 real angle1, real angle2,
59 Color *color);
60 static void fill_arc(Renderer *renderer,
61 Point *center,
62 real width, real height,
63 real angle1, real angle2,
64 Color *color);
65 static void draw_ellipse(Renderer *renderer,
66 Point *center,
67 real width, real height,
68 Color *color);
69 static void fill_ellipse(Renderer *renderer,
70 Point *center,
71 real width, real height,
72 Color *color);
73 static void draw_bezier(Renderer *renderer,
74 BezPoint *points,
75 int numpoints,
76 Color *color);
77 static void fill_bezier(Renderer *renderer,
78 BezPoint *points, /* Last point must be same as first point */
79 int numpoints,
80 Color *color);
81 static void draw_string(Renderer *renderer,
82 const gchar *text,
83 Point *pos, Alignment alignment,
84 Color *color);
85 static void draw_image(Renderer *renderer,
86 Point *point,
87 real width, real height,
88 DiaImage image);
89 static void draw_rounded_rect(Renderer *renderer,
90 Point *ul_corner, Point *lr_corner,
91 Color *color, real rounding);
92 static void fill_rounded_rect(Renderer *renderer,
93 Point *ul_corner, Point *lr_corner,
94 Color *color, real rounding);
95 static void draw_line_with_arrows(Renderer *renderer,
96 Point *start, Point *end,
97 real line_width,
98 Color *line_color,
99 Arrow *start_arrow,
100 Arrow *end_arrow);
101 static void draw_polyline_with_arrows(Renderer *renderer,
102 Point *points, int n_points,
103 real line_width,
104 Color *line_color,
105 Arrow *start_arrow,
106 Arrow *end_arrow);
107 static void draw_arc_with_arrows(Renderer *renderer,
108 Point *start, Point *end,
109 Point *midpoint,
110 real line_width,
111 Color *color,
112 Arrow *start_arrow,
113 Arrow *end_arrow);
114 static void draw_bezier_with_arrows(Renderer *renderer,
115 BezPoint *points,
116 int num_points,
117 real line_width,
118 Color *color,
119 Arrow *start_arrow,
120 Arrow *end_arrow);
121 static void draw_object(Renderer *renderer,
122 DiaObject *object);
124 static RenderOps AbstractRenderOps = {
125 begin_render,
126 end_render,
128 /* Line attributes: */
129 set_linewidth,
130 set_linecaps,
131 set_linejoin,
132 set_linestyle,
133 set_dashlength,
134 /* Fill attributes: */
135 set_fillstyle,
136 /* DiaFont stuff: */
137 set_font,
139 /* Lines: */
140 draw_line,
141 draw_polyline,
143 /* Polygons: */
144 draw_polygon,
145 fill_polygon,
147 /* Rectangles: */
148 draw_rect,
149 fill_rect,
151 /* Arcs: */
152 draw_arc,
153 fill_arc,
155 /* Ellipses: */
156 draw_ellipse,
157 fill_ellipse,
159 /* Bezier curves: */
160 draw_bezier,
161 fill_bezier,
163 /* Text: */
164 draw_string,
166 /* Images: */
167 draw_image,
169 /* Later additions, down here for binary combatability */
170 draw_rounded_rect,
171 fill_rounded_rect,
173 /* placeholders */
174 draw_line_with_arrows, /* DrawLineWithArrowsFunc */
175 draw_polyline_with_arrows, /* DrawPolyLineWithArrowsFunc */
176 draw_arc_with_arrows, /* DrawArcWithArrowsFunc */
177 draw_bezier_with_arrows,
179 draw_object,
182 static void begin_render(Renderer *renderer){}
183 static void end_render(Renderer *renderer){}
184 static void set_linewidth(Renderer *renderer, real linewidth){}
185 static void set_linecaps(Renderer *renderer, LineCaps mode){}
186 static void set_linejoin(Renderer *renderer, LineJoin mode){}
187 static void set_linestyle(Renderer *renderer, LineStyle mode){}
188 static void set_dashlength(Renderer *renderer, real length){}
189 static void set_fillstyle(Renderer *renderer, FillStyle mode){}
190 static void set_font(Renderer *renderer, DiaFont *font, real height){}
191 static void draw_line(Renderer *renderer,
192 Point *start, Point *end,
193 Color *line_color){}
196 RenderOps * create_renderops_table(void) {
197 RenderOps *table = g_new(RenderOps, 1);
198 *table = AbstractRenderOps;
199 return table;
202 /* Interim draw_polyline. Doesn't draw nice corners. */
203 static void draw_polyline(Renderer *renderer,
204 Point *points, int num_points,
205 Color *line_color) {
206 int i;
207 for (i = 0; i < num_points-1; i++) {
208 renderer->ops->draw_line(renderer, &points[i], &points[i+1], line_color);
211 /* Interim draw_polyline. Doesn't draw nice corners. */
212 static void draw_polygon(Renderer *renderer,
213 Point *points, int num_points,
214 Color *line_color) {
215 int i;
216 for (i = 0; i < num_points-1; i++) {
217 renderer->ops->draw_line(renderer, &points[i], &points[i+1], line_color);
219 renderer->ops->draw_line(renderer, &points[i], &points[0], line_color);
221 static void fill_polygon(Renderer *renderer,
222 Point *points, int num_points,
223 Color *line_color){}
224 /* Simple draw_rect. Draws, but loses info about rectangularity. */
225 static void draw_rect(Renderer *renderer,
226 Point *ul_corner, Point *lr_corner,
227 Color *color) {
228 Point ur_corner, ll_corner;
229 ur_corner.x = lr_corner->x;
230 ur_corner.y = ul_corner->y;
231 ur_corner.x = ul_corner->x;
232 ur_corner.y = lr_corner->y;
233 renderer->ops->draw_line(renderer, ul_corner, &ur_corner, color);
234 renderer->ops->draw_line(renderer, &ur_corner, lr_corner, color);
235 renderer->ops->draw_line(renderer, lr_corner, &ll_corner, color);
236 renderer->ops->draw_line(renderer, &ll_corner, ul_corner, color);
238 static void fill_rect(Renderer *renderer,
239 Point *ul_corner, Point *lr_corner,
240 Color *color){}
241 static void draw_arc(Renderer *renderer,
242 Point *center,
243 real width, real height,
244 real angle1, real angle2,
245 Color *color){}
246 static void fill_arc(Renderer *renderer,
247 Point *center,
248 real width, real height,
249 real angle1, real angle2,
250 Color *color){}
251 static void draw_ellipse(Renderer *renderer,
252 Point *center,
253 real width, real height,
254 Color *color){}
255 static void fill_ellipse(Renderer *renderer,
256 Point *center,
257 real width, real height,
258 Color *color){}
259 static void draw_bezier(Renderer *renderer,
260 BezPoint *points,
261 int numpoints,
262 Color *color){}
263 static void fill_bezier(Renderer *renderer,
264 BezPoint *points, /* Last point must be same as first point */
265 int numpoints,
266 Color *color){}
267 static void draw_string(Renderer *renderer,
268 const gchar *text,
269 Point *pos, Alignment alignment,
270 Color *color){}
271 static void draw_image(Renderer *renderer,
272 Point *point,
273 real width, real height,
274 DiaImage image){}
275 static void draw_rounded_rect(Renderer *renderer,
276 Point *ul_corner, Point *lr_corner,
277 Color *color, real radius) {
278 Point start, end, center;
280 radius = MIN(radius, (lr_corner->x-ul_corner->x)/2);
281 radius = MIN(radius, (lr_corner->y-ul_corner->y)/2);
282 start.x = center.x = ul_corner->x+radius;
283 end.x = lr_corner->x-radius;
284 start.y = end.y = ul_corner->y;
285 renderer->ops->draw_line(renderer, &start, &end, color);
286 start.y = end.y = lr_corner->y;
287 renderer->ops->draw_line(renderer, &start, &end, color);
289 center.y = ul_corner->y+radius;
290 renderer->ops->draw_arc(renderer, &center,
291 2.0*radius, 2.0*radius,
292 90.0, 180.0, color);
293 center.x = end.x;
294 renderer->ops->draw_arc(renderer, &center,
295 2.0*radius, 2.0*radius,
296 0.0, 90.0, color);
298 start.y = ul_corner->y+radius;
299 start.x = end.x = ul_corner->x;
300 end.y = center.y = lr_corner->y-radius;
301 renderer->ops->draw_line(renderer, &start, &end, color);
302 start.x = end.x = lr_corner->x;
303 renderer->ops->draw_line(renderer, &start, &end, color);
305 center.y = lr_corner->y-radius;
306 center.x = ul_corner->x+radius;
307 renderer->ops->draw_arc(renderer, &center,
308 2.0*radius, 2.0*radius,
309 180.0, 270.0, color);
310 center.x = lr_corner->x-radius;
311 renderer->ops->draw_arc(renderer, &center,
312 2.0*radius, 2.0*radius,
313 270.0, 360.0, color);
315 static void fill_rounded_rect(Renderer *renderer,
316 Point *ul_corner, Point *lr_corner,
317 Color *color, real radius) {
318 Point start, end, center;
320 radius = MIN(radius, (lr_corner->x-ul_corner->x)/2);
321 radius = MIN(radius, (lr_corner->y-ul_corner->y)/2);
322 start.x = center.x = ul_corner->x+radius;
323 end.x = lr_corner->x-radius;
324 start.y = ul_corner->y;
325 end.y = lr_corner->y;
326 renderer->ops->fill_rect(renderer, &start, &end, color);
328 center.y = ul_corner->y+radius;
329 renderer->ops->fill_arc(renderer, &center,
330 2.0*radius, 2.0*radius,
331 90.0, 180.0, color);
332 center.x = end.x;
333 renderer->ops->fill_arc(renderer, &center,
334 2.0*radius, 2.0*radius,
335 0.0, 90.0, color);
337 start.x = ul_corner->x;
338 start.y = ul_corner->y+radius;
339 end.x = lr_corner->x;
340 end.y = center.y = lr_corner->y-radius;
341 renderer->ops->fill_rect(renderer, &start, &end, color);
343 center.y = lr_corner->y-radius;
344 center.x = ul_corner->x+radius;
345 renderer->ops->fill_arc(renderer, &center,
346 2.0*radius, 2.0*radius,
347 180.0, 270.0, color);
348 center.x = lr_corner->x-radius;
349 renderer->ops->fill_arc(renderer, &center,
350 2.0*radius, 2.0*radius,
351 270.0, 360.0, color);
354 static void
355 draw_line_with_arrows(Renderer *renderer,
356 Point *startpoint,
357 Point *endpoint,
358 real line_width,
359 Color *color,
360 Arrow *start_arrow,
361 Arrow *end_arrow)
363 Point oldstart = *startpoint;
364 Point oldend = *endpoint;
365 if (start_arrow != NULL && start_arrow->type != ARROW_NONE) {
366 Point move_arrow, move_line;
367 Point arrow_head;
368 calculate_arrow_point(start_arrow, startpoint, endpoint,
369 &move_arrow, &move_line,
370 line_width);
371 arrow_head = *startpoint;
372 point_sub(&arrow_head, &move_arrow);
373 point_sub(startpoint, &move_line);
374 arrow_draw(renderer, start_arrow->type,
375 &arrow_head, endpoint,
376 start_arrow->length, start_arrow->width,
377 line_width,
378 color, &color_white);
379 #ifdef STEM
380 Point line_start = startpoint;
381 startpoint = arrow_head;
382 point_normalize(&move);
383 point_scale(&move, start_arrow->length);
384 point_sub(startpoint, &move);
385 renderer->ops->draw_line(renderer, &line_start, startpoint, color);
386 #endif
388 if (end_arrow != NULL && end_arrow->type != ARROW_NONE) {
389 Point move_arrow, move_line;
390 Point arrow_head;
391 calculate_arrow_point(end_arrow, endpoint, startpoint,
392 &move_arrow, &move_line,
393 line_width);
394 arrow_head = *endpoint;
395 point_sub(&arrow_head, &move_arrow);
396 point_sub(endpoint, &move_line);
397 arrow_draw(renderer, end_arrow->type,
398 &arrow_head, startpoint,
399 end_arrow->length, end_arrow->width,
400 line_width,
401 color, &color_white);
402 #ifdef STEM
403 Point line_start = endpoint;
404 endpoint = arrow_head;
405 point_normalize(&move);
406 point_scale(&move, end_arrow->length);
407 point_sub(endpoint, &move);
408 renderer->ops->draw_line(renderer, &line_start, endpoint, color);
409 #endif
411 renderer->ops->draw_line(renderer, startpoint, endpoint, color);
413 *startpoint = oldstart;
414 *endpoint = oldend;
417 static void
418 draw_polyline_with_arrows(Renderer *renderer,
419 Point *points, int num_points,
420 real line_width,
421 Color *color,
422 Arrow *start_arrow,
423 Arrow *end_arrow)
425 /* Index of first and last point with a non-zero length segment */
426 int firstline = 0;
427 int lastline = num_points;
428 Point oldstart = points[firstline];
429 Point oldend = points[lastline-1];
431 if (start_arrow != NULL && start_arrow->type != ARROW_NONE) {
432 Point move_arrow, move_line;
433 Point arrow_head;
434 while (firstline < num_points-1 &&
435 distance_point_point(&points[firstline],
436 &points[firstline+1]) < 0.0000001)
437 firstline++;
438 if (firstline == num_points-1)
439 firstline = 0; /* No non-zero lines, it doesn't matter. */
440 oldstart = points[firstline];
441 calculate_arrow_point(start_arrow,
442 &points[firstline], &points[firstline+1],
443 &move_arrow, &move_line,
444 line_width);
445 arrow_head = points[firstline];
446 point_sub(&arrow_head, &move_arrow);
447 point_sub(&points[firstline], &move_line);
448 arrow_draw(renderer, start_arrow->type,
449 &arrow_head, &points[firstline+1],
450 start_arrow->length, start_arrow->width,
451 line_width,
452 color, &color_white);
453 #ifdef STEM
454 Point line_start = &points[firstline];
455 &points[firstline] = arrow_head;
456 point_normalize(&move);
457 point_scale(&move, start_arrow->length);
458 point_sub(&points[firstline], &move);
459 renderer->ops->draw_line(renderer, &line_start, &points[firstline], color);
460 #endif
462 if (end_arrow != NULL && end_arrow->type != ARROW_NONE) {
463 Point move_arrow, move_line;
464 Point arrow_head;
465 while (lastline > 0 &&
466 distance_point_point(&points[lastline-1],
467 &points[lastline-2]) < 0.0000001)
468 lastline--;
469 if (lastline == 0)
470 firstline = num_points; /* No non-zero lines, it doesn't matter. */
471 oldend = points[lastline-1];
472 calculate_arrow_point(end_arrow, &points[lastline-1],
473 &points[lastline-2],
474 &move_arrow, &move_line,
475 line_width);
476 arrow_head = points[lastline-1];
477 point_sub(&arrow_head, &move_arrow);
478 point_sub(&points[lastline-1], &move_line);
479 arrow_draw(renderer, end_arrow->type,
480 &arrow_head, &points[lastline-2],
481 end_arrow->length, end_arrow->width,
482 line_width,
483 color, &color_white);
484 #ifdef STEM
485 Point line_start = &points[lastline-1];
486 &points[lastline-1] = arrow_head;
487 point_normalize(&move);
488 point_scale(&move, end_arrow->length);
489 point_sub(&points[lastline-1], &move);
490 renderer->ops->draw_line(renderer, &line_start, &points[lastline-1], color);
491 #endif
493 /* Don't draw degenerate line segments at end of line */
494 renderer->ops->draw_polyline(renderer, &points[firstline],
495 lastline-firstline, color);
497 points[firstline] = oldstart;
498 points[lastline-1] = oldend;
501 /** Figure the equation for a line given by two points.
502 * Returns FALSE if the line is vertical (infinite a).
504 static gboolean
505 points_to_line(real *a, real *b, Point *p1, Point *p2)
507 if (fabs(p1->x - p2->x) < 0.000000001)
508 return FALSE;
509 *a = (p2->y-p1->y)/(p2->x-p1->x);
510 *b = p1->y-(*a)*p1->x;
511 return TRUE;
514 /** Find the intersection between two lines.
515 * Returns TRUE if the lines intersect in a single point.
517 static gboolean
518 intersection_line_line(Point *cross,
519 Point *p1a, Point *p1b,
520 Point *p2a, Point *p2b)
522 real a1, b1, a2, b2;
524 /* Find coefficients of lines */
525 if (!(points_to_line(&a1, &b1, p1a, p1b))) {
526 if (!(points_to_line(&a2, &b2, p2a, p2b))) {
527 if (fabs(p1a->x-p2a->x) < 0.00000001) {
528 *cross = *p1a;
529 return TRUE;
530 } else return FALSE;
532 cross->x = p1a->x;
533 cross->y = a2*(p1a->x)+b2;
534 return TRUE;
536 if (!(points_to_line(&a2, &b2, p2a, p2b))) {
537 cross->x = p2a->x;
538 cross->y = a1*(p2a->x)+b1;
539 return TRUE;
541 /* Solve */
542 if (fabs(a1-a2) < 0.000000001) {
543 if (fabs(b1-b2) < 0.000000001) {
544 *cross = *p1a;
545 return TRUE;
546 } else {
547 return FALSE;
549 } else {
551 a1x+b1 = a2x+b2;
552 a1x = a2x+b2-b1;
553 a1x-a2x = b2-b1;
554 (a1-a2)x = b2-b1;
555 x = (b2-b1)/(a1-a2)
557 cross->x = (b2-b1)/(a1-a2);
558 cross->y = a1*cross->x+b1;
559 return TRUE;
563 /** Given three points, find the center of the circle they describe.
564 * Returns FALSE if the center could not be determined (i.e. the points
565 * all lie really close together).
566 * The renderer should disappear once the debugging is done.
568 static gboolean
569 find_center_point(Point *center, Point *p1, Point *p2, Point *p3)
571 Point mid1;
572 Point mid2;
573 Point orth1;
574 Point orth2;
575 real tmp;
577 /* Find vector from middle between two points towards center */
578 mid1 = *p1;
579 point_sub(&mid1, p2);
580 point_scale(&mid1, 0.5);
581 orth1 = mid1;
582 point_add(&mid1, p2); /* Now midpoint between p1 & p2 */
583 tmp = orth1.x;
584 orth1.x = orth1.y;
585 orth1.y = -tmp;
586 point_add(&orth1, &mid1);
588 /* Again, with two other points */
589 mid2 = *p2;
590 point_sub(&mid2, p3);
591 point_scale(&mid2, 0.5);
592 orth2 = mid2;
593 point_add(&mid2, p3); /* Now midpoint between p2 & p3 */
594 tmp = orth2.x;
595 orth2.x = orth2.y;
596 orth2.y = -tmp;
597 point_add(&orth2, &mid2);
599 /* The intersection between these two is the center */
600 if (!intersection_line_line(center, &mid1, &orth1, &mid2, &orth2)) {
601 /* Degenerate circle */
602 /* Either the points are really close together, or directly apart */
603 if (fabs((p1->x + p2->x + p3->x)/3 - p1->x) < 0.0000001 &&
604 fabs((p1->y + p2->y + p3->y)/3 - p1->y) < 0.0000001)
605 return FALSE;
607 return TRUE;
609 return TRUE;
612 static real point_cross(Point *p1, Point *p2)
614 return p1->x*p2->y-p2->x*p1->y;
617 static void
618 draw_arc_with_arrows(Renderer *renderer,
619 Point *startpoint,
620 Point *endpoint,
621 Point *midpoint,
622 real line_width,
623 Color *color,
624 Arrow *start_arrow,
625 Arrow *end_arrow)
627 Point oldstart = *startpoint;
628 Point oldend = *endpoint;
629 Point center;
630 real width, angle1, angle2;
631 Point dot1, dot2;
632 gboolean righthand;
634 if (!find_center_point(&center, startpoint, endpoint, midpoint)) {
635 /* Degenerate circle -- should have been caught by the drawer? */
638 dot1 = *startpoint;
639 point_sub(&dot1, endpoint);
640 point_normalize(&dot1);
641 dot2 = *midpoint;
642 point_sub(&dot2, endpoint);
643 point_normalize(&dot2);
644 righthand = point_cross(&dot1, &dot2) > 0;
646 if (start_arrow != NULL && start_arrow->type != ARROW_NONE) {
647 Point move_arrow, move_line;
648 Point arrow_head;
649 Point arrow_end;
650 real tmp;
652 arrow_end = *startpoint;
653 point_sub(&arrow_end, &center);
654 tmp = arrow_end.x;
655 if (righthand) {
656 arrow_end.x = -arrow_end.y;
657 arrow_end.y = tmp;
658 } else {
659 arrow_end.x = arrow_end.y;
660 arrow_end.y = -tmp;
662 point_add(&arrow_end, startpoint);
664 calculate_arrow_point(start_arrow, startpoint, &arrow_end,
665 &move_arrow, &move_line,
666 line_width);
667 arrow_head = *startpoint;
668 point_sub(&arrow_head, &move_arrow);
669 point_sub(startpoint, &move_line);
670 arrow_draw(renderer, start_arrow->type,
671 &arrow_head, &arrow_end,
672 start_arrow->length, start_arrow->width,
673 line_width,
674 color, &color_white);
675 #ifdef STEM
676 Point line_start = startpoint;
677 startpoint = arrow_head;
678 point_normalize(&move);
679 point_scale(&move, start_arrow->length);
680 point_sub(startpoint, &move);
681 renderer->ops->draw_line(renderer, &line_start, startpoint, color);
682 #endif
684 if (end_arrow != NULL && end_arrow->type != ARROW_NONE) {
685 Point move_arrow, move_line;
686 Point arrow_head;
687 Point arrow_end;
688 real tmp;
690 arrow_end = *endpoint;
691 point_sub(&arrow_end, &center);
692 tmp = arrow_end.x;
693 if (righthand) {
694 arrow_end.x = arrow_end.y;
695 arrow_end.y = -tmp;
696 } else {
697 arrow_end.x = -arrow_end.y;
698 arrow_end.y = tmp;
700 point_add(&arrow_end, endpoint);
702 calculate_arrow_point(end_arrow, endpoint, &arrow_end,
703 &move_arrow, &move_line,
704 line_width);
705 arrow_head = *endpoint;
706 point_sub(&arrow_head, &move_arrow);
707 point_sub(endpoint, &move_line);
708 arrow_draw(renderer, end_arrow->type,
709 &arrow_head, &arrow_end,
710 end_arrow->length, end_arrow->width,
711 line_width,
712 color, &color_white);
713 #ifdef STEM
714 Point line_start = endpoint;
715 endpoint = arrow_head;
716 point_normalize(&move);
717 point_scale(&move, end_arrow->length);
718 point_sub(endpoint, &move);
719 renderer->ops->draw_line(renderer, &line_start, endpoint, color);
720 #endif
723 if (!find_center_point(&center, startpoint, endpoint, midpoint)) {
724 /* Not sure what to do here */
725 *startpoint = oldstart;
726 *endpoint = oldend;
727 return;
729 width = 2*distance_point_point(&center, startpoint);
730 angle1 = -atan2(startpoint->y-center.y, startpoint->x-center.x)*180.0/M_PI;
731 while (angle1 < 0.0) angle1 += 360.0;
732 angle2 = -atan2(endpoint->y-center.y, endpoint->x-center.x)*180.0/M_PI;
733 while (angle2 < 0.0) angle2 += 360.0;
734 if (righthand) {
735 real tmp = angle1;
736 angle1 = angle2;
737 angle2 = tmp;
739 renderer->ops->draw_arc(renderer, &center, width, width,
740 angle1, angle2, color);
742 *startpoint = oldstart;
743 *endpoint = oldend;
746 static void
747 draw_bezier_with_arrows(Renderer *renderer,
748 BezPoint *points,
749 int num_points,
750 real line_width,
751 Color *color,
752 Arrow *start_arrow,
753 Arrow *end_arrow)
755 Point startpoint, endpoint;
757 startpoint = points[0].p1;
758 endpoint = points[num_points-1].p3;
760 if (start_arrow != NULL && start_arrow->type != ARROW_NONE) {
761 Point move_arrow;
762 Point move_line;
763 Point arrow_head;
764 calculate_arrow_point(start_arrow, &points[0].p1, &points[1].p1,
765 &move_arrow, &move_line,
766 line_width);
767 arrow_head = points[0].p1;
768 point_sub(&arrow_head, &move_arrow);
769 point_sub(&points[0].p1, &move_line);
770 arrow_draw(renderer, start_arrow->type,
771 &arrow_head, &points[1].p1,
772 start_arrow->length, start_arrow->width,
773 line_width,
774 color, &color_white);
775 if (0) {
776 Point line_start = points[0].p1;
777 points[0].p1 = arrow_head;
778 point_normalize(&move_arrow);
779 point_scale(&move_arrow, start_arrow->length);
780 point_sub(&points[0].p1, &move_arrow);
781 renderer->ops->draw_line(renderer, &line_start, &points[0].p1, color);
784 if (end_arrow != NULL && end_arrow->type != ARROW_NONE) {
785 Point move_arrow;
786 Point move_line;
787 Point arrow_head;
788 calculate_arrow_point(end_arrow,
789 &points[num_points-1].p3, &points[num_points-1].p2,
790 &move_arrow, &move_line,
791 line_width);
792 arrow_head = points[num_points-1].p3;
793 point_sub(&arrow_head, &move_arrow);
794 point_sub(&points[num_points-1].p3, &move_line);
795 arrow_draw(renderer, end_arrow->type,
796 &arrow_head, &points[num_points-1].p2,
797 end_arrow->length, end_arrow->width,
798 line_width,
799 color, &color_white);
800 if (0) {
801 Point line_start = points[num_points-1].p3;
802 points[num_points-1].p3 = arrow_head;
803 point_normalize(&move_arrow);
804 point_scale(&move_arrow, end_arrow->length);
805 point_sub(&points[num_points-1].p3, &move_arrow);
806 renderer->ops->draw_line(renderer, &line_start, &points[num_points-1].p3, color);
809 renderer->ops->draw_bezier(renderer, points, num_points, color);
811 points[0].p1 = startpoint;
812 points[num_points-1].p3 = endpoint;
816 static void
817 draw_object(Renderer *renderer,
818 DiaObject *object) {
819 object->ops->draw(object, renderer);