Move the sources to trunk
[opencv] / cxcore / src / cxdrawing.cpp
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
48 typedef struct CvPolyEdge
49 {
50     int x, dx;
51     union
52     {
53         struct CvPolyEdge *next;
54         int y0;
55     };
56     int y1;
57 }
58 CvPolyEdge;
59
60 static void
61 icvCollectPolyEdges( CvMat* img, CvSeq* v, CvContour* edges,
62                      const void* color, int line_type,
63                      int shift, CvPoint offset=cvPoint(0,0) );
64
65 static void
66 icvFillEdgeCollection( CvMat* img, CvContour* edges, const void* color );
67
68 static void
69 icvPolyLine( CvMat* img, CvPoint *v, int count, int closed,
70              const void* color, int thickness, int line_type, int shift );
71
72 static void
73 icvFillConvexPoly( CvMat* img, CvPoint* v, int npts,
74                    const void* color, int line_type, int shift );
75
76 /****************************************************************************************\
77 *                                   Lines                                                *
78 \****************************************************************************************/
79
80 CV_IMPL int
81 cvClipLine( 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 */
159 CV_IMPL int
160 cvInitLineIterator( 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
255 static void
256 icvLine( 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 */
282 static 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 */
288 static 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
295 static void
296 icvLineAA( 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
560 static void
561 icvLine2( 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
759 static 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
839 static void
840 icvSinCos( 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 */
850 CV_IMPL int
851 cvEllipse2Poly( 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
911 static void
912 icvEllipseEx( 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 */
987 static void
988 icvFillConvexPoly( 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
1148 static void
1149 icvCollectPolyEdges( 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
1238 static int
1239 icvCmpEdges( 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
1248 static void
1249 icvFillEdgeCollection( 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 */
1410 static void
1411 icvCircle( 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
1556 static void
1557 icvThickLine( 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
1634 static void
1635 icvPolyLine( 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
1672 CV_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
1736 CV_IMPL void
1737 cvLine( 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
1769 CV_IMPL void
1770 cvRectangle( 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
1816 CV_IMPL void
1817 cvCircle( 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
1864 CV_IMPL void
1865 cvEllipse( 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
1913 CV_IMPL void
1914 cvFillConvexPoly( 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
1948 CV_IMPL void
1949 cvFillPoly( 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
2017 CV_IMPL void
2018 cvPolyLine( 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
2070 static const int icvHersheyPlain[] = {
2071 (5 + 4*16) + CV_FONT_HAVE_GREEK,
2072 199, 214, 217, 233, 219, 197, 234, 216, 221, 222, 228, 225, 211, 224, 210, 220,
2073 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 212, 213, 191, 226, 192,
2074 215, 190, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
2075 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 193, 84,
2076 194, 85, 86, 87, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
2077 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
2078 195, 223, 196, 88 };
2079
2080 static const int icvHersheyPlainItalic[] = {
2081 (5 + 4*16) + CV_FONT_ITALIC_ALPHA + CV_FONT_HAVE_GREEK,
2082 199, 214, 217, 233, 219, 197, 234, 216, 221, 222, 228, 225, 211, 224, 210, 220,
2083 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 212, 213, 191, 226, 192,
2084 215, 190, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
2085 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 193, 84,
2086 194, 85, 86, 87, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161,
2087 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176,
2088 195, 223, 196, 88 };
2089
2090 static const int icvHersheyComplexSmall[] = {
2091 (6 + 7*16) + CV_FONT_HAVE_GREEK,
2092 1199, 1214, 1217, 1275, 1274, 1271, 1272, 1216, 1221, 1222, 1219, 1232, 1211, 1231, 1210, 1220,
2093 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1212, 2213, 1241, 1238, 1242,
2094 1215, 1273, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013,
2095 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1223, 1084,
2096 1224, 1247, 586, 1249, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111,
2097 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126,
2098 1225, 1229, 1226, 1246 };
2099
2100 static const int icvHersheyComplexSmallItalic[] = {
2101 (6 + 7*16) + CV_FONT_ITALIC_ALPHA + CV_FONT_HAVE_GREEK,
2102 1199, 1214, 1217, 1275, 1274, 1271, 1272, 1216, 1221, 1222, 1219, 1232, 1211, 1231, 1210, 1220,
2103 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1212, 1213, 1241, 1238, 1242,
2104 1215, 1273, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063,
2105 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1223, 1084,
2106 1224, 1247, 586, 1249, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161,
2107 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176,
2108 1225, 1229, 1226, 1246 };
2109
2110 static const int icvHersheySimplex[] = {
2111 (9 + 12*16) + CV_FONT_HAVE_GREEK,
2112 2199, 714, 717, 733, 719, 697, 734, 716, 721, 722, 728, 725, 711, 724, 710, 720,
2113 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 712, 713, 691, 726, 692,
2114 715, 690, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513,
2115 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 693, 584,
2116 694, 2247, 586, 2249, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611,
2117 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626,
2118 695, 723, 696, 2246 };
2119
2120 static const int icvHersheyDuplex[] = {
2121 (9 + 12*16) + CV_FONT_HAVE_GREEK,
2122 2199, 2714, 2728, 2732, 2719, 2733, 2718, 2727, 2721, 2722, 2723, 2725, 2711, 2724, 2710, 2720,
2123 2700, 2701, 2702, 2703, 2704, 2705, 2706, 2707, 2708, 2709, 2712, 2713, 2730, 2726, 2731,
2124 2715, 2734, 2501, 2502, 2503, 2504, 2505, 2506, 2507, 2508, 2509, 2510, 2511, 2512, 2513,
2125 2514, 2515, 2516, 2517, 2518, 2519, 2520, 2521, 2522, 2523, 2524, 2525, 2526, 2223, 2084,
2126 2224, 2247, 587, 2249, 2601, 2602, 2603, 2604, 2605, 2606, 2607, 2608, 2609, 2610, 2611,
2127 2612, 2613, 2614, 2615, 2616, 2617, 2618, 2619, 2620, 2621, 2622, 2623, 2624, 2625, 2626,
2128 2225, 2229, 2226, 2246 };
2129
2130 static const int icvHersheyComplex[] = {
2131 (9 + 12*16) + CV_FONT_HAVE_GREEK + CV_FONT_HAVE_CYRILLIC,
2132 2199, 2214, 2217, 2275, 2274, 2271, 2272, 2216, 2221, 2222, 2219, 2232, 2211, 2231, 2210, 2220,
2133 2200, 2201, 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, 2212, 2213, 2241, 2238, 2242,
2134 2215, 2273, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013,
2135 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2223, 2084,
2136 2224, 2247, 587, 2249, 2101, 2102, 2103, 2104, 2105, 2106, 2107, 2108, 2109, 2110, 2111,
2137 2112, 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, 2121, 2122, 2123, 2124, 2125, 2126,
2138 2225, 2229, 2226, 2246 };
2139
2140 static const int icvHersheyComplexItalic[] = {
2141 (9 + 12*16) + CV_FONT_ITALIC_ALPHA + CV_FONT_ITALIC_DIGIT + CV_FONT_ITALIC_PUNCT +
2142 CV_FONT_HAVE_GREEK + CV_FONT_HAVE_CYRILLIC,
2143 2199, 2764, 2778, 2782, 2769, 2783, 2768, 2777, 2771, 2772, 2219, 2232, 2211, 2231, 2210, 2220,
2144 2750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2212, 2213, 2241, 2238, 2242,
2145 2765, 2273, 2051, 2052, 2053, 2054, 2055, 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063,
2146 2064, 2065, 2066, 2067, 2068, 2069, 2070, 2071, 2072, 2073, 2074, 2075, 2076, 2223, 2084,
2147 2224, 2247, 587, 2249, 2151, 2152, 2153, 2154, 2155, 2156, 2157, 2158, 2159, 2160, 2161,
2148 2162, 2163, 2164, 2165, 2166, 2167, 2168, 2169, 2170, 2171, 2172, 2173, 2174, 2175, 2176,
2149 2225, 2229, 2226, 2246 };
2150
2151 static const int icvHersheyTriplex[] = {
2152 (9 + 12*16) + CV_FONT_HAVE_GREEK,
2153 2199, 3214, 3228, 3232, 3219, 3233, 3218, 3227, 3221, 3222, 3223, 3225, 3211, 3224, 3210, 3220,
2154 3200, 3201, 3202, 3203, 3204, 3205, 3206, 3207, 3208, 3209, 3212, 3213, 3230, 3226, 3231,
2155 3215, 3234, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3011, 3012, 3013,
2156 2014, 3015, 3016, 3017, 3018, 3019, 3020, 3021, 3022, 3023, 3024, 3025, 3026, 2223, 2084,
2157 2224, 2247, 587, 2249, 3101, 3102, 3103, 3104, 3105, 3106, 3107, 3108, 3109, 3110, 3111,
2158 3112, 3113, 3114, 3115, 3116, 3117, 3118, 3119, 3120, 3121, 3122, 3123, 3124, 3125, 3126,
2159 2225, 2229, 2226, 2246 };
2160
2161 static const int icvHersheyTriplexItalic[] = {
2162 (9 + 12*16) + CV_FONT_ITALIC_ALPHA + CV_FONT_ITALIC_DIGIT +
2163 CV_FONT_ITALIC_PUNCT + CV_FONT_HAVE_GREEK,
2164 2199, 3264, 3278, 3282, 3269, 3233, 3268, 3277, 3271, 3272, 3223, 3225, 3261, 3224, 3260, 3270,
2165 3250, 3251, 3252, 3253, 3254, 3255, 3256, 3257, 3258, 3259, 3262, 3263, 3230, 3226, 3231,
2166 3265, 3234, 3051, 3052, 3053, 3054, 3055, 3056, 3057, 3058, 3059, 3060, 3061, 3062, 3063,
2167 2064, 3065, 3066, 3067, 3068, 3069, 3070, 3071, 3072, 3073, 3074, 3075, 3076, 2223, 2084,
2168 2224, 2247, 587, 2249, 3151, 3152, 3153, 3154, 3155, 3156, 3157, 3158, 3159, 3160, 3161,
2169 3162, 3163, 3164, 3165, 3166, 3167, 3168, 3169, 3170, 3171, 3172, 3173, 3174, 3175, 3176,
2170 2225, 2229, 2226, 2246 };
2171
2172 static const int icvHersheyScriptSimplex[] = {
2173 (9 + 12*16) + CV_FONT_ITALIC_ALPHA + CV_FONT_HAVE_GREEK,
2174 2199, 714, 717, 733, 719, 697, 734, 716, 721, 722, 728, 725, 711, 724, 710, 720,
2175 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 712, 713, 691, 726, 692,
2176 715, 690, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563,
2177 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 693, 584,
2178 694, 2247, 586, 2249, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661,
2179 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676,
2180 695, 723, 696, 2246 };
2181
2182 static const int icvHersheyScriptComplex[] = {
2183 (9 + 12*16) + CV_FONT_ITALIC_ALPHA + CV_FONT_ITALIC_DIGIT + CV_FONT_ITALIC_PUNCT + CV_FONT_HAVE_GREEK,
2184 2199, 2764, 2778, 2782, 2769, 2783, 2768, 2777, 2771, 2772, 2219, 2232, 2211, 2231, 2210, 2220,
2185 2750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2212, 2213, 2241, 2238, 2242,
2186 2215, 2273, 2551, 2552, 2553, 2554, 2555, 2556, 2557, 2558, 2559, 2560, 2561, 2562, 2563,
2187 2564, 2565, 2566, 2567, 2568, 2569, 2570, 2571, 2572, 2573, 2574, 2575, 2576, 2223, 2084,
2188 2224, 2247, 586, 2249, 2651, 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, 2660, 2661,
2189 2662, 2663, 2664, 2665, 2666, 2667, 2668, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2676,
2190 2225, 2229, 2226, 2246 };
2191
2192
2193 CV_IMPL void
2194 cvPutText( 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
2307 CV_IMPL void
2308 cvInitFont( 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
2365 CV_IMPL void
2366 cvGetTextSize( 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
2408 static 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
2414 CV_IMPL void
2415 cvDrawContours( 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. */