00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048 #include <new>
00049
00050
00051 #include "PrimitivesDrawer.h"
00052 #include "Image/ByteImage.h"
00053 #include "Math/Math2d.h"
00054 #include "Structs/Structs.h"
00055 #include "Helpers/helpers.h"
00056
00057
00058 #include <math.h>
00059 #include <limits>
00060
00061
00062
00063
00064
00065
00066
00067 static bool is_indeterminate(const float fValue)
00068 {
00069 return fValue != fValue;
00070 }
00071
00072 static bool is_infinite(const float fValue)
00073 {
00074 return fabsf(fValue) == std::numeric_limits<float>::infinity();
00075 }
00076
00077
00078
00079
00080
00081
00082 void PrimitivesDrawer::DrawPoint(CByteImage *pImage, const Vec2d &point, int r, int g, int b)
00083 {
00084 DrawPoint(pImage, int(point.x + 0.5f), int(point.y + 0.5f), r, g, b);
00085 }
00086
00087 void PrimitivesDrawer::DrawPoint(CByteImage *pImage, int x, int y, int r, int g, int b)
00088 {
00089 const int width = pImage->width;
00090 const int height = pImage->height;
00091 const int nPixels = width * height;
00092
00093 if (x < 0 || x >= width || y < 0 || y >= height)
00094 return;
00095
00096 if (pImage->type == CByteImage::eGrayScale)
00097 {
00098 pImage->pixels[y * width + x] = (r + (g << 1) + b) >> 2;
00099 }
00100 else if (pImage->type == CByteImage::eRGB24)
00101 {
00102 const int offset = 3 * (y * width + x);
00103 pImage->pixels[offset] = r;
00104 pImage->pixels[offset + 1] = g;
00105 pImage->pixels[offset + 2] = b;
00106 }
00107 else if (pImage->type == CByteImage::eRGB24Split)
00108 {
00109 const int offset = y * width + x;
00110 pImage->pixels[offset] = r;
00111 pImage->pixels[offset + nPixels] = g;
00112 pImage->pixels[offset + (nPixels << 1)] = b;
00113 }
00114 }
00115
00116 void PrimitivesDrawer::DrawPointBlended(CByteImage *pImage, const Vec2d &point, int r, int g, int b, float blend)
00117 {
00118 DrawPointBlended(pImage, int(point.x + 0.5f), int(point.y + 0.5f), r, g, b, blend);
00119 }
00120
00121 void PrimitivesDrawer::DrawPointBlended(CByteImage *pImage, int x, int y, int r, int g, int b, float blend)
00122 {
00123 const int width = pImage->width;
00124 const int height = pImage->height;
00125 const int nPixels = width * height;
00126
00127 if (x < 0 || x >= width || y < 0 || y >= height)
00128 return;
00129
00130 if (pImage->type == CByteImage::eGrayScale)
00131 {
00132 const float o = (float) pImage->pixels[y * width + x];
00133 const float n = (float) ((r + (g << 1) + b + 1) >> 2);
00134
00135 pImage->pixels[y * width + x] = (int) ((1.0f - blend) * o + blend * n);
00136 }
00137 else if (pImage->type == CByteImage::eRGB24)
00138 {
00139 const int offset = 3 * (y * width + x);
00140 int ro = pImage->pixels[offset];
00141 int go = pImage->pixels[offset + 1];
00142 int bo = pImage->pixels[offset + 2];
00143
00144 r = (int) ((1.0f - blend) * (float) ro + blend * (float) r);
00145 g = (int) ((1.0f - blend) * (float) go + blend * (float) g);
00146 b = (int) ((1.0f - blend) * (float) bo + blend * (float) b);
00147
00148 pImage->pixels[offset] = r;
00149 pImage->pixels[offset + 1] = g;
00150 pImage->pixels[offset + 2] = b;
00151 }
00152 else if (pImage->type == CByteImage::eRGB24Split)
00153 {
00154 const int offset = y * width + x;
00155
00156 int ro = pImage->pixels[offset];
00157 int go = pImage->pixels[offset + nPixels];
00158 int bo = pImage->pixels[offset + (nPixels << 1)];
00159
00160 r = (int) ((1.0f - blend) * (float) ro + blend * (float) r);
00161 g = (int) ((1.0f - blend) * (float) go + blend * (float) g);
00162 b = (int) ((1.0f - blend) * (float) bo + blend * (float) b);
00163
00164 pImage->pixels[offset] = r;
00165 pImage->pixels[offset + nPixels] = g;
00166 pImage->pixels[offset + (nPixels << 1)] = b;
00167 }
00168 }
00169
00170 void PrimitivesDrawer::DrawPoints(CByteImage *pImage, const CVec2dArray &points, int r, int g, int b)
00171 {
00172 const int nPoints = points.GetSize();
00173
00174 for (int i = 0; i < nPoints; i++)
00175 DrawPoint(pImage, points[i], r, g, b);
00176 }
00177
00178
00179 void PrimitivesDrawer::DrawRegion(CByteImage *pImage, const MyRegion ®ion, int r, int g, int b, int thickness)
00180 {
00181 if (thickness == -1)
00182 {
00183 for (int y = region.min_y; y <= region.max_y; y++)
00184 for (int x = region.min_x; x <= region.max_x; x++)
00185 DrawPoint(pImage, x, y, r, g, b);
00186 }
00187 else
00188 {
00189 const Vec2d p1 = { float(region.min_x), float(region.min_y) };
00190 const Vec2d p2 = { float(region.max_x), float(region.min_y) };
00191 const Vec2d p3 = { float(region.max_x), float(region.max_y) };
00192 const Vec2d p4 = { float(region.min_x), float(region.max_y) };
00193
00194 DrawLine(pImage, p1, p2, r, g, b, thickness);
00195 DrawLine(pImage, p2, p3, r, g, b, thickness);
00196 DrawLine(pImage, p3, p4, r, g, b, thickness);
00197 DrawLine(pImage, p4, p1, r, g, b, thickness);
00198 }
00199 }
00200
00201 void PrimitivesDrawer::DrawLine(CByteImage *pImage, const Vec2d &p1, const Vec2d &p2, int r, int g, int b, int thickness)
00202 {
00203 if (is_indeterminate(p1.x) || is_indeterminate(p1.y) || is_indeterminate(p2.x) || is_indeterminate(p2.y))
00204 return;
00205
00206 if (is_infinite(p1.x) || is_infinite(p1.y) || is_infinite(p2.x) || is_infinite(p2.y))
00207 return;
00208
00209 const float dx = p1.x - p2.x;
00210 const float dy = p1.y - p2.y;
00211
00212 if (thickness == 1)
00213 {
00214 if (fabsf(dx) < 0.01f && fabsf(dy) < 0.01f)
00215 {
00216 PrimitivesDrawer::DrawPoint(pImage, p1, r, g, b);
00217 }
00218 else if (fabsf(dy) < fabsf(dx))
00219 {
00220 const float slope = dy / dx;
00221 const int max_x = int(p2.x + 0.5f);
00222 float y = p1.y + 0.5f;
00223
00224 if (p1.x < p2.x)
00225 {
00226 for (int x = int(p1.x + 0.5f); x <= max_x; x++, y += slope)
00227 PrimitivesDrawer::DrawPoint(pImage, x, int(y), r, g, b);
00228 }
00229 else
00230 {
00231 for (int x = int(p1.x + 0.5f); x >= max_x; x--, y -= slope)
00232 PrimitivesDrawer::DrawPoint(pImage, x, int(y), r, g, b);
00233 }
00234 }
00235 else
00236 {
00237 const float slope = dx / dy;
00238 const int max_y = int(p2.y + 0.5f);
00239 float x = p1.x + 0.5f;
00240
00241 if (p1.y < p2.y)
00242 {
00243 for (int y = int(p1.y + 0.5f); y <= max_y; y++, x += slope)
00244 PrimitivesDrawer::DrawPoint(pImage, int(x), y, r, g, b);
00245 }
00246 else
00247 {
00248 for (int y = int(p1.y + 0.5f); y >= max_y; y--, x -= slope)
00249 PrimitivesDrawer::DrawPoint(pImage, int(x), y, r, g, b);
00250 }
00251 }
00252 }
00253 else
00254 {
00255 const float radius = 0.5f * thickness;
00256
00257 if (fabsf(dx) < 0.01f && fabsf(dy) < 0.01f)
00258 {
00259 PrimitivesDrawer::DrawCircle(pImage, p1, radius, r, g, b, -1);
00260 }
00261 else if (fabsf(dy) < fabsf(dx))
00262 {
00263 const float slope = dy / dx;
00264 const int max_x = int(p2.x + 0.5f);
00265 float y = p1.y + 0.5f;
00266
00267 if (p1.x < p2.x)
00268 {
00269 for (int x = int(p1.x + 0.5f); x <= max_x; x++, y += slope)
00270 PrimitivesDrawer::DrawCircle(pImage, float(x), floor(y), radius, r, g, b, -1);
00271 }
00272 else
00273 {
00274 for (int x = int(p1.x + 0.5f); x >= max_x; x--, y -= slope)
00275 PrimitivesDrawer::DrawCircle(pImage, float(x), floor(y), radius, r, g, b, -1);
00276 }
00277 }
00278 else
00279 {
00280 const float slope = dx / dy;
00281 const int max_y = int(p2.y + 0.5f);
00282 float x = p1.x + 0.5f;
00283
00284 if (p1.y < p2.y)
00285 {
00286 for (int y = int(p1.y + 0.5f); y <= max_y; y++, x += slope)
00287 PrimitivesDrawer::DrawCircle(pImage, floor(x), float(y), radius, r, g, b, -1);
00288 }
00289 else
00290 {
00291 for (int y = int(p1.y + 0.5f); y >= max_y; y--, x -= slope)
00292 PrimitivesDrawer::DrawCircle(pImage, floor(x), float(y), radius, r, g, b, -1);
00293 }
00294 }
00295 }
00296 }
00297
00298 void PrimitivesDrawer::DrawLine(CByteImage *pImage, const PointPair2d &line, int r, int g, int b, int thickness)
00299 {
00300 DrawLine(pImage, line.p1, line.p2, r, g, b, thickness);
00301 }
00302
00303 void DrawCircleAA(CByteImage *pImage, float mx, float my, float radius, int r, int g, int b, int thickness)
00304 {
00305 const int min_x = int(mx - radius);
00306 const int min_y = int(my - radius);
00307 const int max_x = int(mx + radius);
00308 const int max_y = int(my + radius);
00309 int i;
00310
00311 const float r2 = radius * radius;
00312
00313 if (thickness == -1)
00314 {
00315 for (i = min_y; i <= max_y; i++)
00316 {
00317 const float d = r2 - (my - (float)i) * (my - (float)i);
00318
00319 if (d >= 0)
00320 {
00321 const float x = sqrtf((float)d);
00322
00323 int sx = (int)ceil(mx - x);
00324 int ex = (int)floor(mx + x);
00325
00326 float sb = (float)sx - (mx - x);
00327 float eb = (mx + x) - (float)ex;
00328
00329 PrimitivesDrawer::DrawPointBlended(pImage, sx, i, r, g, b, sb);
00330
00331 for (int j = sx+1; j <= ex-1; j++)
00332 PrimitivesDrawer::DrawPoint(pImage, j, i, r, g, b);
00333
00334 PrimitivesDrawer::DrawPointBlended(pImage, ex, i, r, g, b, eb);
00335 }
00336 }
00337 }
00338 else
00339 {
00340 if (thickness == 1)
00341 {
00342 for (i = min_y; i <= max_y; i++)
00343 {
00344 const float d = r2 - (my - (float)i) * (my - (float)i);
00345
00346 if (d >= 0)
00347 {
00348 const float x = sqrtf(d);
00349
00350 int sx = (int)ceil(mx - x);
00351 int ex = (int)floor(mx + x);
00352
00353 float sb = (float)sx - (mx - x);
00354 float eb = (mx + x) - (float)ex;
00355
00356 PrimitivesDrawer::DrawPointBlended(pImage, sx-1, i, r, g, b, sb);
00357 PrimitivesDrawer::DrawPointBlended(pImage, sx, i, r, g, b, 1.0f - sb);
00358
00359 PrimitivesDrawer::DrawPointBlended(pImage, ex, i, r, g, b, 1.0f - eb);
00360 PrimitivesDrawer::DrawPointBlended(pImage, ex+1, i, r, g, b, eb);
00361 }
00362 }
00363
00364 for (i = min_x; i <= max_x; i++)
00365 {
00366 const float d = r2 - (mx - (float)i) * (mx - (float)i);
00367
00368 if (d >= 0)
00369 {
00370 const float y = sqrtf(d);
00371
00372 int sy = (int)ceil(my - y);
00373 int ey = (int)floor(my + y);
00374
00375 float sb = (float)sy - (my - y);
00376 float eb = (my + y) - (float)ey;
00377
00378 PrimitivesDrawer::DrawPointBlended(pImage, i, sy-1, r, g, b, sb);
00379 PrimitivesDrawer::DrawPointBlended(pImage, i, sy, r, g, b, 1.0f - sb);
00380
00381 PrimitivesDrawer::DrawPointBlended(pImage, i, ey, r, g, b, 1.0f - eb);
00382 PrimitivesDrawer::DrawPointBlended(pImage, i, ey+1, r, g, b, eb);
00383 }
00384 }
00385 }
00386 else
00387 {
00388 const float radius = 0.5f * (float)thickness;
00389
00390 for (i = min_x; i <= max_x; i++)
00391 {
00392 const float d = r2 - (mx - i) * (mx - i);
00393
00394 if (d >= 0.0f)
00395 {
00396 const float y = sqrtf(d);
00397 DrawCircleAA(pImage, float(i), floor(my + y), radius, r, g, b, -1);
00398 DrawCircleAA(pImage, float(i), floor(my - y), radius, r, g, b, -1);
00399 }
00400 }
00401
00402 for (i = min_y; i <= max_y; i++)
00403 {
00404 const float d = r2 - (my - i) * (my - i);
00405
00406 if (d >= 0.0f)
00407 {
00408 const float x = sqrtf(d);
00409 DrawCircleAA(pImage, floor(mx + x), float(i), radius, r, g, b, -1);
00410 DrawCircleAA(pImage, floor(mx - x), float(i), radius, r, g, b, -1);
00411 }
00412 }
00413 }
00414 }
00415 }
00416
00417 void PrimitivesDrawer::DrawCircle(CByteImage *pImage, float mx, float my, float radius, int r, int g, int b, int thickness, bool antiAlias)
00418 {
00419 if (antiAlias)
00420 {
00421 DrawCircleAA(pImage, mx, my, radius, r, g, b, thickness);
00422 return;
00423 }
00424
00425 const int mx_int = my_round(mx);
00426 const int my_int = my_round(my);
00427 const int radius_int = my_round(radius);
00428
00429 mx = float(mx_int);
00430 my = float(my_int);
00431
00432 const int min_x = mx_int - radius_int;
00433 const int min_y = my_int - radius_int;
00434 const int max_x = mx_int + radius_int;
00435 const int max_y = my_int + radius_int;
00436
00437 const int r2 = radius_int * radius_int;
00438
00439 if (thickness == -1)
00440 {
00441 int i;
00442
00443 for (i = min_y; i <= max_y; i++)
00444 {
00445 const int d = r2 - (my_int - i) * (my_int - i);
00446
00447 if (d >= 0)
00448 {
00449 const int x = int(sqrtf(float(d)) + 0.5f);
00450
00451 const int sx = mx_int - x;
00452 const int ex = mx_int + x;
00453
00454 for (int j = sx; j <= ex; j++)
00455 PrimitivesDrawer::DrawPoint(pImage, j, i, r, g, b);
00456 }
00457 }
00458
00459 for (i = min_x; i <= max_x; i++)
00460 {
00461 const int d = r2 - (mx_int - i) * (mx_int - i);
00462
00463 if (d >= 0)
00464 {
00465 const int y = int(sqrtf(float(d)) + 0.5f);
00466
00467 PrimitivesDrawer::DrawPoint(pImage, i, my_int - y, r, g, b);
00468 PrimitivesDrawer::DrawPoint(pImage, i, my_int + y, r, g, b);
00469 }
00470 }
00471 }
00472 else
00473 {
00474 if (thickness == 1)
00475 {
00476 int i;
00477
00478 for (i = min_y; i <= max_y; i++)
00479 {
00480 const int d = r2 - (my_int - i) * (my_int - i);
00481
00482 if (d >= 0)
00483 {
00484 const int x = int(sqrtf(float(d)) + 0.5f);
00485
00486 PrimitivesDrawer::DrawPoint(pImage, mx_int - x, i, r, g, b);
00487 PrimitivesDrawer::DrawPoint(pImage, mx_int + x, i, r, g, b);
00488 }
00489 }
00490
00491 for (i = min_x; i <= max_x; i++)
00492 {
00493 const int d = r2 - (mx_int - i) * (mx_int - i);
00494
00495 if (d >= 0)
00496 {
00497 const int y = int(sqrtf(float(d)) + 0.5f);
00498
00499 PrimitivesDrawer::DrawPoint(pImage, i, my_int - y, r, g, b);
00500 PrimitivesDrawer::DrawPoint(pImage, i, my_int + y, r, g, b);
00501 }
00502 }
00503 }
00504 else
00505 {
00506 const float fThicknessRadius = 0.5f * thickness;
00507
00508 int i;
00509
00510 for (i = min_x; i <= max_x; i++)
00511 {
00512 const int d = r2 - (mx_int - i) * (mx_int - i);
00513
00514 if (d >= 0)
00515 {
00516 const int y = int(sqrtf(float(d)) + 0.5f);
00517
00518 PrimitivesDrawer::DrawCircle(pImage, float(i), float(my_int - y), fThicknessRadius, r, g, b, -1);
00519 PrimitivesDrawer::DrawCircle(pImage, float(i), float(my_int + y), fThicknessRadius, r, g, b, -1);
00520 }
00521 }
00522
00523 for (i = min_y; i <= max_y; i++)
00524 {
00525 const int d = r2 - (my_int - i) * (my_int - i);
00526
00527 if (d >= 0)
00528 {
00529 const int x = int(sqrtf(float(d)) + 0.5f);
00530
00531 PrimitivesDrawer::DrawCircle(pImage, float(mx_int - x), float(i), fThicknessRadius, r, g, b, -1);
00532 PrimitivesDrawer::DrawCircle(pImage, float(mx_int + x), float(i), fThicknessRadius, r, g, b, -1);
00533 }
00534 }
00535 }
00536 }
00537 }
00538
00539 void PrimitivesDrawer::DrawCircle(CByteImage *pImage, const Vec2d ¢er, float radius, int r, int g, int b, int thickness, bool antiAlias)
00540 {
00541 DrawCircle(pImage, center.x, center.y, radius, r, g, b, thickness, antiAlias);
00542 }
00543
00544 void PrimitivesDrawer::DrawCircle(CByteImage *pImage, const Circle2d &circle, int r, int g, int b, int thickness, bool antiAlias)
00545 {
00546 DrawCircle(pImage, circle.center.x, circle.center.y, circle.radius, r, g, b, thickness, antiAlias);
00547 }
00548
00549 void PrimitivesDrawer::DrawLineNormal(CByteImage *pImage, float nx, float ny, float c, int r, int g, int b, int thickness)
00550 {
00551 if (thickness == 1)
00552 {
00553 if (fabsf(nx) > fabsf(ny))
00554 {
00555 const float m = -ny / nx;
00556 const float cc = -c / nx;
00557
00558 for (int y = 0; y < pImage->height; y++)
00559 {
00560 Vec2d p = { floor(m * y + cc + 0.5f), float(y) };
00561 PrimitivesDrawer::DrawPoint(pImage, p, r, g, b);
00562 }
00563 }
00564 else
00565 {
00566 const float m = -nx / ny;
00567 const float cc = -c / ny;
00568
00569 for (int x = 0; x < pImage->width; x++)
00570 {
00571 Vec2d p = { float(x), floor(m * x + cc + 0.5f) };
00572 PrimitivesDrawer::DrawPoint(pImage, p, r, g, b);
00573 }
00574 }
00575 }
00576 else
00577 {
00578 const float radius = 0.5f * thickness;
00579
00580 if (fabsf(nx) > fabsf(ny))
00581 {
00582 const float m = -ny / nx;
00583 const float cc = -c / nx;
00584
00585 for (int y = 0; y < pImage->height; y++)
00586 {
00587 Vec2d p = { floor(m * y + cc + 0.5f), float(y) };
00588 PrimitivesDrawer::DrawCircle(pImage, p, radius, r, g, b);
00589 }
00590 }
00591 else
00592 {
00593 const float m = -nx / ny;
00594 const float cc = -c / ny;
00595
00596 for (int x = 0; x < pImage->width; x++)
00597 {
00598 Vec2d p = { float(x), floor(m * x + cc + 0.5f) };
00599 PrimitivesDrawer::DrawCircle(pImage, p, radius, r, g, b);
00600 }
00601 }
00602 }
00603 }
00604
00605 void PrimitivesDrawer::DrawLinePolar(CByteImage *pImage, float theta, float r, int color_r, int color_g, int color_b, int thickness)
00606 {
00607 DrawLineNormal(pImage, cosf(theta), sinf(theta), -r, color_r, color_g, color_b, thickness);
00608 }
00609
00610 void PrimitivesDrawer::DrawLine(CByteImage *pImage, const StraightLine2d &line, int r, int g, int b, int thickness)
00611 {
00612 DrawLineNormal(pImage, line.normalVector.x, line.normalVector.y, line.c, r, g, b, thickness);
00613 }
00614
00615 void PrimitivesDrawer::DrawCross(CByteImage *pImage, const Vec2d &point, int length, int r, int g, int b)
00616 {
00617 const int x = int(point.x + 0.5f);
00618 const int y = int(point.y + 0.5f);
00619
00620 const int l = length / 2;
00621
00622 for (int i = -l; i <= l; i++)
00623 {
00624 PrimitivesDrawer::DrawPoint(pImage, x + i, y, r, g, b);
00625 PrimitivesDrawer::DrawPoint(pImage, x, y + i, r, g, b);
00626 }
00627 }
00628
00629
00630
00631
00632 struct Edge
00633 {
00634 Edge()
00635 {
00636 next = 0;
00637 }
00638
00639
00640 int max_y;
00641
00642
00643 float x_intersection;
00644
00645
00646 float inverse_gradient;
00647
00648
00649 Edge *next;
00650 };
00651
00652 struct Vec2dInt
00653 {
00654 int x;
00655 int y;
00656 };
00657
00658 static void InsertEdge(Edge *ppEdgeList, Edge *pEdge)
00659 {
00660
00661 Edge *q = ppEdgeList;
00662 Edge *p = q->next;
00663
00664 while (p)
00665 {
00666 if (pEdge->x_intersection < p->x_intersection)
00667 break;
00668
00669 q = p;
00670 p = p->next;
00671 }
00672
00673 pEdge->next = q->next;
00674 q->next = pEdge;
00675 }
00676
00677
00678
00679
00680
00681
00682 static void MakeEdgeRecord(const Vec2dInt &lower, const Vec2dInt &upper, int yComp, Edge *pEdge, Edge **ppEdgeList, int height)
00683 {
00684 pEdge->inverse_gradient = float(upper.x - lower.x) / float(upper.y - lower.y);
00685 pEdge->x_intersection = float(lower.x);
00686
00687 if (upper.y < yComp)
00688 pEdge->max_y = upper.y - 1;
00689 else
00690 pEdge->max_y = upper.y;
00691
00692 if (lower.y >= 0 && lower.y < height)
00693 InsertEdge(ppEdgeList[lower.y], pEdge);
00694 }
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705 static int NextY(int nIndex, const Vec2dInt *pPoints, int nVertices)
00706 {
00707
00708 int j = nIndex + 1 > nVertices - 1 ? 0 : nIndex + 1;
00709
00710 while (pPoints[nIndex].y == pPoints[j].y)
00711 {
00712 if (j + 1 > nVertices - 1)
00713 j = 0;
00714 else
00715 j++;
00716 }
00717
00718 return pPoints[j].y;
00719 }
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729 static void BuildEdgeList(const Vec2dInt *pPoints, int nPoints, Edge **ppResultEdges, int height)
00730 {
00731 int nPreviousY = pPoints[nPoints - 2].y;
00732 Vec2dInt v1 = { pPoints[nPoints - 1].x, pPoints[nPoints - 1].y };
00733
00734 for (int i = 0; i < nPoints; i++)
00735 {
00736 Vec2dInt v2 = pPoints[i];
00737
00738 if (v1.y != v2.y)
00739 {
00740 Edge *pEdge = new Edge();
00741
00742 if (v1.y < v2.y)
00743 MakeEdgeRecord(v1, v2, NextY(i, pPoints, nPoints), pEdge, ppResultEdges, height);
00744 else
00745 MakeEdgeRecord(v2, v1, nPreviousY, pEdge, ppResultEdges, height);
00746 }
00747
00748 nPreviousY = v1.y;
00749 v1 = v2;
00750 }
00751 }
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767 static void BuildActiveList(int y, Edge *pActiveEdge, Edge **ppEdges)
00768 {
00769 Edge *p = ppEdges[y]->next;
00770
00771 while (p)
00772 {
00773 Edge *q = p->next;
00774 InsertEdge(pActiveEdge, p);
00775 p = q;
00776 }
00777 }
00778
00779
00780
00781
00782
00783
00784 static void FillScan(CByteImage *pImage, int y, Edge *pActiveEdge, int r, int g, int b)
00785 {
00786 const int width = pImage->width;
00787 const int height = pImage->height;
00788 const int nPixels = width * height;
00789
00790 if (y < 0 || y >= height)
00791 return;
00792
00793 unsigned char *pixels = pImage->type == CByteImage::eRGB24 ? pImage->pixels + 3 * y * width : pImage->pixels + y * width;
00794
00795 Edge *p1 = pActiveEdge->next;
00796
00797 while (p1 && p1->next)
00798 {
00799 const Edge *p2 = p1->next;
00800
00801 const int x1 = MY_MIN(MY_MAX(int(p1->x_intersection + 0.5f), 0), pImage->width - 1);
00802 const int x2 = MY_MAX(MY_MIN(int(p2->x_intersection + 0.5f), pImage->width - 1), 0);
00803
00804 if (pImage->type == CByteImage::eRGB24)
00805 {
00806 for (int x = x1, offset = 3 * x1; x <= x2; x++, offset += 3)
00807 {
00808 pixels[offset] = r;
00809 pixels[offset + 1] = g;
00810 pixels[offset + 2] = b;
00811 }
00812 }
00813 else if (pImage->type == CByteImage::eRGB24Split)
00814 {
00815 memset(pixels + x1, r, x2 - x1 + 1);
00816 memset(pixels + x1 + nPixels, g, x2 - x1 + 1);
00817 memset(pixels + x1 + (nPixels << 1), b, x2 - x1 + 1);
00818 }
00819
00820 p1 = p2->next;
00821 }
00822 }
00823
00824 static void FillScan(CByteImage *pImage, int y, Edge *pActiveEdge, int g)
00825 {
00826 if (y < 0 || y >= pImage->height)
00827 return;
00828
00829 unsigned char *pixels = pImage->pixels + y * pImage->width;
00830
00831 Edge *p1 = pActiveEdge->next;
00832
00833 while (p1 && p1->next)
00834 {
00835 const Edge *p2 = p1->next;
00836
00837 const int x1 = MY_MIN(MY_MAX(int(p1->x_intersection + 0.5f), 0), pImage->width - 1);
00838 const int x2 = MY_MAX(MY_MIN(int(p2->x_intersection + 0.5f), pImage->width - 1), 0);
00839
00840 memset(pixels + x1, g, x2 - x1 + 1);
00841
00842 p1 = p2->next;
00843 }
00844 }
00845
00846 static void DeleteAfter(Edge *pEdge)
00847 {
00848
00849 Edge *p = pEdge->next;
00850 pEdge->next = p->next;
00851 delete p;
00852 }
00853
00854 static void UpdateActiveList(int y, Edge *pActiveEdge)
00855 {
00856
00857
00858 Edge *q = pActiveEdge;
00859 Edge *p = pActiveEdge->next;
00860
00861 while (p)
00862 {
00863 if (y >= p->max_y)
00864 {
00865 p = p->next;
00866 DeleteAfter(q);
00867 }
00868 else
00869 {
00870 p->x_intersection += p->inverse_gradient;
00871 q = p;
00872 p = p->next;
00873 }
00874 }
00875 }
00876
00877 static void ResortActiveList(Edge *pActiveEdge)
00878 {
00879
00880 Edge *p = pActiveEdge->next;
00881 pActiveEdge->next = 0;
00882
00883 while (p)
00884 {
00885 Edge *q = p->next;
00886 InsertEdge(pActiveEdge, p);
00887 p = q;
00888 }
00889 }
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900 static void FillPolygon(CByteImage *pImage, const Vec2d *pPoints, int nPoints, int r, int g, int b)
00901 {
00902 const int height = pImage->height;
00903
00904 int i;
00905
00906
00907 Edge **ppEdges = new Edge*[height];
00908 for (i = 0; i < height; i++)
00909 ppEdges[i] = new Edge();
00910
00911
00912 Vec2dInt *pPointsInt = new Vec2dInt[nPoints];
00913 for (i = 0; i < nPoints; i++)
00914 {
00915 pPointsInt[i].x = int(pPoints[i].x + 0.5f);
00916 pPointsInt[i].y = int(pPoints[i].y + 0.5f);
00917 }
00918
00919 if (pPoints[0].x == pPoints[nPoints - 1].x && pPoints[0].y == pPoints[nPoints - 1].y)
00920 nPoints--;
00921
00922
00923 BuildEdgeList(pPointsInt, nPoints, ppEdges, height);
00924
00925
00926 delete [] pPointsInt;
00927
00928 Edge *pActiveEdge = new Edge();
00929
00930
00931 for (i = 0; i < height; i++)
00932 {
00933 BuildActiveList(i, pActiveEdge, ppEdges);
00934
00935 if (pActiveEdge->next)
00936 {
00937 if (pImage->type == CByteImage::eGrayScale)
00938 FillScan(pImage, i, pActiveEdge, (r + (g << 1) + b + 2) >> 2);
00939 else
00940 FillScan(pImage, i, pActiveEdge, r, g, b);
00941
00942 UpdateActiveList(i, pActiveEdge);
00943 ResortActiveList(pActiveEdge);
00944 }
00945 }
00946
00947
00948 for (i = 0; i < height; i++)
00949 delete ppEdges[i];
00950 delete [] ppEdges;
00951 delete pActiveEdge;
00952 }
00953
00954 void PrimitivesDrawer::DrawPolygon(CByteImage *pImage, const Vec2d *pPoints, int nPoints, int r, int g, int b, int thickness)
00955 {
00956 if (nPoints < 3)
00957 {
00958 printf("error: at least three points must be provided for PrimitivesDrawer::DrawPolygon\n");
00959 return;
00960 }
00961
00962 if (thickness == -1)
00963 {
00964 FillPolygon(pImage, pPoints, nPoints, r, g, b);
00965 }
00966 else
00967 {
00968 for (int i = 0; i < nPoints - 1; i++)
00969 DrawLine(pImage, pPoints[i], pPoints[i + 1], r, g, b, thickness);
00970
00971 if (pPoints[0].x != pPoints[nPoints - 1].x || pPoints[0].y != pPoints[nPoints - 1].y)
00972 DrawLine(pImage, pPoints[nPoints - 1], pPoints[0], r, g, b, thickness);
00973 }
00974 }
00975
00976 void PrimitivesDrawer::DrawPolygon(CByteImage *pImage, const CVec2dArray &points, int r, int g, int b, int thickness)
00977 {
00978 const int nPoints = points.GetSize();
00979
00980 Vec2d *pPoints = new Vec2d[nPoints];
00981
00982 for (int i = 0; i < nPoints; i++)
00983 Math2d::SetVec(pPoints[i], points[i]);
00984
00985 DrawPolygon(pImage, pPoints, nPoints, r, g, b, thickness);
00986
00987 delete [] pPoints;
00988 }
00989
00990 void PrimitivesDrawer::DrawEllipse(CByteImage *pImage, const Ellipse2d &ellipse, int r, int g, int b, int thickness)
00991 {
00992 const float mx = ellipse.center.x;
00993 const float my = ellipse.center.y;
00994
00995 const int min_x = int(mx - ellipse.radius_x + 0.5f);
00996 const int min_y = int(my - ellipse.radius_y + 0.5f);
00997 const int max_x = int(mx + ellipse.radius_x + 0.5f);
00998 const int max_y = int(my + ellipse.radius_y + 0.5f);
00999
01000 const int rx = int(ellipse.radius_x + 0.5f);
01001 const int ry = int(ellipse.radius_y + 0.5f);
01002
01003 int i;
01004
01005 const float a2 = ellipse.radius_x * ellipse.radius_x;
01006 const float b2 = ellipse.radius_y * ellipse.radius_y;
01007 const float a2divb2 = a2 / b2;
01008 const float b2diva2 = b2 / a2;
01009
01010 const float ca = cosf(ellipse.angle);
01011 const float sa = sinf(ellipse.angle);
01012
01013 if (thickness == -1)
01014 {
01015 printf("error: filling of ellipses has not been implemented yet in PrimitivesDrawer::DrawEllipse\n");
01016 }
01017 else
01018 {
01019 if (thickness == 1)
01020 {
01021 for (i = -ry; i <= ry; i++)
01022 {
01023 const float y = float(i);
01024 const float d = a2 - a2divb2 * y * y;
01025
01026 if (d >= 0.0f)
01027 {
01028 const float x = sqrtf(d);
01029
01030 const float xr = ca * x - sa * y;
01031 const float yr = sa * x + ca * y;
01032
01033 PrimitivesDrawer::DrawPoint(pImage, int(mx + xr + 0.5f), int(my + yr + 0.5f), r, g, b);
01034 PrimitivesDrawer::DrawPoint(pImage, int(mx - xr + 0.5f), int(my - yr + 0.5f) , r, g, b);
01035 }
01036 }
01037
01038 for (i = -rx; i <= rx; i++)
01039 {
01040 const float x = float(i);
01041 const float d = b2 - b2diva2 * x * x;
01042
01043 if (d >= 0.0f)
01044 {
01045 const float y = sqrtf(d);
01046
01047 const float xr = ca * x - sa * y;
01048 const float yr = sa * x + ca * y;
01049
01050 PrimitivesDrawer::DrawPoint(pImage, int(mx + xr + 0.5f), int(my + yr + 0.5f), r, g, b);
01051 PrimitivesDrawer::DrawPoint(pImage, int(mx - xr + 0.5f), int(my - yr + 0.5f), r, g, b);
01052 }
01053 }
01054 }
01055 else
01056 {
01057 const float thickness_radius = 0.5f * thickness;
01058
01059 for (i = -ry; i <= ry; i++)
01060 {
01061 const float y = float(i);
01062 const float d = a2 - a2divb2 * y * y;
01063
01064 if (d >= 0.0f)
01065 {
01066 const float x = sqrtf(d);
01067
01068 const float xr = ca * x - sa * y;
01069 const float yr = sa * x + ca * y;
01070
01071 PrimitivesDrawer::DrawCircle(pImage, mx + xr, my + yr, thickness_radius, r, g, b, -1);
01072 PrimitivesDrawer::DrawCircle(pImage, mx - xr, my - yr, thickness_radius, r, g, b, -1);
01073 }
01074 }
01075
01076 for (i = -rx; i <= rx; i++)
01077 {
01078 const float x = float(i);
01079 const float d = b2 - b2diva2 * x * x;
01080
01081 if (d >= 0.0f)
01082 {
01083 const float y = sqrtf(d);
01084
01085 const float xr = ca * x - sa * y;
01086 const float yr = sa * x + ca * y;
01087
01088 PrimitivesDrawer::DrawCircle(pImage, mx + xr, my + yr, thickness_radius, r, g, b, -1);
01089 PrimitivesDrawer::DrawCircle(pImage, mx - xr, my - yr, thickness_radius, r, g, b, -1);
01090 }
01091 }
01092 }
01093 }
01094 }
01095
01096 void PrimitivesDrawer::DrawRectangle(CByteImage *pImage, const Rectangle2d &rectangle, int r, int g, int b, int thickness)
01097 {
01098 Vec2d cornerPoints[4];
01099 Math2d::ComputeRectangleCornerPoints(rectangle, cornerPoints);
01100
01101 DrawPolygon(pImage, cornerPoints, 4, r, g, b, thickness);
01102 }