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