Home | History | Annotate | Download | only in src
      1 /*M///////////////////////////////////////////////////////////////////////////////////////
      2 //
      3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
      4 //
      5 //  By downloading, copying, installing or using the software you agree to this license.
      6 //  If you do not agree to this license, do not download, install,
      7 //  copy or use the software.
      8 //
      9 //
     10 //                        Intel License Agreement
     11 //                For Open Source Computer Vision Library
     12 //
     13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
     14 // Third party copyrights are property of their respective owners.
     15 //
     16 // Redistribution and use in source and binary forms, with or without modification,
     17 // are permitted provided that the following conditions are met:
     18 //
     19 //   * Redistribution's of source code must retain the above copyright notice,
     20 //     this list of conditions and the following disclaimer.
     21 //
     22 //   * Redistribution's in binary form must reproduce the above copyright notice,
     23 //     this list of conditions and the following disclaimer in the documentation
     24 //     and/or other materials provided with the distribution.
     25 //
     26 //   * The name of Intel Corporation may not be used to endorse or promote products
     27 //     derived from this software without specific prior written permission.
     28 //
     29 // This software is provided by the copyright holders and contributors "as is" and
     30 // any express or implied warranties, including, but not limited to, the implied
     31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
     32 // In no event shall the Intel Corporation or contributors be liable for any direct,
     33 // indirect, incidental, special, exemplary, or consequential damages
     34 // (including, but not limited to, procurement of substitute goods or services;
     35 // loss of use, data, or profits; or business interruption) however caused
     36 // and on any theory of liability, whether in contract, strict liability,
     37 // or tort (including negligence or otherwise) arising in any way out of
     38 // the use of this software, even if advised of the possibility of such damage.
     39 //
     40 //M*/
     41 #include "precomp.hpp"
     42 
     43 namespace cv
     44 {
     45 
     46 enum { XY_SHIFT = 16, XY_ONE = 1 << XY_SHIFT, DRAWING_STORAGE_BLOCK = (1<<12) - 256 };
     47 
     48 static const int MAX_THICKNESS = 32767;
     49 
     50 struct PolyEdge
     51 {
     52     PolyEdge() : y0(0), y1(0), x(0), dx(0), next(0) {}
     53     //PolyEdge(int _y0, int _y1, int _x, int _dx) : y0(_y0), y1(_y1), x(_x), dx(_dx) {}
     54 
     55     int y0, y1;
     56     int x, dx;
     57     PolyEdge *next;
     58 };
     59 
     60 static void
     61 CollectPolyEdges( Mat& img, const Point* v, int npts,
     62                   std::vector<PolyEdge>& edges, const void* color, int line_type,
     63                   int shift, Point offset=Point() );
     64 
     65 static void
     66 FillEdgeCollection( Mat& img, std::vector<PolyEdge>& edges, const void* color );
     67 
     68 static void
     69 PolyLine( Mat& img, const Point* v, int npts, bool closed,
     70           const void* color, int thickness, int line_type, int shift );
     71 
     72 static void
     73 FillConvexPoly( Mat& img, const Point* v, int npts,
     74                 const void* color, int line_type, int shift );
     75 
     76 /****************************************************************************************\
     77 *                                   Lines                                                *
     78 \****************************************************************************************/
     79 
     80 bool clipLine( Size img_size, Point& pt1, Point& pt2 )
     81 {
     82     int64 x1, y1, x2, y2;
     83     int c1, c2;
     84     int64 right = img_size.width-1, bottom = img_size.height-1;
     85 
     86     if( img_size.width <= 0 || img_size.height <= 0 )
     87         return false;
     88 
     89     x1 = pt1.x; y1 = pt1.y; x2 = pt2.x; y2 = pt2.y;
     90     c1 = (x1 < 0) + (x1 > right) * 2 + (y1 < 0) * 4 + (y1 > bottom) * 8;
     91     c2 = (x2 < 0) + (x2 > right) * 2 + (y2 < 0) * 4 + (y2 > bottom) * 8;
     92 
     93     if( (c1 & c2) == 0 && (c1 | c2) != 0 )
     94     {
     95         int64 a;
     96         if( c1 & 12 )
     97         {
     98             a = c1 < 8 ? 0 : bottom;
     99             x1 +=  (a - y1) * (x2 - x1) / (y2 - y1);
    100             y1 = a;
    101             c1 = (x1 < 0) + (x1 > right) * 2;
    102         }
    103         if( c2 & 12 )
    104         {
    105             a = c2 < 8 ? 0 : bottom;
    106             x2 += (a - y2) * (x2 - x1) / (y2 - y1);
    107             y2 = a;
    108             c2 = (x2 < 0) + (x2 > right) * 2;
    109         }
    110         if( (c1 & c2) == 0 && (c1 | c2) != 0 )
    111         {
    112             if( c1 )
    113             {
    114                 a = c1 == 1 ? 0 : right;
    115                 y1 += (a - x1) * (y2 - y1) / (x2 - x1);
    116                 x1 = a;
    117                 c1 = 0;
    118             }
    119             if( c2 )
    120             {
    121                 a = c2 == 1 ? 0 : right;
    122                 y2 += (a - x2) * (y2 - y1) / (x2 - x1);
    123                 x2 = a;
    124                 c2 = 0;
    125             }
    126         }
    127 
    128         assert( (c1 & c2) != 0 || (x1 | y1 | x2 | y2) >= 0 );
    129 
    130         pt1.x = (int)x1;
    131         pt1.y = (int)y1;
    132         pt2.x = (int)x2;
    133         pt2.y = (int)y2;
    134     }
    135 
    136     return (c1 | c2) == 0;
    137 }
    138 
    139 bool clipLine( Rect img_rect, Point& pt1, Point& pt2 )
    140 {
    141     Point tl = img_rect.tl();
    142     pt1 -= tl; pt2 -= tl;
    143     bool inside = clipLine(img_rect.size(), pt1, pt2);
    144     pt1 += tl; pt2 += tl;
    145 
    146     return inside;
    147 }
    148 
    149 /*
    150    Initializes line iterator.
    151    Returns number of points on the line or negative number if error.
    152 */
    153 LineIterator::LineIterator(const Mat& img, Point pt1, Point pt2,
    154                            int connectivity, bool left_to_right)
    155 {
    156     count = -1;
    157 
    158     CV_Assert( connectivity == 8 || connectivity == 4 );
    159 
    160     if( (unsigned)pt1.x >= (unsigned)(img.cols) ||
    161         (unsigned)pt2.x >= (unsigned)(img.cols) ||
    162         (unsigned)pt1.y >= (unsigned)(img.rows) ||
    163         (unsigned)pt2.y >= (unsigned)(img.rows) )
    164     {
    165         if( !clipLine( img.size(), pt1, pt2 ) )
    166         {
    167             ptr = img.data;
    168             err = plusDelta = minusDelta = plusStep = minusStep = count = 0;
    169             return;
    170         }
    171     }
    172 
    173     int bt_pix0 = (int)img.elemSize(), bt_pix = bt_pix0;
    174     size_t istep = img.step;
    175 
    176     int dx = pt2.x - pt1.x;
    177     int dy = pt2.y - pt1.y;
    178     int s = dx < 0 ? -1 : 0;
    179 
    180     if( left_to_right )
    181     {
    182         dx = (dx ^ s) - s;
    183         dy = (dy ^ s) - s;
    184         pt1.x ^= (pt1.x ^ pt2.x) & s;
    185         pt1.y ^= (pt1.y ^ pt2.y) & s;
    186     }
    187     else
    188     {
    189         dx = (dx ^ s) - s;
    190         bt_pix = (bt_pix ^ s) - s;
    191     }
    192 
    193     ptr = (uchar*)(img.data + pt1.y * istep + pt1.x * bt_pix0);
    194 
    195     s = dy < 0 ? -1 : 0;
    196     dy = (dy ^ s) - s;
    197     istep = (istep ^ s) - s;
    198 
    199     s = dy > dx ? -1 : 0;
    200 
    201     /* conditional swaps */
    202     dx ^= dy & s;
    203     dy ^= dx & s;
    204     dx ^= dy & s;
    205 
    206     bt_pix ^= istep & s;
    207     istep ^= bt_pix & s;
    208     bt_pix ^= istep & s;
    209 
    210     if( connectivity == 8 )
    211     {
    212         assert( dx >= 0 && dy >= 0 );
    213 
    214         err = dx - (dy + dy);
    215         plusDelta = dx + dx;
    216         minusDelta = -(dy + dy);
    217         plusStep = (int)istep;
    218         minusStep = bt_pix;
    219         count = dx + 1;
    220     }
    221     else /* connectivity == 4 */
    222     {
    223         assert( dx >= 0 && dy >= 0 );
    224 
    225         err = 0;
    226         plusDelta = (dx + dx) + (dy + dy);
    227         minusDelta = -(dy + dy);
    228         plusStep = (int)istep - bt_pix;
    229         minusStep = bt_pix;
    230         count = dx + dy + 1;
    231     }
    232 
    233     this->ptr0 = img.ptr();
    234     this->step = (int)img.step;
    235     this->elemSize = bt_pix0;
    236 }
    237 
    238 static void
    239 Line( Mat& img, Point pt1, Point pt2,
    240       const void* _color, int connectivity = 8 )
    241 {
    242     if( connectivity == 0 )
    243         connectivity = 8;
    244     else if( connectivity == 1 )
    245         connectivity = 4;
    246 
    247     LineIterator iterator(img, pt1, pt2, connectivity, true);
    248     int i, count = iterator.count;
    249     int pix_size = (int)img.elemSize();
    250     const uchar* color = (const uchar*)_color;
    251 
    252     for( i = 0; i < count; i++, ++iterator )
    253     {
    254         uchar* ptr = *iterator;
    255         if( pix_size == 1 )
    256             ptr[0] = color[0];
    257         else if( pix_size == 3 )
    258         {
    259             ptr[0] = color[0];
    260             ptr[1] = color[1];
    261             ptr[2] = color[2];
    262         }
    263         else
    264             memcpy( *iterator, color, pix_size );
    265     }
    266 }
    267 
    268 
    269 /* Correction table depent on the slope */
    270 static const uchar SlopeCorrTable[] = {
    271     181, 181, 181, 182, 182, 183, 184, 185, 187, 188, 190, 192, 194, 196, 198, 201,
    272     203, 206, 209, 211, 214, 218, 221, 224, 227, 231, 235, 238, 242, 246, 250, 254
    273 };
    274 
    275 /* Gaussian for antialiasing filter */
    276 static const int FilterTable[] = {
    277     168, 177, 185, 194, 202, 210, 218, 224, 231, 236, 241, 246, 249, 252, 254, 254,
    278     254, 254, 252, 249, 246, 241, 236, 231, 224, 218, 210, 202, 194, 185, 177, 168,
    279     158, 149, 140, 131, 122, 114, 105, 97, 89, 82, 75, 68, 62, 56, 50, 45,
    280     40, 36, 32, 28, 25, 22, 19, 16, 14, 12, 11, 9, 8, 7, 5, 5
    281 };
    282 
    283 static void
    284 LineAA( Mat& img, Point pt1, Point pt2, const void* color )
    285 {
    286     int dx, dy;
    287     int ecount, scount = 0;
    288     int slope;
    289     int ax, ay;
    290     int x_step, y_step;
    291     int i, j;
    292     int ep_table[9];
    293     int cb = ((uchar*)color)[0], cg = ((uchar*)color)[1], cr = ((uchar*)color)[2], ca = ((uchar*)color)[3];
    294     int _cb, _cg, _cr, _ca;
    295     int nch = img.channels();
    296     uchar* ptr = img.ptr();
    297     size_t step = img.step;
    298     Size size = img.size();
    299 
    300     if( !((nch == 1 || nch == 3 || nch == 4) && img.depth() == CV_8U) )
    301     {
    302         Line(img, pt1, pt2, color);
    303         return;
    304     }
    305 
    306     pt1.x -= XY_ONE*2;
    307     pt1.y -= XY_ONE*2;
    308     pt2.x -= XY_ONE*2;
    309     pt2.y -= XY_ONE*2;
    310     ptr += img.step*2 + 2*nch;
    311 
    312     size.width = ((size.width - 5) << XY_SHIFT) + 1;
    313     size.height = ((size.height - 5) << XY_SHIFT) + 1;
    314 
    315     if( !clipLine( size, pt1, pt2 ))
    316         return;
    317 
    318     dx = pt2.x - pt1.x;
    319     dy = pt2.y - pt1.y;
    320 
    321     j = dx < 0 ? -1 : 0;
    322     ax = (dx ^ j) - j;
    323     i = dy < 0 ? -1 : 0;
    324     ay = (dy ^ i) - i;
    325 
    326     if( ax > ay )
    327     {
    328         dx = ax;
    329         dy = (dy ^ j) - j;
    330         pt1.x ^= pt2.x & j;
    331         pt2.x ^= pt1.x & j;
    332         pt1.x ^= pt2.x & j;
    333         pt1.y ^= pt2.y & j;
    334         pt2.y ^= pt1.y & j;
    335         pt1.y ^= pt2.y & j;
    336 
    337         x_step = XY_ONE;
    338         y_step = (int) (((int64) dy << XY_SHIFT) / (ax | 1));
    339         pt2.x += XY_ONE;
    340         ecount = (pt2.x >> XY_SHIFT) - (pt1.x >> XY_SHIFT);
    341         j = -(pt1.x & (XY_ONE - 1));
    342         pt1.y += (int) ((((int64) y_step) * j) >> XY_SHIFT) + (XY_ONE >> 1);
    343         slope = (y_step >> (XY_SHIFT - 5)) & 0x3f;
    344         slope ^= (y_step < 0 ? 0x3f : 0);
    345 
    346         /* Get 4-bit fractions for end-point adjustments */
    347         i = (pt1.x >> (XY_SHIFT - 7)) & 0x78;
    348         j = (pt2.x >> (XY_SHIFT - 7)) & 0x78;
    349     }
    350     else
    351     {
    352         dy = ay;
    353         dx = (dx ^ i) - i;
    354         pt1.x ^= pt2.x & i;
    355         pt2.x ^= pt1.x & i;
    356         pt1.x ^= pt2.x & i;
    357         pt1.y ^= pt2.y & i;
    358         pt2.y ^= pt1.y & i;
    359         pt1.y ^= pt2.y & i;
    360 
    361         x_step = (int) (((int64) dx << XY_SHIFT) / (ay | 1));
    362         y_step = XY_ONE;
    363         pt2.y += XY_ONE;
    364         ecount = (pt2.y >> XY_SHIFT) - (pt1.y >> XY_SHIFT);
    365         j = -(pt1.y & (XY_ONE - 1));
    366         pt1.x += (int) ((((int64) x_step) * j) >> XY_SHIFT) + (XY_ONE >> 1);
    367         slope = (x_step >> (XY_SHIFT - 5)) & 0x3f;
    368         slope ^= (x_step < 0 ? 0x3f : 0);
    369 
    370         /* Get 4-bit fractions for end-point adjustments */
    371         i = (pt1.y >> (XY_SHIFT - 7)) & 0x78;
    372         j = (pt2.y >> (XY_SHIFT - 7)) & 0x78;
    373     }
    374 
    375     slope = (slope & 0x20) ? 0x100 : SlopeCorrTable[slope];
    376 
    377     /* Calc end point correction table */
    378     {
    379         int t0 = slope << 7;
    380         int t1 = ((0x78 - i) | 4) * slope;
    381         int t2 = (j | 4) * slope;
    382 
    383         ep_table[0] = 0;
    384         ep_table[8] = slope;
    385         ep_table[1] = ep_table[3] = ((((j - i) & 0x78) | 4) * slope >> 8) & 0x1ff;
    386         ep_table[2] = (t1 >> 8) & 0x1ff;
    387         ep_table[4] = ((((j - i) + 0x80) | 4) * slope >> 8) & 0x1ff;
    388         ep_table[5] = ((t1 + t0) >> 8) & 0x1ff;
    389         ep_table[6] = (t2 >> 8) & 0x1ff;
    390         ep_table[7] = ((t2 + t0) >> 8) & 0x1ff;
    391     }
    392 
    393     if( nch == 3 )
    394     {
    395         #define  ICV_PUT_POINT()            \
    396         {                                   \
    397             _cb = tptr[0];                  \
    398             _cb += ((cb - _cb)*a + 127)>> 8;\
    399             _cg = tptr[1];                  \
    400             _cg += ((cg - _cg)*a + 127)>> 8;\
    401             _cr = tptr[2];                  \
    402             _cr += ((cr - _cr)*a + 127)>> 8;\
    403             tptr[0] = (uchar)_cb;           \
    404             tptr[1] = (uchar)_cg;           \
    405             tptr[2] = (uchar)_cr;           \
    406         }
    407         if( ax > ay )
    408         {
    409             ptr += (pt1.x >> XY_SHIFT) * 3;
    410 
    411             while( ecount >= 0 )
    412             {
    413                 uchar *tptr = ptr + ((pt1.y >> XY_SHIFT) - 1) * step;
    414 
    415                 int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
    416                                        (((ecount >= 2) + 1) & (ecount | 2))];
    417                 int a, dist = (pt1.y >> (XY_SHIFT - 5)) & 31;
    418 
    419                 a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff;
    420                 ICV_PUT_POINT();
    421                 ICV_PUT_POINT();
    422 
    423                 tptr += step;
    424                 a = (ep_corr * FilterTable[dist] >> 8) & 0xff;
    425                 ICV_PUT_POINT();
    426                 ICV_PUT_POINT();
    427 
    428                 tptr += step;
    429                 a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff;
    430                 ICV_PUT_POINT();
    431                 ICV_PUT_POINT();
    432 
    433                 pt1.y += y_step;
    434                 ptr += 3;
    435                 scount++;
    436                 ecount--;
    437             }
    438         }
    439         else
    440         {
    441             ptr += (pt1.y >> XY_SHIFT) * step;
    442 
    443             while( ecount >= 0 )
    444             {
    445                 uchar *tptr = ptr + ((pt1.x >> XY_SHIFT) - 1) * 3;
    446 
    447                 int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
    448                                        (((ecount >= 2) + 1) & (ecount | 2))];
    449                 int a, dist = (pt1.x >> (XY_SHIFT - 5)) & 31;
    450 
    451                 a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff;
    452                 ICV_PUT_POINT();
    453                 ICV_PUT_POINT();
    454 
    455                 tptr += 3;
    456                 a = (ep_corr * FilterTable[dist] >> 8) & 0xff;
    457                 ICV_PUT_POINT();
    458                 ICV_PUT_POINT();
    459 
    460                 tptr += 3;
    461                 a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff;
    462                 ICV_PUT_POINT();
    463                 ICV_PUT_POINT();
    464 
    465                 pt1.x += x_step;
    466                 ptr += step;
    467                 scount++;
    468                 ecount--;
    469             }
    470         }
    471         #undef ICV_PUT_POINT
    472     }
    473     else if(nch == 1)
    474     {
    475         #define  ICV_PUT_POINT()            \
    476         {                                   \
    477             _cb = tptr[0];                  \
    478             _cb += ((cb - _cb)*a + 127)>> 8;\
    479             tptr[0] = (uchar)_cb;           \
    480         }
    481 
    482         if( ax > ay )
    483         {
    484             ptr += (pt1.x >> XY_SHIFT);
    485 
    486             while( ecount >= 0 )
    487             {
    488                 uchar *tptr = ptr + ((pt1.y >> XY_SHIFT) - 1) * step;
    489 
    490                 int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
    491                                        (((ecount >= 2) + 1) & (ecount | 2))];
    492                 int a, dist = (pt1.y >> (XY_SHIFT - 5)) & 31;
    493 
    494                 a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff;
    495                 ICV_PUT_POINT();
    496                 ICV_PUT_POINT();
    497 
    498                 tptr += step;
    499                 a = (ep_corr * FilterTable[dist] >> 8) & 0xff;
    500                 ICV_PUT_POINT();
    501                 ICV_PUT_POINT();
    502 
    503                 tptr += step;
    504                 a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff;
    505                 ICV_PUT_POINT();
    506                 ICV_PUT_POINT();
    507 
    508                 pt1.y += y_step;
    509                 ptr++;
    510                 scount++;
    511                 ecount--;
    512             }
    513         }
    514         else
    515         {
    516             ptr += (pt1.y >> XY_SHIFT) * step;
    517 
    518             while( ecount >= 0 )
    519             {
    520                 uchar *tptr = ptr + ((pt1.x >> XY_SHIFT) - 1);
    521 
    522                 int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
    523                                        (((ecount >= 2) + 1) & (ecount | 2))];
    524                 int a, dist = (pt1.x >> (XY_SHIFT - 5)) & 31;
    525 
    526                 a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff;
    527                 ICV_PUT_POINT();
    528                 ICV_PUT_POINT();
    529 
    530                 tptr++;
    531                 a = (ep_corr * FilterTable[dist] >> 8) & 0xff;
    532                 ICV_PUT_POINT();
    533                 ICV_PUT_POINT();
    534 
    535                 tptr++;
    536                 a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff;
    537                 ICV_PUT_POINT();
    538                 ICV_PUT_POINT();
    539 
    540                 pt1.x += x_step;
    541                 ptr += step;
    542                 scount++;
    543                 ecount--;
    544             }
    545         }
    546         #undef ICV_PUT_POINT
    547     }
    548     else
    549     {
    550         #define  ICV_PUT_POINT()            \
    551         {                                   \
    552             _cb = tptr[0];                  \
    553             _cb += ((cb - _cb)*a + 127)>> 8;\
    554             _cg = tptr[1];                  \
    555             _cg += ((cg - _cg)*a + 127)>> 8;\
    556             _cr = tptr[2];                  \
    557             _cr += ((cr - _cr)*a + 127)>> 8;\
    558             _ca = tptr[3];                  \
    559             _ca += ((ca - _ca)*a + 127)>> 8;\
    560             tptr[0] = (uchar)_cb;           \
    561             tptr[1] = (uchar)_cg;           \
    562             tptr[2] = (uchar)_cr;           \
    563             tptr[3] = (uchar)_ca;           \
    564         }
    565         if( ax > ay )
    566         {
    567             ptr += (pt1.x >> XY_SHIFT) * 4;
    568 
    569             while( ecount >= 0 )
    570             {
    571                 uchar *tptr = ptr + ((pt1.y >> XY_SHIFT) - 1) * step;
    572 
    573                 int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
    574                                        (((ecount >= 2) + 1) & (ecount | 2))];
    575                 int a, dist = (pt1.y >> (XY_SHIFT - 5)) & 31;
    576 
    577                 a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff;
    578                 ICV_PUT_POINT();
    579                 ICV_PUT_POINT();
    580 
    581                 tptr += step;
    582                 a = (ep_corr * FilterTable[dist] >> 8) & 0xff;
    583                 ICV_PUT_POINT();
    584                 ICV_PUT_POINT();
    585 
    586                 tptr += step;
    587                 a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff;
    588                 ICV_PUT_POINT();
    589                 ICV_PUT_POINT();
    590 
    591                 pt1.y += y_step;
    592                 ptr += 4;
    593                 scount++;
    594                 ecount--;
    595             }
    596         }
    597         else
    598         {
    599             ptr += (pt1.y >> XY_SHIFT) * step;
    600 
    601             while( ecount >= 0 )
    602             {
    603                 uchar *tptr = ptr + ((pt1.x >> XY_SHIFT) - 1) * 4;
    604 
    605                 int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
    606                                        (((ecount >= 2) + 1) & (ecount | 2))];
    607                 int a, dist = (pt1.x >> (XY_SHIFT - 5)) & 31;
    608 
    609                 a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff;
    610                 ICV_PUT_POINT();
    611                 ICV_PUT_POINT();
    612 
    613                 tptr += step;
    614                 a = (ep_corr * FilterTable[dist] >> 8) & 0xff;
    615                 ICV_PUT_POINT();
    616                 ICV_PUT_POINT();
    617 
    618                 tptr += step;
    619                 a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff;
    620                 ICV_PUT_POINT();
    621                 ICV_PUT_POINT();
    622 
    623                 pt1.x += x_step;
    624                 ptr += step;
    625                 scount++;
    626                 ecount--;
    627             }
    628         }
    629         #undef ICV_PUT_POINT
    630     }
    631 }
    632 
    633 
    634 static void
    635 Line2( Mat& img, Point pt1, Point pt2, const void* color )
    636 {
    637     int dx, dy;
    638     int ecount;
    639     int ax, ay;
    640     int i, j, x, y;
    641     int x_step, y_step;
    642     int cb = ((uchar*)color)[0];
    643     int cg = ((uchar*)color)[1];
    644     int cr = ((uchar*)color)[2];
    645     int pix_size = (int)img.elemSize();
    646     uchar *ptr = img.ptr(), *tptr;
    647     size_t step = img.step;
    648     Size size = img.size(), sizeScaled(size.width*XY_ONE, size.height*XY_ONE);
    649 
    650     //assert( img && (nch == 1 || nch == 3) && img.depth() == CV_8U );
    651 
    652     if( !clipLine( sizeScaled, pt1, pt2 ))
    653         return;
    654 
    655     dx = pt2.x - pt1.x;
    656     dy = pt2.y - pt1.y;
    657 
    658     j = dx < 0 ? -1 : 0;
    659     ax = (dx ^ j) - j;
    660     i = dy < 0 ? -1 : 0;
    661     ay = (dy ^ i) - i;
    662 
    663     if( ax > ay )
    664     {
    665         dx = ax;
    666         dy = (dy ^ j) - j;
    667         pt1.x ^= pt2.x & j;
    668         pt2.x ^= pt1.x & j;
    669         pt1.x ^= pt2.x & j;
    670         pt1.y ^= pt2.y & j;
    671         pt2.y ^= pt1.y & j;
    672         pt1.y ^= pt2.y & j;
    673 
    674         x_step = XY_ONE;
    675         y_step = (int) (((int64) dy << XY_SHIFT) / (ax | 1));
    676         ecount = (pt2.x - pt1.x) >> XY_SHIFT;
    677     }
    678     else
    679     {
    680         dy = ay;
    681         dx = (dx ^ i) - i;
    682         pt1.x ^= pt2.x & i;
    683         pt2.x ^= pt1.x & i;
    684         pt1.x ^= pt2.x & i;
    685         pt1.y ^= pt2.y & i;
    686         pt2.y ^= pt1.y & i;
    687         pt1.y ^= pt2.y & i;
    688 
    689         x_step = (int) (((int64) dx << XY_SHIFT) / (ay | 1));
    690         y_step = XY_ONE;
    691         ecount = (pt2.y - pt1.y) >> XY_SHIFT;
    692     }
    693 
    694     pt1.x += (XY_ONE >> 1);
    695     pt1.y += (XY_ONE >> 1);
    696 
    697     if( pix_size == 3 )
    698     {
    699         #define  ICV_PUT_POINT(_x,_y)   \
    700         x = (_x); y = (_y);             \
    701         if( 0 <= x && x < size.width && \
    702             0 <= y && y < size.height ) \
    703         {                               \
    704             tptr = ptr + y*step + x*3;  \
    705             tptr[0] = (uchar)cb;        \
    706             tptr[1] = (uchar)cg;        \
    707             tptr[2] = (uchar)cr;        \
    708         }
    709 
    710         ICV_PUT_POINT((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT,
    711                       (pt2.y + (XY_ONE >> 1)) >> XY_SHIFT);
    712 
    713         if( ax > ay )
    714         {
    715             pt1.x >>= XY_SHIFT;
    716 
    717             while( ecount >= 0 )
    718             {
    719                 ICV_PUT_POINT(pt1.x, pt1.y >> XY_SHIFT);
    720                 pt1.x++;
    721                 pt1.y += y_step;
    722                 ecount--;
    723             }
    724         }
    725         else
    726         {
    727             pt1.y >>= XY_SHIFT;
    728 
    729             while( ecount >= 0 )
    730             {
    731                 ICV_PUT_POINT(pt1.x >> XY_SHIFT, pt1.y);
    732                 pt1.x += x_step;
    733                 pt1.y++;
    734                 ecount--;
    735             }
    736         }
    737 
    738         #undef ICV_PUT_POINT
    739     }
    740     else if( pix_size == 1 )
    741     {
    742         #define  ICV_PUT_POINT(_x,_y) \
    743         x = (_x); y = (_y);           \
    744         if( 0 <= x && x < size.width && \
    745             0 <= y && y < size.height ) \
    746         {                           \
    747             tptr = ptr + y*step + x;\
    748             tptr[0] = (uchar)cb;    \
    749         }
    750 
    751         ICV_PUT_POINT((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT,
    752                       (pt2.y + (XY_ONE >> 1)) >> XY_SHIFT);
    753 
    754         if( ax > ay )
    755         {
    756             pt1.x >>= XY_SHIFT;
    757 
    758             while( ecount >= 0 )
    759             {
    760                 ICV_PUT_POINT(pt1.x, pt1.y >> XY_SHIFT);
    761                 pt1.x++;
    762                 pt1.y += y_step;
    763                 ecount--;
    764             }
    765         }
    766         else
    767         {
    768             pt1.y >>= XY_SHIFT;
    769 
    770             while( ecount >= 0 )
    771             {
    772                 ICV_PUT_POINT(pt1.x >> XY_SHIFT, pt1.y);
    773                 pt1.x += x_step;
    774                 pt1.y++;
    775                 ecount--;
    776             }
    777         }
    778 
    779         #undef ICV_PUT_POINT
    780     }
    781     else
    782     {
    783         #define  ICV_PUT_POINT(_x,_y)   \
    784         x = (_x); y = (_y);             \
    785         if( 0 <= x && x < size.width && \
    786             0 <= y && y < size.height ) \
    787         {                               \
    788             tptr = ptr + y*step + x*pix_size;\
    789             for( j = 0; j < pix_size; j++ ) \
    790                 tptr[j] = ((uchar*)color)[j]; \
    791         }
    792 
    793         ICV_PUT_POINT((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT,
    794                       (pt2.y + (XY_ONE >> 1)) >> XY_SHIFT);
    795 
    796         if( ax > ay )
    797         {
    798             pt1.x >>= XY_SHIFT;
    799 
    800             while( ecount >= 0 )
    801             {
    802                 ICV_PUT_POINT(pt1.x, pt1.y >> XY_SHIFT);
    803                 pt1.x++;
    804                 pt1.y += y_step;
    805                 ecount--;
    806             }
    807         }
    808         else
    809         {
    810             pt1.y >>= XY_SHIFT;
    811 
    812             while( ecount >= 0 )
    813             {
    814                 ICV_PUT_POINT(pt1.x >> XY_SHIFT, pt1.y);
    815                 pt1.x += x_step;
    816                 pt1.y++;
    817                 ecount--;
    818             }
    819         }
    820 
    821         #undef ICV_PUT_POINT
    822     }
    823 }
    824 
    825 
    826 /****************************************************************************************\
    827 *                   Antialiazed Elliptic Arcs via Antialiazed Lines                      *
    828 \****************************************************************************************/
    829 
    830 static const float SinTable[] =
    831     { 0.0000000f, 0.0174524f, 0.0348995f, 0.0523360f, 0.0697565f, 0.0871557f,
    832     0.1045285f, 0.1218693f, 0.1391731f, 0.1564345f, 0.1736482f, 0.1908090f,
    833     0.2079117f, 0.2249511f, 0.2419219f, 0.2588190f, 0.2756374f, 0.2923717f,
    834     0.3090170f, 0.3255682f, 0.3420201f, 0.3583679f, 0.3746066f, 0.3907311f,
    835     0.4067366f, 0.4226183f, 0.4383711f, 0.4539905f, 0.4694716f, 0.4848096f,
    836     0.5000000f, 0.5150381f, 0.5299193f, 0.5446390f, 0.5591929f, 0.5735764f,
    837     0.5877853f, 0.6018150f, 0.6156615f, 0.6293204f, 0.6427876f, 0.6560590f,
    838     0.6691306f, 0.6819984f, 0.6946584f, 0.7071068f, 0.7193398f, 0.7313537f,
    839     0.7431448f, 0.7547096f, 0.7660444f, 0.7771460f, 0.7880108f, 0.7986355f,
    840     0.8090170f, 0.8191520f, 0.8290376f, 0.8386706f, 0.8480481f, 0.8571673f,
    841     0.8660254f, 0.8746197f, 0.8829476f, 0.8910065f, 0.8987940f, 0.9063078f,
    842     0.9135455f, 0.9205049f, 0.9271839f, 0.9335804f, 0.9396926f, 0.9455186f,
    843     0.9510565f, 0.9563048f, 0.9612617f, 0.9659258f, 0.9702957f, 0.9743701f,
    844     0.9781476f, 0.9816272f, 0.9848078f, 0.9876883f, 0.9902681f, 0.9925462f,
    845     0.9945219f, 0.9961947f, 0.9975641f, 0.9986295f, 0.9993908f, 0.9998477f,
    846     1.0000000f, 0.9998477f, 0.9993908f, 0.9986295f, 0.9975641f, 0.9961947f,
    847     0.9945219f, 0.9925462f, 0.9902681f, 0.9876883f, 0.9848078f, 0.9816272f,
    848     0.9781476f, 0.9743701f, 0.9702957f, 0.9659258f, 0.9612617f, 0.9563048f,
    849     0.9510565f, 0.9455186f, 0.9396926f, 0.9335804f, 0.9271839f, 0.9205049f,
    850     0.9135455f, 0.9063078f, 0.8987940f, 0.8910065f, 0.8829476f, 0.8746197f,
    851     0.8660254f, 0.8571673f, 0.8480481f, 0.8386706f, 0.8290376f, 0.8191520f,
    852     0.8090170f, 0.7986355f, 0.7880108f, 0.7771460f, 0.7660444f, 0.7547096f,
    853     0.7431448f, 0.7313537f, 0.7193398f, 0.7071068f, 0.6946584f, 0.6819984f,
    854     0.6691306f, 0.6560590f, 0.6427876f, 0.6293204f, 0.6156615f, 0.6018150f,
    855     0.5877853f, 0.5735764f, 0.5591929f, 0.5446390f, 0.5299193f, 0.5150381f,
    856     0.5000000f, 0.4848096f, 0.4694716f, 0.4539905f, 0.4383711f, 0.4226183f,
    857     0.4067366f, 0.3907311f, 0.3746066f, 0.3583679f, 0.3420201f, 0.3255682f,
    858     0.3090170f, 0.2923717f, 0.2756374f, 0.2588190f, 0.2419219f, 0.2249511f,
    859     0.2079117f, 0.1908090f, 0.1736482f, 0.1564345f, 0.1391731f, 0.1218693f,
    860     0.1045285f, 0.0871557f, 0.0697565f, 0.0523360f, 0.0348995f, 0.0174524f,
    861     0.0000000f, -0.0174524f, -0.0348995f, -0.0523360f, -0.0697565f, -0.0871557f,
    862     -0.1045285f, -0.1218693f, -0.1391731f, -0.1564345f, -0.1736482f, -0.1908090f,
    863     -0.2079117f, -0.2249511f, -0.2419219f, -0.2588190f, -0.2756374f, -0.2923717f,
    864     -0.3090170f, -0.3255682f, -0.3420201f, -0.3583679f, -0.3746066f, -0.3907311f,
    865     -0.4067366f, -0.4226183f, -0.4383711f, -0.4539905f, -0.4694716f, -0.4848096f,
    866     -0.5000000f, -0.5150381f, -0.5299193f, -0.5446390f, -0.5591929f, -0.5735764f,
    867     -0.5877853f, -0.6018150f, -0.6156615f, -0.6293204f, -0.6427876f, -0.6560590f,
    868     -0.6691306f, -0.6819984f, -0.6946584f, -0.7071068f, -0.7193398f, -0.7313537f,
    869     -0.7431448f, -0.7547096f, -0.7660444f, -0.7771460f, -0.7880108f, -0.7986355f,
    870     -0.8090170f, -0.8191520f, -0.8290376f, -0.8386706f, -0.8480481f, -0.8571673f,
    871     -0.8660254f, -0.8746197f, -0.8829476f, -0.8910065f, -0.8987940f, -0.9063078f,
    872     -0.9135455f, -0.9205049f, -0.9271839f, -0.9335804f, -0.9396926f, -0.9455186f,
    873     -0.9510565f, -0.9563048f, -0.9612617f, -0.9659258f, -0.9702957f, -0.9743701f,
    874     -0.9781476f, -0.9816272f, -0.9848078f, -0.9876883f, -0.9902681f, -0.9925462f,
    875     -0.9945219f, -0.9961947f, -0.9975641f, -0.9986295f, -0.9993908f, -0.9998477f,
    876     -1.0000000f, -0.9998477f, -0.9993908f, -0.9986295f, -0.9975641f, -0.9961947f,
    877     -0.9945219f, -0.9925462f, -0.9902681f, -0.9876883f, -0.9848078f, -0.9816272f,
    878     -0.9781476f, -0.9743701f, -0.9702957f, -0.9659258f, -0.9612617f, -0.9563048f,
    879     -0.9510565f, -0.9455186f, -0.9396926f, -0.9335804f, -0.9271839f, -0.9205049f,
    880     -0.9135455f, -0.9063078f, -0.8987940f, -0.8910065f, -0.8829476f, -0.8746197f,
    881     -0.8660254f, -0.8571673f, -0.8480481f, -0.8386706f, -0.8290376f, -0.8191520f,
    882     -0.8090170f, -0.7986355f, -0.7880108f, -0.7771460f, -0.7660444f, -0.7547096f,
    883     -0.7431448f, -0.7313537f, -0.7193398f, -0.7071068f, -0.6946584f, -0.6819984f,
    884     -0.6691306f, -0.6560590f, -0.6427876f, -0.6293204f, -0.6156615f, -0.6018150f,
    885     -0.5877853f, -0.5735764f, -0.5591929f, -0.5446390f, -0.5299193f, -0.5150381f,
    886     -0.5000000f, -0.4848096f, -0.4694716f, -0.4539905f, -0.4383711f, -0.4226183f,
    887     -0.4067366f, -0.3907311f, -0.3746066f, -0.3583679f, -0.3420201f, -0.3255682f,
    888     -0.3090170f, -0.2923717f, -0.2756374f, -0.2588190f, -0.2419219f, -0.2249511f,
    889     -0.2079117f, -0.1908090f, -0.1736482f, -0.1564345f, -0.1391731f, -0.1218693f,
    890     -0.1045285f, -0.0871557f, -0.0697565f, -0.0523360f, -0.0348995f, -0.0174524f,
    891     -0.0000000f, 0.0174524f, 0.0348995f, 0.0523360f, 0.0697565f, 0.0871557f,
    892     0.1045285f, 0.1218693f, 0.1391731f, 0.1564345f, 0.1736482f, 0.1908090f,
    893     0.2079117f, 0.2249511f, 0.2419219f, 0.2588190f, 0.2756374f, 0.2923717f,
    894     0.3090170f, 0.3255682f, 0.3420201f, 0.3583679f, 0.3746066f, 0.3907311f,
    895     0.4067366f, 0.4226183f, 0.4383711f, 0.4539905f, 0.4694716f, 0.4848096f,
    896     0.5000000f, 0.5150381f, 0.5299193f, 0.5446390f, 0.5591929f, 0.5735764f,
    897     0.5877853f, 0.6018150f, 0.6156615f, 0.6293204f, 0.6427876f, 0.6560590f,
    898     0.6691306f, 0.6819984f, 0.6946584f, 0.7071068f, 0.7193398f, 0.7313537f,
    899     0.7431448f, 0.7547096f, 0.7660444f, 0.7771460f, 0.7880108f, 0.7986355f,
    900     0.8090170f, 0.8191520f, 0.8290376f, 0.8386706f, 0.8480481f, 0.8571673f,
    901     0.8660254f, 0.8746197f, 0.8829476f, 0.8910065f, 0.8987940f, 0.9063078f,
    902     0.9135455f, 0.9205049f, 0.9271839f, 0.9335804f, 0.9396926f, 0.9455186f,
    903     0.9510565f, 0.9563048f, 0.9612617f, 0.9659258f, 0.9702957f, 0.9743701f,
    904     0.9781476f, 0.9816272f, 0.9848078f, 0.9876883f, 0.9902681f, 0.9925462f,
    905     0.9945219f, 0.9961947f, 0.9975641f, 0.9986295f, 0.9993908f, 0.9998477f,
    906     1.0000000f
    907 };
    908 
    909 
    910 static void
    911 sincos( int angle, float& cosval, float& sinval )
    912 {
    913     angle += (angle < 0 ? 360 : 0);
    914     sinval = SinTable[angle];
    915     cosval = SinTable[450 - angle];
    916 }
    917 
    918 /*
    919    constructs polygon that represents elliptic arc.
    920 */
    921 void ellipse2Poly( Point center, Size axes, int angle,
    922                    int arc_start, int arc_end,
    923                    int delta, std::vector<Point>& pts )
    924 {
    925     float alpha, beta;
    926     double size_a = axes.width, size_b = axes.height;
    927     double cx = center.x, cy = center.y;
    928     Point prevPt(INT_MIN,INT_MIN);
    929     int i;
    930 
    931     while( angle < 0 )
    932         angle += 360;
    933     while( angle > 360 )
    934         angle -= 360;
    935 
    936     if( arc_start > arc_end )
    937     {
    938         i = arc_start;
    939         arc_start = arc_end;
    940         arc_end = i;
    941     }
    942     while( arc_start < 0 )
    943     {
    944         arc_start += 360;
    945         arc_end += 360;
    946     }
    947     while( arc_end > 360 )
    948     {
    949         arc_end -= 360;
    950         arc_start -= 360;
    951     }
    952     if( arc_end - arc_start > 360 )
    953     {
    954         arc_start = 0;
    955         arc_end = 360;
    956     }
    957     sincos( angle, alpha, beta );
    958     pts.resize(0);
    959 
    960     for( i = arc_start; i < arc_end + delta; i += delta )
    961     {
    962         double x, y;
    963         angle = i;
    964         if( angle > arc_end )
    965             angle = arc_end;
    966         if( angle < 0 )
    967             angle += 360;
    968 
    969         x = size_a * SinTable[450-angle];
    970         y = size_b * SinTable[angle];
    971         Point pt;
    972         pt.x = cvRound( cx + x * alpha - y * beta );
    973         pt.y = cvRound( cy + x * beta + y * alpha );
    974         if( pt != prevPt ){
    975             pts.push_back(pt);
    976             prevPt = pt;
    977         }
    978     }
    979 
    980     // If there are no points, it's a zero-size polygon
    981     if( pts.size() == 1) {
    982         pts.assign(2,center);
    983     }
    984 }
    985 
    986 
    987 static void
    988 EllipseEx( Mat& img, Point center, Size axes,
    989            int angle, int arc_start, int arc_end,
    990            const void* color, int thickness, int line_type )
    991 {
    992     axes.width = std::abs(axes.width), axes.height = std::abs(axes.height);
    993     int delta = (std::max(axes.width,axes.height)+(XY_ONE>>1))>>XY_SHIFT;
    994     delta = delta < 3 ? 90 : delta < 10 ? 30 : delta < 15 ? 18 : 5;
    995 
    996     std::vector<Point> v;
    997     ellipse2Poly( center, axes, angle, arc_start, arc_end, delta, v );
    998 
    999     if( thickness >= 0 )
   1000         PolyLine( img, &v[0], (int)v.size(), false, color, thickness, line_type, XY_SHIFT );
   1001     else if( arc_end - arc_start >= 360 )
   1002         FillConvexPoly( img, &v[0], (int)v.size(), color, line_type, XY_SHIFT );
   1003     else
   1004     {
   1005         v.push_back(center);
   1006         std::vector<PolyEdge> edges;
   1007         CollectPolyEdges( img,  &v[0], (int)v.size(), edges, color, line_type, XY_SHIFT );
   1008         FillEdgeCollection( img, edges, color );
   1009     }
   1010 }
   1011 
   1012 
   1013 /****************************************************************************************\
   1014 *                                Polygons filling                                        *
   1015 \****************************************************************************************/
   1016 
   1017 /* helper macros: filling horizontal row */
   1018 #define ICV_HLINE( ptr, xl, xr, color, pix_size )            \
   1019 {                                                            \
   1020     uchar* hline_ptr = (uchar*)(ptr) + (xl)*(pix_size);      \
   1021     uchar* hline_max_ptr = (uchar*)(ptr) + (xr)*(pix_size);  \
   1022                                                              \
   1023     for( ; hline_ptr <= hline_max_ptr; hline_ptr += (pix_size))\
   1024     {                                                        \
   1025         int hline_j;                                         \
   1026         for( hline_j = 0; hline_j < (pix_size); hline_j++ )  \
   1027         {                                                    \
   1028             hline_ptr[hline_j] = ((uchar*)color)[hline_j];   \
   1029         }                                                    \
   1030     }                                                        \
   1031 }
   1032 
   1033 
   1034 /* filling convex polygon. v - array of vertices, ntps - number of points */
   1035 static void
   1036 FillConvexPoly( Mat& img, const Point* v, int npts, const void* color, int line_type, int shift )
   1037 {
   1038     struct
   1039     {
   1040         int idx, di;
   1041         int x, dx, ye;
   1042     }
   1043     edge[2];
   1044 
   1045     int delta = shift ? 1 << (shift - 1) : 0;
   1046     int i, y, imin = 0, left = 0, right = 1, x1, x2;
   1047     int edges = npts;
   1048     int xmin, xmax, ymin, ymax;
   1049     uchar* ptr = img.ptr();
   1050     Size size = img.size();
   1051     int pix_size = (int)img.elemSize();
   1052     Point p0;
   1053     int delta1, delta2;
   1054 
   1055     if( line_type < CV_AA )
   1056         delta1 = delta2 = XY_ONE >> 1;
   1057     else
   1058         delta1 = XY_ONE - 1, delta2 = 0;
   1059 
   1060     p0 = v[npts - 1];
   1061     p0.x <<= XY_SHIFT - shift;
   1062     p0.y <<= XY_SHIFT - shift;
   1063 
   1064     assert( 0 <= shift && shift <= XY_SHIFT );
   1065     xmin = xmax = v[0].x;
   1066     ymin = ymax = v[0].y;
   1067 
   1068     for( i = 0; i < npts; i++ )
   1069     {
   1070         Point p = v[i];
   1071         if( p.y < ymin )
   1072         {
   1073             ymin = p.y;
   1074             imin = i;
   1075         }
   1076 
   1077         ymax = std::max( ymax, p.y );
   1078         xmax = std::max( xmax, p.x );
   1079         xmin = MIN( xmin, p.x );
   1080 
   1081         p.x <<= XY_SHIFT - shift;
   1082         p.y <<= XY_SHIFT - shift;
   1083 
   1084         if( line_type <= 8 )
   1085         {
   1086             if( shift == 0 )
   1087             {
   1088                 Point pt0, pt1;
   1089                 pt0.x = p0.x >> XY_SHIFT;
   1090                 pt0.y = p0.y >> XY_SHIFT;
   1091                 pt1.x = p.x >> XY_SHIFT;
   1092                 pt1.y = p.y >> XY_SHIFT;
   1093                 Line( img, pt0, pt1, color, line_type );
   1094             }
   1095             else
   1096                 Line2( img, p0, p, color );
   1097         }
   1098         else
   1099             LineAA( img, p0, p, color );
   1100         p0 = p;
   1101     }
   1102 
   1103     xmin = (xmin + delta) >> shift;
   1104     xmax = (xmax + delta) >> shift;
   1105     ymin = (ymin + delta) >> shift;
   1106     ymax = (ymax + delta) >> shift;
   1107 
   1108     if( npts < 3 || xmax < 0 || ymax < 0 || xmin >= size.width || ymin >= size.height )
   1109         return;
   1110 
   1111     ymax = MIN( ymax, size.height - 1 );
   1112     edge[0].idx = edge[1].idx = imin;
   1113 
   1114     edge[0].ye = edge[1].ye = y = ymin;
   1115     edge[0].di = 1;
   1116     edge[1].di = npts - 1;
   1117 
   1118     ptr += img.step*y;
   1119 
   1120     do
   1121     {
   1122         if( line_type < CV_AA || y < ymax || y == ymin )
   1123         {
   1124             for( i = 0; i < 2; i++ )
   1125             {
   1126                 if( y >= edge[i].ye )
   1127                 {
   1128                     int idx = edge[i].idx, di = edge[i].di;
   1129                     int xs = 0, xe, ye, ty = 0;
   1130 
   1131                     for(;;)
   1132                     {
   1133                         ty = (v[idx].y + delta) >> shift;
   1134                         if( ty > y || edges == 0 )
   1135                             break;
   1136                         xs = v[idx].x;
   1137                         idx += di;
   1138                         idx -= ((idx < npts) - 1) & npts;   /* idx -= idx >= npts ? npts : 0 */
   1139                         edges--;
   1140                     }
   1141 
   1142                     ye = ty;
   1143                     xs <<= XY_SHIFT - shift;
   1144                     xe = v[idx].x << (XY_SHIFT - shift);
   1145 
   1146                     /* no more edges */
   1147                     if( y >= ye )
   1148                         return;
   1149 
   1150                     edge[i].ye = ye;
   1151                     edge[i].dx = ((xe - xs)*2 + (ye - y)) / (2 * (ye - y));
   1152                     edge[i].x = xs;
   1153                     edge[i].idx = idx;
   1154                 }
   1155             }
   1156         }
   1157 
   1158         if( edge[left].x > edge[right].x )
   1159         {
   1160             left ^= 1;
   1161             right ^= 1;
   1162         }
   1163 
   1164         x1 = edge[left].x;
   1165         x2 = edge[right].x;
   1166 
   1167         if( y >= 0 )
   1168         {
   1169             int xx1 = (x1 + delta1) >> XY_SHIFT;
   1170             int xx2 = (x2 + delta2) >> XY_SHIFT;
   1171 
   1172             if( xx2 >= 0 && xx1 < size.width )
   1173             {
   1174                 if( xx1 < 0 )
   1175                     xx1 = 0;
   1176                 if( xx2 >= size.width )
   1177                     xx2 = size.width - 1;
   1178                 ICV_HLINE( ptr, xx1, xx2, color, pix_size );
   1179             }
   1180         }
   1181 
   1182         x1 += edge[left].dx;
   1183         x2 += edge[right].dx;
   1184 
   1185         edge[left].x = x1;
   1186         edge[right].x = x2;
   1187         ptr += img.step;
   1188     }
   1189     while( ++y <= ymax );
   1190 }
   1191 
   1192 
   1193 /******** Arbitrary polygon **********/
   1194 
   1195 static void
   1196 CollectPolyEdges( Mat& img, const Point* v, int count, std::vector<PolyEdge>& edges,
   1197                   const void* color, int line_type, int shift, Point offset )
   1198 {
   1199     int i, delta = offset.y + (shift ? 1 << (shift - 1) : 0);
   1200     Point pt0 = v[count-1], pt1;
   1201     pt0.x = (pt0.x + offset.x) << (XY_SHIFT - shift);
   1202     pt0.y = (pt0.y + delta) >> shift;
   1203 
   1204     edges.reserve( edges.size() + count );
   1205 
   1206     for( i = 0; i < count; i++, pt0 = pt1 )
   1207     {
   1208         Point t0, t1;
   1209         PolyEdge edge;
   1210 
   1211         pt1 = v[i];
   1212         pt1.x = (pt1.x + offset.x) << (XY_SHIFT - shift);
   1213         pt1.y = (pt1.y + delta) >> shift;
   1214 
   1215         if( line_type < CV_AA )
   1216         {
   1217             t0.y = pt0.y; t1.y = pt1.y;
   1218             t0.x = (pt0.x + (XY_ONE >> 1)) >> XY_SHIFT;
   1219             t1.x = (pt1.x + (XY_ONE >> 1)) >> XY_SHIFT;
   1220             Line( img, t0, t1, color, line_type );
   1221         }
   1222         else
   1223         {
   1224             t0.x = pt0.x; t1.x = pt1.x;
   1225             t0.y = pt0.y << XY_SHIFT;
   1226             t1.y = pt1.y << XY_SHIFT;
   1227             LineAA( img, t0, t1, color );
   1228         }
   1229 
   1230         if( pt0.y == pt1.y )
   1231             continue;
   1232 
   1233         if( pt0.y < pt1.y )
   1234         {
   1235             edge.y0 = pt0.y;
   1236             edge.y1 = pt1.y;
   1237             edge.x = pt0.x;
   1238         }
   1239         else
   1240         {
   1241             edge.y0 = pt1.y;
   1242             edge.y1 = pt0.y;
   1243             edge.x = pt1.x;
   1244         }
   1245         edge.dx = (pt1.x - pt0.x) / (pt1.y - pt0.y);
   1246         edges.push_back(edge);
   1247     }
   1248 }
   1249 
   1250 struct CmpEdges
   1251 {
   1252     bool operator ()(const PolyEdge& e1, const PolyEdge& e2)
   1253     {
   1254         return e1.y0 - e2.y0 ? e1.y0 < e2.y0 :
   1255             e1.x - e2.x ? e1.x < e2.x : e1.dx < e2.dx;
   1256     }
   1257 };
   1258 
   1259 /**************** helper macros and functions for sequence/contour processing ***********/
   1260 
   1261 static void
   1262 FillEdgeCollection( Mat& img, std::vector<PolyEdge>& edges, const void* color )
   1263 {
   1264     PolyEdge tmp;
   1265     int i, y, total = (int)edges.size();
   1266     Size size = img.size();
   1267     PolyEdge* e;
   1268     int y_max = INT_MIN, x_max = INT_MIN, y_min = INT_MAX, x_min = INT_MAX;
   1269     int pix_size = (int)img.elemSize();
   1270 
   1271     if( total < 2 )
   1272         return;
   1273 
   1274     for( i = 0; i < total; i++ )
   1275     {
   1276         PolyEdge& e1 = edges[i];
   1277         assert( e1.y0 < e1.y1 );
   1278         // Determine x-coordinate of the end of the edge.
   1279         // (This is not necessary x-coordinate of any vertex in the array.)
   1280         int x1 = e1.x + (e1.y1 - e1.y0) * e1.dx;
   1281         y_min = std::min( y_min, e1.y0 );
   1282         y_max = std::max( y_max, e1.y1 );
   1283         x_min = std::min( x_min, e1.x );
   1284         x_max = std::max( x_max, e1.x );
   1285         x_min = std::min( x_min, x1 );
   1286         x_max = std::max( x_max, x1 );
   1287     }
   1288 
   1289     if( y_max < 0 || y_min >= size.height || x_max < 0 || x_min >= (size.width<<XY_SHIFT) )
   1290         return;
   1291 
   1292     std::sort( edges.begin(), edges.end(), CmpEdges() );
   1293 
   1294     // start drawing
   1295     tmp.y0 = INT_MAX;
   1296     edges.push_back(tmp); // after this point we do not add
   1297                           // any elements to edges, thus we can use pointers
   1298     i = 0;
   1299     tmp.next = 0;
   1300     e = &edges[i];
   1301     y_max = MIN( y_max, size.height );
   1302 
   1303     for( y = e->y0; y < y_max; y++ )
   1304     {
   1305         PolyEdge *last, *prelast, *keep_prelast;
   1306         int sort_flag = 0;
   1307         int draw = 0;
   1308         int clipline = y < 0;
   1309 
   1310         prelast = &tmp;
   1311         last = tmp.next;
   1312         while( last || e->y0 == y )
   1313         {
   1314             if( last && last->y1 == y )
   1315             {
   1316                 // exclude edge if y reachs its lower point
   1317                 prelast->next = last->next;
   1318                 last = last->next;
   1319                 continue;
   1320             }
   1321             keep_prelast = prelast;
   1322             if( last && (e->y0 > y || last->x < e->x) )
   1323             {
   1324                 // go to the next edge in active list
   1325                 prelast = last;
   1326                 last = last->next;
   1327             }
   1328             else if( i < total )
   1329             {
   1330                 // insert new edge into active list if y reachs its upper point
   1331                 prelast->next = e;
   1332                 e->next = last;
   1333                 prelast = e;
   1334                 e = &edges[++i];
   1335             }
   1336             else
   1337                 break;
   1338 
   1339             if( draw )
   1340             {
   1341                 if( !clipline )
   1342                 {
   1343                     // convert x's from fixed-point to image coordinates
   1344                     uchar *timg = img.ptr(y);
   1345                     int x1 = keep_prelast->x;
   1346                     int x2 = prelast->x;
   1347 
   1348                     if( x1 > x2 )
   1349                     {
   1350                         int t = x1;
   1351 
   1352                         x1 = x2;
   1353                         x2 = t;
   1354                     }
   1355 
   1356                     x1 = (x1 + XY_ONE - 1) >> XY_SHIFT;
   1357                     x2 = x2 >> XY_SHIFT;
   1358 
   1359                     // clip and draw the line
   1360                     if( x1 < size.width && x2 >= 0 )
   1361                     {
   1362                         if( x1 < 0 )
   1363                             x1 = 0;
   1364                         if( x2 >= size.width )
   1365                             x2 = size.width - 1;
   1366                         ICV_HLINE( timg, x1, x2, color, pix_size );
   1367                     }
   1368                 }
   1369                 keep_prelast->x += keep_prelast->dx;
   1370                 prelast->x += prelast->dx;
   1371             }
   1372             draw ^= 1;
   1373         }
   1374 
   1375         // sort edges (using bubble sort)
   1376         keep_prelast = 0;
   1377 
   1378         do
   1379         {
   1380             prelast = &tmp;
   1381             last = tmp.next;
   1382 
   1383             while( last != keep_prelast && last->next != 0 )
   1384             {
   1385                 PolyEdge *te = last->next;
   1386 
   1387                 // swap edges
   1388                 if( last->x > te->x )
   1389                 {
   1390                     prelast->next = te;
   1391                     last->next = te->next;
   1392                     te->next = last;
   1393                     prelast = te;
   1394                     sort_flag = 1;
   1395                 }
   1396                 else
   1397                 {
   1398                     prelast = last;
   1399                     last = te;
   1400                 }
   1401             }
   1402             keep_prelast = prelast;
   1403         }
   1404         while( sort_flag && keep_prelast != tmp.next && keep_prelast != &tmp );
   1405     }
   1406 }
   1407 
   1408 
   1409 /* draws simple or filled circle */
   1410 static void
   1411 Circle( Mat& img, Point center, int radius, const void* color, int fill )
   1412 {
   1413     Size size = img.size();
   1414     size_t step = img.step;
   1415     int pix_size = (int)img.elemSize();
   1416     uchar* ptr = img.ptr();
   1417     int err = 0, dx = radius, dy = 0, plus = 1, minus = (radius << 1) - 1;
   1418     int inside = center.x >= radius && center.x < size.width - radius &&
   1419         center.y >= radius && center.y < size.height - radius;
   1420 
   1421     #define ICV_PUT_POINT( ptr, x )     \
   1422         memcpy( ptr + (x)*pix_size, color, pix_size );
   1423 
   1424     while( dx >= dy )
   1425     {
   1426         int mask;
   1427         int y11 = center.y - dy, y12 = center.y + dy, y21 = center.y - dx, y22 = center.y + dx;
   1428         int x11 = center.x - dx, x12 = center.x + dx, x21 = center.x - dy, x22 = center.x + dy;
   1429 
   1430         if( inside )
   1431         {
   1432             uchar *tptr0 = ptr + y11 * step;
   1433             uchar *tptr1 = ptr + y12 * step;
   1434 
   1435             if( !fill )
   1436             {
   1437                 ICV_PUT_POINT( tptr0, x11 );
   1438                 ICV_PUT_POINT( tptr1, x11 );
   1439                 ICV_PUT_POINT( tptr0, x12 );
   1440                 ICV_PUT_POINT( tptr1, x12 );
   1441             }
   1442             else
   1443             {
   1444                 ICV_HLINE( tptr0, x11, x12, color, pix_size );
   1445                 ICV_HLINE( tptr1, x11, x12, color, pix_size );
   1446             }
   1447 
   1448             tptr0 = ptr + y21 * step;
   1449             tptr1 = ptr + y22 * step;
   1450 
   1451             if( !fill )
   1452             {
   1453                 ICV_PUT_POINT( tptr0, x21 );
   1454                 ICV_PUT_POINT( tptr1, x21 );
   1455                 ICV_PUT_POINT( tptr0, x22 );
   1456                 ICV_PUT_POINT( tptr1, x22 );
   1457             }
   1458             else
   1459             {
   1460                 ICV_HLINE( tptr0, x21, x22, color, pix_size );
   1461                 ICV_HLINE( tptr1, x21, x22, color, pix_size );
   1462             }
   1463         }
   1464         else if( x11 < size.width && x12 >= 0 && y21 < size.height && y22 >= 0 )
   1465         {
   1466             if( fill )
   1467             {
   1468                 x11 = std::max( x11, 0 );
   1469                 x12 = MIN( x12, size.width - 1 );
   1470             }
   1471 
   1472             if( (unsigned)y11 < (unsigned)size.height )
   1473             {
   1474                 uchar *tptr = ptr + y11 * step;
   1475 
   1476                 if( !fill )
   1477                 {
   1478                     if( x11 >= 0 )
   1479                         ICV_PUT_POINT( tptr, x11 );
   1480                     if( x12 < size.width )
   1481                         ICV_PUT_POINT( tptr, x12 );
   1482                 }
   1483                 else
   1484                     ICV_HLINE( tptr, x11, x12, color, pix_size );
   1485             }
   1486 
   1487             if( (unsigned)y12 < (unsigned)size.height )
   1488             {
   1489                 uchar *tptr = ptr + y12 * step;
   1490 
   1491                 if( !fill )
   1492                 {
   1493                     if( x11 >= 0 )
   1494                         ICV_PUT_POINT( tptr, x11 );
   1495                     if( x12 < size.width )
   1496                         ICV_PUT_POINT( tptr, x12 );
   1497                 }
   1498                 else
   1499                     ICV_HLINE( tptr, x11, x12, color, pix_size );
   1500             }
   1501 
   1502             if( x21 < size.width && x22 >= 0 )
   1503             {
   1504                 if( fill )
   1505                 {
   1506                     x21 = std::max( x21, 0 );
   1507                     x22 = MIN( x22, size.width - 1 );
   1508                 }
   1509 
   1510                 if( (unsigned)y21 < (unsigned)size.height )
   1511                 {
   1512                     uchar *tptr = ptr + y21 * step;
   1513 
   1514                     if( !fill )
   1515                     {
   1516                         if( x21 >= 0 )
   1517                             ICV_PUT_POINT( tptr, x21 );
   1518                         if( x22 < size.width )
   1519                             ICV_PUT_POINT( tptr, x22 );
   1520                     }
   1521                     else
   1522                         ICV_HLINE( tptr, x21, x22, color, pix_size );
   1523                 }
   1524 
   1525                 if( (unsigned)y22 < (unsigned)size.height )
   1526                 {
   1527                     uchar *tptr = ptr + y22 * step;
   1528 
   1529                     if( !fill )
   1530                     {
   1531                         if( x21 >= 0 )
   1532                             ICV_PUT_POINT( tptr, x21 );
   1533                         if( x22 < size.width )
   1534                             ICV_PUT_POINT( tptr, x22 );
   1535                     }
   1536                     else
   1537                         ICV_HLINE( tptr, x21, x22, color, pix_size );
   1538                 }
   1539             }
   1540         }
   1541         dy++;
   1542         err += plus;
   1543         plus += 2;
   1544 
   1545         mask = (err <= 0) - 1;
   1546 
   1547         err -= minus & mask;
   1548         dx += mask;
   1549         minus -= mask & 2;
   1550     }
   1551 
   1552     #undef  ICV_PUT_POINT
   1553 }
   1554 
   1555 
   1556 static void
   1557 ThickLine( Mat& img, Point p0, Point p1, const void* color,
   1558            int thickness, int line_type, int flags, int shift )
   1559 {
   1560     static const double INV_XY_ONE = 1./XY_ONE;
   1561 
   1562     p0.x <<= XY_SHIFT - shift;
   1563     p0.y <<= XY_SHIFT - shift;
   1564     p1.x <<= XY_SHIFT - shift;
   1565     p1.y <<= XY_SHIFT - shift;
   1566 
   1567     if( thickness <= 1 )
   1568     {
   1569         if( line_type < CV_AA )
   1570         {
   1571             if( line_type == 1 || line_type == 4 || shift == 0 )
   1572             {
   1573                 p0.x = (p0.x + (XY_ONE>>1)) >> XY_SHIFT;
   1574                 p0.y = (p0.y + (XY_ONE>>1)) >> XY_SHIFT;
   1575                 p1.x = (p1.x + (XY_ONE>>1)) >> XY_SHIFT;
   1576                 p1.y = (p1.y + (XY_ONE>>1)) >> XY_SHIFT;
   1577                 Line( img, p0, p1, color, line_type );
   1578             }
   1579             else
   1580                 Line2( img, p0, p1, color );
   1581         }
   1582         else
   1583             LineAA( img, p0, p1, color );
   1584     }
   1585     else
   1586     {
   1587         Point pt[4], dp = Point(0,0);
   1588         double dx = (p0.x - p1.x)*INV_XY_ONE, dy = (p1.y - p0.y)*INV_XY_ONE;
   1589         double r = dx * dx + dy * dy;
   1590         int i, oddThickness = thickness & 1;
   1591         thickness <<= XY_SHIFT - 1;
   1592 
   1593         if( fabs(r) > DBL_EPSILON )
   1594         {
   1595             r = (thickness + oddThickness*XY_ONE*0.5)/std::sqrt(r);
   1596             dp.x = cvRound( dy * r );
   1597             dp.y = cvRound( dx * r );
   1598 
   1599             pt[0].x = p0.x + dp.x;
   1600             pt[0].y = p0.y + dp.y;
   1601             pt[1].x = p0.x - dp.x;
   1602             pt[1].y = p0.y - dp.y;
   1603             pt[2].x = p1.x - dp.x;
   1604             pt[2].y = p1.y - dp.y;
   1605             pt[3].x = p1.x + dp.x;
   1606             pt[3].y = p1.y + dp.y;
   1607 
   1608             FillConvexPoly( img, pt, 4, color, line_type, XY_SHIFT );
   1609         }
   1610 
   1611         for( i = 0; i < 2; i++ )
   1612         {
   1613             if( flags & (i+1) )
   1614             {
   1615                 if( line_type < CV_AA )
   1616                 {
   1617                     Point center;
   1618                     center.x = (p0.x + (XY_ONE>>1)) >> XY_SHIFT;
   1619                     center.y = (p0.y + (XY_ONE>>1)) >> XY_SHIFT;
   1620                     Circle( img, center, (thickness + (XY_ONE>>1)) >> XY_SHIFT, color, 1 );
   1621                 }
   1622                 else
   1623                 {
   1624                     EllipseEx( img, p0, cvSize(thickness, thickness),
   1625                                0, 0, 360, color, -1, line_type );
   1626                 }
   1627             }
   1628             p0 = p1;
   1629         }
   1630     }
   1631 }
   1632 
   1633 
   1634 static void
   1635 PolyLine( Mat& img, const Point* v, int count, bool is_closed,
   1636           const void* color, int thickness,
   1637           int line_type, int shift )
   1638 {
   1639     if( !v || count <= 0 )
   1640         return;
   1641 
   1642     int i = is_closed ? count - 1 : 0;
   1643     int flags = 2 + !is_closed;
   1644     Point p0;
   1645     CV_Assert( 0 <= shift && shift <= XY_SHIFT && thickness >= 0 );
   1646 
   1647     p0 = v[i];
   1648     for( i = !is_closed; i < count; i++ )
   1649     {
   1650         Point p = v[i];
   1651         ThickLine( img, p0, p, color, thickness, line_type, flags, shift );
   1652         p0 = p;
   1653         flags = 2;
   1654     }
   1655 }
   1656 
   1657 /****************************************************************************************\
   1658 *                              External functions                                        *
   1659 \****************************************************************************************/
   1660 
   1661 void line( InputOutputArray _img, Point pt1, Point pt2, const Scalar& color,
   1662            int thickness, int line_type, int shift )
   1663 {
   1664     Mat img = _img.getMat();
   1665 
   1666     if( line_type == CV_AA && img.depth() != CV_8U )
   1667         line_type = 8;
   1668 
   1669     CV_Assert( 0 <= thickness && thickness <= MAX_THICKNESS );
   1670     CV_Assert( 0 <= shift && shift <= XY_SHIFT );
   1671 
   1672     double buf[4];
   1673     scalarToRawData( color, buf, img.type(), 0 );
   1674     ThickLine( img, pt1, pt2, buf, thickness, line_type, 3, shift );
   1675 }
   1676 
   1677 void arrowedLine(InputOutputArray img, Point pt1, Point pt2, const Scalar& color,
   1678            int thickness, int line_type, int shift, double tipLength)
   1679 {
   1680     const double tipSize = norm(pt1-pt2)*tipLength; // Factor to normalize the size of the tip depending on the length of the arrow
   1681 
   1682     line(img, pt1, pt2, color, thickness, line_type, shift);
   1683 
   1684     const double angle = atan2( (double) pt1.y - pt2.y, (double) pt1.x - pt2.x );
   1685 
   1686     Point p(cvRound(pt2.x + tipSize * cos(angle + CV_PI / 4)),
   1687         cvRound(pt2.y + tipSize * sin(angle + CV_PI / 4)));
   1688     line(img, p, pt2, color, thickness, line_type, shift);
   1689 
   1690     p.x = cvRound(pt2.x + tipSize * cos(angle - CV_PI / 4));
   1691     p.y = cvRound(pt2.y + tipSize * sin(angle - CV_PI / 4));
   1692     line(img, p, pt2, color, thickness, line_type, shift);
   1693 }
   1694 
   1695 void rectangle( InputOutputArray _img, Point pt1, Point pt2,
   1696                 const Scalar& color, int thickness,
   1697                 int lineType, int shift )
   1698 {
   1699     Mat img = _img.getMat();
   1700 
   1701     if( lineType == CV_AA && img.depth() != CV_8U )
   1702         lineType = 8;
   1703 
   1704     CV_Assert( thickness <= MAX_THICKNESS );
   1705     CV_Assert( 0 <= shift && shift <= XY_SHIFT );
   1706 
   1707     double buf[4];
   1708     scalarToRawData(color, buf, img.type(), 0);
   1709 
   1710     Point pt[4];
   1711 
   1712     pt[0] = pt1;
   1713     pt[1].x = pt2.x;
   1714     pt[1].y = pt1.y;
   1715     pt[2] = pt2;
   1716     pt[3].x = pt1.x;
   1717     pt[3].y = pt2.y;
   1718 
   1719     if( thickness >= 0 )
   1720         PolyLine( img, pt, 4, true, buf, thickness, lineType, shift );
   1721     else
   1722         FillConvexPoly( img, pt, 4, buf, lineType, shift );
   1723 }
   1724 
   1725 
   1726 void rectangle( Mat& img, Rect rec,
   1727                 const Scalar& color, int thickness,
   1728                 int lineType, int shift )
   1729 {
   1730     CV_Assert( 0 <= shift && shift <= XY_SHIFT );
   1731     if( rec.area() > 0 )
   1732         rectangle( img, rec.tl(), rec.br() - Point(1<<shift,1<<shift),
   1733                    color, thickness, lineType, shift );
   1734 }
   1735 
   1736 
   1737 void circle( InputOutputArray _img, Point center, int radius,
   1738              const Scalar& color, int thickness, int line_type, int shift )
   1739 {
   1740     Mat img = _img.getMat();
   1741 
   1742     if( line_type == CV_AA && img.depth() != CV_8U )
   1743         line_type = 8;
   1744 
   1745     CV_Assert( radius >= 0 && thickness <= MAX_THICKNESS &&
   1746         0 <= shift && shift <= XY_SHIFT );
   1747 
   1748     double buf[4];
   1749     scalarToRawData(color, buf, img.type(), 0);
   1750 
   1751     if( thickness > 1 || line_type >= CV_AA )
   1752     {
   1753         center.x <<= XY_SHIFT - shift;
   1754         center.y <<= XY_SHIFT - shift;
   1755         radius <<= XY_SHIFT - shift;
   1756         EllipseEx( img, center, Size(radius, radius),
   1757                    0, 0, 360, buf, thickness, line_type );
   1758     }
   1759     else
   1760         Circle( img, center, radius, buf, thickness < 0 );
   1761 }
   1762 
   1763 
   1764 void ellipse( InputOutputArray _img, Point center, Size axes,
   1765               double angle, double start_angle, double end_angle,
   1766               const Scalar& color, int thickness, int line_type, int shift )
   1767 {
   1768     Mat img = _img.getMat();
   1769 
   1770     if( line_type == CV_AA && img.depth() != CV_8U )
   1771         line_type = 8;
   1772 
   1773     CV_Assert( axes.width >= 0 && axes.height >= 0 &&
   1774         thickness <= MAX_THICKNESS && 0 <= shift && shift <= XY_SHIFT );
   1775 
   1776     double buf[4];
   1777     scalarToRawData(color, buf, img.type(), 0);
   1778 
   1779     int _angle = cvRound(angle);
   1780     int _start_angle = cvRound(start_angle);
   1781     int _end_angle = cvRound(end_angle);
   1782     center.x <<= XY_SHIFT - shift;
   1783     center.y <<= XY_SHIFT - shift;
   1784     axes.width <<= XY_SHIFT - shift;
   1785     axes.height <<= XY_SHIFT - shift;
   1786 
   1787     EllipseEx( img, center, axes, _angle, _start_angle,
   1788                _end_angle, buf, thickness, line_type );
   1789 }
   1790 
   1791 void ellipse(InputOutputArray _img, const RotatedRect& box, const Scalar& color,
   1792              int thickness, int lineType)
   1793 {
   1794     Mat img = _img.getMat();
   1795 
   1796     if( lineType == CV_AA && img.depth() != CV_8U )
   1797         lineType = 8;
   1798 
   1799     CV_Assert( box.size.width >= 0 && box.size.height >= 0 &&
   1800                thickness <= MAX_THICKNESS );
   1801 
   1802     double buf[4];
   1803     scalarToRawData(color, buf, img.type(), 0);
   1804 
   1805     int _angle = cvRound(box.angle);
   1806     Point center(cvRound(box.center.x*(1 << XY_SHIFT)),
   1807                  cvRound(box.center.y*(1 << XY_SHIFT)));
   1808     Size axes(cvRound(box.size.width*(1 << (XY_SHIFT - 1))),
   1809               cvRound(box.size.height*(1 << (XY_SHIFT - 1))));
   1810     EllipseEx( img, center, axes, _angle, 0, 360, buf, thickness, lineType );
   1811 }
   1812 
   1813 void fillConvexPoly( Mat& img, const Point* pts, int npts,
   1814                      const Scalar& color, int line_type, int shift )
   1815 {
   1816     if( !pts || npts <= 0 )
   1817         return;
   1818 
   1819     if( line_type == CV_AA && img.depth() != CV_8U )
   1820         line_type = 8;
   1821 
   1822     double buf[4];
   1823     CV_Assert( 0 <= shift && shift <=  XY_SHIFT );
   1824     scalarToRawData(color, buf, img.type(), 0);
   1825     FillConvexPoly( img, pts, npts, buf, line_type, shift );
   1826 }
   1827 
   1828 
   1829 void fillPoly( Mat& img, const Point** pts, const int* npts, int ncontours,
   1830                const Scalar& color, int line_type,
   1831                int shift, Point offset )
   1832 {
   1833     if( line_type == CV_AA && img.depth() != CV_8U )
   1834         line_type = 8;
   1835 
   1836     CV_Assert( pts && npts && ncontours >= 0 && 0 <= shift && shift <= XY_SHIFT );
   1837 
   1838     double buf[4];
   1839     scalarToRawData(color, buf, img.type(), 0);
   1840 
   1841     std::vector<PolyEdge> edges;
   1842 
   1843     int i, total = 0;
   1844     for( i = 0; i < ncontours; i++ )
   1845         total += npts[i];
   1846 
   1847     edges.reserve( total + 1 );
   1848     for( i = 0; i < ncontours; i++ )
   1849         CollectPolyEdges( img, pts[i], npts[i], edges, buf, line_type, shift, offset );
   1850 
   1851     FillEdgeCollection(img, edges, buf);
   1852 }
   1853 
   1854 
   1855 void polylines( Mat& img, const Point* const* pts, const int* npts, int ncontours, bool isClosed,
   1856                 const Scalar& color, int thickness, int line_type, int shift )
   1857 {
   1858     if( line_type == CV_AA && img.depth() != CV_8U )
   1859         line_type = 8;
   1860 
   1861     CV_Assert( pts && npts && ncontours >= 0 &&
   1862                0 <= thickness && thickness <= MAX_THICKNESS &&
   1863                0 <= shift && shift <= XY_SHIFT );
   1864 
   1865     double buf[4];
   1866     scalarToRawData( color, buf, img.type(), 0 );
   1867 
   1868     for( int i = 0; i < ncontours; i++ )
   1869         PolyLine( img, pts[i], npts[i], isClosed, buf, thickness, line_type, shift );
   1870 }
   1871 
   1872 
   1873 enum { FONT_SIZE_SHIFT=8, FONT_ITALIC_ALPHA=(1 << 8),
   1874        FONT_ITALIC_DIGIT=(2 << 8), FONT_ITALIC_PUNCT=(4 << 8),
   1875        FONT_ITALIC_BRACES=(8 << 8), FONT_HAVE_GREEK=(16 << 8),
   1876        FONT_HAVE_CYRILLIC=(32 << 8) };
   1877 
   1878 static const int HersheyPlain[] = {
   1879 (5 + 4*16) + FONT_HAVE_GREEK,
   1880 199, 214, 217, 233, 219, 197, 234, 216, 221, 222, 228, 225, 211, 224, 210, 220,
   1881 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 212, 213, 191, 226, 192,
   1882 215, 190, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
   1883 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 193, 84,
   1884 194, 85, 86, 87, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
   1885 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
   1886 195, 223, 196, 88 };
   1887 
   1888 static const int HersheyPlainItalic[] = {
   1889 (5 + 4*16) + FONT_ITALIC_ALPHA + FONT_HAVE_GREEK,
   1890 199, 214, 217, 233, 219, 197, 234, 216, 221, 222, 228, 225, 211, 224, 210, 220,
   1891 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 212, 213, 191, 226, 192,
   1892 215, 190, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
   1893 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 193, 84,
   1894 194, 85, 86, 87, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161,
   1895 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176,
   1896 195, 223, 196, 88 };
   1897 
   1898 static const int HersheyComplexSmall[] = {
   1899 (6 + 7*16) + FONT_HAVE_GREEK,
   1900 1199, 1214, 1217, 1275, 1274, 1271, 1272, 1216, 1221, 1222, 1219, 1232, 1211, 1231, 1210, 1220,
   1901 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1212, 2213, 1241, 1238, 1242,
   1902 1215, 1273, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013,
   1903 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1223, 1084,
   1904 1224, 1247, 586, 1249, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111,
   1905 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126,
   1906 1225, 1229, 1226, 1246 };
   1907 
   1908 static const int HersheyComplexSmallItalic[] = {
   1909 (6 + 7*16) + FONT_ITALIC_ALPHA + FONT_HAVE_GREEK,
   1910 1199, 1214, 1217, 1275, 1274, 1271, 1272, 1216, 1221, 1222, 1219, 1232, 1211, 1231, 1210, 1220,
   1911 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1212, 1213, 1241, 1238, 1242,
   1912 1215, 1273, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063,
   1913 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1223, 1084,
   1914 1224, 1247, 586, 1249, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161,
   1915 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176,
   1916 1225, 1229, 1226, 1246 };
   1917 
   1918 static const int HersheySimplex[] = {
   1919 (9 + 12*16) + FONT_HAVE_GREEK,
   1920 2199, 714, 717, 733, 719, 697, 734, 716, 721, 722, 728, 725, 711, 724, 710, 720,
   1921 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 712, 713, 691, 726, 692,
   1922 715, 690, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513,
   1923 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 693, 584,
   1924 694, 2247, 586, 2249, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611,
   1925 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626,
   1926 695, 723, 696, 2246 };
   1927 
   1928 static const int HersheyDuplex[] = {
   1929 (9 + 12*16) + FONT_HAVE_GREEK,
   1930 2199, 2714, 2728, 2732, 2719, 2733, 2718, 2727, 2721, 2722, 2723, 2725, 2711, 2724, 2710, 2720,
   1931 2700, 2701, 2702, 2703, 2704, 2705, 2706, 2707, 2708, 2709, 2712, 2713, 2730, 2726, 2731,
   1932 2715, 2734, 2501, 2502, 2503, 2504, 2505, 2506, 2507, 2508, 2509, 2510, 2511, 2512, 2513,
   1933 2514, 2515, 2516, 2517, 2518, 2519, 2520, 2521, 2522, 2523, 2524, 2525, 2526, 2223, 2084,
   1934 2224, 2247, 587, 2249, 2601, 2602, 2603, 2604, 2605, 2606, 2607, 2608, 2609, 2610, 2611,
   1935 2612, 2613, 2614, 2615, 2616, 2617, 2618, 2619, 2620, 2621, 2622, 2623, 2624, 2625, 2626,
   1936 2225, 2229, 2226, 2246 };
   1937 
   1938 static const int HersheyComplex[] = {
   1939 (9 + 12*16) + FONT_HAVE_GREEK + FONT_HAVE_CYRILLIC,
   1940 2199, 2214, 2217, 2275, 2274, 2271, 2272, 2216, 2221, 2222, 2219, 2232, 2211, 2231, 2210, 2220,
   1941 2200, 2201, 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, 2212, 2213, 2241, 2238, 2242,
   1942 2215, 2273, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013,
   1943 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2223, 2084,
   1944 2224, 2247, 587, 2249, 2101, 2102, 2103, 2104, 2105, 2106, 2107, 2108, 2109, 2110, 2111,
   1945 2112, 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, 2121, 2122, 2123, 2124, 2125, 2126,
   1946 2225, 2229, 2226, 2246, 2801, 2802, 2803, 2804, 2805, 2806, 2807, 2808, 2809, 2810, 2811,
   1947 2812, 2813, 2814, 2815, 2816, 2817, 2818, 2819, 2820, 2821, 2822, 2823, 2824, 2825, 2826,
   1948 2827, 2828, 2829, 2830, 2831, 2832, 2901, 2902, 2903, 2904, 2905, 2906, 2907, 2908, 2909,
   1949 2910, 2911, 2912, 2913, 2914, 2915, 2916, 2917, 2918, 2919, 2920, 2921, 2922, 2923, 2924,
   1950 2925, 2926, 2927, 2928, 2929, 2930, 2931, 2932};
   1951 
   1952 static const int HersheyComplexItalic[] = {
   1953 (9 + 12*16) + FONT_ITALIC_ALPHA + FONT_ITALIC_DIGIT + FONT_ITALIC_PUNCT +
   1954 FONT_HAVE_GREEK + FONT_HAVE_CYRILLIC,
   1955 2199, 2764, 2778, 2782, 2769, 2783, 2768, 2777, 2771, 2772, 2219, 2232, 2211, 2231, 2210, 2220,
   1956 2750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2212, 2213, 2241, 2238, 2242,
   1957 2765, 2273, 2051, 2052, 2053, 2054, 2055, 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063,
   1958 2064, 2065, 2066, 2067, 2068, 2069, 2070, 2071, 2072, 2073, 2074, 2075, 2076, 2223, 2084,
   1959 2224, 2247, 587, 2249, 2151, 2152, 2153, 2154, 2155, 2156, 2157, 2158, 2159, 2160, 2161,
   1960 2162, 2163, 2164, 2165, 2166, 2167, 2168, 2169, 2170, 2171, 2172, 2173, 2174, 2175, 2176,
   1961 2225, 2229, 2226, 2246 };
   1962 
   1963 static const int HersheyTriplex[] = {
   1964 (9 + 12*16) + FONT_HAVE_GREEK,
   1965 2199, 3214, 3228, 3232, 3219, 3233, 3218, 3227, 3221, 3222, 3223, 3225, 3211, 3224, 3210, 3220,
   1966 3200, 3201, 3202, 3203, 3204, 3205, 3206, 3207, 3208, 3209, 3212, 3213, 3230, 3226, 3231,
   1967 3215, 3234, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3011, 3012, 3013,
   1968 2014, 3015, 3016, 3017, 3018, 3019, 3020, 3021, 3022, 3023, 3024, 3025, 3026, 2223, 2084,
   1969 2224, 2247, 587, 2249, 3101, 3102, 3103, 3104, 3105, 3106, 3107, 3108, 3109, 3110, 3111,
   1970 3112, 3113, 3114, 3115, 3116, 3117, 3118, 3119, 3120, 3121, 3122, 3123, 3124, 3125, 3126,
   1971 2225, 2229, 2226, 2246 };
   1972 
   1973 static const int HersheyTriplexItalic[] = {
   1974 (9 + 12*16) + FONT_ITALIC_ALPHA + FONT_ITALIC_DIGIT +
   1975 FONT_ITALIC_PUNCT + FONT_HAVE_GREEK,
   1976 2199, 3264, 3278, 3282, 3269, 3233, 3268, 3277, 3271, 3272, 3223, 3225, 3261, 3224, 3260, 3270,
   1977 3250, 3251, 3252, 3253, 3254, 3255, 3256, 3257, 3258, 3259, 3262, 3263, 3230, 3226, 3231,
   1978 3265, 3234, 3051, 3052, 3053, 3054, 3055, 3056, 3057, 3058, 3059, 3060, 3061, 3062, 3063,
   1979 2064, 3065, 3066, 3067, 3068, 3069, 3070, 3071, 3072, 3073, 3074, 3075, 3076, 2223, 2084,
   1980 2224, 2247, 587, 2249, 3151, 3152, 3153, 3154, 3155, 3156, 3157, 3158, 3159, 3160, 3161,
   1981 3162, 3163, 3164, 3165, 3166, 3167, 3168, 3169, 3170, 3171, 3172, 3173, 3174, 3175, 3176,
   1982 2225, 2229, 2226, 2246 };
   1983 
   1984 static const int HersheyScriptSimplex[] = {
   1985 (9 + 12*16) + FONT_ITALIC_ALPHA + FONT_HAVE_GREEK,
   1986 2199, 714, 717, 733, 719, 697, 734, 716, 721, 722, 728, 725, 711, 724, 710, 720,
   1987 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 712, 713, 691, 726, 692,
   1988 715, 690, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563,
   1989 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 693, 584,
   1990 694, 2247, 586, 2249, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661,
   1991 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676,
   1992 695, 723, 696, 2246 };
   1993 
   1994 static const int HersheyScriptComplex[] = {
   1995 (9 + 12*16) + FONT_ITALIC_ALPHA + FONT_ITALIC_DIGIT + FONT_ITALIC_PUNCT + FONT_HAVE_GREEK,
   1996 2199, 2764, 2778, 2782, 2769, 2783, 2768, 2777, 2771, 2772, 2219, 2232, 2211, 2231, 2210, 2220,
   1997 2750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2212, 2213, 2241, 2238, 2242,
   1998 2215, 2273, 2551, 2552, 2553, 2554, 2555, 2556, 2557, 2558, 2559, 2560, 2561, 2562, 2563,
   1999 2564, 2565, 2566, 2567, 2568, 2569, 2570, 2571, 2572, 2573, 2574, 2575, 2576, 2223, 2084,
   2000 2224, 2247, 586, 2249, 2651, 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, 2660, 2661,
   2001 2662, 2663, 2664, 2665, 2666, 2667, 2668, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2676,
   2002 2225, 2229, 2226, 2246 };
   2003 
   2004 
   2005 static const int* getFontData(int fontFace)
   2006 {
   2007     bool isItalic = (fontFace & FONT_ITALIC) != 0;
   2008     const int* ascii = 0;
   2009 
   2010     switch( fontFace & 15 )
   2011     {
   2012     case FONT_HERSHEY_SIMPLEX:
   2013         ascii = HersheySimplex;
   2014         break;
   2015     case FONT_HERSHEY_PLAIN:
   2016         ascii = !isItalic ? HersheyPlain : HersheyPlainItalic;
   2017         break;
   2018     case FONT_HERSHEY_DUPLEX:
   2019         ascii = HersheyDuplex;
   2020         break;
   2021     case FONT_HERSHEY_COMPLEX:
   2022         ascii = !isItalic ? HersheyComplex : HersheyComplexItalic;
   2023         break;
   2024     case FONT_HERSHEY_TRIPLEX:
   2025         ascii = !isItalic ? HersheyTriplex : HersheyTriplexItalic;
   2026         break;
   2027     case FONT_HERSHEY_COMPLEX_SMALL:
   2028         ascii = !isItalic ? HersheyComplexSmall : HersheyComplexSmallItalic;
   2029         break;
   2030     case FONT_HERSHEY_SCRIPT_SIMPLEX:
   2031         ascii = HersheyScriptSimplex;
   2032         break;
   2033     case FONT_HERSHEY_SCRIPT_COMPLEX:
   2034         ascii = HersheyScriptComplex;
   2035         break;
   2036     default:
   2037         CV_Error( CV_StsOutOfRange, "Unknown font type" );
   2038     }
   2039     return ascii;
   2040 }
   2041 
   2042 inline void readCheck(int &c, int &i, const String &text, int fontFace)
   2043 {
   2044 
   2045     int leftBoundary = ' ', rightBoundary = 127;
   2046 
   2047     if(c >= 0x80 && fontFace == FONT_HERSHEY_COMPLEX)
   2048     {
   2049         if(c == 0xD0 && (uchar)text[i + 1] >= 0x90 && (uchar)text[i + 1] <= 0xBF)
   2050         {
   2051             c = (uchar)text[++i] - 17;
   2052             leftBoundary = 127;
   2053             rightBoundary = 175;
   2054         }
   2055         else if(c == 0xD1 && (uchar)text[i + 1] >= 0x80 && (uchar)text[i + 1] <= 0x8F)
   2056         {
   2057             c = (uchar)text[++i] + 47;
   2058             leftBoundary = 175;
   2059             rightBoundary = 191;
   2060         }
   2061         else
   2062         {
   2063             if(c >= 0xC0 && text[i+1] != 0) //2 bytes utf
   2064                 i++;
   2065 
   2066             if(c >= 0xE0 && text[i+1] != 0) //3 bytes utf
   2067                 i++;
   2068 
   2069             if(c >= 0xF0 && text[i+1] != 0) //4 bytes utf
   2070                 i++;
   2071 
   2072             if(c >= 0xF8 && text[i+1] != 0) //5 bytes utf
   2073                 i++;
   2074 
   2075             if(c >= 0xFC && text[i+1] != 0) //6 bytes utf
   2076                 i++;
   2077 
   2078             c = '?';
   2079         }
   2080     }
   2081 
   2082     if(c >= rightBoundary || c < leftBoundary)
   2083         c = '?';
   2084 }
   2085 
   2086 extern const char* g_HersheyGlyphs[];
   2087 
   2088 void putText( InputOutputArray _img, const String& text, Point org,
   2089               int fontFace, double fontScale, Scalar color,
   2090               int thickness, int line_type, bool bottomLeftOrigin )
   2091 
   2092 {
   2093     Mat img = _img.getMat();
   2094     const int* ascii = getFontData(fontFace);
   2095 
   2096     double buf[4];
   2097     scalarToRawData(color, buf, img.type(), 0);
   2098 
   2099     int base_line = -(ascii[0] & 15);
   2100     int hscale = cvRound(fontScale*XY_ONE), vscale = hscale;
   2101 
   2102     if( line_type == CV_AA && img.depth() != CV_8U )
   2103         line_type = 8;
   2104 
   2105     if( bottomLeftOrigin )
   2106         vscale = -vscale;
   2107 
   2108     int view_x = org.x << XY_SHIFT;
   2109     int view_y = (org.y << XY_SHIFT) + base_line*vscale;
   2110     std::vector<Point> pts;
   2111     pts.reserve(1 << 10);
   2112     const char **faces = cv::g_HersheyGlyphs;
   2113 
   2114     for( int i = 0; text[i] != '\0'; i++ )
   2115     {
   2116         int c = (uchar)text[i];
   2117         Point p;
   2118 
   2119         readCheck(c, i, text, fontFace);
   2120 
   2121         const char* ptr = faces[ascii[(c-' ')+1]];
   2122         p.x = (uchar)ptr[0] - 'R';
   2123         p.y = (uchar)ptr[1] - 'R';
   2124         int dx = p.y*hscale;
   2125         view_x -= p.x*hscale;
   2126         pts.resize(0);
   2127 
   2128         for( ptr += 2;; )
   2129         {
   2130             if( *ptr == ' ' || !*ptr )
   2131             {
   2132                 if( pts.size() > 1 )
   2133                     PolyLine( img, &pts[0], (int)pts.size(), false, buf, thickness, line_type, XY_SHIFT );
   2134                 if( !*ptr++ )
   2135                     break;
   2136                 pts.resize(0);
   2137             }
   2138             else
   2139             {
   2140                 p.x = (uchar)ptr[0] - 'R';
   2141                 p.y = (uchar)ptr[1] - 'R';
   2142                 ptr += 2;
   2143                 pts.push_back(Point(p.x*hscale + view_x, p.y*vscale + view_y));
   2144             }
   2145         }
   2146         view_x += dx;
   2147     }
   2148 }
   2149 
   2150 Size getTextSize( const String& text, int fontFace, double fontScale, int thickness, int* _base_line)
   2151 {
   2152     Size size;
   2153     double view_x = 0;
   2154     const char **faces = cv::g_HersheyGlyphs;
   2155     const int* ascii = getFontData(fontFace);
   2156 
   2157     int base_line = (ascii[0] & 15);
   2158     int cap_line = (ascii[0] >> 4) & 15;
   2159     size.height = cvRound((cap_line + base_line)*fontScale + (thickness+1)/2);
   2160 
   2161     for( int i = 0; text[i] != '\0'; i++ )
   2162     {
   2163         int c = (uchar)text[i];
   2164         Point p;
   2165 
   2166         readCheck(c, i, text, fontFace);
   2167 
   2168         const char* ptr = faces[ascii[(c-' ')+1]];
   2169         p.x = (uchar)ptr[0] - 'R';
   2170         p.y = (uchar)ptr[1] - 'R';
   2171         view_x += (p.y - p.x)*fontScale;
   2172     }
   2173 
   2174     size.width = cvRound(view_x + thickness);
   2175     if( _base_line )
   2176         *_base_line = cvRound(base_line*fontScale + thickness*0.5);
   2177     return size;
   2178 }
   2179 
   2180 }
   2181 
   2182 
   2183 void cv::fillConvexPoly(InputOutputArray _img, InputArray _points,
   2184                         const Scalar& color, int lineType, int shift)
   2185 {
   2186     Mat img = _img.getMat(), points = _points.getMat();
   2187     CV_Assert(points.checkVector(2, CV_32S) >= 0);
   2188     fillConvexPoly(img, points.ptr<Point>(), points.rows*points.cols*points.channels()/2, color, lineType, shift);
   2189 }
   2190 
   2191 
   2192 void cv::fillPoly(InputOutputArray _img, InputArrayOfArrays pts,
   2193                   const Scalar& color, int lineType, int shift, Point offset)
   2194 {
   2195     Mat img = _img.getMat();
   2196     int i, ncontours = (int)pts.total();
   2197     if( ncontours == 0 )
   2198         return;
   2199     AutoBuffer<Point*> _ptsptr(ncontours);
   2200     AutoBuffer<int> _npts(ncontours);
   2201     Point** ptsptr = _ptsptr;
   2202     int* npts = _npts;
   2203 
   2204     for( i = 0; i < ncontours; i++ )
   2205     {
   2206         Mat p = pts.getMat(i);
   2207         CV_Assert(p.checkVector(2, CV_32S) >= 0);
   2208         ptsptr[i] = p.ptr<Point>();
   2209         npts[i] = p.rows*p.cols*p.channels()/2;
   2210     }
   2211     fillPoly(img, (const Point**)ptsptr, npts, (int)ncontours, color, lineType, shift, offset);
   2212 }
   2213 
   2214 
   2215 void cv::polylines(InputOutputArray _img, InputArrayOfArrays pts,
   2216                    bool isClosed, const Scalar& color,
   2217                    int thickness, int lineType, int shift )
   2218 {
   2219     Mat img = _img.getMat();
   2220     bool manyContours = pts.kind() == _InputArray::STD_VECTOR_VECTOR ||
   2221                         pts.kind() == _InputArray::STD_VECTOR_MAT;
   2222     int i, ncontours = manyContours ? (int)pts.total() : 1;
   2223     if( ncontours == 0 )
   2224         return;
   2225     AutoBuffer<Point*> _ptsptr(ncontours);
   2226     AutoBuffer<int> _npts(ncontours);
   2227     Point** ptsptr = _ptsptr;
   2228     int* npts = _npts;
   2229 
   2230     for( i = 0; i < ncontours; i++ )
   2231     {
   2232         Mat p = pts.getMat(manyContours ? i : -1);
   2233         if( p.total() == 0 )
   2234         {
   2235             npts[i] = 0;
   2236             continue;
   2237         }
   2238         CV_Assert(p.checkVector(2, CV_32S) >= 0);
   2239         ptsptr[i] = p.ptr<Point>();
   2240         npts[i] = p.rows*p.cols*p.channels()/2;
   2241     }
   2242     polylines(img, (const Point**)ptsptr, npts, (int)ncontours, isClosed, color, thickness, lineType, shift);
   2243 }
   2244 
   2245 namespace
   2246 {
   2247 using namespace cv;
   2248 
   2249 static void addChildContour(InputArrayOfArrays contours,
   2250                             size_t ncontours,
   2251                             const Vec4i* hierarchy,
   2252                             int i, std::vector<CvSeq>& seq,
   2253                             std::vector<CvSeqBlock>& block)
   2254 {
   2255     for( ; i >= 0; i = hierarchy[i][0] )
   2256     {
   2257         Mat ci = contours.getMat(i);
   2258         cvMakeSeqHeaderForArray(CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(Point),
   2259                                 !ci.empty() ? (void*)ci.ptr() : 0, (int)ci.total(),
   2260                                 &seq[i], &block[i] );
   2261 
   2262         int h_next = hierarchy[i][0], h_prev = hierarchy[i][1],
   2263             v_next = hierarchy[i][2], v_prev = hierarchy[i][3];
   2264         seq[i].h_next = (size_t)h_next < ncontours ? &seq[h_next] : 0;
   2265         seq[i].h_prev = (size_t)h_prev < ncontours ? &seq[h_prev] : 0;
   2266         seq[i].v_next = (size_t)v_next < ncontours ? &seq[v_next] : 0;
   2267         seq[i].v_prev = (size_t)v_prev < ncontours ? &seq[v_prev] : 0;
   2268 
   2269         if( v_next >= 0 )
   2270             addChildContour(contours, ncontours, hierarchy, v_next, seq, block);
   2271     }
   2272 }
   2273 }
   2274 
   2275 void cv::drawContours( InputOutputArray _image, InputArrayOfArrays _contours,
   2276                    int contourIdx, const Scalar& color, int thickness,
   2277                    int lineType, InputArray _hierarchy,
   2278                    int maxLevel, Point offset )
   2279 {
   2280     Mat image = _image.getMat(), hierarchy = _hierarchy.getMat();
   2281     CvMat _cimage = image;
   2282 
   2283     size_t ncontours = _contours.total();
   2284     size_t i = 0, first = 0, last = ncontours;
   2285     std::vector<CvSeq> seq;
   2286     std::vector<CvSeqBlock> block;
   2287 
   2288     if( !last )
   2289         return;
   2290 
   2291     seq.resize(last);
   2292     block.resize(last);
   2293 
   2294     for( i = first; i < last; i++ )
   2295         seq[i].first = 0;
   2296 
   2297     if( contourIdx >= 0 )
   2298     {
   2299         CV_Assert( 0 <= contourIdx && contourIdx < (int)last );
   2300         first = contourIdx;
   2301         last = contourIdx + 1;
   2302     }
   2303 
   2304     for( i = first; i < last; i++ )
   2305     {
   2306         Mat ci = _contours.getMat((int)i);
   2307         if( ci.empty() )
   2308             continue;
   2309         int npoints = ci.checkVector(2, CV_32S);
   2310         CV_Assert( npoints > 0 );
   2311         cvMakeSeqHeaderForArray( CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(Point),
   2312                                  ci.ptr(), npoints, &seq[i], &block[i] );
   2313     }
   2314 
   2315     if( hierarchy.empty() || maxLevel == 0 )
   2316         for( i = first; i < last; i++ )
   2317         {
   2318             seq[i].h_next = i < last-1 ? &seq[i+1] : 0;
   2319             seq[i].h_prev = i > first ? &seq[i-1] : 0;
   2320         }
   2321     else
   2322     {
   2323         size_t count = last - first;
   2324         CV_Assert(hierarchy.total() == ncontours && hierarchy.type() == CV_32SC4 );
   2325         const Vec4i* h = hierarchy.ptr<Vec4i>();
   2326 
   2327         if( count == ncontours )
   2328         {
   2329             for( i = first; i < last; i++ )
   2330             {
   2331                 int h_next = h[i][0], h_prev = h[i][1],
   2332                     v_next = h[i][2], v_prev = h[i][3];
   2333                 seq[i].h_next = (size_t)h_next < count ? &seq[h_next] : 0;
   2334                 seq[i].h_prev = (size_t)h_prev < count ? &seq[h_prev] : 0;
   2335                 seq[i].v_next = (size_t)v_next < count ? &seq[v_next] : 0;
   2336                 seq[i].v_prev = (size_t)v_prev < count ? &seq[v_prev] : 0;
   2337             }
   2338         }
   2339         else
   2340         {
   2341             int child = h[first][2];
   2342             if( child >= 0 )
   2343             {
   2344                 addChildContour(_contours, ncontours, h, child, seq, block);
   2345                 seq[first].v_next = &seq[child];
   2346             }
   2347         }
   2348     }
   2349 
   2350     cvDrawContours( &_cimage, &seq[first], color, color, contourIdx >= 0 ?
   2351                    -maxLevel : maxLevel, thickness, lineType, offset );
   2352 }
   2353 
   2354 
   2355 
   2356 static const int CodeDeltas[8][2] =
   2357 { {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1} };
   2358 
   2359 #define CV_ADJUST_EDGE_COUNT( count, seq )  \
   2360     ((count) -= ((count) == (seq)->total && !CV_IS_SEQ_CLOSED(seq)))
   2361 
   2362 CV_IMPL void
   2363 cvDrawContours( void* _img, CvSeq* contour,
   2364                 CvScalar _externalColor, CvScalar _holeColor,
   2365                 int  maxLevel, int thickness,
   2366                 int line_type, CvPoint _offset )
   2367 {
   2368     CvSeq *contour0 = contour, *h_next = 0;
   2369     CvTreeNodeIterator iterator;
   2370     std::vector<cv::PolyEdge> edges;
   2371     std::vector<cv::Point> pts;
   2372     cv::Scalar externalColor = _externalColor, holeColor = _holeColor;
   2373     cv::Mat img = cv::cvarrToMat(_img);
   2374     cv::Point offset = _offset;
   2375     double ext_buf[4], hole_buf[4];
   2376 
   2377     if( line_type == CV_AA && img.depth() != CV_8U )
   2378         line_type = 8;
   2379 
   2380     if( !contour )
   2381         return;
   2382 
   2383     CV_Assert( thickness <= MAX_THICKNESS );
   2384 
   2385     scalarToRawData( externalColor, ext_buf, img.type(), 0 );
   2386     scalarToRawData( holeColor, hole_buf, img.type(), 0 );
   2387 
   2388     maxLevel = MAX(maxLevel, INT_MIN+2);
   2389     maxLevel = MIN(maxLevel, INT_MAX-1);
   2390 
   2391     if( maxLevel < 0 )
   2392     {
   2393         h_next = contour->h_next;
   2394         contour->h_next = 0;
   2395         maxLevel = -maxLevel+1;
   2396     }
   2397 
   2398     cvInitTreeNodeIterator( &iterator, contour, maxLevel );
   2399     while( (contour = (CvSeq*)cvNextTreeNode( &iterator )) != 0 )
   2400     {
   2401         CvSeqReader reader;
   2402         int i, count = contour->total;
   2403         int elem_type = CV_MAT_TYPE(contour->flags);
   2404         void* clr = (contour->flags & CV_SEQ_FLAG_HOLE) == 0 ? ext_buf : hole_buf;
   2405 
   2406         cvStartReadSeq( contour, &reader, 0 );
   2407         if( thickness < 0 )
   2408             pts.resize(0);
   2409 
   2410         if( CV_IS_SEQ_CHAIN_CONTOUR( contour ))
   2411         {
   2412             cv::Point pt = ((CvChain*)contour)->origin;
   2413             cv::Point prev_pt = pt;
   2414             char prev_code = reader.ptr ? reader.ptr[0] : '\0';
   2415 
   2416             prev_pt += offset;
   2417 
   2418             for( i = 0; i < count; i++ )
   2419             {
   2420                 char code;
   2421                 CV_READ_SEQ_ELEM( code, reader );
   2422 
   2423                 assert( (code & ~7) == 0 );
   2424 
   2425                 if( code != prev_code )
   2426                 {
   2427                     prev_code = code;
   2428                     if( thickness >= 0 )
   2429                         cv::ThickLine( img, prev_pt, pt, clr, thickness, line_type, 2, 0 );
   2430                     else
   2431                         pts.push_back(pt);
   2432                     prev_pt = pt;
   2433                 }
   2434 
   2435                 pt.x += CodeDeltas[(int)code][0];
   2436                 pt.y += CodeDeltas[(int)code][1];
   2437             }
   2438 
   2439             if( thickness >= 0 )
   2440                 cv::ThickLine( img, prev_pt,
   2441                     cv::Point(((CvChain*)contour)->origin) + offset,
   2442                     clr, thickness, line_type, 2, 0 );
   2443             else
   2444                 cv::CollectPolyEdges(img, &pts[0], (int)pts.size(),
   2445                                      edges, ext_buf, line_type, 0, offset);
   2446         }
   2447         else if( CV_IS_SEQ_POLYLINE( contour ))
   2448         {
   2449             CV_Assert( elem_type == CV_32SC2 );
   2450             cv::Point pt1, pt2;
   2451             int shift = 0;
   2452 
   2453             count -= !CV_IS_SEQ_CLOSED(contour);
   2454             CV_READ_SEQ_ELEM( pt1, reader );
   2455             pt1 += offset;
   2456             if( thickness < 0 )
   2457                 pts.push_back(pt1);
   2458 
   2459             for( i = 0; i < count; i++ )
   2460             {
   2461                 CV_READ_SEQ_ELEM( pt2, reader );
   2462                 pt2 += offset;
   2463                 if( thickness >= 0 )
   2464                     cv::ThickLine( img, pt1, pt2, clr, thickness, line_type, 2, shift );
   2465                 else
   2466                     pts.push_back(pt2);
   2467                 pt1 = pt2;
   2468             }
   2469             if( thickness < 0 )
   2470                 cv::CollectPolyEdges( img, &pts[0], (int)pts.size(),
   2471                                       edges, ext_buf, line_type, 0, cv::Point() );
   2472         }
   2473     }
   2474 
   2475     if( thickness < 0 )
   2476         cv::FillEdgeCollection( img, edges, ext_buf );
   2477 
   2478     if( h_next && contour0 )
   2479         contour0->h_next = h_next;
   2480 }
   2481 
   2482 CV_IMPL int
   2483 cvClipLine( CvSize size, CvPoint* pt1, CvPoint* pt2 )
   2484 {
   2485     CV_Assert( pt1 && pt2 );
   2486     return cv::clipLine( size, *(cv::Point*)pt1, *(cv::Point*)pt2 );
   2487 }
   2488 
   2489 
   2490 CV_IMPL int
   2491 cvEllipse2Poly( CvPoint center, CvSize axes, int angle,
   2492                 int arc_start, int arc_end, CvPoint* _pts, int delta )
   2493 {
   2494     std::vector<cv::Point> pts;
   2495     cv::ellipse2Poly( center, axes, angle, arc_start, arc_end, delta, pts );
   2496     memcpy( _pts, &pts[0], pts.size()*sizeof(_pts[0]) );
   2497     return (int)pts.size();
   2498 }
   2499 
   2500 CV_IMPL CvScalar
   2501 cvColorToScalar( double packed_color, int type )
   2502 {
   2503     CvScalar scalar;
   2504 
   2505     if( CV_MAT_DEPTH( type ) == CV_8U )
   2506     {
   2507         int icolor = cvRound( packed_color );
   2508         if( CV_MAT_CN( type ) > 1 )
   2509         {
   2510             scalar.val[0] = icolor & 255;
   2511             scalar.val[1] = (icolor >> 8) & 255;
   2512             scalar.val[2] = (icolor >> 16) & 255;
   2513             scalar.val[3] = (icolor >> 24) & 255;
   2514         }
   2515         else
   2516         {
   2517             scalar.val[0] = cv::saturate_cast<uchar>( icolor );
   2518             scalar.val[1] = scalar.val[2] = scalar.val[3] = 0;
   2519         }
   2520     }
   2521     else if( CV_MAT_DEPTH( type ) == CV_8S )
   2522     {
   2523         int icolor = cvRound( packed_color );
   2524         if( CV_MAT_CN( type ) > 1 )
   2525         {
   2526             scalar.val[0] = (char)icolor;
   2527             scalar.val[1] = (char)(icolor >> 8);
   2528             scalar.val[2] = (char)(icolor >> 16);
   2529             scalar.val[3] = (char)(icolor >> 24);
   2530         }
   2531         else
   2532         {
   2533             scalar.val[0] = cv::saturate_cast<schar>( icolor );
   2534             scalar.val[1] = scalar.val[2] = scalar.val[3] = 0;
   2535         }
   2536     }
   2537     else
   2538     {
   2539         int cn = CV_MAT_CN( type );
   2540         switch( cn )
   2541         {
   2542         case 1:
   2543             scalar.val[0] = packed_color;
   2544             scalar.val[1] = scalar.val[2] = scalar.val[3] = 0;
   2545             break;
   2546         case 2:
   2547             scalar.val[0] = scalar.val[1] = packed_color;
   2548             scalar.val[2] = scalar.val[3] = 0;
   2549             break;
   2550         case 3:
   2551             scalar.val[0] = scalar.val[1] = scalar.val[2] = packed_color;
   2552             scalar.val[3] = 0;
   2553             break;
   2554         default:
   2555             scalar.val[0] = scalar.val[1] =
   2556                 scalar.val[2] = scalar.val[3] = packed_color;
   2557             break;
   2558         }
   2559     }
   2560 
   2561     return scalar;
   2562 }
   2563 
   2564 CV_IMPL int
   2565 cvInitLineIterator( const CvArr* img, CvPoint pt1, CvPoint pt2,
   2566                     CvLineIterator* iterator, int connectivity,
   2567                     int left_to_right )
   2568 {
   2569     CV_Assert( iterator != 0 );
   2570     cv::LineIterator li(cv::cvarrToMat(img), pt1, pt2, connectivity, left_to_right!=0);
   2571 
   2572     iterator->err = li.err;
   2573     iterator->minus_delta = li.minusDelta;
   2574     iterator->plus_delta = li.plusDelta;
   2575     iterator->minus_step = li.minusStep;
   2576     iterator->plus_step = li.plusStep;
   2577     iterator->ptr = li.ptr;
   2578 
   2579     return li.count;
   2580 }
   2581 
   2582 CV_IMPL void
   2583 cvLine( CvArr* _img, CvPoint pt1, CvPoint pt2, CvScalar color,
   2584         int thickness, int line_type, int shift )
   2585 {
   2586     cv::Mat img = cv::cvarrToMat(_img);
   2587     cv::line( img, pt1, pt2, color, thickness, line_type, shift );
   2588 }
   2589 
   2590 CV_IMPL void
   2591 cvRectangle( CvArr* _img, CvPoint pt1, CvPoint pt2,
   2592              CvScalar color, int thickness,
   2593              int line_type, int shift )
   2594 {
   2595     cv::Mat img = cv::cvarrToMat(_img);
   2596     cv::rectangle( img, pt1, pt2, color, thickness, line_type, shift );
   2597 }
   2598 
   2599 CV_IMPL void
   2600 cvRectangleR( CvArr* _img, CvRect rec,
   2601               CvScalar color, int thickness,
   2602               int line_type, int shift )
   2603 {
   2604     cv::Mat img = cv::cvarrToMat(_img);
   2605     cv::rectangle( img, rec, color, thickness, line_type, shift );
   2606 }
   2607 
   2608 CV_IMPL void
   2609 cvCircle( CvArr* _img, CvPoint center, int radius,
   2610           CvScalar color, int thickness, int line_type, int shift )
   2611 {
   2612     cv::Mat img = cv::cvarrToMat(_img);
   2613     cv::circle( img, center, radius, color, thickness, line_type, shift );
   2614 }
   2615 
   2616 CV_IMPL void
   2617 cvEllipse( CvArr* _img, CvPoint center, CvSize axes,
   2618            double angle, double start_angle, double end_angle,
   2619            CvScalar color, int thickness, int line_type, int shift )
   2620 {
   2621     cv::Mat img = cv::cvarrToMat(_img);
   2622     cv::ellipse( img, center, axes, angle, start_angle, end_angle,
   2623         color, thickness, line_type, shift );
   2624 }
   2625 
   2626 CV_IMPL void
   2627 cvFillConvexPoly( CvArr* _img, const CvPoint *pts, int npts,
   2628                   CvScalar color, int line_type, int shift )
   2629 {
   2630     cv::Mat img = cv::cvarrToMat(_img);
   2631     cv::fillConvexPoly( img, (const cv::Point*)pts, npts,
   2632                         color, line_type, shift );
   2633 }
   2634 
   2635 CV_IMPL void
   2636 cvFillPoly( CvArr* _img, CvPoint **pts, const int *npts, int ncontours,
   2637             CvScalar color, int line_type, int shift )
   2638 {
   2639     cv::Mat img = cv::cvarrToMat(_img);
   2640 
   2641     cv::fillPoly( img, (const cv::Point**)pts, npts, ncontours, color, line_type, shift );
   2642 }
   2643 
   2644 CV_IMPL void
   2645 cvPolyLine( CvArr* _img, CvPoint **pts, const int *npts,
   2646             int ncontours, int closed, CvScalar color,
   2647             int thickness, int line_type, int shift )
   2648 {
   2649     cv::Mat img = cv::cvarrToMat(_img);
   2650 
   2651     cv::polylines( img, (const cv::Point**)pts, npts, ncontours,
   2652                    closed != 0, color, thickness, line_type, shift );
   2653 }
   2654 
   2655 CV_IMPL void
   2656 cvPutText( CvArr* _img, const char *text, CvPoint org, const CvFont *_font, CvScalar color )
   2657 {
   2658     cv::Mat img = cv::cvarrToMat(_img);
   2659     CV_Assert( text != 0 && _font != 0);
   2660     cv::putText( img, text, org, _font->font_face, (_font->hscale+_font->vscale)*0.5,
   2661                 color, _font->thickness, _font->line_type,
   2662                 CV_IS_IMAGE(_img) && ((IplImage*)_img)->origin != 0 );
   2663 }
   2664 
   2665 
   2666 CV_IMPL void
   2667 cvInitFont( CvFont *font, int font_face, double hscale, double vscale,
   2668             double shear, int thickness, int line_type )
   2669 {
   2670     CV_Assert( font != 0 && hscale > 0 && vscale > 0 && thickness >= 0 );
   2671 
   2672     font->ascii = cv::getFontData(font_face);
   2673     font->font_face = font_face;
   2674     font->hscale = (float)hscale;
   2675     font->vscale = (float)vscale;
   2676     font->thickness = thickness;
   2677     font->shear = (float)shear;
   2678     font->greek = font->cyrillic = 0;
   2679     font->line_type = line_type;
   2680 }
   2681 
   2682 CV_IMPL void
   2683 cvGetTextSize( const char *text, const CvFont *_font, CvSize *_size, int *_base_line )
   2684 {
   2685     CV_Assert(text != 0 && _font != 0);
   2686     cv::Size size = cv::getTextSize( text, _font->font_face, (_font->hscale + _font->vscale)*0.5,
   2687                                      _font->thickness, _base_line );
   2688     if( _size )
   2689         *_size = size;
   2690 }
   2691 
   2692 /* End of file. */
   2693