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
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
,
40 static void draw_polyline(Renderer
*renderer
,
41 Point
*points
, int num_points
,
43 static void draw_polygon(Renderer
*renderer
,
44 Point
*points
, int num_points
,
46 static void fill_polygon(Renderer
*renderer
,
47 Point
*points
, int num_points
,
49 static void draw_rect(Renderer
*renderer
,
50 Point
*ul_corner
, Point
*lr_corner
,
52 static void fill_rect(Renderer
*renderer
,
53 Point
*ul_corner
, Point
*lr_corner
,
55 static void draw_arc(Renderer
*renderer
,
57 real width
, real height
,
58 real angle1
, real angle2
,
60 static void fill_arc(Renderer
*renderer
,
62 real width
, real height
,
63 real angle1
, real angle2
,
65 static void draw_ellipse(Renderer
*renderer
,
67 real width
, real height
,
69 static void fill_ellipse(Renderer
*renderer
,
71 real width
, real height
,
73 static void draw_bezier(Renderer
*renderer
,
77 static void fill_bezier(Renderer
*renderer
,
78 BezPoint
*points
, /* Last point must be same as first point */
81 static void draw_string(Renderer
*renderer
,
83 Point
*pos
, Alignment alignment
,
85 static void draw_image(Renderer
*renderer
,
87 real width
, real height
,
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
,
101 static void draw_polyline_with_arrows(Renderer
*renderer
,
102 Point
*points
, int n_points
,
107 static void draw_arc_with_arrows(Renderer
*renderer
,
108 Point
*start
, Point
*end
,
114 static void draw_bezier_with_arrows(Renderer
*renderer
,
121 static void draw_object(Renderer
*renderer
,
124 static RenderOps AbstractRenderOps
= {
128 /* Line attributes: */
134 /* Fill attributes: */
169 /* Later additions, down here for binary combatability */
174 draw_line_with_arrows
, /* DrawLineWithArrowsFunc */
175 draw_polyline_with_arrows
, /* DrawPolyLineWithArrowsFunc */
176 draw_arc_with_arrows
, /* DrawArcWithArrowsFunc */
177 draw_bezier_with_arrows
,
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
,
196 RenderOps
* create_renderops_table(void) {
197 RenderOps
*table
= g_new(RenderOps
, 1);
198 *table
= AbstractRenderOps
;
202 /* Interim draw_polyline. Doesn't draw nice corners. */
203 static void draw_polyline(Renderer
*renderer
,
204 Point
*points
, int num_points
,
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
,
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
,
224 /* Simple draw_rect. Draws, but loses info about rectangularity. */
225 static void draw_rect(Renderer
*renderer
,
226 Point
*ul_corner
, Point
*lr_corner
,
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
,
241 static void draw_arc(Renderer
*renderer
,
243 real width
, real height
,
244 real angle1
, real angle2
,
246 static void fill_arc(Renderer
*renderer
,
248 real width
, real height
,
249 real angle1
, real angle2
,
251 static void draw_ellipse(Renderer
*renderer
,
253 real width
, real height
,
255 static void fill_ellipse(Renderer
*renderer
,
257 real width
, real height
,
259 static void draw_bezier(Renderer
*renderer
,
263 static void fill_bezier(Renderer
*renderer
,
264 BezPoint
*points
, /* Last point must be same as first point */
267 static void draw_string(Renderer
*renderer
,
269 Point
*pos
, Alignment alignment
,
271 static void draw_image(Renderer
*renderer
,
273 real width
, real height
,
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
, ¢er
,
291 2.0*radius
, 2.0*radius
,
294 renderer
->ops
->draw_arc(renderer
, ¢er
,
295 2.0*radius
, 2.0*radius
,
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
, ¢er
,
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
, ¢er
,
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
, ¢er
,
330 2.0*radius
, 2.0*radius
,
333 renderer
->ops
->fill_arc(renderer
, ¢er
,
334 2.0*radius
, 2.0*radius
,
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
, ¢er
,
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
, ¢er
,
350 2.0*radius
, 2.0*radius
,
351 270.0, 360.0, color
);
355 draw_line_with_arrows(Renderer
*renderer
,
363 Point oldstart
= *startpoint
;
364 Point oldend
= *endpoint
;
365 if (start_arrow
!= NULL
&& start_arrow
->type
!= ARROW_NONE
) {
366 Point move_arrow
, move_line
;
368 calculate_arrow_point(start_arrow
, startpoint
, endpoint
,
369 &move_arrow
, &move_line
,
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
,
378 color
, &color_white
);
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
);
388 if (end_arrow
!= NULL
&& end_arrow
->type
!= ARROW_NONE
) {
389 Point move_arrow
, move_line
;
391 calculate_arrow_point(end_arrow
, endpoint
, startpoint
,
392 &move_arrow
, &move_line
,
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
,
401 color
, &color_white
);
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
);
411 renderer
->ops
->draw_line(renderer
, startpoint
, endpoint
, color
);
413 *startpoint
= oldstart
;
418 draw_polyline_with_arrows(Renderer
*renderer
,
419 Point
*points
, int num_points
,
425 /* Index of first and last point with a non-zero length segment */
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
;
434 while (firstline
< num_points
-1 &&
435 distance_point_point(&points
[firstline
],
436 &points
[firstline
+1]) < 0.0000001)
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
,
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
,
452 color
, &color_white
);
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
);
462 if (end_arrow
!= NULL
&& end_arrow
->type
!= ARROW_NONE
) {
463 Point move_arrow
, move_line
;
465 while (lastline
> 0 &&
466 distance_point_point(&points
[lastline
-1],
467 &points
[lastline
-2]) < 0.0000001)
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],
474 &move_arrow
, &move_line
,
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
,
483 color
, &color_white
);
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
);
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).
505 points_to_line(real
*a
, real
*b
, Point
*p1
, Point
*p2
)
507 if (fabs(p1
->x
- p2
->x
) < 0.000000001)
509 *a
= (p2
->y
-p1
->y
)/(p2
->x
-p1
->x
);
510 *b
= p1
->y
-(*a
)*p1
->x
;
514 /** Find the intersection between two lines.
515 * Returns TRUE if the lines intersect in a single point.
518 intersection_line_line(Point
*cross
,
519 Point
*p1a
, Point
*p1b
,
520 Point
*p2a
, Point
*p2b
)
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) {
533 cross
->y
= a2
*(p1a
->x
)+b2
;
536 if (!(points_to_line(&a2
, &b2
, p2a
, p2b
))) {
538 cross
->y
= a1
*(p2a
->x
)+b1
;
542 if (fabs(a1
-a2
) < 0.000000001) {
543 if (fabs(b1
-b2
) < 0.000000001) {
557 cross
->x
= (b2
-b1
)/(a1
-a2
);
558 cross
->y
= a1
*cross
->x
+b1
;
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.
569 find_center_point(Point
*center
, Point
*p1
, Point
*p2
, Point
*p3
)
577 /* Find vector from middle between two points towards center */
579 point_sub(&mid1
, p2
);
580 point_scale(&mid1
, 0.5);
582 point_add(&mid1
, p2
); /* Now midpoint between p1 & p2 */
586 point_add(&orth1
, &mid1
);
588 /* Again, with two other points */
590 point_sub(&mid2
, p3
);
591 point_scale(&mid2
, 0.5);
593 point_add(&mid2
, p3
); /* Now midpoint between p2 & p3 */
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)
612 static real
point_cross(Point
*p1
, Point
*p2
)
614 return p1
->x
*p2
->y
-p2
->x
*p1
->y
;
618 draw_arc_with_arrows(Renderer
*renderer
,
627 Point oldstart
= *startpoint
;
628 Point oldend
= *endpoint
;
630 real width
, angle1
, angle2
;
634 if (!find_center_point(¢er
, startpoint
, endpoint
, midpoint
)) {
635 /* Degenerate circle -- should have been caught by the drawer? */
639 point_sub(&dot1
, endpoint
);
640 point_normalize(&dot1
);
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
;
652 arrow_end
= *startpoint
;
653 point_sub(&arrow_end
, ¢er
);
656 arrow_end
.x
= -arrow_end
.y
;
659 arrow_end
.x
= arrow_end
.y
;
662 point_add(&arrow_end
, startpoint
);
664 calculate_arrow_point(start_arrow
, startpoint
, &arrow_end
,
665 &move_arrow
, &move_line
,
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
,
674 color
, &color_white
);
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
);
684 if (end_arrow
!= NULL
&& end_arrow
->type
!= ARROW_NONE
) {
685 Point move_arrow
, move_line
;
690 arrow_end
= *endpoint
;
691 point_sub(&arrow_end
, ¢er
);
694 arrow_end
.x
= arrow_end
.y
;
697 arrow_end
.x
= -arrow_end
.y
;
700 point_add(&arrow_end
, endpoint
);
702 calculate_arrow_point(end_arrow
, endpoint
, &arrow_end
,
703 &move_arrow
, &move_line
,
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
,
712 color
, &color_white
);
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
);
723 if (!find_center_point(¢er
, startpoint
, endpoint
, midpoint
)) {
724 /* Not sure what to do here */
725 *startpoint
= oldstart
;
729 width
= 2*distance_point_point(¢er
, 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;
739 renderer
->ops
->draw_arc(renderer
, ¢er
, width
, width
,
740 angle1
, angle2
, color
);
742 *startpoint
= oldstart
;
747 draw_bezier_with_arrows(Renderer
*renderer
,
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
) {
764 calculate_arrow_point(start_arrow
, &points
[0].p1
, &points
[1].p1
,
765 &move_arrow
, &move_line
,
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
,
774 color
, &color_white
);
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
) {
788 calculate_arrow_point(end_arrow
,
789 &points
[num_points
-1].p3
, &points
[num_points
-1].p2
,
790 &move_arrow
, &move_line
,
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
,
799 color
, &color_white
);
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
;
817 draw_object(Renderer
*renderer
,
819 object
->ops
->draw(object
, renderer
);