aboutsummaryrefslogtreecommitdiffstats
path: root/rtgrpblib_draw_linear_bezier.c
blob: 5c835912d04f3f14ea7b7e567e4970e9508fd38d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/* See LICENSE file for copyright and license details. */
#include "common.h"
#ifndef TEST


void
rtgrpblib_draw_linear_bezier(RASTER *restrict raster, double x1, double y1, double x2, double y2)
{
	double w, h, dx, dy, x, y;
	int xdir, ydir;

	dx = x2 - x1;
	dy = y2 - y1;
	xdir = SIGNUM(dx);
	ydir = SIGNUM(dy);

	if (!ydir) {
		/* For horizontal lines, it is enough that we have the
		 * corners mapped onto the raster, which we must have
		 * since a glyph cannot just contain a line, but outlines:
		 * in `fill`, the line will not make a contribution because
		 * `.opposite_coverage` for each cell will be zero, and
		 * consequentially, `.cell_coverage` will also be zero */
		return;
	}

	/* We cut of everything above and below the raster,
	 * as these do not contribute to the result */
	h = (double)raster->height;
	if (y1 < 0 && y2 < 0)
		return;
	if (y1 >= h && y2 >= h)
		return;
	if (y1 < 0 && y2 >= 0) {
		x1 = x1 + (0 - y1) * dx / dy;
		y1 = 0;
	} else if (y2 < 0 && y1 >= 0) {
		x2 = x1 + (0 - y1) * dx / dy;
		y2 = 0;
	}
	if (y1 < h && y2 >= h) {
		x2 = x1 + (h - y1) * dx / dy;
		y2 = h;
	} else if (y2 < h && y1 >= h) {
		x1 = x1 + (h - y1) * dx / dy;
		y1 = h;
	}

	/* Dealing with the left and the right section
	 * is not as simple as `fill` assumes that the
	 * sum of each line's `.opposite_coverage` is 0.
	 * Therefore must must identify the parts of the
	 * line that are left of the raster, right of
	 * the raster, and inside the raster. The parts
	 * that are outside the raster are move to the
	 * edge, or rather their show on the edges are
	 * used. */
	w = (double)raster->width;
	if (x1 <= 0 && x2 <= 0) {
		draw_vertical_line(raster, 0, y1, y2, ydir);
		return;
	}
	if (x1 >= w && x2 >= w) {
		draw_vertical_line_opposite_only(raster, raster->width - 1, y1, y2, ydir);
		return;
	}
	if (x1 < 0 && x2 >= 0) {
		y = y1 + (0 - x1) * dy / dx;
		x = 0;
		draw_vertical_line(raster, 0, y1, y, ydir);
		x1 = x;
		y1 = y;
	} else if (x2 < 0 && x1 >= 0) {
		y = y1 + (0 - x1) * dy / dx;
		x = 0;
		draw_vertical_line(raster, 0, y, y2, ydir);
		x2 = x;
		y2 = y;
	}
	if (x1 < w && x2 >= w) {
		y = y1 + (w - x1) * dy / dx;
		x = w;
		draw_vertical_line_opposite_only(raster, raster->width - 1, y, y2, ydir);
		x2 = x;
		y2 = y;
	} else if (x2 < w && x1 >= w) {
		y = y1 + (w - x1) * dy / dx;
		x = w;
		draw_vertical_line_opposite_only(raster, raster->width - 1, y1, y, ydir);
		x1 = x;
		y1 = y;
	}

	/* Now we can finally draw the part of the
	 * line that is inside the raster */
	if (!xdir) {
		/* Optimisation for vertical lines. It also serves
		 * to illustrate how the algorithm is designed. */
		draw_vertical_line(raster, x1, y1, y2, ydir);
	} else {
		draw_diagonal_line(raster, x1, y1, x2, y2, dx, dy, xdir, ydir);
	}
}


#else


int
main(void)
{
	return 0; /* TODO add test */
}


#endif