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 "_cxcore.h"
42
43#define  XY_SHIFT  16
44#define  XY_ONE    (1 << XY_SHIFT)
45
46#define CV_DRAWING_STORAGE_BLOCK ((1 << 12) - 256)
47
48typedef struct CvPolyEdge
49{
50    int x, dx;
51    union
52    {
53        struct CvPolyEdge *next;
54        int y0;
55    };
56    int y1;
57}
58CvPolyEdge;
59
60static void
61icvCollectPolyEdges( CvMat* img, CvSeq* v, CvContour* edges,
62                     const void* color, int line_type,
63                     int shift, CvPoint offset=cvPoint(0,0) );
64
65static void
66icvFillEdgeCollection( CvMat* img, CvContour* edges, const void* color );
67
68static void
69icvPolyLine( CvMat* img, CvPoint *v, int count, int closed,
70             const void* color, int thickness, int line_type, int shift );
71
72static void
73icvFillConvexPoly( CvMat* img, CvPoint* v, int npts,
74                   const void* color, int line_type, int shift );
75
76/****************************************************************************************\
77*                                   Lines                                                *
78\****************************************************************************************/
79
80CV_IMPL int
81cvClipLine( CvSize img_size, CvPoint* pt1, CvPoint* pt2 )
82{
83    int result = 0;
84
85    CV_FUNCNAME( "cvClipLine" );
86
87    __BEGIN__;
88
89    int x1, y1, x2, y2;
90    int c1, c2;
91    int right = img_size.width-1, bottom = img_size.height-1;
92
93    if( !pt1 || !pt2 )
94        CV_ERROR( CV_StsNullPtr, "One of point pointers is NULL" );
95
96    if( right < 0 || bottom < 0 )
97        CV_ERROR( CV_StsOutOfRange, "Image width or height are negative" );
98
99    x1 = pt1->x; y1 = pt1->y; x2 = pt2->x; y2 = pt2->y;
100    c1 = (x1 < 0) + (x1 > right) * 2 + (y1 < 0) * 4 + (y1 > bottom) * 8;
101    c2 = (x2 < 0) + (x2 > right) * 2 + (y2 < 0) * 4 + (y2 > bottom) * 8;
102
103    if( (c1 & c2) == 0 && (c1 | c2) != 0 )
104    {
105        int a;
106
107        if( c1 & 12 )
108        {
109            a = c1 < 8 ? 0 : bottom;
110            x1 += (int) (((int64) (a - y1)) * (x2 - x1) / (y2 - y1));
111            y1 = a;
112            c1 = (x1 < 0) + (x1 > right) * 2;
113        }
114        if( c2 & 12 )
115        {
116            a = c2 < 8 ? 0 : bottom;
117            x2 += (int) (((int64) (a - y2)) * (x2 - x1) / (y2 - y1));
118            y2 = a;
119            c2 = (x2 < 0) + (x2 > right) * 2;
120        }
121        if( (c1 & c2) == 0 && (c1 | c2) != 0 )
122        {
123            if( c1 )
124            {
125                a = c1 == 1 ? 0 : right;
126                y1 += (int) (((int64) (a - x1)) * (y2 - y1) / (x2 - x1));
127                x1 = a;
128                c1 = 0;
129            }
130            if( c2 )
131            {
132                a = c2 == 1 ? 0 : right;
133                y2 += (int) (((int64) (a - x2)) * (y2 - y1) / (x2 - x1));
134                x2 = a;
135                c2 = 0;
136            }
137        }
138
139        assert( (c1 & c2) != 0 || (x1 | y1 | x2 | y2) >= 0 );
140
141        pt1->x = x1;
142        pt1->y = y1;
143        pt2->x = x2;
144        pt2->y = y2;
145    }
146
147    result = ( c1 | c2 ) == 0;
148
149    __END__;
150
151    return result;
152}
153
154
155/*
156   Initializes line iterator.
157   Returns number of points on the line or negative number if error.
158*/
159CV_IMPL int
160cvInitLineIterator( const CvArr* img, CvPoint pt1, CvPoint pt2,
161                    CvLineIterator* iterator, int connectivity,
162                    int left_to_right )
163{
164    int count = -1;
165
166    CV_FUNCNAME( "cvInitLineIterator" );
167
168    __BEGIN__;
169
170    CvMat stub, *mat = (CvMat*)img;
171    int dx, dy, s;
172    int bt_pix, bt_pix0, step;
173
174    if( !CV_IS_MAT(mat) )
175        CV_CALL( mat = cvGetMat( mat, &stub ));
176
177    if( !iterator )
178        CV_ERROR( CV_StsNullPtr, "Pointer to the iterator state is NULL" );
179
180    if( connectivity != 8 && connectivity != 4 )
181        CV_ERROR( CV_StsBadArg, "Connectivity must be 8 or 4" );
182
183    if( (unsigned)pt1.x >= (unsigned)(mat->width) ||
184        (unsigned)pt2.x >= (unsigned)(mat->width) ||
185        (unsigned)pt1.y >= (unsigned)(mat->height) ||
186        (unsigned)pt2.y >= (unsigned)(mat->height) )
187        CV_ERROR( CV_StsBadPoint,
188            "One of the ending points is outside of the image, use cvClipLine" );
189
190    bt_pix0 = bt_pix = CV_ELEM_SIZE(mat->type);
191    step = mat->step;
192
193    dx = pt2.x - pt1.x;
194    dy = pt2.y - pt1.y;
195    s = dx < 0 ? -1 : 0;
196
197    if( left_to_right )
198    {
199        dx = (dx ^ s) - s;
200        dy = (dy ^ s) - s;
201        pt1.x ^= (pt1.x ^ pt2.x) & s;
202        pt1.y ^= (pt1.y ^ pt2.y) & s;
203    }
204    else
205    {
206        dx = (dx ^ s) - s;
207        bt_pix = (bt_pix ^ s) - s;
208    }
209
210    iterator->ptr = (uchar*)(mat->data.ptr + pt1.y * step + pt1.x * bt_pix0);
211
212    s = dy < 0 ? -1 : 0;
213    dy = (dy ^ s) - s;
214    step = (step ^ s) - s;
215
216    s = dy > dx ? -1 : 0;
217
218    /* conditional swaps */
219    dx ^= dy & s;
220    dy ^= dx & s;
221    dx ^= dy & s;
222
223    bt_pix ^= step & s;
224    step ^= bt_pix & s;
225    bt_pix ^= step & s;
226
227    if( connectivity == 8 )
228    {
229        assert( dx >= 0 && dy >= 0 );
230
231        iterator->err = dx - (dy + dy);
232        iterator->plus_delta = dx + dx;
233        iterator->minus_delta = -(dy + dy);
234        iterator->plus_step = step;
235        iterator->minus_step = bt_pix;
236        count = dx + 1;
237    }
238    else /* connectivity == 4 */
239    {
240        assert( dx >= 0 && dy >= 0 );
241
242        iterator->err = 0;
243        iterator->plus_delta = (dx + dx) + (dy + dy);
244        iterator->minus_delta = -(dy + dy);
245        iterator->plus_step = step - bt_pix;
246        iterator->minus_step = bt_pix;
247        count = dx + dy + 1;
248    }
249
250    __END__;
251
252    return count;
253}
254
255static void
256icvLine( CvMat* mat, CvPoint pt1, CvPoint pt2,
257         const void* color, int connectivity = 8 )
258{
259    if( cvClipLine( cvGetMatSize(mat), &pt1, &pt2 ))
260    {
261        CvLineIterator iterator;
262        int pix_size = CV_ELEM_SIZE(mat->type);
263        int i, count;
264
265        if( connectivity == 0 )
266            connectivity = 8;
267        if( connectivity == 1 )
268            connectivity = 4;
269
270        count = cvInitLineIterator( mat, pt1, pt2, &iterator, connectivity, 1 );
271
272        for( i = 0; i < count; i++ )
273        {
274            CV_MEMCPY_AUTO( iterator.ptr, color, pix_size );
275            CV_NEXT_LINE_POINT( iterator );
276        }
277    }
278}
279
280
281/* Correction table depent on the slope */
282static const uchar icvSlopeCorrTable[] = {
283    181, 181, 181, 182, 182, 183, 184, 185, 187, 188, 190, 192, 194, 196, 198, 201,
284    203, 206, 209, 211, 214, 218, 221, 224, 227, 231, 235, 238, 242, 246, 250, 254
285};
286
287/* Gaussian for antialiasing filter */
288static const int icvFilterTable[] = {
289    168, 177, 185, 194, 202, 210, 218, 224, 231, 236, 241, 246, 249, 252, 254, 254,
290    254, 254, 252, 249, 246, 241, 236, 231, 224, 218, 210, 202, 194, 185, 177, 168,
291    158, 149, 140, 131, 122, 114, 105, 97, 89, 82, 75, 68, 62, 56, 50, 45,
292    40, 36, 32, 28, 25, 22, 19, 16, 14, 12, 11, 9, 8, 7, 5, 5
293};
294
295static void
296icvLineAA( CvMat* img, CvPoint pt1, CvPoint pt2,
297           const void* color )
298{
299    int dx, dy;
300    int ecount, scount = 0;
301    int slope;
302    int ax, ay;
303    int x_step, y_step;
304    int i, j;
305    int ep_table[9];
306    int cb = ((uchar*)color)[0], cg = ((uchar*)color)[1], cr = ((uchar*)color)[2];
307    int _cb, _cg, _cr;
308    int nch = CV_MAT_CN( img->type );
309    uchar* ptr = (uchar*)(img->data.ptr);
310    int step = img->step;
311    CvSize size = cvGetMatSize( img );
312
313    assert( img && (nch == 1 || nch == 3) && CV_MAT_DEPTH(img->type) == CV_8U );
314
315    pt1.x -= XY_ONE*2;
316    pt1.y -= XY_ONE*2;
317    pt2.x -= XY_ONE*2;
318    pt2.y -= XY_ONE*2;
319    ptr += img->step*2 + 2*nch;
320
321    size.width = ((size.width - 5) << XY_SHIFT) + 1;
322    size.height = ((size.height - 5) << XY_SHIFT) + 1;
323
324    if( !cvClipLine( size, &pt1, &pt2 ))
325        return;
326
327    dx = pt2.x - pt1.x;
328    dy = pt2.y - pt1.y;
329
330    j = dx < 0 ? -1 : 0;
331    ax = (dx ^ j) - j;
332    i = dy < 0 ? -1 : 0;
333    ay = (dy ^ i) - i;
334
335    if( ax > ay )
336    {
337        dx = ax;
338        dy = (dy ^ j) - j;
339        pt1.x ^= pt2.x & j;
340        pt2.x ^= pt1.x & j;
341        pt1.x ^= pt2.x & j;
342        pt1.y ^= pt2.y & j;
343        pt2.y ^= pt1.y & j;
344        pt1.y ^= pt2.y & j;
345
346        x_step = XY_ONE;
347        y_step = (int) (((int64) dy << XY_SHIFT) / (ax | 1));
348        pt2.x += XY_ONE;
349        ecount = (pt2.x >> XY_SHIFT) - (pt1.x >> XY_SHIFT);
350        j = -(pt1.x & (XY_ONE - 1));
351        pt1.y += (int) ((((int64) y_step) * j) >> XY_SHIFT) + (XY_ONE >> 1);
352        slope = (y_step >> (XY_SHIFT - 5)) & 0x3f;
353        slope ^= (y_step < 0 ? 0x3f : 0);
354
355        /* Get 4-bit fractions for end-point adjustments */
356        i = (pt1.x >> (XY_SHIFT - 7)) & 0x78;
357        j = (pt2.x >> (XY_SHIFT - 7)) & 0x78;
358    }
359    else
360    {
361        dy = ay;
362        dx = (dx ^ i) - i;
363        pt1.x ^= pt2.x & i;
364        pt2.x ^= pt1.x & i;
365        pt1.x ^= pt2.x & i;
366        pt1.y ^= pt2.y & i;
367        pt2.y ^= pt1.y & i;
368        pt1.y ^= pt2.y & i;
369
370        x_step = (int) (((int64) dx << XY_SHIFT) / (ay | 1));
371        y_step = XY_ONE;
372        pt2.y += XY_ONE;
373        ecount = (pt2.y >> XY_SHIFT) - (pt1.y >> XY_SHIFT);
374        j = -(pt1.y & (XY_ONE - 1));
375        pt1.x += (int) ((((int64) x_step) * j) >> XY_SHIFT) + (XY_ONE >> 1);
376        slope = (x_step >> (XY_SHIFT - 5)) & 0x3f;
377        slope ^= (x_step < 0 ? 0x3f : 0);
378
379        /* Get 4-bit fractions for end-point adjustments */
380        i = (pt1.y >> (XY_SHIFT - 7)) & 0x78;
381        j = (pt2.y >> (XY_SHIFT - 7)) & 0x78;
382    }
383
384    slope = (slope & 0x20) ? 0x100 : icvSlopeCorrTable[slope];
385
386    /* Calc end point correction table */
387    {
388        int t0 = slope << 7;
389        int t1 = ((0x78 - i) | 4) * slope;
390        int t2 = (j | 4) * slope;
391
392        ep_table[0] = 0;
393        ep_table[8] = slope;
394        ep_table[1] = ep_table[3] = ((((j - i) & 0x78) | 4) * slope >> 8) & 0x1ff;
395        ep_table[2] = (t1 >> 8) & 0x1ff;
396        ep_table[4] = ((((j - i) + 0x80) | 4) * slope >> 8) & 0x1ff;
397        ep_table[5] = ((t1 + t0) >> 8) & 0x1ff;
398        ep_table[6] = (t2 >> 8) & 0x1ff;
399        ep_table[7] = ((t2 + t0) >> 8) & 0x1ff;
400    }
401
402    if( nch == 3 )
403    {
404        #define  ICV_PUT_POINT()            \
405        {                                   \
406            _cb = tptr[0];                  \
407            _cb += ((cb - _cb)*a + 127)>> 8;\
408            _cg = tptr[1];                  \
409            _cg += ((cg - _cg)*a + 127)>> 8;\
410            _cr = tptr[2];                  \
411            _cr += ((cr - _cr)*a + 127)>> 8;\
412            tptr[0] = (uchar)_cb;           \
413            tptr[1] = (uchar)_cg;           \
414            tptr[2] = (uchar)_cr;           \
415        }
416        if( ax > ay )
417        {
418            ptr += (pt1.x >> XY_SHIFT) * 3;
419
420            while( ecount >= 0 )
421            {
422                uchar *tptr = ptr + ((pt1.y >> XY_SHIFT) - 1) * step;
423
424                int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
425                                       (((ecount >= 2) + 1) & (ecount | 2))];
426                int a, dist = (pt1.y >> (XY_SHIFT - 5)) & 31;
427
428                a = (ep_corr * icvFilterTable[dist + 32] >> 8) & 0xff;
429                ICV_PUT_POINT();
430                ICV_PUT_POINT();
431
432                tptr += step;
433                a = (ep_corr * icvFilterTable[dist] >> 8) & 0xff;
434                ICV_PUT_POINT();
435                ICV_PUT_POINT();
436
437                tptr += step;
438                a = (ep_corr * icvFilterTable[63 - dist] >> 8) & 0xff;
439                ICV_PUT_POINT();
440                ICV_PUT_POINT();
441
442                pt1.y += y_step;
443                ptr += 3;
444                scount++;
445                ecount--;
446            }
447        }
448        else
449        {
450            ptr += (pt1.y >> XY_SHIFT) * step;
451
452            while( ecount >= 0 )
453            {
454                uchar *tptr = ptr + ((pt1.x >> XY_SHIFT) - 1) * 3;
455
456                int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
457                                       (((ecount >= 2) + 1) & (ecount | 2))];
458                int a, dist = (pt1.x >> (XY_SHIFT - 5)) & 31;
459
460                a = (ep_corr * icvFilterTable[dist + 32] >> 8) & 0xff;
461                ICV_PUT_POINT();
462                ICV_PUT_POINT();
463
464                tptr += 3;
465                a = (ep_corr * icvFilterTable[dist] >> 8) & 0xff;
466                ICV_PUT_POINT();
467                ICV_PUT_POINT();
468
469                tptr += 3;
470                a = (ep_corr * icvFilterTable[63 - dist] >> 8) & 0xff;
471                ICV_PUT_POINT();
472                ICV_PUT_POINT();
473
474                pt1.x += x_step;
475                ptr += step;
476                scount++;
477                ecount--;
478            }
479        }
480        #undef ICV_PUT_POINT
481    }
482    else
483    {
484        #define  ICV_PUT_POINT()            \
485        {                                   \
486            _cb = tptr[0];                  \
487            _cb += ((cb - _cb)*a + 127)>> 8;\
488            tptr[0] = (uchar)_cb;           \
489        }
490
491        if( ax > ay )
492        {
493            ptr += (pt1.x >> XY_SHIFT);
494
495            while( ecount >= 0 )
496            {
497                uchar *tptr = ptr + ((pt1.y >> XY_SHIFT) - 1) * step;
498
499                int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
500                                       (((ecount >= 2) + 1) & (ecount | 2))];
501                int a, dist = (pt1.y >> (XY_SHIFT - 5)) & 31;
502
503                a = (ep_corr * icvFilterTable[dist + 32] >> 8) & 0xff;
504                ICV_PUT_POINT();
505                ICV_PUT_POINT();
506
507                tptr += step;
508                a = (ep_corr * icvFilterTable[dist] >> 8) & 0xff;
509                ICV_PUT_POINT();
510                ICV_PUT_POINT();
511
512                tptr += step;
513                a = (ep_corr * icvFilterTable[63 - dist] >> 8) & 0xff;
514                ICV_PUT_POINT();
515                ICV_PUT_POINT();
516
517                pt1.y += y_step;
518                ptr++;
519                scount++;
520                ecount--;
521            }
522        }
523        else
524        {
525            ptr += (pt1.y >> XY_SHIFT) * step;
526
527            while( ecount >= 0 )
528            {
529                uchar *tptr = ptr + ((pt1.x >> XY_SHIFT) - 1);
530
531                int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
532                                       (((ecount >= 2) + 1) & (ecount | 2))];
533                int a, dist = (pt1.x >> (XY_SHIFT - 5)) & 31;
534
535                a = (ep_corr * icvFilterTable[dist + 32] >> 8) & 0xff;
536                ICV_PUT_POINT();
537                ICV_PUT_POINT();
538
539                tptr++;
540                a = (ep_corr * icvFilterTable[dist] >> 8) & 0xff;
541                ICV_PUT_POINT();
542                ICV_PUT_POINT();
543
544                tptr++;
545                a = (ep_corr * icvFilterTable[63 - dist] >> 8) & 0xff;
546                ICV_PUT_POINT();
547                ICV_PUT_POINT();
548
549                pt1.x += x_step;
550                ptr += step;
551                scount++;
552                ecount--;
553            }
554        }
555        #undef ICV_PUT_POINT
556    }
557}
558
559
560static void
561icvLine2( CvMat* img, CvPoint pt1, CvPoint pt2, const void* color )
562{
563    int dx, dy;
564    int ecount;
565    int ax, ay;
566    int i, j;
567    int x_step, y_step;
568    int cb = ((uchar*)color)[0];
569    int cg = ((uchar*)color)[1];
570    int cr = ((uchar*)color)[2];
571    int pix_size = CV_ELEM_SIZE( img->type );
572    uchar *ptr = (uchar*)(img->data.ptr), *tptr;
573    int step = img->step;
574    CvSize size = cvGetMatSize( img );
575
576    //assert( img && (nch == 1 || nch == 3) && CV_MAT_DEPTH(img->type) == CV_8U );
577
578    pt1.x -= XY_ONE*2;
579    pt1.y -= XY_ONE*2;
580    pt2.x -= XY_ONE*2;
581    pt2.y -= XY_ONE*2;
582    ptr += img->step*2 + 2*pix_size;
583
584    size.width = ((size.width - 5) << XY_SHIFT) + 1;
585    size.height = ((size.height - 5) << XY_SHIFT) + 1;
586
587    if( !cvClipLine( size, &pt1, &pt2 ))
588        return;
589
590    dx = pt2.x - pt1.x;
591    dy = pt2.y - pt1.y;
592
593    j = dx < 0 ? -1 : 0;
594    ax = (dx ^ j) - j;
595    i = dy < 0 ? -1 : 0;
596    ay = (dy ^ i) - i;
597
598    if( ax > ay )
599    {
600        dx = ax;
601        dy = (dy ^ j) - j;
602        pt1.x ^= pt2.x & j;
603        pt2.x ^= pt1.x & j;
604        pt1.x ^= pt2.x & j;
605        pt1.y ^= pt2.y & j;
606        pt2.y ^= pt1.y & j;
607        pt1.y ^= pt2.y & j;
608
609        x_step = XY_ONE;
610        y_step = (int) (((int64) dy << XY_SHIFT) / (ax | 1));
611        ecount = (pt2.x - pt1.x) >> XY_SHIFT;
612    }
613    else
614    {
615        dy = ay;
616        dx = (dx ^ i) - i;
617        pt1.x ^= pt2.x & i;
618        pt2.x ^= pt1.x & i;
619        pt1.x ^= pt2.x & i;
620        pt1.y ^= pt2.y & i;
621        pt2.y ^= pt1.y & i;
622        pt1.y ^= pt2.y & i;
623
624        x_step = (int) (((int64) dx << XY_SHIFT) / (ay | 1));
625        y_step = XY_ONE;
626        ecount = (pt2.y - pt1.y) >> XY_SHIFT;
627    }
628
629    pt1.x += (XY_ONE >> 1);
630    pt1.y += (XY_ONE >> 1);
631
632    if( pix_size == 3 )
633    {
634        #define  ICV_PUT_POINT()    \
635        {                           \
636            tptr[0] = (uchar)cb;    \
637            tptr[1] = (uchar)cg;    \
638            tptr[2] = (uchar)cr;    \
639        }
640
641        tptr = ptr + ((pt2.x + (XY_ONE >> 1))>> XY_SHIFT)*3 +
642            ((pt2.y + (XY_ONE >> 1)) >> XY_SHIFT)*step;
643        ICV_PUT_POINT();
644
645        if( ax > ay )
646        {
647            ptr += (pt1.x >> XY_SHIFT) * 3;
648
649            while( ecount >= 0 )
650            {
651                tptr = ptr + (pt1.y >> XY_SHIFT) * step;
652                ICV_PUT_POINT();
653                pt1.y += y_step;
654                ptr += 3;
655                ecount--;
656            }
657        }
658        else
659        {
660            ptr += (pt1.y >> XY_SHIFT) * step;
661
662            while( ecount >= 0 )
663            {
664                tptr = ptr + (pt1.x >> XY_SHIFT) * 3;
665                ICV_PUT_POINT();
666                pt1.x += x_step;
667                ptr += step;
668                ecount--;
669            }
670        }
671
672        #undef ICV_PUT_POINT
673    }
674    else if( pix_size == 1 )
675    {
676        #define  ICV_PUT_POINT()            \
677        {                                   \
678            tptr[0] = (uchar)cb;            \
679        }
680
681        tptr = ptr + ((pt2.x + (XY_ONE >> 1))>> XY_SHIFT) +
682            ((pt2.y + (XY_ONE >> 1)) >> XY_SHIFT)*step;
683        ICV_PUT_POINT();
684
685        if( ax > ay )
686        {
687            ptr += (pt1.x >> XY_SHIFT);
688
689            while( ecount >= 0 )
690            {
691                tptr = ptr + (pt1.y >> XY_SHIFT) * step;
692                ICV_PUT_POINT();
693                pt1.y += y_step;
694                ptr++;
695                ecount--;
696            }
697        }
698        else
699        {
700            ptr += (pt1.y >> XY_SHIFT) * step;
701
702            while( ecount >= 0 )
703            {
704                tptr = ptr + (pt1.x >> XY_SHIFT);
705                ICV_PUT_POINT();
706                pt1.x += x_step;
707                ptr += step;
708                ecount--;
709            }
710        }
711        #undef ICV_PUT_POINT
712    }
713    else
714    {
715        #define  ICV_PUT_POINT()                \
716            for( j = 0; j < pix_size; j++ )     \
717                tptr[j] = ((uchar*)color)[j];
718
719        tptr = ptr + ((pt2.x + (XY_ONE >> 1))>> XY_SHIFT)*pix_size +
720            ((pt2.y + (XY_ONE >> 1)) >> XY_SHIFT)*step;
721        ICV_PUT_POINT();
722
723        if( ax > ay )
724        {
725            ptr += (pt1.x >> XY_SHIFT) * pix_size;
726
727            while( ecount >= 0 )
728            {
729                tptr = ptr + (pt1.y >> XY_SHIFT) * step;
730                ICV_PUT_POINT();
731                pt1.y += y_step;
732                ptr += pix_size;
733                ecount--;
734            }
735        }
736        else
737        {
738            ptr += (pt1.y >> XY_SHIFT) * step;
739
740            while( ecount >= 0 )
741            {
742                tptr = ptr + (pt1.x >> XY_SHIFT) * pix_size;
743                ICV_PUT_POINT();
744                pt1.x += x_step;
745                ptr += step;
746                ecount--;
747            }
748        }
749
750        #undef ICV_PUT_POINT
751    }
752}
753
754
755/****************************************************************************************\
756*                   Antialiazed Elliptic Arcs via Antialiazed Lines                      *
757\****************************************************************************************/
758
759static const float icvSinTable[] =
760    { 0.0000000f, 0.0174524f, 0.0348995f, 0.0523360f, 0.0697565f, 0.0871557f,
761    0.1045285f, 0.1218693f, 0.1391731f, 0.1564345f, 0.1736482f, 0.1908090f,
762    0.2079117f, 0.2249511f, 0.2419219f, 0.2588190f, 0.2756374f, 0.2923717f,
763    0.3090170f, 0.3255682f, 0.3420201f, 0.3583679f, 0.3746066f, 0.3907311f,
764    0.4067366f, 0.4226183f, 0.4383711f, 0.4539905f, 0.4694716f, 0.4848096f,
765    0.5000000f, 0.5150381f, 0.5299193f, 0.5446390f, 0.5591929f, 0.5735764f,
766    0.5877853f, 0.6018150f, 0.6156615f, 0.6293204f, 0.6427876f, 0.6560590f,
767    0.6691306f, 0.6819984f, 0.6946584f, 0.7071068f, 0.7193398f, 0.7313537f,
768    0.7431448f, 0.7547096f, 0.7660444f, 0.7771460f, 0.7880108f, 0.7986355f,
769    0.8090170f, 0.8191520f, 0.8290376f, 0.8386706f, 0.8480481f, 0.8571673f,
770    0.8660254f, 0.8746197f, 0.8829476f, 0.8910065f, 0.8987940f, 0.9063078f,
771    0.9135455f, 0.9205049f, 0.9271839f, 0.9335804f, 0.9396926f, 0.9455186f,
772    0.9510565f, 0.9563048f, 0.9612617f, 0.9659258f, 0.9702957f, 0.9743701f,
773    0.9781476f, 0.9816272f, 0.9848078f, 0.9876883f, 0.9902681f, 0.9925462f,
774    0.9945219f, 0.9961947f, 0.9975641f, 0.9986295f, 0.9993908f, 0.9998477f,
775    1.0000000f, 0.9998477f, 0.9993908f, 0.9986295f, 0.9975641f, 0.9961947f,
776    0.9945219f, 0.9925462f, 0.9902681f, 0.9876883f, 0.9848078f, 0.9816272f,
777    0.9781476f, 0.9743701f, 0.9702957f, 0.9659258f, 0.9612617f, 0.9563048f,
778    0.9510565f, 0.9455186f, 0.9396926f, 0.9335804f, 0.9271839f, 0.9205049f,
779    0.9135455f, 0.9063078f, 0.8987940f, 0.8910065f, 0.8829476f, 0.8746197f,
780    0.8660254f, 0.8571673f, 0.8480481f, 0.8386706f, 0.8290376f, 0.8191520f,
781    0.8090170f, 0.7986355f, 0.7880108f, 0.7771460f, 0.7660444f, 0.7547096f,
782    0.7431448f, 0.7313537f, 0.7193398f, 0.7071068f, 0.6946584f, 0.6819984f,
783    0.6691306f, 0.6560590f, 0.6427876f, 0.6293204f, 0.6156615f, 0.6018150f,
784    0.5877853f, 0.5735764f, 0.5591929f, 0.5446390f, 0.5299193f, 0.5150381f,
785    0.5000000f, 0.4848096f, 0.4694716f, 0.4539905f, 0.4383711f, 0.4226183f,
786    0.4067366f, 0.3907311f, 0.3746066f, 0.3583679f, 0.3420201f, 0.3255682f,
787    0.3090170f, 0.2923717f, 0.2756374f, 0.2588190f, 0.2419219f, 0.2249511f,
788    0.2079117f, 0.1908090f, 0.1736482f, 0.1564345f, 0.1391731f, 0.1218693f,
789    0.1045285f, 0.0871557f, 0.0697565f, 0.0523360f, 0.0348995f, 0.0174524f,
790    0.0000000f, -0.0174524f, -0.0348995f, -0.0523360f, -0.0697565f, -0.0871557f,
791    -0.1045285f, -0.1218693f, -0.1391731f, -0.1564345f, -0.1736482f, -0.1908090f,
792    -0.2079117f, -0.2249511f, -0.2419219f, -0.2588190f, -0.2756374f, -0.2923717f,
793    -0.3090170f, -0.3255682f, -0.3420201f, -0.3583679f, -0.3746066f, -0.3907311f,
794    -0.4067366f, -0.4226183f, -0.4383711f, -0.4539905f, -0.4694716f, -0.4848096f,
795    -0.5000000f, -0.5150381f, -0.5299193f, -0.5446390f, -0.5591929f, -0.5735764f,
796    -0.5877853f, -0.6018150f, -0.6156615f, -0.6293204f, -0.6427876f, -0.6560590f,
797    -0.6691306f, -0.6819984f, -0.6946584f, -0.7071068f, -0.7193398f, -0.7313537f,
798    -0.7431448f, -0.7547096f, -0.7660444f, -0.7771460f, -0.7880108f, -0.7986355f,
799    -0.8090170f, -0.8191520f, -0.8290376f, -0.8386706f, -0.8480481f, -0.8571673f,
800    -0.8660254f, -0.8746197f, -0.8829476f, -0.8910065f, -0.8987940f, -0.9063078f,
801    -0.9135455f, -0.9205049f, -0.9271839f, -0.9335804f, -0.9396926f, -0.9455186f,
802    -0.9510565f, -0.9563048f, -0.9612617f, -0.9659258f, -0.9702957f, -0.9743701f,
803    -0.9781476f, -0.9816272f, -0.9848078f, -0.9876883f, -0.9902681f, -0.9925462f,
804    -0.9945219f, -0.9961947f, -0.9975641f, -0.9986295f, -0.9993908f, -0.9998477f,
805    -1.0000000f, -0.9998477f, -0.9993908f, -0.9986295f, -0.9975641f, -0.9961947f,
806    -0.9945219f, -0.9925462f, -0.9902681f, -0.9876883f, -0.9848078f, -0.9816272f,
807    -0.9781476f, -0.9743701f, -0.9702957f, -0.9659258f, -0.9612617f, -0.9563048f,
808    -0.9510565f, -0.9455186f, -0.9396926f, -0.9335804f, -0.9271839f, -0.9205049f,
809    -0.9135455f, -0.9063078f, -0.8987940f, -0.8910065f, -0.8829476f, -0.8746197f,
810    -0.8660254f, -0.8571673f, -0.8480481f, -0.8386706f, -0.8290376f, -0.8191520f,
811    -0.8090170f, -0.7986355f, -0.7880108f, -0.7771460f, -0.7660444f, -0.7547096f,
812    -0.7431448f, -0.7313537f, -0.7193398f, -0.7071068f, -0.6946584f, -0.6819984f,
813    -0.6691306f, -0.6560590f, -0.6427876f, -0.6293204f, -0.6156615f, -0.6018150f,
814    -0.5877853f, -0.5735764f, -0.5591929f, -0.5446390f, -0.5299193f, -0.5150381f,
815    -0.5000000f, -0.4848096f, -0.4694716f, -0.4539905f, -0.4383711f, -0.4226183f,
816    -0.4067366f, -0.3907311f, -0.3746066f, -0.3583679f, -0.3420201f, -0.3255682f,
817    -0.3090170f, -0.2923717f, -0.2756374f, -0.2588190f, -0.2419219f, -0.2249511f,
818    -0.2079117f, -0.1908090f, -0.1736482f, -0.1564345f, -0.1391731f, -0.1218693f,
819    -0.1045285f, -0.0871557f, -0.0697565f, -0.0523360f, -0.0348995f, -0.0174524f,
820    -0.0000000f, 0.0174524f, 0.0348995f, 0.0523360f, 0.0697565f, 0.0871557f,
821    0.1045285f, 0.1218693f, 0.1391731f, 0.1564345f, 0.1736482f, 0.1908090f,
822    0.2079117f, 0.2249511f, 0.2419219f, 0.2588190f, 0.2756374f, 0.2923717f,
823    0.3090170f, 0.3255682f, 0.3420201f, 0.3583679f, 0.3746066f, 0.3907311f,
824    0.4067366f, 0.4226183f, 0.4383711f, 0.4539905f, 0.4694716f, 0.4848096f,
825    0.5000000f, 0.5150381f, 0.5299193f, 0.5446390f, 0.5591929f, 0.5735764f,
826    0.5877853f, 0.6018150f, 0.6156615f, 0.6293204f, 0.6427876f, 0.6560590f,
827    0.6691306f, 0.6819984f, 0.6946584f, 0.7071068f, 0.7193398f, 0.7313537f,
828    0.7431448f, 0.7547096f, 0.7660444f, 0.7771460f, 0.7880108f, 0.7986355f,
829    0.8090170f, 0.8191520f, 0.8290376f, 0.8386706f, 0.8480481f, 0.8571673f,
830    0.8660254f, 0.8746197f, 0.8829476f, 0.8910065f, 0.8987940f, 0.9063078f,
831    0.9135455f, 0.9205049f, 0.9271839f, 0.9335804f, 0.9396926f, 0.9455186f,
832    0.9510565f, 0.9563048f, 0.9612617f, 0.9659258f, 0.9702957f, 0.9743701f,
833    0.9781476f, 0.9816272f, 0.9848078f, 0.9876883f, 0.9902681f, 0.9925462f,
834    0.9945219f, 0.9961947f, 0.9975641f, 0.9986295f, 0.9993908f, 0.9998477f,
835    1.0000000f
836};
837
838
839static void
840icvSinCos( int angle, float *cosval, float *sinval )
841{
842    angle += (angle < 0 ? 360 : 0);
843    *sinval = icvSinTable[angle];
844    *cosval = icvSinTable[450 - angle];
845}
846
847/*
848   constructs polygon that represents elliptic arc.
849*/
850CV_IMPL int
851cvEllipse2Poly( CvPoint center, CvSize axes, int angle,
852                int arc_start, int arc_end, CvPoint* pts, int delta )
853{
854    float alpha, beta;
855    double size_a = axes.width, size_b = axes.height;
856    double cx = center.x, cy = center.y;
857    CvPoint *pts_origin = pts;
858    int i;
859
860    while( angle < 0 )
861        angle += 360;
862    while( angle > 360 )
863        angle -= 360;
864
865    if( arc_start > arc_end )
866    {
867        i = arc_start;
868        arc_start = arc_end;
869        arc_end = i;
870    }
871    while( arc_start < 0 )
872    {
873        arc_start += 360;
874        arc_end += 360;
875    }
876    while( arc_end > 360 )
877    {
878        arc_end -= 360;
879        arc_start -= 360;
880    }
881    if( arc_end - arc_start > 360 )
882    {
883        arc_start = 0;
884        arc_end = 360;
885    }
886    icvSinCos( angle, &alpha, &beta );
887
888    for( i = arc_start; i < arc_end + delta; i += delta )
889    {
890        double x, y;
891        angle = i;
892        if( angle > arc_end )
893            angle = arc_end;
894        if( angle < 0 )
895            angle += 360;
896
897        x = size_a * icvSinTable[450-angle];
898        y = size_b * icvSinTable[angle];
899        pts->x = cvRound( cx + x * alpha - y * beta );
900        pts->y = cvRound( cy - x * beta - y * alpha );
901        pts += i == arc_start || pts->x != pts[-1].x || pts->y != pts[-1].y;
902    }
903
904    i = (int)(pts - pts_origin);
905    for( ; i < 2; i++ )
906        pts_origin[i] = pts_origin[i-1];
907    return i;
908}
909
910
911static void
912icvEllipseEx( CvMat* img, CvPoint center, CvSize axes,
913              int angle, int arc_start, int arc_end,
914              const void* color, int thickness, int line_type )
915{
916    CvMemStorage* st = 0;
917
918    CV_FUNCNAME( "icvEllipseEx" );
919
920    __BEGIN__;
921
922    CvPoint v[1 << 8];
923    int count, delta;
924
925    if( axes.width < 0 || axes.height < 0 )
926        CV_ERROR( CV_StsBadSize, "" );
927
928    delta = (MAX(axes.width,axes.height)+(XY_ONE>>1))>>XY_SHIFT;
929    delta = delta < 3 ? 90 : delta < 10 ? 30 : delta < 15 ? 18 : 5;
930
931    count = cvEllipse2Poly( center, axes, angle, arc_start, arc_end, v, delta );
932
933    if( thickness >= 0 )
934    {
935        icvPolyLine( img, v, count, 0, color, thickness, line_type, XY_SHIFT );
936    }
937    else if( arc_end - arc_start >= 360 )
938    {
939        icvFillConvexPoly( img, v, count, color, line_type, XY_SHIFT );
940    }
941    else
942    {
943        CvContour* edges;
944        CvSeq vtx;
945        CvSeqBlock block;
946
947        CV_CALL( st = cvCreateMemStorage( CV_DRAWING_STORAGE_BLOCK ));
948        CV_CALL( edges = (CvContour*)cvCreateSeq( 0, sizeof(CvContour), sizeof(CvPolyEdge), st ));
949        v[count++] = center;
950
951        CV_CALL( cvMakeSeqHeaderForArray( CV_32SC2, sizeof(CvSeq), sizeof(CvPoint),
952                                          v, count, &vtx, &block ));
953
954        CV_CALL( icvCollectPolyEdges( img, &vtx, edges, color, line_type, XY_SHIFT ));
955        CV_CALL( icvFillEdgeCollection( img, edges, color ));
956    }
957
958    __END__;
959
960    if( st )
961        cvReleaseMemStorage( &st );
962}
963
964
965/****************************************************************************************\
966*                                Polygons filling                                        *
967\****************************************************************************************/
968
969/* helper macros: filling horizontal row */
970#define ICV_HLINE( ptr, xl, xr, color, pix_size )            \
971{                                                            \
972    uchar* hline_ptr = (uchar*)(ptr) + (xl)*(pix_size);      \
973    uchar* hline_max_ptr = (uchar*)(ptr) + (xr)*(pix_size);  \
974                                                             \
975    for( ; hline_ptr <= hline_max_ptr; hline_ptr += (pix_size))\
976    {                                                        \
977        int hline_j;                                         \
978        for( hline_j = 0; hline_j < (pix_size); hline_j++ )  \
979        {                                                    \
980            hline_ptr[hline_j] = ((uchar*)color)[hline_j];   \
981        }                                                    \
982    }                                                        \
983}
984
985
986/* filling convex polygon. v - array of vertices, ntps - number of points */
987static void
988icvFillConvexPoly( CvMat* img, CvPoint *v, int npts, const void* color, int line_type, int shift )
989{
990    struct
991    {
992        int idx, di;
993        int x, dx, ye;
994    }
995    edge[2];
996
997    int delta = shift ? 1 << (shift - 1) : 0;
998    int i, y, imin = 0, left = 0, right = 1, x1, x2;
999    int edges = npts;
1000    int xmin, xmax, ymin, ymax;
1001    uchar* ptr = img->data.ptr;
1002    CvSize size = cvGetMatSize( img );
1003    int pix_size = CV_ELEM_SIZE(img->type);
1004    CvPoint p0;
1005    int delta1, delta2;
1006
1007    if( line_type < CV_AA )
1008        delta1 = delta2 = XY_ONE >> 1;
1009        //delta1 = 0, delta2 = XY_ONE - 1;
1010    else
1011        delta1 = XY_ONE - 1, delta2 = 0;
1012
1013    p0 = v[npts - 1];
1014    p0.x <<= XY_SHIFT - shift;
1015    p0.y <<= XY_SHIFT - shift;
1016
1017    assert( 0 <= shift && shift <= XY_SHIFT );
1018    xmin = xmax = v[0].x;
1019    ymin = ymax = v[0].y;
1020
1021    for( i = 0; i < npts; i++ )
1022    {
1023        CvPoint p = v[i];
1024        if( p.y < ymin )
1025        {
1026            ymin = p.y;
1027            imin = i;
1028        }
1029
1030        ymax = MAX( ymax, p.y );
1031        xmax = MAX( xmax, p.x );
1032        xmin = MIN( xmin, p.x );
1033
1034        p.x <<= XY_SHIFT - shift;
1035        p.y <<= XY_SHIFT - shift;
1036
1037        if( line_type <= 8 )
1038        {
1039            if( shift == 0 )
1040            {
1041                CvPoint pt0, pt1;
1042                pt0.x = p0.x >> XY_SHIFT;
1043                pt0.y = p0.y >> XY_SHIFT;
1044                pt1.x = p.x >> XY_SHIFT;
1045                pt1.y = p.y >> XY_SHIFT;
1046                icvLine( img, pt0, pt1, color, line_type );
1047            }
1048            else
1049                icvLine2( img, p0, p, color );
1050        }
1051        else
1052            icvLineAA( img, p0, p, color );
1053        p0 = p;
1054    }
1055
1056    xmin = (xmin + delta) >> shift;
1057    xmax = (xmax + delta) >> shift;
1058    ymin = (ymin + delta) >> shift;
1059    ymax = (ymax + delta) >> shift;
1060
1061    if( npts < 3 || xmax < 0 || ymax < 0 || xmin >= size.width || ymin >= size.height )
1062        return;
1063
1064    ymax = MIN( ymax, size.height - 1 );
1065    edge[0].idx = edge[1].idx = imin;
1066
1067    edge[0].ye = edge[1].ye = y = ymin;
1068    edge[0].di = 1;
1069    edge[1].di = npts - 1;
1070
1071    ptr += img->step*y;
1072
1073    do
1074    {
1075        if( line_type < CV_AA || y < ymax || y == ymin )
1076        {
1077            for( i = 0; i < 2; i++ )
1078            {
1079                if( y >= edge[i].ye )
1080                {
1081                    int idx = edge[i].idx, di = edge[i].di;
1082                    int xs = 0, xe, ye, ty = 0;
1083
1084                    for(;;)
1085                    {
1086                        ty = (v[idx].y + delta) >> shift;
1087                        if( ty > y || edges == 0 )
1088                            break;
1089                        xs = v[idx].x;
1090                        idx += di;
1091                        idx -= ((idx < npts) - 1) & npts;   /* idx -= idx >= npts ? npts : 0 */
1092                        edges--;
1093                    }
1094
1095                    ye = ty;
1096                    xs <<= XY_SHIFT - shift;
1097                    xe = v[idx].x << (XY_SHIFT - shift);
1098
1099                    /* no more edges */
1100                    if( y >= ye )
1101                        return;
1102
1103                    edge[i].ye = ye;
1104                    edge[i].dx = ((xe - xs)*2 + (ye - y)) / (2 * (ye - y));
1105                    edge[i].x = xs;
1106                    edge[i].idx = idx;
1107                }
1108            }
1109        }
1110
1111        if( edge[left].x > edge[right].x )
1112        {
1113            left ^= 1;
1114            right ^= 1;
1115        }
1116
1117        x1 = edge[left].x;
1118        x2 = edge[right].x;
1119
1120        if( y >= 0 )
1121        {
1122            int xx1 = (x1 + delta1) >> XY_SHIFT;
1123            int xx2 = (x2 + delta2) >> XY_SHIFT;
1124
1125            if( xx2 >= 0 && xx1 < size.width )
1126            {
1127                if( xx1 < 0 )
1128                    xx1 = 0;
1129                if( xx2 >= size.width )
1130                    xx2 = size.width - 1;
1131                ICV_HLINE( ptr, xx1, xx2, color, pix_size );
1132            }
1133        }
1134
1135        x1 += edge[left].dx;
1136        x2 += edge[right].dx;
1137
1138        edge[left].x = x1;
1139        edge[right].x = x2;
1140        ptr += img->step;
1141    }
1142    while( ++y <= ymax );
1143}
1144
1145
1146/******** Arbitrary polygon **********/
1147
1148static void
1149icvCollectPolyEdges( CvMat* img, CvSeq* v, CvContour* edges,
1150                     const void* color, int line_type, int shift,
1151                     CvPoint offset )
1152{
1153    int  i, count = v->total;
1154    CvRect bounds = edges->rect;
1155    int delta = offset.y + (shift ? 1 << (shift - 1) : 0);
1156    int elem_type = CV_MAT_TYPE(v->flags);
1157
1158    CvSeqReader reader;
1159    CvSeqWriter writer;
1160
1161    cvStartReadSeq( v, &reader );
1162    cvStartAppendToSeq( (CvSeq*)edges, &writer );
1163
1164    for( i = 0; i < count; i++ )
1165    {
1166        CvPoint pt0, pt1, t0, t1;
1167        CvPolyEdge edge;
1168        CV_READ_EDGE( pt0, pt1, reader );
1169
1170        if( elem_type == CV_32SC2 )
1171        {
1172            pt0.x = (pt0.x + offset.x) << (XY_SHIFT - shift);
1173            pt0.y = (pt0.y + delta) >> shift;
1174            pt1.x = (pt1.x + offset.x) << (XY_SHIFT - shift);
1175            pt1.y = (pt1.y + delta) >> shift;
1176        }
1177        else
1178        {
1179            Cv32suf x, y;
1180            assert( shift == 0 );
1181
1182            x.i = pt0.x; y.i = pt0.y;
1183            pt0.x = cvRound((x.f + offset.x) * XY_ONE);
1184            pt0.y = cvRound(y.f + offset.y);
1185            x.i = pt1.x; y.i = pt1.y;
1186            pt1.x = cvRound((x.f + offset.x) * XY_ONE);
1187            pt1.y = cvRound(y.f + offset.y);
1188        }
1189
1190        if( line_type < CV_AA )
1191        {
1192            t0.y = pt0.y; t1.y = pt1.y;
1193            t0.x = (pt0.x + (XY_ONE >> 1)) >> XY_SHIFT;
1194            t1.x = (pt1.x + (XY_ONE >> 1)) >> XY_SHIFT;
1195            icvLine( img, t0, t1, color, line_type );
1196        }
1197        else
1198        {
1199            t0.x = pt0.x; t1.x = pt1.x;
1200            t0.y = pt0.y << XY_SHIFT;
1201            t1.y = pt1.y << XY_SHIFT;
1202            icvLineAA( img, t0, t1, color );
1203        }
1204
1205        if( pt0.y == pt1.y )
1206            continue;
1207
1208        if( pt0.y > pt1.y )
1209            CV_SWAP( pt0, pt1, t0 );
1210
1211        bounds.y = MIN( bounds.y, pt0.y );
1212        bounds.height = MAX( bounds.height, pt1.y );
1213
1214        if( pt0.x < pt1.x )
1215        {
1216            bounds.x = MIN( bounds.x, pt0.x );
1217            bounds.width = MAX( bounds.width, pt1.x );
1218        }
1219        else
1220        {
1221            bounds.x = MIN( bounds.x, pt1.x );
1222            bounds.width = MAX( bounds.width, pt0.x );
1223        }
1224
1225        edge.y0 = pt0.y;
1226        edge.y1 = pt1.y;
1227        edge.x = pt0.x;
1228        edge.dx = (pt1.x - pt0.x) / (pt1.y - pt0.y);
1229        assert( edge.y0 < edge.y1 );
1230
1231        CV_WRITE_SEQ_ELEM( edge, writer );
1232    }
1233
1234    edges->rect = bounds;
1235    cvEndWriteSeq( &writer );
1236}
1237
1238static int
1239icvCmpEdges( const void* _e1, const void* _e2, void* /*userdata*/ )
1240{
1241    CvPolyEdge *e1 = (CvPolyEdge*)_e1, *e2 = (CvPolyEdge*)_e2;
1242    return e1->y0 - e2->y0 ? e1->y0 - e2->y0 :
1243           e1->x - e2->x ? e1->x - e2->x : e1->dx - e2->dx;
1244}
1245
1246/**************** helper macros and functions for sequence/contour processing ***********/
1247
1248static void
1249icvFillEdgeCollection( CvMat* img, CvContour* edges, const void* color )
1250{
1251    CvPolyEdge tmp;
1252    int i, y, total = edges->total;
1253    CvSeqReader reader;
1254    CvSize size = cvGetMatSize(img);
1255    CvPolyEdge* e;
1256    int y_max = INT_MIN;
1257    int pix_size = CV_ELEM_SIZE(img->type);
1258
1259    __BEGIN__;
1260
1261    memset( &tmp, 0, sizeof(tmp));
1262
1263    /* check parameters */
1264    if( edges->total < 2 || edges->rect.height < 0 || edges->rect.y >= size.height ||
1265        edges->rect.width < 0 || edges->rect.x >= size.width )
1266        EXIT;
1267
1268    cvSeqSort( (CvSeq*)edges, icvCmpEdges, 0 );
1269    cvStartReadSeq( (CvSeq*)edges, &reader );
1270
1271#ifdef _DEBUG
1272    e = &tmp;
1273    tmp.y0 = INT_MIN;
1274#endif
1275
1276    for( i = 0; i < total; i++ )
1277    {
1278        CvPolyEdge* e1 = (CvPolyEdge*)(reader.ptr);
1279
1280#ifdef _DEBUG
1281        assert( e1->y0 < e1->y1 && (i == 0 || icvCmpEdges( e, e1, 0 ) <= 0) );
1282        e = e1;
1283#endif
1284        y_max = MAX( y_max, e1->y1 );
1285
1286        CV_NEXT_SEQ_ELEM( sizeof(CvPolyEdge), reader );
1287    }
1288
1289    /* start drawing */
1290    tmp.y0 = INT_MAX;
1291    cvSeqPush( (CvSeq*)edges, &tmp );
1292
1293    i = 0;
1294    tmp.next = 0;
1295    cvStartReadSeq( (CvSeq*)edges, &reader );
1296    e = (CvPolyEdge*)(reader.ptr);
1297    y_max = MIN( y_max, size.height );
1298
1299    for( y = e->y0; y < y_max; y++ )
1300    {
1301        CvPolyEdge *last, *prelast, *keep_prelast;
1302        int sort_flag = 0;
1303        int draw = 0;
1304        int clipline = y < 0;
1305
1306        prelast = &tmp;
1307        last = tmp.next;
1308        while( last || e->y0 == y )
1309        {
1310            if( last && last->y1 == y )
1311            {
1312                /* exlude edge if y reachs its lower point */
1313                prelast->next = last->next;
1314                last = last->next;
1315                continue;
1316            }
1317            keep_prelast = prelast;
1318            if( last && (e->y0 > y || last->x < e->x) )
1319            {
1320                /* go to the next edge in active list */
1321                prelast = last;
1322                last = last->next;
1323            }
1324            else if( i < total )
1325            {
1326                /* insert new edge into active list if y reachs its upper point */
1327                prelast->next = e;
1328                e->next = last;
1329                prelast = e;
1330                CV_NEXT_SEQ_ELEM( edges->elem_size, reader );
1331                e = (CvPolyEdge*)(reader.ptr);
1332                i++;
1333            }
1334            else
1335                break;
1336
1337            if( draw )
1338            {
1339                if( !clipline )
1340                {
1341                    /* convert x's from fixed-point to image coordinates */
1342                    uchar *timg = (uchar*)(img->data.ptr) + y * img->step;
1343                    int x1 = keep_prelast->x;
1344                    int x2 = prelast->x;
1345
1346                    if( x1 > x2 )
1347                    {
1348                        int t = x1;
1349
1350                        x1 = x2;
1351                        x2 = t;
1352                    }
1353
1354                    x1 = (x1 + XY_ONE - 1) >> XY_SHIFT;
1355                    x2 = x2 >> XY_SHIFT;
1356
1357                    /* clip and draw the line */
1358                    if( x1 < size.width && x2 >= 0 )
1359                    {
1360                        if( x1 < 0 )
1361                            x1 = 0;
1362                        if( x2 >= size.width )
1363                            x2 = size.width - 1;
1364                        ICV_HLINE( timg, x1, x2, color, pix_size );
1365                    }
1366                }
1367                keep_prelast->x += keep_prelast->dx;
1368                prelast->x += prelast->dx;
1369            }
1370            draw ^= 1;
1371        }
1372
1373        /* sort edges (bubble sort on list) */
1374        keep_prelast = 0;
1375
1376        do
1377        {
1378            prelast = &tmp;
1379            last = tmp.next;
1380
1381            while( last != keep_prelast && last->next != 0 )
1382            {
1383                CvPolyEdge *te = last->next;
1384
1385                /* swap edges */
1386                if( last->x > te->x )
1387                {
1388                    prelast->next = te;
1389                    last->next = te->next;
1390                    te->next = last;
1391                    prelast = te;
1392                    sort_flag = 1;
1393                }
1394                else
1395                {
1396                    prelast = last;
1397                    last = te;
1398                }
1399            }
1400            keep_prelast = prelast;
1401        }
1402        while( sort_flag && keep_prelast != tmp.next && keep_prelast != &tmp );
1403    }
1404
1405    __END__;
1406}
1407
1408
1409/* draws simple or filled circle */
1410static void
1411icvCircle( CvMat* img, CvPoint center, int radius, const void* color, int fill )
1412{
1413    CvSize size = cvGetMatSize( img );
1414    int step = img->step;
1415    int pix_size = CV_ELEM_SIZE(img->type);
1416    uchar* ptr = (uchar*)(img->data.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        CV_MEMCPY_CHAR( 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 = 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 = 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
1556static void
1557icvThickLine( CvMat* img, CvPoint p0, CvPoint 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                icvLine( img, p0, p1, color, line_type );
1578            }
1579            else
1580                icvLine2( img, p0, p1, color );
1581        }
1582        else
1583            icvLineAA( img, p0, p1, color );
1584    }
1585    else
1586    {
1587        CvPoint pt[4], dp = {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;
1591        thickness <<= XY_SHIFT - 1;
1592
1593        if( fabs(r) > DBL_EPSILON )
1594        {
1595            r = thickness * cvInvSqrt( (float) r );
1596            dp.x = cvRound( dy * r );
1597            dp.y = cvRound( dx * r );
1598        }
1599
1600        pt[0].x = p0.x + dp.x;
1601        pt[0].y = p0.y + dp.y;
1602        pt[1].x = p0.x - dp.x;
1603        pt[1].y = p0.y - dp.y;
1604        pt[2].x = p1.x - dp.x;
1605        pt[2].y = p1.y - dp.y;
1606        pt[3].x = p1.x + dp.x;
1607        pt[3].y = p1.y + dp.y;
1608
1609        icvFillConvexPoly( img, pt, 4, color, line_type, XY_SHIFT );
1610
1611        for( i = 0; i < 2; i++ )
1612        {
1613            if( flags & (i+1) )
1614            {
1615                if( line_type < CV_AA )
1616                {
1617                    CvPoint center;
1618                    center.x = (p0.x + (XY_ONE>>1)) >> XY_SHIFT;
1619                    center.y = (p0.y + (XY_ONE>>1)) >> XY_SHIFT;
1620                    icvCircle( img, center, thickness >> XY_SHIFT, color, 1 );
1621                }
1622                else
1623                {
1624                    icvEllipseEx( img, p0, cvSize(thickness, thickness),
1625                                  0, 0, 360, color, -1, line_type );
1626                }
1627            }
1628            p0 = p1;
1629        }
1630    }
1631}
1632
1633
1634static void
1635icvPolyLine( CvMat* img, CvPoint *v, int count, int is_closed,
1636             const void* color, int thickness,
1637             int line_type, int shift )
1638{
1639    CV_FUNCNAME("icvPolyLine");
1640
1641    __BEGIN__;
1642
1643    if( count > 0 )
1644    {
1645        int i = is_closed ? count - 1 : 0;
1646        int flags = 2 + !is_closed;
1647        CvPoint p0;
1648        assert( 0 <= shift && shift <= XY_SHIFT );
1649        assert( img && thickness >= 0 );
1650        assert( v && count >= 0 );
1651
1652        if( !v )
1653            CV_ERROR( CV_StsNullPtr, "" );
1654
1655        p0 = v[i];
1656        for( i = !is_closed; i < count; i++ )
1657        {
1658            CvPoint p = v[i];
1659            icvThickLine( img, p0, p, color, thickness, line_type, flags, shift );
1660            p0 = p;
1661            flags = 2;
1662        }
1663    }
1664
1665    __END__;
1666}
1667
1668/****************************************************************************************\
1669*                              External functions                                        *
1670\****************************************************************************************/
1671
1672CV_IMPL CvScalar cvColorToScalar( double packed_color, int type )
1673{
1674    CvScalar scalar;
1675
1676    if( CV_MAT_DEPTH( type ) == CV_8U )
1677    {
1678        int icolor = cvRound( packed_color );
1679        if( CV_MAT_CN( type ) > 1 )
1680        {
1681            scalar.val[0] = icolor & 255;
1682            scalar.val[1] = (icolor >> 8) & 255;
1683            scalar.val[2] = (icolor >> 16) & 255;
1684            scalar.val[3] = (icolor >> 24) & 255;
1685        }
1686        else
1687        {
1688            scalar.val[0] = CV_CAST_8U( icolor );
1689            scalar.val[1] = scalar.val[2] = scalar.val[3] = 0;
1690        }
1691    }
1692    else if( CV_MAT_DEPTH( type ) == CV_8S )
1693    {
1694        int icolor = cvRound( packed_color );
1695        if( CV_MAT_CN( type ) > 1 )
1696        {
1697            scalar.val[0] = (char)icolor;
1698            scalar.val[1] = (char)(icolor >> 8);
1699            scalar.val[2] = (char)(icolor >> 16);
1700            scalar.val[3] = (char)(icolor >> 24);
1701        }
1702        else
1703        {
1704            scalar.val[0] = CV_CAST_8S( icolor );
1705            scalar.val[1] = scalar.val[2] = scalar.val[3] = 0;
1706        }
1707    }
1708    else
1709    {
1710        int cn = CV_MAT_CN( type );
1711        switch( cn )
1712        {
1713        case 1:
1714            scalar.val[0] = packed_color;
1715            scalar.val[1] = scalar.val[2] = scalar.val[3] = 0;
1716            break;
1717        case 2:
1718            scalar.val[0] = scalar.val[1] = packed_color;
1719            scalar.val[2] = scalar.val[3] = 0;
1720            break;
1721        case 3:
1722            scalar.val[0] = scalar.val[1] = scalar.val[2] = packed_color;
1723            scalar.val[3] = 0;
1724            break;
1725        default:
1726            scalar.val[0] = scalar.val[1] =
1727                scalar.val[2] = scalar.val[3] = packed_color;
1728            break;
1729        }
1730    }
1731
1732    return scalar;
1733}
1734
1735
1736CV_IMPL void
1737cvLine( void* img, CvPoint pt1, CvPoint pt2, CvScalar color,
1738        int thickness, int line_type, int shift )
1739{
1740    CV_FUNCNAME( "cvLine" );
1741
1742    __BEGIN__;
1743
1744    int coi = 0;
1745    CvMat stub, *mat = (CvMat*)img;
1746    double buf[4];
1747
1748    CV_CALL( mat = cvGetMat( img, &stub, &coi ));
1749
1750    if( line_type == CV_AA && CV_MAT_DEPTH(mat->type) != CV_8U )
1751        line_type = 8;
1752
1753    if( coi != 0 )
1754        CV_ERROR( CV_BadCOI, cvUnsupportedFormat );
1755
1756    if( (unsigned)thickness > 255  )
1757        CV_ERROR( CV_StsOutOfRange, "" );
1758
1759    if( shift < 0 || XY_SHIFT < shift )
1760        CV_ERROR( CV_StsOutOfRange, "shift must be between 0 and 16" );
1761
1762    CV_CALL( cvScalarToRawData( &color, buf, mat->type, 0 ));
1763    icvThickLine( mat, pt1, pt2, buf, thickness, line_type, 3, shift );
1764
1765    __END__;
1766}
1767
1768
1769CV_IMPL void
1770cvRectangle( void* img, CvPoint pt1, CvPoint pt2,
1771             CvScalar color, int thickness,
1772             int line_type, int shift )
1773{
1774    CvPoint pt[4];
1775
1776    CV_FUNCNAME("cvRectangle");
1777
1778    __BEGIN__;
1779
1780    int coi = 0;
1781    CvMat stub, *mat = (CvMat*)img;
1782    double buf[4];
1783
1784    if( thickness > 255 )
1785        CV_ERROR( CV_StsOutOfRange, "" );
1786
1787    CV_CALL( mat = cvGetMat( img, &stub, &coi ));
1788
1789    if( line_type == CV_AA && CV_MAT_DEPTH(mat->type) != CV_8U )
1790        line_type = 8;
1791
1792    if( coi != 0 )
1793        CV_ERROR( CV_BadCOI, cvUnsupportedFormat );
1794
1795    if( shift < 0 || XY_SHIFT < shift )
1796        CV_ERROR( CV_StsOutOfRange, "shift must be between 0 and 16" );
1797
1798    CV_CALL( cvScalarToRawData( &color, buf, mat->type, 0 ));
1799
1800    pt[0] = pt1;
1801    pt[1].x = pt2.x;
1802    pt[1].y = pt1.y;
1803    pt[2] = pt2;
1804    pt[3].x = pt1.x;
1805    pt[3].y = pt2.y;
1806
1807    if( thickness >= 0 )
1808        icvPolyLine( mat, pt, 4, 1, buf, thickness, line_type, shift );
1809    else
1810        icvFillConvexPoly( mat, pt, 4, buf, line_type, shift );
1811
1812    __END__;
1813}
1814
1815
1816CV_IMPL void
1817cvCircle( void *img, CvPoint center, int radius,
1818          CvScalar color, int thickness, int line_type, int shift )
1819{
1820    CV_FUNCNAME( "cvCircle" );
1821
1822    __BEGIN__;
1823
1824    int coi = 0;
1825    CvMat stub, *mat = (CvMat*)img;
1826    double buf[4];
1827
1828    CV_CALL( mat = cvGetMat( mat, &stub, &coi ));
1829
1830    if( line_type == CV_AA && CV_MAT_DEPTH(mat->type) != CV_8U )
1831        line_type = 8;
1832
1833    if( coi != 0 )
1834        CV_ERROR( CV_BadCOI, cvUnsupportedFormat );
1835
1836    if( radius < 0 )
1837        CV_ERROR( CV_StsOutOfRange, "" );
1838
1839    if( thickness > 255 )
1840        CV_ERROR( CV_StsOutOfRange, "" );
1841
1842    if( shift < 0 || XY_SHIFT < shift )
1843        CV_ERROR( CV_StsOutOfRange, "shift must be between 0 and 16" );
1844
1845    CV_CALL( cvScalarToRawData( &color, buf, mat->type, 0 ));
1846
1847    if( thickness > 1 || line_type >= CV_AA )
1848    {
1849        center.x <<= XY_SHIFT - shift;
1850        center.y <<= XY_SHIFT - shift;
1851        radius <<= XY_SHIFT - shift;
1852        icvEllipseEx( mat, center, cvSize( radius, radius ),
1853                      0, 0, 360, buf, thickness, line_type );
1854    }
1855    else
1856    {
1857        icvCircle( mat, center, radius, buf, thickness < 0 );
1858    }
1859
1860    __END__;
1861}
1862
1863
1864CV_IMPL void
1865cvEllipse( void *img, CvPoint center, CvSize axes,
1866           double angle, double start_angle, double end_angle,
1867           CvScalar color, int thickness, int line_type, int shift )
1868{
1869    CV_FUNCNAME( "cvEllipse" );
1870
1871    __BEGIN__;
1872
1873    int coi = 0;
1874    CvMat stub, *mat = (CvMat*)img;
1875    double buf[4];
1876
1877    CV_CALL( mat = cvGetMat( mat, &stub, &coi ));
1878
1879    if( line_type == CV_AA && CV_MAT_DEPTH(mat->type) != CV_8U )
1880        line_type = 8;
1881
1882    if( coi != 0 )
1883        CV_ERROR( CV_BadCOI, cvUnsupportedFormat );
1884
1885    if( axes.width < 0 || axes.height < 0 )
1886        CV_ERROR( CV_StsOutOfRange, "" );
1887
1888    if( thickness > 255 )
1889        CV_ERROR( CV_StsOutOfRange, "" );
1890
1891    if( shift < 0 || XY_SHIFT < shift )
1892        CV_ERROR( CV_StsOutOfRange, "shift must be between 0 and 16" );
1893
1894    CV_CALL( cvScalarToRawData( &color, buf, mat->type, 0 ));
1895
1896    {
1897        int _angle = cvRound(angle);
1898        int _start_angle = cvRound(start_angle);
1899        int _end_angle = cvRound(end_angle);
1900        center.x <<= XY_SHIFT - shift;
1901        center.y <<= XY_SHIFT - shift;
1902        axes.width <<= XY_SHIFT - shift;
1903        axes.height <<= XY_SHIFT - shift;
1904
1905        CV_CALL( icvEllipseEx( mat, center, axes, _angle, _start_angle,
1906                               _end_angle, buf, thickness, line_type ));
1907    }
1908
1909    __END__;
1910}
1911
1912
1913CV_IMPL void
1914cvFillConvexPoly( void *img, CvPoint *pts, int npts, CvScalar color, int line_type, int shift )
1915{
1916    CV_FUNCNAME( "cvFillConvexPoly" );
1917
1918    __BEGIN__;
1919
1920    int coi = 0;
1921    CvMat stub, *mat = (CvMat*)img;
1922    double buf[4];
1923
1924    CV_CALL( mat = cvGetMat( mat, &stub, &coi ));
1925
1926    if( line_type == CV_AA && CV_MAT_DEPTH(mat->type) != CV_8U )
1927        line_type = 8;
1928
1929    if( coi != 0 )
1930        CV_ERROR( CV_BadCOI, cvUnsupportedFormat );
1931
1932    if( !pts )
1933        CV_ERROR( CV_StsNullPtr, "" );
1934
1935    if( npts <= 0 )
1936        CV_ERROR( CV_StsOutOfRange, "" );
1937
1938    if( shift < 0 || XY_SHIFT < shift )
1939        CV_ERROR( CV_StsOutOfRange, "shift must be between 0 and 16" );
1940
1941    CV_CALL( cvScalarToRawData( &color, buf, mat->type, 0 ));
1942    icvFillConvexPoly( mat, pts, npts, buf, line_type, shift );
1943
1944    __END__;
1945}
1946
1947
1948CV_IMPL void
1949cvFillPoly( void *img, CvPoint **pts, int *npts, int contours,
1950            CvScalar color, int line_type, int shift )
1951{
1952    CvMemStorage* st = 0;
1953
1954    CV_FUNCNAME( "cvFillPoly" );
1955
1956    __BEGIN__;
1957
1958    int coi = 0;
1959    CvMat stub, *mat = (CvMat*)img;
1960    double buf[4];
1961
1962    CV_CALL( mat = cvGetMat( mat, &stub, &coi ));
1963
1964    if( line_type == CV_AA && CV_MAT_DEPTH(mat->type) != CV_8U )
1965        line_type = 8;
1966
1967    if( coi != 0 )
1968        CV_ERROR( CV_BadCOI, cvUnsupportedFormat );
1969
1970    if( contours <= 0 )
1971        CV_ERROR( CV_StsBadArg, "" );
1972
1973    if( !pts )
1974        CV_ERROR( CV_StsNullPtr, "" );
1975
1976    if( npts <= 0 )
1977        CV_ERROR( CV_StsNullPtr, "" );
1978
1979    if( shift < 0 || XY_SHIFT < shift )
1980        CV_ERROR( CV_StsOutOfRange, "shift must be between 0 and 16" );
1981
1982    CV_CALL( cvScalarToRawData( &color, buf, mat->type, 0 ));
1983
1984    {
1985        CvContour* edges = 0;
1986        CvSeq vtx;
1987        CvSeqBlock block;
1988
1989        CV_CALL( st = cvCreateMemStorage( CV_DRAWING_STORAGE_BLOCK ));
1990        CV_CALL( edges = (CvContour*)cvCreateSeq( 0, sizeof(CvContour),
1991                                                  sizeof(CvPolyEdge), st ));
1992
1993        for( int i = 0; i < contours; i++ )
1994        {
1995            if( !pts[i] )
1996                CV_ERROR( CV_StsNullPtr, "" );
1997
1998            if( npts[i] < 0 )
1999                CV_ERROR( CV_StsOutOfRange, "" );
2000
2001            cvMakeSeqHeaderForArray( CV_32SC2, sizeof(CvSeq), sizeof(CvPoint),
2002                                     pts[i], npts[i], &vtx, &block );
2003
2004            CV_CALL( icvCollectPolyEdges( mat, &vtx, edges, buf, line_type, shift ));
2005        }
2006
2007        CV_CALL( icvFillEdgeCollection( mat, edges, buf ));
2008    }
2009
2010    __END__;
2011
2012    cvReleaseMemStorage( &st );
2013}
2014
2015
2016
2017CV_IMPL void
2018cvPolyLine( void *img, CvPoint **pts, int *npts,
2019            int contours, int closed, CvScalar color,
2020            int thickness, int line_type, int shift )
2021{
2022    CV_FUNCNAME( "cvPolyLine" );
2023
2024    __BEGIN__;
2025
2026    int coi = 0, i;
2027    CvMat stub, *mat = (CvMat*)img;
2028    double buf[4];
2029
2030    CV_CALL( mat = cvGetMat( mat, &stub, &coi ));
2031
2032    if( line_type == CV_AA && CV_MAT_DEPTH(mat->type) != CV_8U )
2033        line_type = 8;
2034
2035    if( coi != 0 )
2036        CV_ERROR( CV_BadCOI, cvUnsupportedFormat );
2037
2038    if( contours <= 0 )
2039        CV_ERROR( CV_StsBadArg, "" );
2040
2041    if( thickness < -1 || thickness > 255 )
2042        CV_ERROR( CV_StsBadArg, "" );
2043
2044    if( !pts )
2045        CV_ERROR( CV_StsNullPtr, "" );
2046
2047    if( npts <= 0 )
2048        CV_ERROR( CV_StsNullPtr, "" );
2049
2050    if( shift < 0 || XY_SHIFT < shift )
2051        CV_ERROR( CV_StsOutOfRange, "shift must be between 0 and 16" );
2052
2053    CV_CALL( cvScalarToRawData( &color, buf, mat->type, 0 ));
2054
2055    for( i = 0; i < contours; i++ )
2056        icvPolyLine( mat, pts[i], npts[i], closed, buf, thickness, line_type, shift );
2057
2058    __END__;
2059}
2060
2061
2062#define CV_FONT_SIZE_SHIFT     8
2063#define CV_FONT_ITALIC_ALPHA   (1 << 8)
2064#define CV_FONT_ITALIC_DIGIT   (2 << 8)
2065#define CV_FONT_ITALIC_PUNCT   (4 << 8)
2066#define CV_FONT_ITALIC_BRACES  (8 << 8)
2067#define CV_FONT_HAVE_GREEK     (16 << 8)
2068#define CV_FONT_HAVE_CYRILLIC  (32 << 8)
2069
2070static const int icvHersheyPlain[] = {
2071(5 + 4*16) + CV_FONT_HAVE_GREEK,
2072199, 214, 217, 233, 219, 197, 234, 216, 221, 222, 228, 225, 211, 224, 210, 220,
2073200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 212, 213, 191, 226, 192,
2074215, 190, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
207514, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 193, 84,
2076194, 85, 86, 87, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
2077112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
2078195, 223, 196, 88 };
2079
2080static const int icvHersheyPlainItalic[] = {
2081(5 + 4*16) + CV_FONT_ITALIC_ALPHA + CV_FONT_HAVE_GREEK,
2082199, 214, 217, 233, 219, 197, 234, 216, 221, 222, 228, 225, 211, 224, 210, 220,
2083200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 212, 213, 191, 226, 192,
2084215, 190, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
208564, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 193, 84,
2086194, 85, 86, 87, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161,
2087162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176,
2088195, 223, 196, 88 };
2089
2090static const int icvHersheyComplexSmall[] = {
2091(6 + 7*16) + CV_FONT_HAVE_GREEK,
20921199, 1214, 1217, 1275, 1274, 1271, 1272, 1216, 1221, 1222, 1219, 1232, 1211, 1231, 1210, 1220,
20931200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1212, 2213, 1241, 1238, 1242,
20941215, 1273, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013,
20951014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1223, 1084,
20961224, 1247, 586, 1249, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111,
20971112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126,
20981225, 1229, 1226, 1246 };
2099
2100static const int icvHersheyComplexSmallItalic[] = {
2101(6 + 7*16) + CV_FONT_ITALIC_ALPHA + CV_FONT_HAVE_GREEK,
21021199, 1214, 1217, 1275, 1274, 1271, 1272, 1216, 1221, 1222, 1219, 1232, 1211, 1231, 1210, 1220,
21031200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1212, 1213, 1241, 1238, 1242,
21041215, 1273, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063,
21051064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1223, 1084,
21061224, 1247, 586, 1249, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161,
21071162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176,
21081225, 1229, 1226, 1246 };
2109
2110static const int icvHersheySimplex[] = {
2111(9 + 12*16) + CV_FONT_HAVE_GREEK,
21122199, 714, 717, 733, 719, 697, 734, 716, 721, 722, 728, 725, 711, 724, 710, 720,
2113700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 712, 713, 691, 726, 692,
2114715, 690, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513,
2115514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 693, 584,
2116694, 2247, 586, 2249, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611,
2117612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626,
2118695, 723, 696, 2246 };
2119
2120static const int icvHersheyDuplex[] = {
2121(9 + 12*16) + CV_FONT_HAVE_GREEK,
21222199, 2714, 2728, 2732, 2719, 2733, 2718, 2727, 2721, 2722, 2723, 2725, 2711, 2724, 2710, 2720,
21232700, 2701, 2702, 2703, 2704, 2705, 2706, 2707, 2708, 2709, 2712, 2713, 2730, 2726, 2731,
21242715, 2734, 2501, 2502, 2503, 2504, 2505, 2506, 2507, 2508, 2509, 2510, 2511, 2512, 2513,
21252514, 2515, 2516, 2517, 2518, 2519, 2520, 2521, 2522, 2523, 2524, 2525, 2526, 2223, 2084,
21262224, 2247, 587, 2249, 2601, 2602, 2603, 2604, 2605, 2606, 2607, 2608, 2609, 2610, 2611,
21272612, 2613, 2614, 2615, 2616, 2617, 2618, 2619, 2620, 2621, 2622, 2623, 2624, 2625, 2626,
21282225, 2229, 2226, 2246 };
2129
2130static const int icvHersheyComplex[] = {
2131(9 + 12*16) + CV_FONT_HAVE_GREEK + CV_FONT_HAVE_CYRILLIC,
21322199, 2214, 2217, 2275, 2274, 2271, 2272, 2216, 2221, 2222, 2219, 2232, 2211, 2231, 2210, 2220,
21332200, 2201, 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, 2212, 2213, 2241, 2238, 2242,
21342215, 2273, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013,
21352014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2223, 2084,
21362224, 2247, 587, 2249, 2101, 2102, 2103, 2104, 2105, 2106, 2107, 2108, 2109, 2110, 2111,
21372112, 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, 2121, 2122, 2123, 2124, 2125, 2126,
21382225, 2229, 2226, 2246 };
2139
2140static const int icvHersheyComplexItalic[] = {
2141(9 + 12*16) + CV_FONT_ITALIC_ALPHA + CV_FONT_ITALIC_DIGIT + CV_FONT_ITALIC_PUNCT +
2142CV_FONT_HAVE_GREEK + CV_FONT_HAVE_CYRILLIC,
21432199, 2764, 2778, 2782, 2769, 2783, 2768, 2777, 2771, 2772, 2219, 2232, 2211, 2231, 2210, 2220,
21442750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2212, 2213, 2241, 2238, 2242,
21452765, 2273, 2051, 2052, 2053, 2054, 2055, 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063,
21462064, 2065, 2066, 2067, 2068, 2069, 2070, 2071, 2072, 2073, 2074, 2075, 2076, 2223, 2084,
21472224, 2247, 587, 2249, 2151, 2152, 2153, 2154, 2155, 2156, 2157, 2158, 2159, 2160, 2161,
21482162, 2163, 2164, 2165, 2166, 2167, 2168, 2169, 2170, 2171, 2172, 2173, 2174, 2175, 2176,
21492225, 2229, 2226, 2246 };
2150
2151static const int icvHersheyTriplex[] = {
2152(9 + 12*16) + CV_FONT_HAVE_GREEK,
21532199, 3214, 3228, 3232, 3219, 3233, 3218, 3227, 3221, 3222, 3223, 3225, 3211, 3224, 3210, 3220,
21543200, 3201, 3202, 3203, 3204, 3205, 3206, 3207, 3208, 3209, 3212, 3213, 3230, 3226, 3231,
21553215, 3234, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3011, 3012, 3013,
21562014, 3015, 3016, 3017, 3018, 3019, 3020, 3021, 3022, 3023, 3024, 3025, 3026, 2223, 2084,
21572224, 2247, 587, 2249, 3101, 3102, 3103, 3104, 3105, 3106, 3107, 3108, 3109, 3110, 3111,
21583112, 3113, 3114, 3115, 3116, 3117, 3118, 3119, 3120, 3121, 3122, 3123, 3124, 3125, 3126,
21592225, 2229, 2226, 2246 };
2160
2161static const int icvHersheyTriplexItalic[] = {
2162(9 + 12*16) + CV_FONT_ITALIC_ALPHA + CV_FONT_ITALIC_DIGIT +
2163CV_FONT_ITALIC_PUNCT + CV_FONT_HAVE_GREEK,
21642199, 3264, 3278, 3282, 3269, 3233, 3268, 3277, 3271, 3272, 3223, 3225, 3261, 3224, 3260, 3270,
21653250, 3251, 3252, 3253, 3254, 3255, 3256, 3257, 3258, 3259, 3262, 3263, 3230, 3226, 3231,
21663265, 3234, 3051, 3052, 3053, 3054, 3055, 3056, 3057, 3058, 3059, 3060, 3061, 3062, 3063,
21672064, 3065, 3066, 3067, 3068, 3069, 3070, 3071, 3072, 3073, 3074, 3075, 3076, 2223, 2084,
21682224, 2247, 587, 2249, 3151, 3152, 3153, 3154, 3155, 3156, 3157, 3158, 3159, 3160, 3161,
21693162, 3163, 3164, 3165, 3166, 3167, 3168, 3169, 3170, 3171, 3172, 3173, 3174, 3175, 3176,
21702225, 2229, 2226, 2246 };
2171
2172static const int icvHersheyScriptSimplex[] = {
2173(9 + 12*16) + CV_FONT_ITALIC_ALPHA + CV_FONT_HAVE_GREEK,
21742199, 714, 717, 733, 719, 697, 734, 716, 721, 722, 728, 725, 711, 724, 710, 720,
2175700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 712, 713, 691, 726, 692,
2176715, 690, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563,
2177564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 693, 584,
2178694, 2247, 586, 2249, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661,
2179662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676,
2180695, 723, 696, 2246 };
2181
2182static const int icvHersheyScriptComplex[] = {
2183(9 + 12*16) + CV_FONT_ITALIC_ALPHA + CV_FONT_ITALIC_DIGIT + CV_FONT_ITALIC_PUNCT + CV_FONT_HAVE_GREEK,
21842199, 2764, 2778, 2782, 2769, 2783, 2768, 2777, 2771, 2772, 2219, 2232, 2211, 2231, 2210, 2220,
21852750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2212, 2213, 2241, 2238, 2242,
21862215, 2273, 2551, 2552, 2553, 2554, 2555, 2556, 2557, 2558, 2559, 2560, 2561, 2562, 2563,
21872564, 2565, 2566, 2567, 2568, 2569, 2570, 2571, 2572, 2573, 2574, 2575, 2576, 2223, 2084,
21882224, 2247, 586, 2249, 2651, 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, 2660, 2661,
21892662, 2663, 2664, 2665, 2666, 2667, 2668, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2676,
21902225, 2229, 2226, 2246 };
2191
2192
2193CV_IMPL void
2194cvPutText( void *img, const char *text, CvPoint org, const CvFont *font, CvScalar color )
2195{
2196    CV_FUNCNAME( "cvPutText" );
2197
2198    __BEGIN__;
2199
2200    int view_x, view_y;
2201    int coi = 0;
2202    int top_bottom = 0, base_line;
2203    int hscale, vscale, default_shear, italic_shear;
2204    int thickness, line_type;
2205    CvMat stub, *mat = (CvMat*)img;
2206    double buf[4];
2207    CvPoint pt[1 << 10];
2208    int count;
2209
2210    int i;
2211    const char **faces = icvHersheyGlyphs;
2212
2213    CV_CALL( mat = cvGetMat( mat, &stub, &coi ));
2214
2215    if( coi != 0 )
2216        CV_ERROR( CV_BadCOI, cvUnsupportedFormat );
2217
2218    if( CV_IS_IMAGE_HDR(img) && ((IplImage*)img)->origin )
2219        top_bottom = 1;
2220
2221    if( !text || !font || !font->ascii )
2222        CV_ERROR( CV_StsNullPtr, "" );
2223
2224    CV_CALL( cvScalarToRawData( &color, buf, mat->type, 0 ));
2225    base_line = -(font->ascii[0] & 15);
2226    hscale = cvRound(font->hscale*XY_ONE);
2227    vscale = cvRound(font->vscale*XY_ONE);
2228    default_shear = cvRound(font->shear*font->vscale*XY_ONE);
2229    italic_shear = !(font->font_face & CV_FONT_ITALIC) ? 0 : cvRound(font->vscale*.25*XY_ONE);
2230    thickness = font->thickness;
2231    line_type = font->line_type;
2232
2233    if( line_type == CV_AA && CV_MAT_DEPTH(mat->type) != CV_8U )
2234        line_type = 8;
2235
2236    if( top_bottom )
2237        vscale = -vscale;
2238
2239    view_x = org.x << XY_SHIFT;
2240    view_y = (org.y << XY_SHIFT) + base_line*vscale;
2241
2242    for( i = 0; text[i] != '\0'; i++ )
2243    {
2244        int c = (uchar)text[i];
2245        int dx, shear = default_shear;
2246        const char* ptr;
2247        CvPoint p;
2248
2249        if( c > 128 || c < ' ' )
2250            c = '?';
2251
2252        if( italic_shear )
2253        {
2254            if( ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))
2255            {
2256                if( !(font->ascii[0] & CV_FONT_ITALIC_ALPHA) )
2257                    shear += italic_shear;
2258            }
2259            else if( '0' <= c && c <= '9' )
2260            {
2261                if( !(font->ascii[0] & CV_FONT_ITALIC_DIGIT) )
2262                    shear += italic_shear;
2263            }
2264            else if( c < 'A' )
2265            {
2266                if( !(font->ascii[0] & CV_FONT_ITALIC_PUNCT) )
2267                    shear += italic_shear;
2268            }
2269            else
2270            {
2271                shear += italic_shear;
2272            }
2273        }
2274
2275        ptr = faces[font->ascii[(c-' ')+1]];
2276        p.x = (unsigned char)ptr[0] - 'R';
2277        p.y = (unsigned char)ptr[1] - 'R';
2278        dx = p.y*hscale;
2279        view_x -= p.x*hscale;
2280        count = 0;
2281
2282        for( ptr += 2;; )
2283        {
2284            if( *ptr == ' ' || !*ptr )
2285            {
2286                if( count > 1 )
2287                    icvPolyLine( mat, pt, count, 0, buf, thickness, line_type, XY_SHIFT );
2288                if( !*ptr++ )
2289                    break;
2290                count = 0;
2291            }
2292            else
2293            {
2294                p.x = (unsigned char)ptr[0] - 'R';
2295                p.y = (unsigned char)ptr[1] - 'R';
2296                ptr += 2;
2297                pt[count].x = p.x*hscale - p.y*shear + view_x;
2298                pt[count++].y = p.y*vscale + view_y;
2299            }
2300        }
2301        view_x += dx;
2302    }
2303
2304    __END__;
2305}
2306
2307CV_IMPL void
2308cvInitFont( CvFont *font, int font_face, double hscale, double vscale,
2309            double shear, int thickness, int line_type )
2310{
2311    CV_FUNCNAME( "cvInitFont" );
2312
2313    __BEGIN__;
2314
2315    int is_italic = font_face & CV_FONT_ITALIC;
2316
2317    if( !font )
2318        CV_ERROR( CV_StsNullPtr, "" );
2319
2320    if( hscale <= 0 || vscale <= 0 || thickness < 0 )
2321        CV_ERROR( CV_StsOutOfRange, "" );
2322
2323    switch( (font_face & 7) )
2324    {
2325    case CV_FONT_HERSHEY_SIMPLEX:
2326        font->ascii = icvHersheySimplex;
2327        break;
2328    case CV_FONT_HERSHEY_PLAIN:
2329        font->ascii = !is_italic ? icvHersheyPlain : icvHersheyPlainItalic;
2330        break;
2331    case CV_FONT_HERSHEY_DUPLEX:
2332        font->ascii = icvHersheyDuplex;
2333        break;
2334    case CV_FONT_HERSHEY_COMPLEX:
2335        font->ascii = !is_italic ? icvHersheyComplex : icvHersheyComplexItalic;
2336        break;
2337    case CV_FONT_HERSHEY_TRIPLEX:
2338        font->ascii = !is_italic ? icvHersheyTriplex : icvHersheyTriplexItalic;
2339        break;
2340    case CV_FONT_HERSHEY_COMPLEX_SMALL:
2341        font->ascii = !is_italic ? icvHersheyComplexSmall : icvHersheyComplexSmallItalic;
2342        break;
2343    case CV_FONT_HERSHEY_SCRIPT_SIMPLEX:
2344        font->ascii = icvHersheyScriptSimplex;
2345        break;
2346    case CV_FONT_HERSHEY_SCRIPT_COMPLEX:
2347        font->ascii = icvHersheyScriptComplex;
2348        break;
2349    default:
2350        CV_ERROR( CV_StsOutOfRange, "Unknown font type" );
2351    }
2352
2353    font->font_face = font_face;
2354    font->hscale = (float)hscale;
2355    font->vscale = (float)vscale;
2356    font->thickness = thickness;
2357    font->shear = (float)shear;
2358    font->greek = font->cyrillic = 0;
2359    font->line_type = line_type;
2360
2361    __END__;
2362}
2363
2364
2365CV_IMPL void
2366cvGetTextSize( const char *text, const CvFont *font, CvSize *size, int *_base_line )
2367{
2368    CV_FUNCNAME( "cvGetTextSize" );
2369
2370    __BEGIN__;
2371
2372    float view_x = 0;
2373    int base_line, cap_line;
2374
2375    int i;
2376    const char **faces = icvHersheyGlyphs;
2377
2378    if( !text || !font || !font->ascii || !size )
2379        CV_ERROR( CV_StsNullPtr, "" );
2380
2381    base_line = (font->ascii[0] & 15);
2382    cap_line = (font->ascii[0] >> 4) & 15;
2383    if( _base_line )
2384        *_base_line = cvRound(base_line*font->vscale);
2385    size->height = cvRound((cap_line + base_line)*font->vscale + font->thickness);
2386
2387    for( i = 0; text[i] != '\0'; i++ )
2388    {
2389        int c = (uchar)text[i];
2390        const char* ptr;
2391        CvPoint p;
2392
2393        if( c > 128 || c < ' ' )
2394            c = '?';
2395
2396        ptr = faces[font->ascii[(c-' ')+1]];
2397        p.x = (unsigned char)ptr[0] - 'R';
2398        p.y = (unsigned char)ptr[1] - 'R';
2399        view_x += (p.y - p.x)*font->hscale;
2400    }
2401
2402    size->width = cvRound(view_x + font->thickness);
2403
2404    __END__;
2405}
2406
2407
2408static const CvPoint icvCodeDeltas[8] =
2409{ {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1} };
2410
2411#define CV_ADJUST_EDGE_COUNT( count, seq )  \
2412    ((count) -= ((count) == (seq)->total && !CV_IS_SEQ_CLOSED(seq)))
2413
2414CV_IMPL void
2415cvDrawContours( void*  img,  CvSeq*  contour,
2416                CvScalar externalColor, CvScalar holeColor,
2417                int  maxLevel, int thickness,
2418                int line_type, CvPoint offset )
2419{
2420    CvSeq *contour0 = contour, *h_next = 0;
2421    CvMemStorage* st = 0;
2422    CvSeq* tseq = 0;
2423    CvContour* edges = 0;
2424    CvSeqWriter writer;
2425    CvTreeNodeIterator iterator;
2426
2427    CV_FUNCNAME( "cvDrawContours" );
2428
2429    __BEGIN__;
2430
2431    int coi = 0;
2432    CvMat stub, *mat = (CvMat*)img;
2433    double ext_buf[4], hole_buf[4];
2434
2435    CV_CALL( mat = cvGetMat( mat, &stub, &coi ));
2436
2437    if( line_type == CV_AA && CV_MAT_DEPTH(mat->type) != CV_8U )
2438        line_type = 8;
2439
2440    if( !contour )
2441        EXIT;
2442
2443    if( coi != 0 )
2444        CV_ERROR( CV_BadCOI, cvUnsupportedFormat );
2445
2446    if( thickness < -1 || thickness > 255 )
2447        CV_ERROR( CV_StsOutOfRange, "" );
2448
2449    CV_CALL( cvScalarToRawData( &externalColor, ext_buf, mat->type, 0 ));
2450    CV_CALL( cvScalarToRawData( &holeColor, hole_buf, mat->type, 0 ));
2451
2452    if( maxLevel < 0 )
2453    {
2454        h_next = contour->h_next;
2455        contour->h_next = 0;
2456        maxLevel = -maxLevel+1;
2457    }
2458
2459    if( thickness < 0 )
2460    {
2461        if( contour->storage )
2462            st = cvCreateChildMemStorage( contour->storage );
2463        else
2464            st = cvCreateMemStorage( CV_DRAWING_STORAGE_BLOCK );
2465        tseq = cvCreateSeq( 0, sizeof(CvContour), sizeof(CvPoint), st );
2466        edges = (CvContour*)cvCreateSeq( 0, sizeof(CvContour), sizeof(CvPolyEdge), st );
2467    }
2468
2469    memset( &writer, 0, sizeof(writer));
2470
2471    cvInitTreeNodeIterator( &iterator, contour, maxLevel );
2472
2473    while( (contour = (CvSeq*)cvNextTreeNode( &iterator )) != 0 )
2474    {
2475        CvSeqReader reader;
2476        int i, count = contour->total;
2477        int elem_type = CV_MAT_TYPE(contour->flags);
2478        void* clr = (contour->flags & CV_SEQ_FLAG_HOLE) == 0 ? ext_buf : hole_buf;
2479
2480        cvStartReadSeq( contour, &reader, 0 );
2481
2482        if( CV_IS_SEQ_CHAIN_CONTOUR( contour ))
2483        {
2484            CvPoint pt = ((CvChain*)contour)->origin;
2485            CvPoint prev_pt = pt;
2486            char prev_code = reader.ptr ? reader.ptr[0] : '\0';
2487
2488            if( thickness < 0 )
2489            {
2490                cvClearSeq( tseq );
2491                cvStartAppendToSeq( tseq, &writer );
2492                CV_WRITE_SEQ_ELEM( pt, writer );
2493            }
2494
2495            prev_pt.x += offset.x;
2496            prev_pt.y += offset.y;
2497
2498            for( i = 0; i < count; i++ )
2499            {
2500                char code;
2501                CV_READ_SEQ_ELEM( code, reader );
2502
2503                assert( (code & ~7) == 0 );
2504
2505                if( code != prev_code )
2506                {
2507                    prev_code = code;
2508                    if( thickness >= 0 )
2509                    {
2510                        icvThickLine( mat, prev_pt, pt, clr, thickness, line_type, 2, 0 );
2511                    }
2512                    else
2513                    {
2514                        CV_WRITE_SEQ_ELEM( pt, writer );
2515                    }
2516                    prev_pt = pt;
2517                }
2518
2519                pt.x += icvCodeDeltas[(int)code].x;
2520                pt.y += icvCodeDeltas[(int)code].y;
2521            }
2522
2523            if( thickness >= 0 )
2524            {
2525                icvThickLine( mat, prev_pt, ((CvChain*)contour)->origin,
2526                              clr, thickness, line_type, 2, 0 );
2527            }
2528            else
2529            {
2530                CV_WRITE_SEQ_ELEM( pt, writer );
2531                cvEndWriteSeq( &writer );
2532                CV_CALL( icvCollectPolyEdges( mat, tseq, edges, ext_buf, line_type, 0 ));
2533            }
2534        }
2535        else if( CV_IS_SEQ_POLYLINE( contour ))
2536        {
2537            if( thickness >= 0 )
2538            {
2539                CvPoint pt1, pt2;
2540                int shift = 0;
2541
2542                count -= !CV_IS_SEQ_CLOSED(contour);
2543                if( elem_type == CV_32SC2 )
2544                {
2545                    CV_READ_SEQ_ELEM( pt1, reader );
2546                    pt1.x += offset.x;
2547                    pt1.y += offset.y;
2548                }
2549                else
2550                {
2551                    CvPoint2D32f pt1f;
2552                    CV_READ_SEQ_ELEM( pt1f, reader );
2553                    pt1.x = cvRound( (pt1f.x + offset.x) * XY_ONE );
2554                    pt1.y = cvRound( (pt1f.y + offset.y) * XY_ONE );
2555                    shift = XY_SHIFT;
2556                }
2557
2558                for( i = 0; i < count; i++ )
2559                {
2560                    if( elem_type == CV_32SC2 )
2561                    {
2562                        CV_READ_SEQ_ELEM( pt2, reader );
2563                        pt2.x += offset.x;
2564                        pt2.y += offset.y;
2565                    }
2566                    else
2567                    {
2568                        CvPoint2D32f pt2f;
2569                        CV_READ_SEQ_ELEM( pt2f, reader );
2570                        pt2.x = cvRound( pt2f.x * XY_ONE );
2571                        pt2.y = cvRound( pt2f.y * XY_ONE );
2572                    }
2573                    icvThickLine( mat, pt1, pt2, clr, thickness, line_type, 2, shift );
2574                    pt1 = pt2;
2575                }
2576            }
2577            else
2578            {
2579                CV_CALL( icvCollectPolyEdges( mat, contour, edges, ext_buf, line_type, 0, offset ));
2580            }
2581        }
2582    }
2583
2584    if( thickness < 0 )
2585    {
2586        CV_CALL( icvFillEdgeCollection( mat, edges, ext_buf ));
2587    }
2588
2589    __END__;
2590
2591    if( h_next && contour0 )
2592        contour0->h_next = h_next;
2593
2594    cvReleaseMemStorage( &st );
2595}
2596
2597/* End of file. */
2598