1 module rip.draw.primitives;
2 
3 private
4 {
5 	import std.algorithm;
6 	import std.math;
7 
8 	import rip.concepts.color;
9 	import rip.concepts.surface;
10 	import rip.concepts.templates; 
11 }
12 
13 // Рисование точки
14 auto drawPoint(T, S)(Surface surface, RGBColor rgbColor, T x, S y)
15 	if (allArithmetic!(T, S))
16 {
17 	surface[x, y] = rgbColor;
18 }
19 
20 // Рисование линии с помощью цифрового дифференциального анализатора
21 auto drawDDALine(T, U, V, W)(Surface surface, RGBColor rgbColor,T x1, U y1, V x2, W y2)
22 	if (allArithmetic!(T, U, V, W))
23 {
24 	auto deltaX = abs(x1 - x2);
25 	auto deltaY = abs(y1 - y2);
26 	auto L = max(deltaX, deltaY);
27 
28 	if (L == 0)
29 	{
30 		surface[x1, y1] = rgbColor;
31 	}
32 
33 	auto dx = (x2 - x1) / L;
34 	auto dy = (y2 - y1) / L;
35 	float x = x1;
36 	float y = y1;
37 
38 	L++;
39 	while(L--)
40 	{
41 		x += dx;
42 		y += dy;
43 		surface[x1, y1] = rgbColor;
44 	}
45 }
46 
47 // Рисование линии методом Брезенхема
48 auto drawBresenhamLine(T, U, V, W)(Surface surface, RGBColor color, T x1, U y1, V x2, W y2)
49 	if (allArithmetic!(T, U, V, W))
50 {
51 	float a = cast(float) x1;
52 	float b = cast(float) y1;
53 	float c = cast(float) x2;
54 	float d = cast(float) y2;
55 
56 	float dx = (x2 - x1 >= 0 ? 1 : -1);
57 	float dy = (y2 - y1 >= 0 ? 1 : -1);
58 	
59 	float lengthX = abs(x2 - x1);
60 	float lengthY= abs(y2 - y1);
61 	float length = max(lengthX, lengthY);
62 	
63 	if (length == 0)
64 	{
65 		surface[x1, y1] = color;
66 	}
67 	
68 	if (lengthY <= lengthX)
69 	{
70 		float x = x1;
71 		float y = y1;
72 		
73 		length++;
74 		while (length--)
75 		{
76 			surface[x, y] = color;
77 			x += dx;
78 			y += (dy * lengthY) / lengthX;
79 		}
80 	}
81 	else
82 	{
83 		float x = x1;
84 		float y = y1;
85 		
86 		length++;
87 		while(length--)
88 		{
89 			surface[x, y] = color;
90 			x += (dx * lengthX) / lengthY;
91 			y += dy;
92 		}
93 	}
94 }
95 
96 // Рисование окружности
97 auto drawCircle(T, U, V)(Surface surface, RGBColor color, T x, U y, V r)
98 	if (allArithmetic!(T, U, V))
99 {	
100 	assert (r >= 0);
101 
102 	auto a = cast(float) x;
103 	auto b = cast(float) y;
104 	auto c = cast(float) r;
105 
106 	for (float i = 0.0; i < 360.0; i += 0.01)
107 	{
108 		auto X = cast(int) (a + c * cos(i * PI / 180.0));
109 		auto Y = cast(int) (b + c * sin(i * PI / 180.0));
110 		surface[X, Y] = color;
111 	}
112 }
113 
114 // Рисование конических сечений
115 auto drawConicSection(T, U, V, W)(Surface surface, RGBColor color, T x, U y, V l, W e)
116 	if (allArithmetic!(T, U, V, W))
117 {
118 	auto a = cast(float) x;
119 	auto b = cast(float) y;
120 	auto c = cast(float) l;
121 	auto d = cast(float) e;
122 
123 	for (float i = 0.0; i < 360.0; i += 0.01)
124 	{
125 		auto r = c / (1.0 - d * cos(i * PI / 180.0));
126 		auto X = cast(int) (a + c * cos(i * PI / 180.0));
127 		auto Y = cast(int) (b + c * sin(i * PI / 180.0));
128 		surface[X, Y] = color;
129 	}
130 }
131 
132 // Рисование треугольника
133 auto drawTriangle(P, Q, R, S, T, U)(Surface surface, RGBColor color, P x1, Q y1, R x2, S y2, T x3, U y3)
134 	if (allArithmetic!(P, Q, R, S, T, U))
135 {
136 	auto a = cast(int) x1;
137 	auto b = cast(int) y1;
138 	auto c = cast(int) x2;
139 	auto d = cast(int) y2;
140 	auto e = cast(int) x3;
141 	auto f = cast(int) y3;
142 
143 	surface.drawPoint(color, a, b);
144 	surface.drawPoint(color, c, d);
145 	surface.drawPoint(color, e, f);
146 
147 	surface.drawDDALine(color, a, b, c, d);
148 	surface.drawDDALine(color, c, d, e, f);
149 	surface.drawDDALine(color, e, f, a, b);
150 }
151 
152 // Рисование прямоугольника
153 auto drawRectangle(T, U, V, W)(Surface surface, RGBColor color, T x, U y, V w, W h)
154 	if (allArithmetic!(T, U, V, W))
155 {
156 	assert(w >= 0);
157 	assert(h >= 0);
158 
159 	auto X = cast(int) x;
160 	auto Y = cast(int) y;
161 	auto WW = cast(int) w;
162 	auto HH = cast(int) h;
163 
164 	for (int a = 0; a < HH; a++)
165 	{
166 		surface[X, Y + a] = color;
167 	}
168 	
169 	for (uint b = 0; b < WW; b++)
170 	{
171 		sutface[X + b, Y + HH] = color;
172 	}
173 
174 	for (uint c = 0; c < HH; c++)
175 	{
176 		surface[X + WW, Y + c] = color;
177 	}
178 
179 	for (uint d = 0; d < WW; d++)
180 	{
181 		surface[X + d, Y] = color;
182 	}
183 }
184 
185 // Окружность с заливкой
186 auto drawFilledCircle(T, U, V)(Surface surface, RGBColor color, T x, U y, V r)
187 	if (allArithmetic!(T, U, V))
188 {
189 	auto a = cast(float) x;
190 	auto b = cast(float) y;
191 	auto c = cast(float) r;
192 	
193 	for (float i = 0.0; i < 360.0; i += 0.01)
194 	{
195 		for (float j = 0; j < c; j++)
196 		{
197 			auto X = cast(int) (a + j * cos(i * PI / 180.0));
198 			auto Y = cast(int) (b + j * sin(i * PI / 180.0));
199 			surface[X, Y] = color;
200 		}
201 	}
202 }
203 
204 // Треугольник с заливкой
205 auto drawFilledTriangle(P, Q, R, S, T, U)(Surface surface, RGBColor color, P x1, Q y1, R x2, S y2, T x3, U y3)
206 	if (allArithmetic!(P, Q, R, S, T, U))
207 {
208 	// рисуем треугольник обычный
209 	auto a = cast(float) x1;
210 	auto b = cast(float) y1;
211 	auto c = cast(float) x2;
212 	auto d = cast(float) y2;
213 	auto e = cast(float) x3;
214 	auto f = cast(float) y3;
215 	
216 	surface.drawPoint(color, a, b);
217 	surface.drawPoint(color, c, d);
218 	surface.drawPoint(color, e, f);
219 	
220 	surface.drawDDALine(color, a, b, c, d);
221 	surface.drawDDALine(color, c, d, e, f);
222 	surface.drawDDALine(color, e, f, a, b);
223 
224 	// вычисление знаменателя для барицентрических координат
225 	auto calculateDenominator(float X1, float Y1, float X2, float Y2, float X3, float Y3)
226 	{
227 		return ((Y2 - Y3) * (X1 - X3)) + ((X3 - X2) * (Y1 - Y3));
228 	}
229 
230 	// вычисляем первую барицентрическую координату
231 	auto calculateL1(float x, float y)
232 	{
233 		auto numerator = ((b - f) * (x - e)) + ((e - c) * (y - f));
234 		auto denominator = calculateDenominator(a, b, c, d, e, f);
235 		return numerator / denominator;
236 	}
237 
238 	// вычисляем вторую барицентрическую координату
239 	auto calculateL2(float x, float y)
240 	{
241 		auto numerator = ((f - a) * (x - e)) + ((a - e) * (y - f));
242 		auto denominator = calculateDenominator(a, b, c, d, e, f);
243 		return numerator / denominator;
244 	}
245 
246 	// вычисляем третью барицентрическую координату
247 	auto calculateL3(float L1, float L2)
248 	{
249 		return 1.0 - L1 - L2;
250 	}
251 
252 	// подготовка данных для цикла отрисовки
253 	auto xmin = min(a, c, e);
254 	auto xmax = max(a, c, e);
255 	auto ymin = min(b, d, f);
256 	auto ymax = max(b, d, f);
257 
258 	// Находиться ли величина в интервале [0..1]
259 	bool isBaricentric(float value)
260 	{
261 		return ((value >= 0) && (value <= 1.0));
262 	}
263 
264 	// Находиться ли точка внутри плоскости, ограниченной линиями треугольника
265 	bool isInsideOfTriangle(float x, float y)
266 	{
267 		auto L1 = calculateL1(x, y);
268 		auto L2 = calculateL2(x, y);
269 		auto L3 = calculateL1(L1, L2);
270 		return ((isBaricentric(L1) && isBaricentric(L2) && isBaricentric(L3)));
271 	}
272 
273 	// заливка треугольника
274 	for (float x = xmin; x < xmax; x += 0.1)
275 	{
276 		for (float y = ymin; y < ymax; y += 0.1)
277 		{
278 			if (isInsideOfTriangle(x, y))
279 			{
280 				surface[cast(int) x, cast(int) y] = color;
281 			}
282 		}
283 	}
284 }
285 
286 // Прямоугольник с заливкой
287 auto drawFilledRectangle(T, U, V, W)(Surface surface, RGBColor color, T x, U y, W w, H h)
288 	if (allArithmetic!(T, U, V, W))
289 {
290 	assert(w >= 0);
291 	assert(h >= 0);
292 	
293 	auto X = cast(int) x;
294 	auto Y = cast(int) y;
295 	auto WW = cast(int) w;
296 	auto HH = cast(int) h;
297 
298 	for (int i = 0; i < WW; i++)
299 	{
300 		for (int j = 0; j < HH; j++)
301 		{
302 			surface[X + i, Y + j] = color;
303 		}
304 	}
305 }