ivl 679
ivl/details/image/functions/aa_drawing_functions.hpp
00001 /* This file is part of the ivl C++ library <http://image.ntua.gr/ivl>.
00002    A C++ template library extending syntax towards mathematical notation.
00003 
00004    Copyright (C) 2012 Yannis Avrithis <iavr@image.ntua.gr>
00005    Copyright (C) 2012 Kimon Kontosis <kimonas@image.ntua.gr>
00006 
00007    ivl is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU Lesser General Public License 
00009    version 3 as published by the Free Software Foundation.
00010 
00011    Alternatively, you can redistribute it and/or modify it under the terms 
00012    of the GNU General Public License version 2 as published by the Free 
00013    Software Foundation.
00014 
00015    ivl is distributed in the hope that it will be useful,
00016    but WITHOUT ANY WARRANTY; without even the implied warranty of
00017    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
00018    See the GNU General Public License for more details.
00019 
00020    You should have received a copy of the GNU General Public License 
00021    and a copy of the GNU Lesser General Public License along 
00022    with ivl. If not, see <http://www.gnu.org/licenses/>. */
00023 
00024 #ifndef IVL_IMAGE_DETAILS_FUNCTIONS_AA_DRAWING_FUNCTIONS_HPP
00025 #define IVL_IMAGE_DETAILS_FUNCTIONS_AA_DRAWING_FUNCTIONS_HPP
00026 
00027 namespace ivl {
00028 
00029 namespace image_details {
00030 
00031 inline bool cw(double_point<2> a, double_point<2> b, double_point<2> p)
00032 // returns true if a, b, c are clockwise
00033 {
00034         return (b.y - a.y) * (p.x - a.x) >= (b.x - a.x) * (p.y - a.y);
00035 }
00036 
00037 inline double cwd(double_point<2> a, double_point<2> b, double_point<2> p)
00038 // returns > 0 if a, b, c are clockwise, 0 if they are in line, < 0 counter clockwise
00039 {
00040         return (b.y - a.y) * (p.x - a.x) - (b.x - a.x) * (p.y - a.y);
00041 }
00042 
00043 inline bool intrig(double_point<2> a, double_point<2> b, double_point<2> c, double_point<2> p)
00044 // returns true if the point p lies in the triangle a, b, c (demands: a, b, c clockwise)
00045 {
00046         return cw(a, b, p) && cw(b, c, p) && cw(c, a, p);
00047 }
00048 
00049 inline bool inquad(double_point<2> a, double_point<2> b, double_point<2> c, double_point<2> d, double_point<2> p)
00050 // returns true if the point p is in the quad, and demands a, b, c, d clockwise
00051 {
00052         return cw(a, b, p) && cw(b, c, p) && cw(c, d, p) && cw(d, a, p);
00053 }
00054 
00055 inline bool crossinter(double_point<2> a1, double_point<2> a2, double_point<2> b1, double_point<2> b2)
00056 // returns true if the line segments (a1, a2) and (b1, b2) intersect
00057 {
00058         return (cwd(a1, a2, b1) * cwd(a1, a2, b2) < 0 ) && (cwd(b1, b2, a1) * cwd(b1, b2, a2) < 0 );
00059 }
00060 
00061 inline bool incirc(double_point<2> a, double sqrradius, double_point<2> p)
00062 // returns true if the point is in the circle (a, square_root(sqrradius) )
00063 {
00064         double dy = a.y - p.y;
00065         double dx = a.x - p.x;
00066         return dx * dx + dy * dy <= sqrradius;
00067 }
00068 
00069 inline bool inellipse(double_point<2>::base_class a, double_point<2>::base_class b,
00070                                         double sqrradius, double_point<2>::base_class p)
00071 // returns true if the point is in the circle (a, square_root(sqrradius) )
00072 {
00073         double dy1 = a.y - p.y;
00074         double dx1 = a.x - p.x;
00075         double dy2 = b.y - p.y;
00076         double dx2 = b.x - p.x;
00077 
00078         return dx1 * dx1 + dy1 * dy1 + dx2 * dx2 + dy2 * dy2 +
00079                 2 * std::sqrt((dx1 * dx1 + dy1 * dy1)*(dx2 * dx2 + dy2 * dy2)) <= sqrradius;
00080 }
00081 
00082 inline bool inellipse2(double_point<2>::base_class a, double_point<2>::base_class b,
00083                                         double sqrradius, double thickness,
00084                                         double_point<2>::base_class p)
00085 // returns true if the point is in the circle (a, square_root(sqrradius) )
00086 {
00087         if(thickness < 0 && inellipse(a, b, sqrradius, p)) return true;
00088         if(thickness > 0) {
00089                 double dy = p.y - (a.y + b.y) / 2.;
00090                 double dx = p.x - (a.x + b.x) / 2.;
00091 
00092                 double theta = std::atan2(dy, dx);
00093                 double_point<2> thickvec(std::sin(theta) * thickness,
00094                                                    std::cos(theta) * thickness);
00095 
00096                 if(!inellipse(a, b, sqrradius, p + thickvec)) return false;
00097         }
00098         double dy1 = p.y - a.y;
00099         double dx1 = p.x - a.x;
00100         double dy2 = p.y - b.y;
00101         double dx2 = p.x - b.x;
00102 
00103         double theta1 = std::atan2(dy1, dx1);
00104         double theta2 = std::atan2(dy2, dx2);
00105 
00106         double_point<2> normvec((std::sin(theta1) + std::sin(theta2)),
00107                                                   (std::cos(theta1) + std::cos(theta2)));
00108 
00109         theta1 = std::atan2(normvec.y, normvec.x);
00110 
00111         double_point<2> thickvec(std::sin(theta1) * thickness,
00112                                                    std::cos(theta1) * thickness);
00113 
00114 /*      double prevdy1 = dy1;
00115         double prevdy2 = dy2;
00116         double prevdx1 = dx1;
00117         double prevdx2 = dx2; */
00118 
00119         p = p + thickvec;
00120 
00121         return inellipse(a, b, sqrradius, p);
00122 
00123 /*      TODO: check if overextending inner thickness goes out of boundary of ellipse
00124         dy1  += normvec.y;
00125         dy2 += normvec.y;
00126         dx1 += normvec.x;
00127         dx2 += normvec.x;
00128 
00129         if(dy1 * prevdy1 < 0) dy1 = 0;
00130         if(dy2 * prevdy2 < 0) dy2 = 0;
00131         if(dx1 * prevdx1 < 0) dx1 = 0;
00132         if(dx2 * prevdx2 < 0) dx2 = 0;
00133 */
00134 
00135 }
00136 
00137 
00138 
00139 template <class T, class D>
00140 void AA_trig_artsy_impl(image<T, D>& im, double_point<2> a, double_point<2> b, double_point<2> c, color<T, D::Ch> col, int multisample = 32, double opacity = 1.)
00141 {
00142         if(!cw(a, b, c)) std::swap(b, c);
00143 
00144         int y0 = int(min(arr<double>(a.y, b.y, c.y))) - 1;
00145         int x0 = int(min(arr<double>(a.x, b.x, c.x))) - 1;
00146         int y1 = int(ivl::max(arr<double>(a.y, b.y, c.y))) + 1;
00147         int x1 = int(max(arr<double>(a.x, b.x, c.x))) + 1;
00148 
00149         y0 = std::max(y0, 0);
00150         x0 = std::max(x0, 0);
00151         y1 = std::min(y1, int(im.rows() - 1));
00152         x1 = std::min(x1, int(im.cols() - 1));
00153 
00154         double coveradd = opacity / double(multisample * multisample);
00155         double pixeladd = 1. / double(multisample - 1);
00156         array<double> colord = cast<double>(col);
00157 
00158         int y, x, i, j;
00159 
00160         for(y = y0; y < y1; y++) {
00161 
00162                 for(x = x0; x < x1; x++) {
00163 
00164                         double_point<2> px1(double(y) - .5, double(x) - .5);
00165                         double_point<2> px2(double(y) + .5, double(x) - .5);
00166                         double_point<2> px3(double(y) + .5, double(x) + .5);
00167                         double_point<2> px4(double(y) - .5, double(x) + .5);
00168 
00169                         bool pin1 = intrig(a, b, c, px1);
00170                         bool pin2 = intrig(a, b, c, px2);
00171                         bool pin3 = intrig(a, b, c, px3);
00172                         bool pin4 = intrig(a, b, c, px4);
00173 
00174                         bool allin = pin1 && pin2 && pin3 && pin4;
00175                         bool partin = pin1 || pin2 || pin3 || pin4;
00176 
00177                         if(!partin) partin =
00178                                 crossinter(px1, px2, a, b) || crossinter(px1, px2, b, c) || crossinter(px1, px2, c, a) ||
00179                                 crossinter(px2, px3, a, b) || crossinter(px2, px3, b, c) || crossinter(px2, px3, c, a) ||
00180                                 crossinter(px3, px4, a, b) || crossinter(px3, px4, b, c) || crossinter(px3, px4, c, a) ||
00181                                 crossinter(px4, px1, a, b) || crossinter(px4, px1, b, c) || crossinter(px4, px1, c, a);
00182 
00183                         array<double> interp;
00184                         double cover = 0.0;
00185 
00186                         if(0 && allin) im.col(y, x) = col;
00187                         else if(1 || partin) { // AA
00188                                 interp = cast<double>(im.col(y, x));
00189 
00190                                 for(i = 0; i < multisample; i++) {
00191 
00192                                         for(j = 0; j < multisample; j++) {
00193 
00194                                                 if(intrig(a, b, c, px1)) cover += coveradd;
00195 
00196                                                 px1.x += pixeladd;
00197                                         }
00198                                         px1.y += pixeladd;
00199                                 }
00200 
00201                                 interp *= (double(1.) - cover);
00202                                 interp += colord * cover;
00203 
00204                                 im.col(y, x) = cast<T>(interp);
00205                         }
00206                 }
00207         }
00208 }
00209 
00210 
00211 template <class T, class D>
00212 void AA_trig_impl(image<T, D>& im, double_point<2> a, double_point<2> b, double_point<2> c, color<T, D::Ch> col, int multisample = 8, double opacity = 1.)
00213 {
00214         // ensures that points in triangle are given in clockwise order
00215         if(!cw(a, b, c)) std::swap(b, c);
00216 
00217         // bounding box
00218         int y0 = int(min(arr<double>(a.y, b.y, c.y))) - 1;
00219         int x0 = int(min(arr<double>(a.x, b.x, c.x))) - 1;
00220         int y1 = int(max(arr<double>(a.y, b.y, c.y))) + 1;
00221         int x1 = int(max(arr<double>(a.x, b.x, c.x))) + 1;
00222 
00223         // clipping!
00224         y0 = std::max(y0, 0);
00225         x0 = std::max(x0, 0);
00226         y1 = std::min(y1, int(im.rows() - 1));
00227         x1 = std::min(x1, int(im.cols() - 1));
00228 
00229         // for multisampling
00230         double coveradd = opacity / double(multisample * multisample);
00231         double pixeladd = 1. / double(multisample + 1);
00232 
00233         // the color, in array format due to incompatibility issues. TODO: fix
00234         array<double> colord = cast<double>(col);
00235 
00236         int y, x, i, j;
00237 
00238         for(y = y0; y < y1; y++) {
00239 
00240                 for(x = x0; x < x1; x++) {
00241 
00242                         // the four corners that enclose the pixel
00243                         double_point<2> px1(double(y) - .5, double(x) - .5);
00244                         double_point<2> px2(double(y) + .5, double(x) - .5);
00245                         double_point<2> px3(double(y) + .5, double(x) + .5);
00246                         double_point<2> px4(double(y) - .5, double(x) + .5);
00247 
00248                         // checks if each of the four corners are in the shape
00249                         bool pin1 = intrig(a, b, c, px1);
00250                         bool pin2 = intrig(a, b, c, px2);
00251                         bool pin3 = intrig(a, b, c, px3);
00252                         bool pin4 = intrig(a, b, c, px4);
00253 
00254                         bool allin = pin1 && pin2 && pin3 && pin4;
00255                         bool partin = pin1 || pin2 || pin3 || pin4;
00256 
00257                         // if no point is in the shape we need to assure that
00258                         // also the shape is not in the pixel box
00259                         // the test for a tiny shape that lies fully in the pixel is omitted for speed (not very useful)
00260                         if(!partin) partin =
00261                                 crossinter(px1, px2, a, b) || crossinter(px1, px2, b, c) || crossinter(px1, px2, c, a) ||
00262                                 crossinter(px2, px3, a, b) || crossinter(px2, px3, b, c) || crossinter(px2, px3, c, a) ||
00263                                 crossinter(px3, px4, a, b) || crossinter(px3, px4, b, c) || crossinter(px3, px4, c, a) ||
00264                                 crossinter(px4, px1, a, b) || crossinter(px4, px1, b, c) || crossinter(px4, px1, c, a);
00265 
00266                         array<double> interp;
00267                         double cover = 0.0;
00268 
00269                         if(allin) {
00270                                 if(opacity == 1.) im.col(y, x) = col;
00271                                 else {
00272                                         interp = cast<double>(im.col(y, x));
00273                                         interp *= (double(1.) - opacity);
00274                                         interp += colord * opacity;
00275 
00276                                         im.col(y, x) = cast<T>(interp);
00277                                 }
00278                         } else if(partin) { // AA
00279                                 interp = cast<double>(im.col(y, x));
00280 
00281                                 px1.x += pixeladd;
00282                                 px1.y += pixeladd;
00283 
00284                                 for(i = 0; i < multisample; i++) {
00285 
00286                                         for(j = 0; j < multisample; j++) {
00287 
00288                                                 // tests a grid of (multisample x multisample) points
00289                                                 // in the pixel box and counts how many are in the shape
00290                                                 if(intrig(a, b, c, px1)) cover += coveradd;
00291 
00292                                                 px1.x += pixeladd;
00293                                         }
00294                                         px1.x = px2.x + pixeladd;
00295                                         px1.y += pixeladd;
00296                                 }
00297 
00298                                 // perform transparency with cover as a parameter
00299                                 interp *= (double(1.) - cover);
00300                                 interp += colord * cover;
00301 
00302                                 im.col(y, x) = cast<T>(interp);
00303                         }
00304                 }
00305         }
00306 }
00307 
00308 
00309 template <class T, class D>
00310 void AA_quad_impl(image<T, D>& im, double_point<2> a, double_point<2> b, double_point<2> c, double_point<2> d,
00311         color<T, D::Ch> col, int multisample = 8, double opacity = 1.)
00312 {
00313         // tries to put the points in the quad in clockwise order
00314         if(!cw(a, b, c)) std::swap(b, d);
00315 
00316         CHECK(cw(a, b, c), eshape()); // TODO: needs egeometry, but dont do it in this branch
00317         CHECK(cw(b, c, d), eshape()); // TODO: needs egeometry, but dont do it in this branch
00318         CHECK(cw(c, d, a), eshape()); // TODO: needs egeometry, but dont do it in this branch
00319         // "Quad is not cw"
00320 
00321         // bounding box
00322         int y0 = int(min(arr<double>(a.y, b.y, c.y, d.y))) - 1;
00323         int x0 = int(min(arr<double>(a.x, b.x, c.x, d.x))) - 1;
00324         int y1 = int(max(arr<double>(a.y, b.y, c.y, d.y))) + 1;
00325         int x1 = int(max(arr<double>(a.x, b.x, c.x, d.x))) + 1;
00326 
00327         // clipping!
00328         y0 = std::max(y0, 0);
00329         x0 = std::max(x0, 0);
00330         y1 = std::min(y1, int(im.rows() - 1));
00331         x1 = std::min(x1, int(im.cols() - 1));
00332 
00333         // for multisampling
00334         double coveradd = opacity / double(multisample * multisample);
00335         double pixeladd = 1. / double(multisample + 1);
00336 
00337         // the color, in array format due to incompatibility issues. TODO: fix
00338         array<double> colord = ivl::cast<double>(col);
00339 
00340         int y, x, i, j;
00341 
00342         for(y = y0; y < y1; y++) {
00343 
00344                 for(x = x0; x < x1; x++) {
00345 
00346                         // the four corners that enclose the pixel
00347                         double_point<2> px1(double(y) - .5, double(x) - .5);
00348                         double_point<2> px2(double(y) + .5, double(x) - .5);
00349                         double_point<2> px3(double(y) + .5, double(x) + .5);
00350                         double_point<2> px4(double(y) - .5, double(x) + .5);
00351 
00352                         // checks if each of the four corners are in the shape
00353                         bool pin1 = inquad(a, b, c, d, px1);
00354                         bool pin2 = inquad(a, b, c, d, px2);
00355                         bool pin3 = inquad(a, b, c, d, px3);
00356                         bool pin4 = inquad(a, b, c, d, px4);
00357 
00358                         bool allin = pin1 && pin2 && pin3 && pin4;
00359                         bool partin = pin1 || pin2 || pin3 || pin4;
00360 
00361                         // if no point is in the shape we need to assure that
00362                         // also the shape is not in the pixel box
00363                         // the test for a tiny shape that lies fully in the pixel is omitted for speed (not very useful)
00364                         if(!partin) partin =
00365                                 crossinter(px1, px2, a, b) || crossinter(px1, px2, b, c) || crossinter(px1, px2, c, d) ||
00366                                 crossinter(px2, px3, a, b) || crossinter(px2, px3, b, c) || crossinter(px2, px3, c, d) ||
00367                                 crossinter(px3, px4, a, b) || crossinter(px3, px4, b, c) || crossinter(px3, px4, c, d) ||
00368                                 crossinter(px4, px1, a, b) || crossinter(px4, px1, b, c) || crossinter(px4, px1, c, d);
00369 
00370                         // interpolated color for opacity
00371                         array<double> interp;
00372                         // pixel coverage accumulator 0.0 - 1.0
00373                         double cover = 0.0;
00374 
00375                         if(allin) {
00376                                 if(opacity == 1.) im.col(y, x) = col;
00377                                 else {
00378                                         interp = cast<double>(im.col(y, x));
00379                                         interp *= (double(1.) - opacity);
00380                                         interp += colord * opacity;
00381 
00382                                         im.col(y, x) = cast<T>(interp);
00383                                 }
00384                         } else if(partin) { // AA
00385                                 interp = cast<double>(im.col(y, x));
00386 
00387                                 px1.x += pixeladd;
00388                                 px1.y += pixeladd;
00389 
00390                                 for(i = 0; i < multisample; i++) {
00391 
00392                                         for(j = 0; j < multisample; j++) {
00393                                                 // tests a grid of (multisample x multisample) points
00394                                                 // in the pixel box and counts how many are in the shape
00395                                                 if(inquad(a, b, c, d, px1)) cover += coveradd;
00396 
00397                                                 px1.x += pixeladd;
00398                                         }
00399                                         px1.x = px2.x + pixeladd;
00400                                         px1.y += pixeladd;
00401                                 }
00402 
00403                                 // perform transparency with cover as a parameter
00404                                 interp *= (double(1.) - cover);
00405                                 interp += colord * cover;
00406 
00407                                 im.col(y, x) = cast<T>(interp);
00408                         }
00409                 }
00410         }
00411 }
00412 
00413 
00414 template <class T, class D>
00415 void AA_circ_impl(image<T, D>& im, double_point<2> a, double radius, color<T, D::Ch> col, int multisample = 8, double opacity = 1.)
00416 {
00417         // bounding box
00418         int y0 = int(a.y - radius) - 1;
00419         int x0 = int(a.x - radius) - 1;
00420         int y1 = int(a.y + radius) + 1;
00421         int x1 = int(a.x + radius) + 1;
00422 
00423         // clipping!
00424         y0 = std::max(y0, 0);
00425         x0 = std::max(x0, 0);
00426         y1 = std::min(y1, int(im.rows() - 1));
00427         x1 = std::min(x1, int(im.cols() - 1));
00428 
00429         double sqrradius = radius * radius;
00430 
00431         // for multisampling
00432         double coveradd = opacity / double(multisample * multisample);
00433         double pixeladd = 1. / double(multisample + 1);
00434 
00435         // the color, in array format due to incompatibility issues. TODO: fix
00436         array<double> colord = cast<double>(col);
00437 
00438         int y, x, i, j;
00439 
00440         for(y = y0; y < y1; y++) {
00441 
00442                 for(x = x0; x < x1; x++) {
00443 
00444                         // the four corners that enclose the pixel
00445                         double_point<2> px1(double(y) - .5, double(x) - .5);
00446                         double_point<2> px2(double(y) + .5, double(x) - .5);
00447                         double_point<2> px3(double(y) + .5, double(x) + .5);
00448                         double_point<2> px4(double(y) - .5, double(x) + .5);
00449 
00450                         // checks if each of the four corners are in the shape
00451                         bool pin1 = incirc(a, sqrradius, px1);
00452                         bool pin2 = incirc(a, sqrradius, px2);
00453                         bool pin3 = incirc(a, sqrradius, px3);
00454                         bool pin4 = incirc(a, sqrradius, px4);
00455 
00456                         bool allin = pin1 && pin2 && pin3 && pin4;
00457                         bool partin = pin1 || pin2 || pin3 || pin4;
00458 
00459                         // if no point is in the shape we need to assure that
00460                         // also the shape is not in the pixel box
00461                         // the test for a circle that intersects the box is omitted for speed (very little quality loss)
00462                         if(!partin) partin = a.x > px1.x && a.x < px3.x && a.y > px1.y && a.y < px3.y;
00463 
00464                         // interpolated color for opacity
00465                         array<double> interp;
00466                         // pixel coverage accumulator 0.0 - 1.0
00467                         double cover = 0.0;
00468 
00469                         if(allin) {
00470                                 if(opacity == 1.) im.col(y, x) = col;
00471                                 else {
00472                                         interp = cast<double>(im.col(y, x));
00473                                         interp *= (double(1.) - opacity);
00474                                         interp += colord * opacity;
00475 
00476                                         im.col(y, x) = cast<T>(interp);
00477                                 }
00478                         } else if(partin) { // AA
00479                                 interp = cast<double>(im.col(y, x));
00480 
00481                                 px1.x += pixeladd;
00482                                 px1.y += pixeladd;
00483 
00484                                 for(i = 0; i < multisample; i++) {
00485 
00486                                         for(j = 0; j < multisample; j++) {
00487                                                 // tests a grid of (multisample x multisample) points
00488                                                 // in the pixel box and counts how many are in the shape
00489                                                 if(incirc(a, sqrradius, px1)) cover += coveradd;
00490 
00491                                                 px1.x += pixeladd;
00492                                         }
00493                                         px1.x = px2.x + pixeladd;
00494                                         px1.y += pixeladd;
00495                                 }
00496 
00497                                 // perform transparency with cover as a parameter
00498                                 interp *= (double(1.) - cover);
00499                                 interp += colord * cover;
00500 
00501                                 im.col(y, x) = cast<T>(interp);
00502                         }
00503                 }
00504         }
00505 }
00506 
00507 
00508 template <class T, class D>
00509 void AA_circle_impl(image<T, D>& im, double_point<2> a, double outradius, double inradius, color<T, D::Ch> col, int multisample = 8, double opacity = 1.)
00510 {
00511         // bounding box
00512         int y0 = int(a.y - outradius) - 1;
00513         int x0 = int(a.x - outradius) - 1;
00514         int y1 = int(a.y + outradius) + 1;
00515         int x1 = int(a.x + outradius) + 1;
00516 
00517         // clipping!
00518         y0 = std::max(y0, 0);
00519         x0 = std::max(x0, 0);
00520         y1 = std::min(y1, int(im.rows() - 1));
00521         x1 = std::min(x1, int(im.cols() - 1));
00522 
00523         double outsqrradius = outradius * outradius;
00524         double insqrradius = inradius * inradius;
00525 
00526         // for multisampling
00527         double coveradd = opacity / double(multisample * multisample);
00528         double pixeladd = 1. / double(multisample + 1);
00529 
00530         // the color, in array format due to incompatibility issues. TODO: fix
00531         array<double> colord = cast<double>(col);
00532 
00533         int y, x, i, j;
00534 
00535         for(y = y0; y < y1; y++) {
00536 
00537                 for(x = x0; x < x1; x++) {
00538 
00539                         // the four corners that enclose the pixel
00540                         double_point<2> px1(double(y) - .5, double(x) - .5);
00541                         double_point<2> px2(double(y) + .5, double(x) - .5);
00542                         double_point<2> px3(double(y) + .5, double(x) + .5);
00543                         double_point<2> px4(double(y) - .5, double(x) + .5);
00544 
00545                         // checks if each of the four corners are in the shape
00546                         bool pin1 = incirc(a, outsqrradius, px1);
00547                         bool pin2 = incirc(a, outsqrradius, px2);
00548                         bool pin3 = incirc(a, outsqrradius, px3);
00549                         bool pin4 = incirc(a, outsqrradius, px4);
00550 
00551                         bool allin = pin1 && pin2 && pin3 && pin4;
00552                         bool partin = pin1 || pin2 || pin3 || pin4;
00553 
00554                         // if no point is in the shape we need to assure that
00555                         // also the shape is not in the pixel box
00556                         // the test for a circle that intersects the box is omitted for speed (very little quality loss)
00557                         if(!partin) partin = a.x > px1.x && a.x < px3.x && a.y > px1.y && a.y < px3.y;
00558                         else {
00559                                 pin1 = incirc(a, insqrradius, px1);
00560                                 pin2 = incirc(a, insqrradius, px2);
00561                                 pin3 = incirc(a, insqrradius, px3);
00562                                 pin4 = incirc(a, insqrradius, px4);
00563                                 if(pin1 || pin2 || pin3 || pin4) allin = false;
00564                                 if(pin1 && pin2 && pin3 && pin4) partin = false;
00565                         }
00566 
00567                         // interpolated color for opacity
00568                         array<double> interp;
00569                         // pixel coverage accumulator 0.0 - 1.0
00570                         double cover = 0.0;
00571 
00572                         if(allin) {
00573                                 if(opacity == 1.) im.col(y, x) = col;
00574                                 else {
00575                                         interp = cast<double>(im.col(y, x));
00576                                         interp *= (double(1.) - opacity);
00577                                         interp += colord * opacity;
00578 
00579                                         im.col(y, x) = cast<T>(interp);
00580                                 }
00581                         } else if(partin) { // AA
00582                                 interp = cast<double>(im.col(y, x));
00583 
00584                                 px1.x += pixeladd;
00585                                 px1.y += pixeladd;
00586 
00587                                 for(i = 0; i < multisample; i++) {
00588 
00589                                         for(j = 0; j < multisample; j++) {
00590                                                 // tests a grid of (multisample x multisample) points
00591                                                 // in the pixel box and counts how many are in the shape
00592                                                 if(incirc(a, outsqrradius, px1) && !incirc(a, insqrradius, px1)) cover += coveradd;
00593 
00594                                                 px1.x += pixeladd;
00595                                         }
00596                                         px1.x = px2.x + pixeladd;
00597                                         px1.y += pixeladd;
00598                                 }
00599 
00600                                 // perform transparency with cover as a parameter
00601                                 interp *= (double(1.) - cover);
00602                                 interp += colord * cover;
00603 
00604                                 im.col(y, x) = cast<T>(interp);
00605                         }
00606                 }
00607         }
00608 }
00609 
00610 template <class T, class D>
00611 void AA_fillellipse_impl(image<T, D>& im, double_point<2> a, double_point<2> b, double radius, color<T, D::Ch> col, int multisample = 8, double opacity = 1.)
00612 {
00613         // bounding box
00614         int y0 = int(std::min(a.y, b.y) - radius) - 1;
00615         int x0 = int(std::min(a.x, b.x) - radius) - 1;
00616         int y1 = int(std::max(a.y, b.y) + radius) + 1;
00617         int x1 = int(std::max(a.x, b.x) + radius) + 1;
00618 
00619         // clipping!
00620         y0 = std::max(y0, 0);
00621         x0 = std::max(x0, 0);
00622         y1 = std::min(y1, int(im.rows() - 1));
00623         x1 = std::min(x1, int(im.cols() - 1));
00624 
00625         double sqrradius = radius * radius;
00626 
00627         // for multisampling
00628         double coveradd = opacity / double(multisample * multisample);
00629         double pixeladd = 1. / double(multisample + 1);
00630 
00631         // the color, in array format due to incompatibility issues. TODO: fix
00632         array<double> colord = cast<double>(col);
00633 
00634         int y, x, i, j;
00635 
00636         for(y = y0; y < y1; y++) {
00637 
00638                 for(x = x0; x < x1; x++) {
00639 
00640                         // the four corners that enclose the pixel
00641                         double_point<2> px1(double(y) - .5, double(x) - .5);
00642                         double_point<2> px2(double(y) + .5, double(x) - .5);
00643                         double_point<2> px3(double(y) + .5, double(x) + .5);
00644                         double_point<2> px4(double(y) - .5, double(x) + .5);
00645 
00646                         // checks if each of the four corners are in the shape
00647                         bool pin1 = inellipse(a, b, sqrradius, px1);
00648                         bool pin2 = inellipse(a, b, sqrradius, px2);
00649                         bool pin3 = inellipse(a, b, sqrradius, px3);
00650                         bool pin4 = inellipse(a, b, sqrradius, px4);
00651 
00652                         bool allin = pin1 && pin2 && pin3 && pin4;
00653                         bool partin = pin1 || pin2 || pin3 || pin4;
00654 
00655                         // if no point is in the shape we need to assure that
00656                         // also the shape is not in the pixel box
00657                         // the test for a circle that intersects the box is omitted for speed (very little quality loss)
00658                         if(!partin) partin = a.x > px1.x && a.x < px3.x && a.y > px1.y && a.y < px3.y;
00659 
00660                         // interpolated color for opacity
00661                         array<double> interp;
00662                         // pixel coverage accumulator 0.0 - 1.0
00663                         double cover = 0.0;
00664 
00665                         if(allin) {
00666                                 if(opacity == 1.) im.col(y, x) = col;
00667                                 else {
00668                                         interp = cast<double>(im.col(y, x));
00669                                         interp *= (double(1.) - opacity);
00670                                         interp += colord * opacity;
00671 
00672                                         im.col(y, x) = cast<T>(interp);
00673                                 }
00674                         } else if(partin) { // AA
00675                                 interp = cast<double>(im.col(y, x));
00676 
00677                                 px1.x += pixeladd;
00678                                 px1.y += pixeladd;
00679 
00680                                 for(i = 0; i < multisample; i++) {
00681 
00682                                         for(j = 0; j < multisample; j++) {
00683                                                 // tests a grid of (multisample x multisample) points
00684                                                 // in the pixel box and counts how many are in the shape
00685                                                 if(inellipse(a, b, sqrradius, px1)) cover += coveradd;
00686 
00687                                                 px1.x += pixeladd;
00688                                         }
00689                                         px1.x = px2.x + pixeladd;
00690                                         px1.y += pixeladd;
00691                                 }
00692 
00693                                 // perform transparency with cover as a parameter
00694                                 interp *= (double(1.) - cover);
00695                                 interp += colord * cover;
00696 
00697                                 im.col(y, x) = cast<T>(interp);
00698                         }
00699                 }
00700         }
00701 }
00702 
00703 
00704 template <class T, class D>
00705 void AA_ellipse_impl(image<T, D>& im, double_point<2> a, double_point<2> b, double radius, double thickness, color<T, D::Ch> col, int multisample = 8, double opacity = 1.)
00706 {
00707         // bounding box
00708         int y0 = int(std::min(a.y, b.y) - radius) - 1;
00709         int x0 = int(std::min(a.x, b.x) - radius) - 1;
00710         int y1 = int(std::max(a.y, b.y) + radius) + 1;
00711         int x1 = int(std::max(a.x, b.x) + radius) + 1;
00712 
00713         double sqrradius = radius * radius;
00714 
00715         // clipping!
00716         y0 = std::max(y0, 0);
00717         x0 = std::max(x0, 0);
00718         y1 = std::min(y1, int(im.rows() - 1));
00719         x1 = std::min(x1, int(im.cols() - 1));
00720 
00721         // for multisampling
00722         double coveradd = opacity / double(multisample * multisample);
00723         double pixeladd = 1. / double(multisample + 1);
00724 
00725         // the color, in array format due to incompatibility issues. TODO: fix
00726         array<double> colord = cast<double>(col);
00727 
00728         int y, x, i, j;
00729 
00730         for(y = y0; y < y1; y++) {
00731 
00732                 for(x = x0; x < x1; x++) {
00733 
00734                         // the four corners that enclose the pixel
00735                         double_point<2> px1(double(y) - .5, double(x) - .5);
00736                         double_point<2> px2(double(y) + .5, double(x) - .5);
00737                         double_point<2> px3(double(y) + .5, double(x) + .5);
00738                         double_point<2> px4(double(y) - .5, double(x) + .5);
00739 
00740                         // checks if each of the four corners are in the shape
00741                         bool pin1 = inellipse2(a, b, sqrradius, -thickness, px1);
00742                         bool pin2 = inellipse2(a, b, sqrradius, -thickness, px2);
00743                         bool pin3 = inellipse2(a, b, sqrradius, -thickness, px3);
00744                         bool pin4 = inellipse2(a, b, sqrradius, -thickness, px4);
00745 
00746                         bool allin = pin1 && pin2 && pin3 && pin4;
00747                         bool partin = pin1 || pin2 || pin3 || pin4;
00748 
00749                         // if no point is in the shape we need to assure that
00750                         // also the shape is not in the pixel box
00751                         // the test for a circle that intersects the box is omitted for speed (very little quality loss)
00752                         if(!partin) partin = a.x > px1.x && a.x < px3.x && a.y > px1.y && a.y < px3.y;
00753                         else {
00754                                 pin1 = inellipse2(a, b, sqrradius, thickness, px1);
00755                                 pin2 = inellipse2(a, b, sqrradius, thickness, px2);
00756                                 pin3 = inellipse2(a, b, sqrradius, thickness, px3);
00757                                 pin4 = inellipse2(a, b, sqrradius, thickness, px4);
00758                                 if(pin1 || pin2 || pin3 || pin4) allin = false;
00759                                 if(pin1 && pin2 && pin3 && pin4) partin = false;
00760                         }
00761 
00762                         // interpolated color for opacity
00763                         array<double> interp;
00764                         // pixel coverage accumulator 0.0 - 1.0
00765                         double cover = 0.0;
00766 
00767                         if(allin) {
00768                                 if(opacity == 1.) im.col(y, x) = col;
00769                                 else {
00770                                         interp = cast<double>(im.col(y, x));
00771                                         interp *= (double(1.) - opacity);
00772                                         interp += colord * opacity;
00773 
00774                                         im.col(y, x) = cast<T>(interp);
00775                                 }
00776                         } else if(partin) { // AA
00777                                 interp = cast<double>(im.col(y, x));
00778 
00779                                 px1.x += pixeladd;
00780                                 px1.y += pixeladd;
00781 
00782                                 for(i = 0; i < multisample; i++) {
00783 
00784                                         for(j = 0; j < multisample; j++) {
00785                                                 // tests a grid of (multisample x multisample) points
00786                                                 // in the pixel box and counts how many are in the shape
00787                                                 if(inellipse2(a, b, sqrradius, -thickness, px1) && !inellipse2(a, b, sqrradius, thickness, px1)) cover += coveradd;
00788 
00789                                                 px1.x += pixeladd;
00790                                         }
00791                                         px1.x = px2.x + pixeladd;
00792                                         px1.y += pixeladd;
00793                                 }
00794 
00795                                 // perform transparency with cover as a parameter
00796                                 interp *= (double(1.) - cover);
00797                                 interp += colord * cover;
00798 
00799                                 im.col(y, x) = cast<T>(interp);
00800                         }
00801                 }
00802         }
00803 }
00804 
00805 
00806 };//namespace image_details
00807 
00808 template <class T, class D>
00809 void AA_trig_artsy(image<T, D>& im, double_point<2> a, double_point<2> b, double_point<2> c, color<T, D::Ch> col, int multisample, double opacity)
00810 {
00811         image_details::AA_trig_artsy_impl(im, a, b, c, col, multisample, opacity);
00812 }
00813 
00814 template <class T, class D>
00815 void AA_trig(image<T, D>& im, double_point<2> a, double_point<2> b, double_point<2> c, color<T, D::Ch> col, int multisample, double opacity)
00816 {
00817         image_details::AA_trig_impl(im, a, b, c, col, multisample, opacity);
00818 }
00819 
00820 template <class T, class D>
00821 void AA_quad(image<T, D>& im, double_point<2> a, double_point<2> b, double_point<2> c, double_point<2> d,
00822         color<T, D::Ch> col, int multisample, double opacity)
00823 {
00824         image_details::AA_quad_impl(im, a, b, c, d, col, multisample, opacity);
00825 }
00826 
00827 template <class T, class D>
00828 void AA_circ(image<T, D>& im, double_point<2> a, double radius, color<T, D::Ch> col, int multisample, double opacity)
00829 {
00830         image_details::AA_circ_impl(im, a, radius, col, multisample, opacity);
00831 }
00832 
00833 template <class T, class D>
00834 void AA_circle(image<T, D>& im, double_point<2> a, double outradius, double inradius, color<T, D::Ch> col, int multisample, double opacity)
00835 {
00836         image_details::AA_circle_impl(im, a, outradius, inradius, col, multisample, opacity);
00837 }
00838 
00839 template <class T, class D>
00840 void AA_fillellipse(image<T, D>& im, double_point<2> a, double_point<2> b, double radius, color<T, D::Ch> col, int multisample, double opacity)
00841 {
00842         image_details::AA_fillellipse_impl(im, a, b, radius, col, multisample, opacity);
00843 }
00844 
00845 template <class T, class D>
00846 void AA_ellipse(image<T, D>& im, double_point<2> a, double_point<2> b, double radius, double thickness, color<T, D::Ch> col, int multisample, double opacity)
00847 {
00848         image_details::AA_ellipse_impl(im, a, b, radius, thickness, col, multisample, opacity);
00849 }
00850 
00851 };//namespace ivl
00852 
00853 #endif // IVL_IMAGE_DETAILS_FUNCTIONS_AA_DRAWING_FUNCTIONS_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations