PrimitivesDrawer.cpp
Go to the documentation of this file.
00001 // ****************************************************************************
00002 // This file is part of the Integrating Vision Toolkit (IVT).
00003 //
00004 // The IVT is maintained by the Karlsruhe Institute of Technology (KIT)
00005 // (www.kit.edu) in cooperation with the company Keyetech (www.keyetech.de).
00006 //
00007 // Copyright (C) 2014 Karlsruhe Institute of Technology (KIT).
00008 // All rights reserved.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are met:
00012 //
00013 // 1. Redistributions of source code must retain the above copyright
00014 //    notice, this list of conditions and the following disclaimer.
00015 //
00016 // 2. Redistributions in binary form must reproduce the above copyright
00017 //    notice, this list of conditions and the following disclaimer in the
00018 //    documentation and/or other materials provided with the distribution.
00019 //
00020 // 3. Neither the name of the KIT nor the names of its contributors may be
00021 //    used to endorse or promote products derived from this software
00022 //    without specific prior written permission.
00023 //
00024 // THIS SOFTWARE IS PROVIDED BY THE KIT AND CONTRIBUTORS “AS IS” AND ANY
00025 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00026 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00027 // DISCLAIMED. IN NO EVENT SHALL THE KIT OR CONTRIBUTORS BE LIABLE FOR ANY
00028 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00029 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00030 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00031 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00032 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00033 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034 // ****************************************************************************
00035 // ****************************************************************************
00036 // Filename:  PrimitivesDrawer.cpp
00037 // Author:    Pedram Azad
00038 // Date:      2005
00039 // ****************************************************************************
00040 // Changes:   03.03.2010, Derick Beng Youh
00041 //            * Added function FillPolygon
00042 // ****************************************************************************
00043 
00044 // ****************************************************************************
00045 // Includes
00046 // ****************************************************************************
00047 
00048 #include <new> // for explicitly using correct new/delete operators on VC DSPs
00049 
00050 // IVT
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 // system
00058 #include <math.h>
00059 #include <limits>
00060 
00061 
00062 
00063 // ****************************************************************************
00064 // Helper functions
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 // Functions
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 &region, 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 &center, 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         // maximum y-coordinate between p1 and p2
00640         int max_y;
00641 
00642         // point of intersection between an edge and a scanline
00643         float x_intersection;
00644         
00645         // inverse of the gradient of an edge dx / dy
00646         float inverse_gradient;
00647 
00648         // the next edge in the linked list
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         // inserts edge into linked list in order of increasing x_intersection field
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 // Store lower-y coordinate and inverse slope for each edge.
00679 // Adjust and store max_y coordinate for edges that are the lower member
00680 // of a monotically increasing or decreasing pair of edges.
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 // For nIndex, return y-coordinate of the next non-horizontal edge which
00698 // can be created by connecting the vertices in pPoints in their respective
00699 // order to one another.
00700 //
00701 // nIndex: index of Vec2dInt to start with
00702 // pPoints: array of points
00703 // nPoints: number of points
00704 // ****************************************************************************
00705 static int NextY(int nIndex, const Vec2dInt *pPoints, int nVertices)
00706 {
00707         //j = k % count - 1 
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 // Function used for creating a list of all edges, according to the points in
00723 // in pPoints, respecting their order, that is pts[0]->pts[1]->..pts[n-1]->pts[0]
00724 // 
00725 // pPoints: array of points of the polygon with order of connection
00726 // nPoints: the number of points of the polygon
00727 // ppEdges: result parameter for the list of edges to be computed
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) // non-horizontal line
00739                 {
00740                         Edge *pEdge = new Edge();
00741                         
00742                         if (v1.y < v2.y)
00743                                 MakeEdgeRecord(v1, v2, NextY(i, pPoints, nPoints), pEdge, ppResultEdges, height); // up-going edge
00744                         else
00745                                 MakeEdgeRecord(v2, v1, nPreviousY, pEdge, ppResultEdges, height); // down-going edge
00746                 }
00747        
00748                 nPreviousY = v1.y;
00749                 v1 = v2;
00750         }
00751 }
00752 
00753 
00754 
00755 
00756 // ****************************************************************************
00757 // During the algorithm, when a scanline intersects an edge on its 
00758 // upper-coordinates, when the scanning is done from up downward, then the edge
00759 // is said to become active, so this method is used to always build a list of
00760 // active edges during the scanning procedure.
00761 //
00762 // y: the y-coordinate of the scan line at every stage of scanning
00763 // pActiveEdge: list of edges that are already active
00764 // ppEdges: list of all the edges of the polygon each of which is tested,
00765 //          if it intersects the scanline (y)
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 // Having all the active edges of each scan stage, all the pixels that lie 
00781 // horizontally between each pair of intersection points are filled with the
00782 // desired color.
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         // delete edge from linked list
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         // delete completed edges
00857         // update attribute x_intersection field for others which are still active
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         // resort active list after it has been updated
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 // Implementation of the scan line fill algorithm by Derick Beng Yuh.
00894 //
00895 // pImage: the target image
00896 // pPoints: array of points of the polygon with order of connection
00897 // nPoints: the number of points of the polygon
00898 // r, g, b: target color in RGB
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         // allocate memory for edges
00907         Edge **ppEdges = new Edge*[height];
00908         for (i = 0; i < height; i++)
00909                 ppEdges[i] = new Edge();
00910 
00911         // convert float points to int
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         // constuct edges 
00923         BuildEdgeList(pPointsInt, nPoints, ppEdges, height);
00924 
00925         // free memory
00926         delete [] pPointsInt;
00927 
00928         Edge *pActiveEdge = new Edge();
00929 
00930         // run algorithm
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         // free memory for edges
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 }


asr_ivt
Author(s): Allgeyer Tobias, Hutmacher Robin, Kleinert Daniel, Meißner Pascal, Scholz Jonas, Stöckle Patrick
autogenerated on Thu Jun 6 2019 21:46:58