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 }