1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
4 * diarenderer.c - GObject based dia renderer base class
5 * Copyright (C) 1998-2002 Various Dia developers
6 * Copyright (C) 2002 Hans Breuer (refactoring)
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "diarenderer.h"
28 struct _BezierApprox
{
34 static void dia_renderer_class_init (DiaRendererClass
*klass
);
36 static int get_width_pixels (DiaRenderer
*);
37 static int get_height_pixels (DiaRenderer
*);
39 static void begin_render (DiaRenderer
*);
40 static void end_render (DiaRenderer
*);
42 static void set_linewidth (DiaRenderer
*renderer
, real linewidth
);
43 static void set_linecaps (DiaRenderer
*renderer
, LineCaps mode
);
44 static void set_linejoin (DiaRenderer
*renderer
, LineJoin mode
);
45 static void set_linestyle (DiaRenderer
*renderer
, LineStyle mode
);
46 static void set_dashlength (DiaRenderer
*renderer
, real length
);
47 static void set_fillstyle (DiaRenderer
*renderer
, FillStyle mode
);
48 static void set_font (DiaRenderer
*renderer
, DiaFont
*font
, real height
);
50 static void draw_line (DiaRenderer
*renderer
,
51 Point
*start
, Point
*end
,
53 static void fill_rect (DiaRenderer
*renderer
,
54 Point
*ul_corner
, Point
*lr_corner
,
56 static void fill_polygon (DiaRenderer
*renderer
,
57 Point
*points
, int num_points
,
59 static void draw_arc (DiaRenderer
*renderer
,
61 real width
, real height
,
62 real angle1
, real angle2
,
64 static void fill_arc (DiaRenderer
*renderer
,
66 real width
, real height
,
67 real angle1
, real angle2
,
69 static void draw_ellipse (DiaRenderer
*renderer
,
71 real width
, real height
,
73 static void fill_ellipse (DiaRenderer
*renderer
,
75 real width
, real height
,
77 static void draw_bezier (DiaRenderer
*renderer
,
81 static void fill_bezier (DiaRenderer
*renderer
,
85 static void draw_string (DiaRenderer
*renderer
,
90 static void draw_image (DiaRenderer
*renderer
,
92 real width
, real height
,
94 static void draw_text (DiaRenderer
*renderer
,
97 static void draw_rect (DiaRenderer
*renderer
,
98 Point
*ul_corner
, Point
*lr_corner
,
100 static void draw_polyline (DiaRenderer
*renderer
,
101 Point
*points
, int num_points
,
103 static void draw_polygon (DiaRenderer
*renderer
,
104 Point
*points
, int num_points
,
107 static real
get_text_width (DiaRenderer
*renderer
,
108 const gchar
*text
, int length
);
110 static void draw_rounded_rect (DiaRenderer
*renderer
,
111 Point
*ul_corner
, Point
*lr_corner
,
112 Color
*color
, real rounding
);
113 static void fill_rounded_rect (DiaRenderer
*renderer
,
114 Point
*ul_corner
, Point
*lr_corner
,
115 Color
*color
, real rounding
);
116 static void draw_line_with_arrows (DiaRenderer
*renderer
,
117 Point
*start
, Point
*end
,
122 static void draw_arc_with_arrows (DiaRenderer
*renderer
,
123 Point
*start
, Point
*end
,
129 static void draw_polyline_with_arrows (DiaRenderer
*renderer
,
130 Point
*points
, int num_points
,
135 static void draw_bezier_with_arrows (DiaRenderer
*renderer
,
143 static gpointer parent_class
= NULL
;
146 dia_renderer_get_type (void)
148 static GType object_type
= 0;
152 static const GTypeInfo object_info
=
154 sizeof (DiaRendererClass
),
155 (GBaseInitFunc
) NULL
,
156 (GBaseFinalizeFunc
) NULL
,
157 (GClassInitFunc
) dia_renderer_class_init
,
158 NULL
, /* class_finalize */
159 NULL
, /* class_data */
160 sizeof (DiaRenderer
),
165 object_type
= g_type_register_static (G_TYPE_OBJECT
,
174 draw_object (DiaRenderer
*renderer
,
177 object
->ops
->draw(object
, renderer
);
181 renderer_finalize (GObject
*object
)
183 DiaRenderer
*renderer
= DIA_RENDERER (object
);
186 dia_font_unref (renderer
->font
);
188 if (renderer
->bezier
)
190 if (renderer
->bezier
->points
)
191 g_free (renderer
->bezier
->points
);
192 g_free (renderer
->bezier
);
195 G_OBJECT_CLASS (parent_class
)->finalize (object
);
199 dia_renderer_class_init (DiaRendererClass
*klass
)
201 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
202 DiaRendererClass
*renderer_class
= DIA_RENDERER_CLASS (klass
);
204 parent_class
= g_type_class_peek_parent (klass
);
206 object_class
->finalize
= renderer_finalize
;
208 renderer_class
->get_width_pixels
= get_width_pixels
;
209 renderer_class
->get_height_pixels
= get_height_pixels
;
210 renderer_class
->draw_object
= draw_object
;
211 renderer_class
->get_text_width
= get_text_width
;
213 renderer_class
->begin_render
= begin_render
;
214 renderer_class
->end_render
= end_render
;
216 renderer_class
->set_linewidth
= set_linewidth
;
217 renderer_class
->set_linecaps
= set_linecaps
;
218 renderer_class
->set_linejoin
= set_linejoin
;
219 renderer_class
->set_linestyle
= set_linestyle
;
220 renderer_class
->set_dashlength
= set_dashlength
;
221 renderer_class
->set_fillstyle
= set_fillstyle
;
222 renderer_class
->set_font
= set_font
;
224 renderer_class
->draw_line
= draw_line
;
225 renderer_class
->fill_rect
= fill_rect
;
226 renderer_class
->fill_polygon
= fill_polygon
;
227 renderer_class
->draw_arc
= draw_arc
;
228 renderer_class
->fill_arc
= fill_arc
;
229 renderer_class
->draw_ellipse
= draw_ellipse
;
230 renderer_class
->fill_ellipse
= fill_ellipse
;
231 renderer_class
->draw_string
= draw_string
;
232 renderer_class
->draw_image
= draw_image
;
234 /* medium level functions */
235 renderer_class
->draw_bezier
= draw_bezier
;
236 renderer_class
->fill_bezier
= fill_bezier
;
237 renderer_class
->draw_rect
= draw_rect
;
238 renderer_class
->draw_polyline
= draw_polyline
;
239 renderer_class
->draw_polygon
= draw_polygon
;
240 renderer_class
->draw_text
= draw_text
;
242 /* highest level functions */
243 renderer_class
->draw_rounded_rect
= draw_rounded_rect
;
244 renderer_class
->fill_rounded_rect
= fill_rounded_rect
;
245 renderer_class
->draw_line_with_arrows
= draw_line_with_arrows
;
246 renderer_class
->draw_arc_with_arrows
= draw_arc_with_arrows
;
247 renderer_class
->draw_polyline_with_arrows
= draw_polyline_with_arrows
;
248 renderer_class
->draw_bezier_with_arrows
= draw_bezier_with_arrows
;
252 begin_render (DiaRenderer
*object
)
254 g_warning ("%s::begin_render not implemented!",
255 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (object
)));
259 end_render (DiaRenderer
*object
)
261 g_warning ("%s::end_render not implemented!",
262 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (object
)));
266 set_linewidth (DiaRenderer
*object
, real linewidth
)
268 g_warning ("%s::set_line_width not implemented!",
269 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (object
)));
273 set_linecaps (DiaRenderer
*object
, LineCaps mode
)
275 g_warning ("%s::set_line_caps not implemented!",
276 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (object
)));
280 set_linejoin (DiaRenderer
*renderer
, LineJoin mode
)
282 g_warning ("%s::set_line_join not implemented!",
283 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer
)));
287 set_linestyle (DiaRenderer
*renderer
, LineStyle mode
)
289 g_warning ("%s::set_line_style not implemented!",
290 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer
)));
294 set_dashlength (DiaRenderer
*renderer
, real length
)
296 g_warning ("%s::set_dash_length not implemented!",
297 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer
)));
301 set_fillstyle (DiaRenderer
*renderer
, FillStyle mode
)
303 g_warning ("%s::set_fill_style not implemented!",
304 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer
)));
308 set_font (DiaRenderer
*renderer
, DiaFont
*font
, real height
)
311 dia_font_unref (renderer
->font
);
312 renderer
->font
= dia_font_ref (font
);
313 renderer
->font_height
= height
;
318 draw_line (DiaRenderer
*renderer
, Point
*start
, Point
*end
, Color
*color
)
320 g_warning ("%s::draw_line not implemented!",
321 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer
)));
325 fill_polygon (DiaRenderer
*renderer
, Point
*points
, int num_points
, Color
*color
)
327 g_warning ("%s::fill_polygon not implemented!",
328 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer
)));
332 draw_arc (DiaRenderer
*renderer
, Point
*center
,
333 real width
, real height
, real angle1
, real angle2
,
336 g_warning ("%s::draw_arc not implemented!",
337 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer
)));
341 fill_rect (DiaRenderer
*renderer
,
342 Point
*ul_corner
, Point
*lr_corner
,
345 g_warning ("%s::fill_rect not implemented!",
346 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer
)));
350 fill_arc (DiaRenderer
*renderer
, Point
*center
,
351 real width
, real height
, real angle1
, real angle2
,
354 g_warning ("%s::fill_arc not implemented!",
355 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer
)));
359 draw_ellipse (DiaRenderer
*renderer
, Point
*center
,
360 real width
, real height
,
363 g_warning ("%s::draw_ellipse not implemented!",
364 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer
)));
368 fill_ellipse (DiaRenderer
*renderer
, Point
*center
,
369 real width
, real height
, Color
*color
)
371 g_warning ("%s::fill_ellipse not implemented!",
372 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer
)));
376 draw_string (DiaRenderer
*renderer
,
377 const gchar
*text
, Point
*pos
, Alignment alignment
,
380 g_warning ("%s::draw_string not implemented!",
381 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer
)));
384 /** Default implementation of draw_text */
385 static void draw_text(DiaRenderer
*renderer
,
390 DIA_RENDERER_GET_CLASS(renderer
)->set_font(renderer
, text
->font
, text
->height
);
392 pos
= text
->position
;
394 for (i
=0;i
<text
->numlines
;i
++) {
395 DIA_RENDERER_GET_CLASS(renderer
)->draw_string(renderer
,
397 &pos
, text
->alignment
,
399 pos
.y
+= text
->height
;
404 draw_image (DiaRenderer
*renderer
,
405 Point
*point
, real width
, real height
,
408 g_warning ("%s::draw_image not implemented!",
409 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer
)));
414 * medium level functions, implemented by the above
416 /* Bezier implementation notes:
417 * These beziers have the following basis matrix:
422 * (At least that's what Hearn and Baker says for beziers.)
424 #define BEZIER_SUBDIVIDE_LIMIT 0.03
425 #define BEZIER_SUBDIVIDE_LIMIT_SQ (BEZIER_SUBDIVIDE_LIMIT*BEZIER_SUBDIVIDE_LIMIT)
428 bezier_add_point(BezierApprox
*bezier
,
431 /* Grow if needed: */
432 if (bezier
->currpoint
== bezier
->numpoints
) {
433 bezier
->numpoints
+= 40;
434 bezier
->points
= g_realloc(bezier
->points
,
435 bezier
->numpoints
*sizeof(Point
));
438 bezier
->points
[bezier
->currpoint
] = *point
;
444 bezier_add_lines(BezierApprox
*bezier
,
454 /* Check if almost flat: */
456 point_sub(&u
, &points
[0]);
458 point_sub(&v
, &points
[0]);
460 v_len_sq
= point_dot(&v
,&v
);
461 if (isnan(v_len_sq
)) {
462 g_warning("v_len_sq is NaN while calculating bezier curve!");
465 if (v_len_sq
< 0.000001)
467 point_scale(&y
, point_dot(&u
,&v
)/v_len_sq
);
470 delta
= point_dot(&x
,&x
);
471 if (delta
< BEZIER_SUBDIVIDE_LIMIT_SQ
) {
473 point_sub(&u
, &points
[3]);
475 point_sub(&v
, &points
[3]);
477 v_len_sq
= point_dot(&v
,&v
);
478 if (v_len_sq
< 0.000001)
480 point_scale(&y
, point_dot(&u
,&v
)/v_len_sq
);
483 delta
= point_dot(&x
,&x
);
484 if (delta
< BEZIER_SUBDIVIDE_LIMIT_SQ
) { /* Almost flat, draw a line */
485 bezier_add_point(bezier
, &points
[3]);
489 /* Subdivide into two bezier curves: */
492 point_add(&middle
, &points
[2]);
493 point_scale(&middle
, 0.5);
498 point_add(&r
[1], &points
[1]);
499 point_scale(&r
[1], 0.5);
502 point_add(&r
[2], &middle
);
503 point_scale(&r
[2], 0.5);
508 point_add(&s
[2], &points
[3]);
509 point_scale(&s
[2], 0.5);
512 point_add(&s
[1], &middle
);
513 point_scale(&s
[1], 0.5);
516 point_add(&r
[3], &s
[1]);
517 point_scale(&r
[3], 0.5);
521 bezier_add_lines(bezier
, r
);
522 bezier_add_lines(bezier
, s
);
526 bezier_add_curve(BezierApprox
*bezier
,
529 /* Is the bezier curve malformed? */
530 if ( (distance_point_point(&points
[0], &points
[1]) < 0.00001) &&
531 (distance_point_point(&points
[2], &points
[3]) < 0.00001) &&
532 (distance_point_point(&points
[0], &points
[3]) < 0.00001)) {
533 bezier_add_point(bezier
, &points
[3]);
536 bezier_add_lines(bezier
, points
);
540 approximate_bezier (BezierApprox
*bezier
,
541 BezPoint
*points
, int numpoints
)
546 if (points
[0].type
!= BEZ_MOVE_TO
)
547 g_warning("first BezPoint must be a BEZ_MOVE_TO");
548 curve
[3] = points
[0].p1
;
549 bezier_add_point(bezier
, &points
[0].p1
);
550 for (i
= 1; i
< numpoints
; i
++)
551 switch (points
[i
].type
) {
553 g_warning("only first BezPoint can be a BEZ_MOVE_TO");
554 curve
[3] = points
[i
].p1
;
557 bezier_add_point(bezier
, &points
[i
].p1
);
558 curve
[3] = points
[i
].p1
;
562 curve
[1] = points
[i
].p1
;
563 curve
[2] = points
[i
].p2
;
564 curve
[3] = points
[i
].p3
;
565 bezier_add_curve(bezier
, curve
);
570 /* bezier approximation with straight lines */
572 draw_bezier (DiaRenderer
*renderer
,
573 BezPoint
*points
, int numpoints
,
576 BezierApprox
*bezier
;
578 if (renderer
->bezier
)
579 bezier
= renderer
->bezier
;
581 renderer
->bezier
= bezier
= g_new0 (BezierApprox
, 1);
583 if (bezier
->points
== NULL
) {
584 bezier
->numpoints
= 30;
585 bezier
->points
= g_malloc(bezier
->numpoints
*sizeof(Point
));
588 bezier
->currpoint
= 0;
589 approximate_bezier (bezier
, points
, numpoints
);
591 DIA_RENDERER_GET_CLASS (renderer
)->draw_polyline (renderer
,
598 fill_bezier (DiaRenderer
*renderer
,
599 BezPoint
*points
, int numpoints
,
602 BezierApprox
*bezier
;
604 if (renderer
->bezier
)
605 bezier
= renderer
->bezier
;
607 renderer
->bezier
= bezier
= g_new0 (BezierApprox
, 1);
609 if (bezier
->points
== NULL
) {
610 bezier
->numpoints
= 30;
611 bezier
->points
= g_malloc(bezier
->numpoints
*sizeof(Point
));
614 bezier
->currpoint
= 0;
615 approximate_bezier (bezier
, points
, numpoints
);
617 DIA_RENDERER_GET_CLASS (renderer
)->fill_polygon (renderer
,
624 draw_rect (DiaRenderer
*renderer
,
625 Point
*ul_corner
, Point
*lr_corner
,
628 DiaRendererClass
*klass
= DIA_RENDERER_GET_CLASS (renderer
);
636 klass
->draw_line (renderer
, ul_corner
, &ur
, color
);
637 klass
->draw_line (renderer
, &ur
, lr_corner
, color
);
638 klass
->draw_line (renderer
, lr_corner
, &ll
, color
);
639 klass
->draw_line (renderer
, &ll
, ul_corner
, color
);
643 draw_polyline (DiaRenderer
*renderer
,
644 Point
*points
, int num_points
,
647 DiaRendererClass
*klass
= DIA_RENDERER_GET_CLASS (renderer
);
650 for (i
= 0; i
< num_points
- 1; i
++)
651 klass
->draw_line (renderer
, &points
[i
+0], &points
[i
+1], color
);
655 draw_polygon (DiaRenderer
*renderer
,
656 Point
*points
, int num_points
,
659 DiaRendererClass
*klass
= DIA_RENDERER_GET_CLASS (renderer
);
662 g_return_if_fail (1 > num_points
);
664 for (i
= 0; i
< num_points
- 1; i
++)
665 klass
->draw_line (renderer
, &points
[i
+0], &points
[i
+1], color
);
666 /* close it in any case */
667 if ( (points
[0].x
!= points
[num_points
-1].x
)
668 || (points
[0].y
!= points
[num_points
-1].y
))
669 klass
->draw_line (renderer
, &points
[num_points
-1], &points
[0], color
);
673 draw_rounded_rect (DiaRenderer
*renderer
,
674 Point
*ul_corner
, Point
*lr_corner
,
675 Color
*color
, real radius
)
677 DiaRendererClass
*renderer_ops
= DIA_RENDERER_GET_CLASS (renderer
);
678 Point start
, end
, center
;
680 radius
= MIN(radius
, (lr_corner
->x
-ul_corner
->x
)/2);
681 radius
= MIN(radius
, (lr_corner
->y
-ul_corner
->y
)/2);
682 start
.x
= center
.x
= ul_corner
->x
+radius
;
683 end
.x
= lr_corner
->x
-radius
;
684 start
.y
= end
.y
= ul_corner
->y
;
685 renderer_ops
->draw_line(renderer
, &start
, &end
, color
);
686 start
.y
= end
.y
= lr_corner
->y
;
687 renderer_ops
->draw_line(renderer
, &start
, &end
, color
);
689 center
.y
= ul_corner
->y
+radius
;
690 renderer_ops
->draw_arc(renderer
, ¢er
,
691 2.0*radius
, 2.0*radius
,
694 renderer_ops
->draw_arc(renderer
, ¢er
,
695 2.0*radius
, 2.0*radius
,
698 start
.y
= ul_corner
->y
+radius
;
699 start
.x
= end
.x
= ul_corner
->x
;
700 end
.y
= center
.y
= lr_corner
->y
-radius
;
701 renderer_ops
->draw_line(renderer
, &start
, &end
, color
);
702 start
.x
= end
.x
= lr_corner
->x
;
703 renderer_ops
->draw_line(renderer
, &start
, &end
, color
);
705 center
.y
= lr_corner
->y
-radius
;
706 center
.x
= ul_corner
->x
+radius
;
707 renderer_ops
->draw_arc(renderer
, ¢er
,
708 2.0*radius
, 2.0*radius
,
709 180.0, 270.0, color
);
710 center
.x
= lr_corner
->x
-radius
;
711 renderer_ops
->draw_arc(renderer
, ¢er
,
712 2.0*radius
, 2.0*radius
,
713 270.0, 360.0, color
);
717 fill_rounded_rect(DiaRenderer
*renderer
,
718 Point
*ul_corner
, Point
*lr_corner
,
719 Color
*color
, real radius
)
721 DiaRendererClass
*renderer_ops
= DIA_RENDERER_GET_CLASS (renderer
);
722 Point start
, end
, center
;
724 radius
= MIN(radius
, (lr_corner
->x
-ul_corner
->x
)/2);
725 radius
= MIN(radius
, (lr_corner
->y
-ul_corner
->y
)/2);
726 start
.x
= center
.x
= ul_corner
->x
+radius
;
727 end
.x
= lr_corner
->x
-radius
;
728 start
.y
= ul_corner
->y
;
729 end
.y
= lr_corner
->y
;
730 renderer_ops
->fill_rect(renderer
, &start
, &end
, color
);
732 center
.y
= ul_corner
->y
+radius
;
733 renderer_ops
->fill_arc(renderer
, ¢er
,
734 2.0*radius
, 2.0*radius
,
737 renderer_ops
->fill_arc(renderer
, ¢er
,
738 2.0*radius
, 2.0*radius
,
742 start
.x
= ul_corner
->x
;
743 start
.y
= ul_corner
->y
+radius
;
744 end
.x
= lr_corner
->x
;
745 end
.y
= center
.y
= lr_corner
->y
-radius
;
746 renderer_ops
->fill_rect(renderer
, &start
, &end
, color
);
748 center
.y
= lr_corner
->y
-radius
;
749 center
.x
= ul_corner
->x
+radius
;
750 renderer_ops
->fill_arc(renderer
, ¢er
,
751 2.0*radius
, 2.0*radius
,
752 180.0, 270.0, color
);
753 center
.x
= lr_corner
->x
-radius
;
754 renderer_ops
->fill_arc(renderer
, ¢er
,
755 2.0*radius
, 2.0*radius
,
756 270.0, 360.0, color
);
760 draw_line_with_arrows(DiaRenderer
*renderer
,
768 Point oldstart
= *startpoint
;
769 Point oldend
= *endpoint
;
770 Point start_arrow_head
;
771 Point end_arrow_head
;
773 /* Calculate how to more the line to account for arrow heads */
774 if (start_arrow
!= NULL
&& start_arrow
->type
!= ARROW_NONE
) {
775 Point move_arrow
, move_line
;
776 calculate_arrow_point(start_arrow
, startpoint
, endpoint
,
777 &move_arrow
, &move_line
,
779 start_arrow_head
= *startpoint
;
780 point_sub(&start_arrow_head
, &move_arrow
);
781 point_sub(startpoint
, &move_line
);
783 if (end_arrow
!= NULL
&& end_arrow
->type
!= ARROW_NONE
) {
784 Point move_arrow
, move_line
;
785 calculate_arrow_point(end_arrow
, endpoint
, startpoint
,
786 &move_arrow
, &move_line
,
788 end_arrow_head
= *endpoint
;
789 point_sub(&end_arrow_head
, &move_arrow
);
790 point_sub(endpoint
, &move_line
);
793 DIA_RENDERER_GET_CLASS(renderer
)->draw_line(renderer
, startpoint
, endpoint
, color
);
795 /* Actual arrow drawing down here so line styles aren't disturbed */
796 if (start_arrow
!= NULL
&& start_arrow
->type
!= ARROW_NONE
)
797 arrow_draw(renderer
, start_arrow
->type
,
798 &start_arrow_head
, endpoint
,
799 start_arrow
->length
, start_arrow
->width
,
801 color
, &color_white
);
802 if (end_arrow
!= NULL
&& end_arrow
->type
!= ARROW_NONE
)
803 arrow_draw(renderer
, end_arrow
->type
,
804 &end_arrow_head
, startpoint
,
805 end_arrow
->length
, end_arrow
->width
,
807 color
, &color_white
);
809 *startpoint
= oldstart
;
814 draw_polyline_with_arrows(DiaRenderer
*renderer
,
815 Point
*points
, int num_points
,
821 /* Index of first and last point with a non-zero length segment */
823 int lastline
= num_points
;
824 Point oldstart
= points
[firstline
];
825 Point oldend
= points
[lastline
-1];
826 Point start_arrow_head
;
827 Point end_arrow_head
;
829 if (start_arrow
!= NULL
&& start_arrow
->type
!= ARROW_NONE
) {
830 Point move_arrow
, move_line
;
831 while (firstline
< num_points
-1 &&
832 distance_point_point(&points
[firstline
],
833 &points
[firstline
+1]) < 0.0000001)
835 if (firstline
== num_points
-1)
836 firstline
= 0; /* No non-zero lines, it doesn't matter. */
837 oldstart
= points
[firstline
];
838 calculate_arrow_point(start_arrow
,
839 &points
[firstline
], &points
[firstline
+1],
840 &move_arrow
, &move_line
,
842 start_arrow_head
= points
[firstline
];
843 point_sub(&start_arrow_head
, &move_arrow
);
844 point_sub(&points
[firstline
], &move_line
);
846 if (end_arrow
!= NULL
&& end_arrow
->type
!= ARROW_NONE
) {
847 Point move_arrow
, move_line
;
848 while (lastline
> 0 &&
849 distance_point_point(&points
[lastline
-1],
850 &points
[lastline
-2]) < 0.0000001)
853 firstline
= num_points
; /* No non-zero lines, it doesn't matter. */
854 oldend
= points
[lastline
-1];
855 calculate_arrow_point(end_arrow
, &points
[lastline
-1],
857 &move_arrow
, &move_line
,
859 end_arrow_head
= points
[lastline
-1];
860 point_sub(&end_arrow_head
, &move_arrow
);
861 point_sub(&points
[lastline
-1], &move_line
);
863 /* Don't draw degenerate line segments at end of line */
864 DIA_RENDERER_GET_CLASS(renderer
)->draw_polyline(renderer
, &points
[firstline
],
865 lastline
-firstline
, color
);
866 if (start_arrow
!= NULL
&& start_arrow
->type
!= ARROW_NONE
)
867 arrow_draw(renderer
, start_arrow
->type
,
868 &start_arrow_head
, &points
[firstline
+1],
869 start_arrow
->length
, start_arrow
->width
,
871 color
, &color_white
);
872 if (end_arrow
!= NULL
&& end_arrow
->type
!= ARROW_NONE
)
873 arrow_draw(renderer
, end_arrow
->type
,
874 &end_arrow_head
, &points
[lastline
-2],
875 end_arrow
->length
, end_arrow
->width
,
877 color
, &color_white
);
879 points
[firstline
] = oldstart
;
880 points
[lastline
-1] = oldend
;
883 /** Figure the equation for a line given by two points.
884 * Returns FALSE if the line is vertical (infinite a).
887 points_to_line(real
*a
, real
*b
, Point
*p1
, Point
*p2
)
889 if (fabs(p1
->x
- p2
->x
) < 0.000000001)
891 *a
= (p2
->y
-p1
->y
)/(p2
->x
-p1
->x
);
892 *b
= p1
->y
-(*a
)*p1
->x
;
896 /** Find the intersection between two lines.
897 * Returns TRUE if the lines intersect in a single point.
900 intersection_line_line(Point
*cross
,
901 Point
*p1a
, Point
*p1b
,
902 Point
*p2a
, Point
*p2b
)
906 /* Find coefficients of lines */
907 if (!(points_to_line(&a1
, &b1
, p1a
, p1b
))) {
908 if (!(points_to_line(&a2
, &b2
, p2a
, p2b
))) {
909 if (fabs(p1a
->x
-p2a
->x
) < 0.00000001) {
915 cross
->y
= a2
*(p1a
->x
)+b2
;
918 if (!(points_to_line(&a2
, &b2
, p2a
, p2b
))) {
920 cross
->y
= a1
*(p2a
->x
)+b1
;
924 if (fabs(a1
-a2
) < 0.000000001) {
925 if (fabs(b1
-b2
) < 0.000000001) {
939 cross
->x
= (b2
-b1
)/(a1
-a2
);
940 cross
->y
= a1
*cross
->x
+b1
;
945 /** Given three points, find the center of the circle they describe.
946 * Returns FALSE if the center could not be determined (i.e. the points
947 * all lie really close together).
948 * The renderer should disappear once the debugging is done.
951 find_center_point(Point
*center
, Point
*p1
, Point
*p2
, Point
*p3
)
959 /* Find vector from middle between two points towards center */
961 point_sub(&mid1
, p2
);
962 point_scale(&mid1
, 0.5);
964 point_add(&mid1
, p2
); /* Now midpoint between p1 & p2 */
968 point_add(&orth1
, &mid1
);
971 /* Again, with two other points */
973 point_sub(&mid2
, p3
);
974 point_scale(&mid2
, 0.5);
976 point_add(&mid2
, p3
); /* Now midpoint between p2 & p3 */
980 point_add(&orth2
, &mid2
);
982 /* The intersection between these two is the center */
983 if (!intersection_line_line(center
, &mid1
, &orth1
, &mid2
, &orth2
)) {
984 /* Degenerate circle */
985 /* Either the points are really close together, or directly apart */
986 printf("Degenerate circle\n");
987 if (fabs((p1
->x
+ p2
->x
+ p3
->x
)/3 - p1
->x
) < 0.0000001 &&
988 fabs((p1
->y
+ p2
->y
+ p3
->y
)/3 - p1
->y
) < 0.0000001)
997 point_cross(Point
*p1
, Point
*p2
)
999 return p1
->x
* p2
->y
- p2
->x
* p1
->y
;
1003 draw_arc_with_arrows (DiaRenderer
*renderer
,
1012 Point oldstart
= *startpoint
;
1013 Point oldend
= *endpoint
;
1015 real width
, angle1
, angle2
;
1018 Point start_arrow_head
;
1019 Point start_arrow_end
;
1020 Point end_arrow_head
;
1021 Point end_arrow_end
;
1023 if (!find_center_point(¢er
, startpoint
, endpoint
, midpoint
)) {
1024 /* Degenerate circle -- should have been caught by the drawer? */
1029 point_sub(&dot1
, endpoint
);
1030 point_normalize(&dot1
);
1032 point_sub(&dot2
, endpoint
);
1033 point_normalize(&dot2
);
1034 righthand
= point_cross(&dot1
, &dot2
) > 0;
1036 if (start_arrow
!= NULL
&& start_arrow
->type
!= ARROW_NONE
) {
1037 Point move_arrow
, move_line
;
1040 start_arrow_end
= *startpoint
;
1041 point_sub(&start_arrow_end
, ¢er
);
1042 tmp
= start_arrow_end
.x
;
1044 start_arrow_end
.x
= -start_arrow_end
.y
;
1045 start_arrow_end
.y
= tmp
;
1047 start_arrow_end
.x
= start_arrow_end
.y
;
1048 start_arrow_end
.y
= -tmp
;
1050 point_add(&start_arrow_end
, startpoint
);
1052 calculate_arrow_point(start_arrow
, startpoint
, &start_arrow_end
,
1053 &move_arrow
, &move_line
,
1055 start_arrow_head
= *startpoint
;
1056 point_sub(&start_arrow_head
, &move_arrow
);
1057 point_sub(startpoint
, &move_line
);
1059 if (end_arrow
!= NULL
&& end_arrow
->type
!= ARROW_NONE
) {
1060 Point move_arrow
, move_line
;
1063 end_arrow_end
= *endpoint
;
1064 point_sub(&end_arrow_end
, ¢er
);
1065 tmp
= end_arrow_end
.x
;
1067 end_arrow_end
.x
= end_arrow_end
.y
;
1068 end_arrow_end
.y
= -tmp
;
1070 end_arrow_end
.x
= -end_arrow_end
.y
;
1071 end_arrow_end
.y
= tmp
;
1073 point_add(&end_arrow_end
, endpoint
);
1075 calculate_arrow_point(end_arrow
, endpoint
, &end_arrow_end
,
1076 &move_arrow
, &move_line
,
1078 end_arrow_head
= *endpoint
;
1079 point_sub(&end_arrow_head
, &move_arrow
);
1080 point_sub(endpoint
, &move_line
);
1083 if (!find_center_point(¢er
, startpoint
, endpoint
, midpoint
)) {
1084 /* Not sure what to do here */
1085 *startpoint
= oldstart
;
1087 printf("Second degenerate circle\n");
1090 width
= 2*distance_point_point(¢er
, startpoint
);
1091 angle1
= -atan2(startpoint
->y
-center
.y
, startpoint
->x
-center
.x
)*180.0/M_PI
;
1092 while (angle1
< 0.0) angle1
+= 360.0;
1093 angle2
= -atan2(endpoint
->y
-center
.y
, endpoint
->x
-center
.x
)*180.0/M_PI
;
1094 while (angle2
< 0.0) angle2
+= 360.0;
1100 DIA_RENDERER_GET_CLASS(renderer
)->draw_arc(renderer
, ¢er
, width
, width
,
1101 angle1
, angle2
, color
);
1102 if (start_arrow
!= NULL
&& start_arrow
->type
!= ARROW_NONE
)
1103 arrow_draw(renderer
, start_arrow
->type
,
1104 &start_arrow_head
, &start_arrow_end
,
1105 start_arrow
->length
, start_arrow
->width
,
1107 color
, &color_white
);
1108 if (end_arrow
!= NULL
&& end_arrow
->type
!= ARROW_NONE
)
1109 arrow_draw(renderer
, end_arrow
->type
,
1110 &end_arrow_head
, &end_arrow_end
,
1111 end_arrow
->length
, end_arrow
->width
,
1113 color
, &color_white
);
1115 *startpoint
= oldstart
;
1120 draw_bezier_with_arrows(DiaRenderer
*renderer
,
1128 Point startpoint
, endpoint
;
1129 Point start_arrow_head
;
1130 Point end_arrow_head
;
1132 startpoint
= points
[0].p1
;
1133 endpoint
= points
[num_points
-1].p3
;
1135 if (start_arrow
!= NULL
&& start_arrow
->type
!= ARROW_NONE
) {
1138 calculate_arrow_point(start_arrow
, &points
[0].p1
, &points
[1].p1
,
1139 &move_arrow
, &move_line
,
1141 start_arrow_head
= points
[0].p1
;
1142 point_sub(&start_arrow_head
, &move_arrow
);
1143 point_sub(&points
[0].p1
, &move_line
);
1145 if (end_arrow
!= NULL
&& end_arrow
->type
!= ARROW_NONE
) {
1148 calculate_arrow_point(end_arrow
,
1149 &points
[num_points
-1].p3
, &points
[num_points
-1].p2
,
1150 &move_arrow
, &move_line
,
1152 end_arrow_head
= points
[num_points
-1].p3
;
1153 point_sub(&end_arrow_head
, &move_arrow
);
1154 point_sub(&points
[num_points
-1].p3
, &move_line
);
1156 DIA_RENDERER_GET_CLASS(renderer
)->draw_bezier(renderer
, points
, num_points
, color
);
1157 if (start_arrow
!= NULL
&& start_arrow
->type
!= ARROW_NONE
)
1158 arrow_draw(renderer
, start_arrow
->type
,
1159 &start_arrow_head
, &points
[1].p1
,
1160 start_arrow
->length
, start_arrow
->width
,
1162 color
, &color_white
);
1163 if (end_arrow
!= NULL
&& end_arrow
->type
!= ARROW_NONE
)
1164 arrow_draw(renderer
, end_arrow
->type
,
1165 &end_arrow_head
, &points
[num_points
-1].p2
,
1166 end_arrow
->length
, end_arrow
->width
,
1168 color
, &color_white
);
1170 points
[0].p1
= startpoint
;
1171 points
[num_points
-1].p3
= endpoint
;
1176 * Should we really provide this ? It formerly was an 'interactive op'
1177 * and depends on DiaRenderer::set_font() not or properly overwritten
1180 get_text_width (DiaRenderer
*renderer
,
1181 const gchar
*text
, int length
)
1185 if (renderer
->font
) {
1186 char *str
= g_strndup (text
, length
);
1188 ret
= dia_font_string_width (str
,
1190 renderer
->font_height
);
1198 get_width_pixels (DiaRenderer
*renderer
)
1200 g_return_val_if_fail (renderer
->is_interactive
, 0);
1205 get_height_pixels (DiaRenderer
*renderer
)
1207 g_return_val_if_fail (renderer
->is_interactive
, 0);
1213 * non member functions
1216 dia_renderer_get_width_pixels (DiaRenderer
*renderer
)
1218 return DIA_RENDERER_GET_CLASS(renderer
)->get_width_pixels (renderer
);
1222 dia_renderer_get_height_pixels (DiaRenderer
*renderer
)
1224 return DIA_RENDERER_GET_CLASS(renderer
)->get_height_pixels (renderer
);