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