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"
42using namespace cv;
43
44namespace cv
45{
46enum { XY_SHIFT = 16, XY_ONE = 1 << XY_SHIFT, DRAWING_STORAGE_BLOCK = (1<<12) - 256 };
47
48static const int MAX_THICKNESS = 32767;
49
50struct 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 int64 x, dx;
57 PolyEdge *next;
58};
59
60static void
61CollectPolyEdges( Mat& img, const Point2l* v, int npts,
62 std::vector<PolyEdge>& edges, const void* color, int line_type,
63 int shift, Point offset=Point() );
64
65static void
66FillEdgeCollection( Mat& img, std::vector<PolyEdge>& edges, const void* color );
67
68static void
69PolyLine( Mat& img, const Point2l* v, int npts, bool closed,
70 const void* color, int thickness, int line_type, int shift );
71
72static void
73FillConvexPoly( Mat& img, const Point2l* v, int npts,
74 const void* color, int line_type, int shift );
75
76/****************************************************************************************\
77* Lines *
78\****************************************************************************************/
79
80bool clipLine( Size img_size, Point& pt1, Point& pt2 )
81{
82 Point2l p1(pt1);
83 Point2l p2(pt2);
84 bool inside = clipLine(imgSize: Size2l(img_size.width, img_size.height), pt1&: p1, pt2&: p2);
85 pt1.x = (int)p1.x;
86 pt1.y = (int)p1.y;
87 pt2.x = (int)p2.x;
88 pt2.y = (int)p2.y;
89 return inside;
90}
91
92bool clipLine( Size2l img_size, Point2l& pt1, Point2l& pt2 )
93{
94 CV_INSTRUMENT_REGION();
95
96 int c1, c2;
97 int64 right = img_size.width-1, bottom = img_size.height-1;
98
99 if( img_size.width <= 0 || img_size.height <= 0 )
100 return false;
101
102 int64 &x1 = pt1.x, &y1 = pt1.y, &x2 = pt2.x, &y2 = pt2.y;
103 c1 = (x1 < 0) + (x1 > right) * 2 + (y1 < 0) * 4 + (y1 > bottom) * 8;
104 c2 = (x2 < 0) + (x2 > right) * 2 + (y2 < 0) * 4 + (y2 > bottom) * 8;
105
106 if( (c1 & c2) == 0 && (c1 | c2) != 0 )
107 {
108 int64 a;
109 if( c1 & 12 )
110 {
111 a = c1 < 8 ? 0 : bottom;
112 x1 += (int64)((double)(a - y1) * (x2 - x1) / (y2 - y1));
113 y1 = a;
114 c1 = (x1 < 0) + (x1 > right) * 2;
115 }
116 if( c2 & 12 )
117 {
118 a = c2 < 8 ? 0 : bottom;
119 x2 += (int64)((double)(a - y2) * (x2 - x1) / (y2 - y1));
120 y2 = a;
121 c2 = (x2 < 0) + (x2 > right) * 2;
122 }
123 if( (c1 & c2) == 0 && (c1 | c2) != 0 )
124 {
125 if( c1 )
126 {
127 a = c1 == 1 ? 0 : right;
128 y1 += (int64)((double)(a - x1) * (y2 - y1) / (x2 - x1));
129 x1 = a;
130 c1 = 0;
131 }
132 if( c2 )
133 {
134 a = c2 == 1 ? 0 : right;
135 y2 += (int64)((double)(a - x2) * (y2 - y1) / (x2 - x1));
136 x2 = a;
137 c2 = 0;
138 }
139 }
140
141 CV_Assert( (c1 & c2) != 0 || (x1 | y1 | x2 | y2) >= 0 );
142 }
143
144 return (c1 | c2) == 0;
145}
146
147bool clipLine( Rect img_rect, Point& pt1, Point& pt2 )
148{
149 CV_INSTRUMENT_REGION();
150
151 Point tl = img_rect.tl();
152 pt1 -= tl; pt2 -= tl;
153 bool inside = clipLine(img_size: img_rect.size(), pt1, pt2);
154 pt1 += tl; pt2 += tl;
155
156 return inside;
157}
158
159void LineIterator::init( const Mat* img, Rect rect, Point pt1_, Point pt2_, int connectivity, bool leftToRight )
160{
161 CV_Assert( connectivity == 8 || connectivity == 4 );
162
163 count = -1;
164 p = Point(0, 0);
165 ptr0 = ptr = 0;
166 step = elemSize = 0;
167 ptmode = !img;
168
169 Point pt1 = pt1_ - rect.tl();
170 Point pt2 = pt2_ - rect.tl();
171
172 if( (unsigned)pt1.x >= (unsigned)(rect.width) ||
173 (unsigned)pt2.x >= (unsigned)(rect.width) ||
174 (unsigned)pt1.y >= (unsigned)(rect.height) ||
175 (unsigned)pt2.y >= (unsigned)(rect.height) )
176 {
177 if( !clipLine(img_size: Size(rect.width, rect.height), pt1, pt2) )
178 {
179 err = plusDelta = minusDelta = plusStep = minusStep = plusShift = minusShift = count = 0;
180 return;
181 }
182 }
183
184 pt1 += rect.tl();
185 pt2 += rect.tl();
186
187 int delta_x = 1, delta_y = 1;
188 int dx = pt2.x - pt1.x;
189 int dy = pt2.y - pt1.y;
190
191 if( dx < 0 )
192 {
193 if( leftToRight )
194 {
195 dx = -dx;
196 dy = -dy;
197 pt1 = pt2;
198 }
199 else
200 {
201 dx = -dx;
202 delta_x = -1;
203 }
204 }
205
206 if( dy < 0 )
207 {
208 dy = -dy;
209 delta_y = -1;
210 }
211
212 bool vert = dy > dx;
213 if( vert )
214 {
215 std::swap(a&: dx, b&: dy);
216 std::swap(a&: delta_x, b&: delta_y);
217 }
218
219 CV_Assert( dx >= 0 && dy >= 0 );
220
221 if( connectivity == 8 )
222 {
223 err = dx - (dy + dy);
224 plusDelta = dx + dx;
225 minusDelta = -(dy + dy);
226 minusShift = delta_x;
227 plusShift = 0;
228 minusStep = 0;
229 plusStep = delta_y;
230 count = dx + 1;
231 }
232 else /* connectivity == 4 */
233 {
234 err = 0;
235 plusDelta = (dx + dx) + (dy + dy);
236 minusDelta = -(dy + dy);
237 minusShift = delta_x;
238 plusShift = -delta_x;
239 minusStep = 0;
240 plusStep = delta_y;
241 count = dx + dy + 1;
242 }
243
244 if( vert )
245 {
246 std::swap(a&: plusStep, b&: plusShift);
247 std::swap(a&: minusStep, b&: minusShift);
248 }
249
250 p = pt1;
251 if( !ptmode )
252 {
253 ptr0 = img->ptr();
254 step = (int)img->step;
255 elemSize = (int)img->elemSize();
256 ptr = (uchar*)ptr0 + (size_t)p.y*step + (size_t)p.x*elemSize;
257 plusStep = plusStep*step + plusShift*elemSize;
258 minusStep = minusStep*step + minusShift*elemSize;
259 }
260}
261
262static void
263Line( Mat& img, Point pt1, Point pt2,
264 const void* _color, int connectivity = 8 )
265{
266 if( connectivity == 0 )
267 connectivity = 8;
268 else if( connectivity == 1 )
269 connectivity = 4;
270
271 LineIterator iterator(img, pt1, pt2, connectivity, true);
272 int i, count = iterator.count;
273 int pix_size = (int)img.elemSize();
274 const uchar* color = (const uchar*)_color;
275
276 if( pix_size == 3 )
277 {
278 for( i = 0; i < count; i++, ++iterator )
279 {
280 uchar* ptr = *iterator;
281 ptr[0] = color[0];
282 ptr[1] = color[1];
283 ptr[2] = color[2];
284 }
285 }
286 else
287 {
288 for( i = 0; i < count; i++, ++iterator )
289 {
290 uchar* ptr = *iterator;
291 if( pix_size == 1 )
292 ptr[0] = color[0];
293 else
294 memcpy( dest: *iterator, src: color, n: pix_size );
295 }
296 }
297}
298
299
300/* Correction table depent on the slope */
301static const uchar SlopeCorrTable[] = {
302 181, 181, 181, 182, 182, 183, 184, 185, 187, 188, 190, 192, 194, 196, 198, 201,
303 203, 206, 209, 211, 214, 218, 221, 224, 227, 231, 235, 238, 242, 246, 250, 254
304};
305
306/* Gaussian for antialiasing filter */
307static const int FilterTable[] = {
308 168, 177, 185, 194, 202, 210, 218, 224, 231, 236, 241, 246, 249, 252, 254, 254,
309 254, 254, 252, 249, 246, 241, 236, 231, 224, 218, 210, 202, 194, 185, 177, 168,
310 158, 149, 140, 131, 122, 114, 105, 97, 89, 82, 75, 68, 62, 56, 50, 45,
311 40, 36, 32, 28, 25, 22, 19, 16, 14, 12, 11, 9, 8, 7, 5, 5
312};
313
314static void
315LineAA( Mat& img, Point2l pt1, Point2l pt2, const void* color )
316{
317 int64 dx, dy;
318 int ecount, scount = 0;
319 int slope;
320 int64 ax, ay;
321 int64 x_step, y_step;
322 int64 i, j;
323 int ep_table[9];
324 int cb = ((uchar*)color)[0], cg = ((uchar*)color)[1], cr = ((uchar*)color)[2], ca = ((uchar*)color)[3];
325 int _cb, _cg, _cr, _ca;
326 int nch = img.channels();
327 uchar* ptr = img.ptr();
328 size_t step = img.step;
329 Size2l size0(img.size()), size = size0;
330
331 if( !((nch == 1 || nch == 3 || nch == 4) && img.depth() == CV_8U) )
332 {
333 Line(img, pt1: Point((int)(pt1.x>>XY_SHIFT), (int)(pt1.y>>XY_SHIFT)), pt2: Point((int)(pt2.x>>XY_SHIFT), (int)(pt2.y>>XY_SHIFT)), color: color);
334 return;
335 }
336
337 size.width <<= XY_SHIFT;
338 size.height <<= XY_SHIFT;
339 if( !clipLine( img_size: size, pt1, pt2 ))
340 return;
341
342 dx = pt2.x - pt1.x;
343 dy = pt2.y - pt1.y;
344
345 j = dx < 0 ? -1 : 0;
346 ax = (dx ^ j) - j;
347 i = dy < 0 ? -1 : 0;
348 ay = (dy ^ i) - i;
349
350 if( ax > ay )
351 {
352 dy = (dy ^ j) - j;
353 pt1.x ^= pt2.x & j;
354 pt2.x ^= pt1.x & j;
355 pt1.x ^= pt2.x & j;
356 pt1.y ^= pt2.y & j;
357 pt2.y ^= pt1.y & j;
358 pt1.y ^= pt2.y & j;
359
360 x_step = XY_ONE;
361 y_step = (int64)((uint64_t)dy << XY_SHIFT) / (ax | 1);
362 pt2.x += XY_ONE;
363 ecount = (int)((pt2.x >> XY_SHIFT) - (pt1.x >> XY_SHIFT));
364 j = -(pt1.x & (XY_ONE - 1));
365 pt1.y += ((y_step * j) >> XY_SHIFT) + (XY_ONE >> 1);
366 slope = (y_step >> (XY_SHIFT - 5)) & 0x3f;
367 slope ^= (y_step < 0 ? 0x3f : 0);
368
369 /* Get 4-bit fractions for end-point adjustments */
370 i = (pt1.x >> (XY_SHIFT - 7)) & 0x78;
371 j = (pt2.x >> (XY_SHIFT - 7)) & 0x78;
372 }
373 else
374 {
375 dx = (dx ^ i) - i;
376 pt1.x ^= pt2.x & i;
377 pt2.x ^= pt1.x & i;
378 pt1.x ^= pt2.x & i;
379 pt1.y ^= pt2.y & i;
380 pt2.y ^= pt1.y & i;
381 pt1.y ^= pt2.y & i;
382
383 x_step = (int64)((uint64_t)dx << XY_SHIFT) / (ay | 1);
384 y_step = XY_ONE;
385 pt2.y += XY_ONE;
386 ecount = (int)((pt2.y >> XY_SHIFT) - (pt1.y >> XY_SHIFT));
387 j = -(pt1.y & (XY_ONE - 1));
388 pt1.x += ((x_step * j) >> XY_SHIFT) + (XY_ONE >> 1);
389 slope = (x_step >> (XY_SHIFT - 5)) & 0x3f;
390 slope ^= (x_step < 0 ? 0x3f : 0);
391
392 /* Get 4-bit fractions for end-point adjustments */
393 i = (pt1.y >> (XY_SHIFT - 7)) & 0x78;
394 j = (pt2.y >> (XY_SHIFT - 7)) & 0x78;
395 }
396
397 slope = (slope & 0x20) ? 0x100 : SlopeCorrTable[slope];
398
399 /* Calc end point correction table */
400 {
401 int t0 = slope << 7;
402 int t1 = ((0x78 - (int)i) | 4) * slope;
403 int t2 = ((int)j | 4) * slope;
404
405 ep_table[0] = 0;
406 ep_table[8] = slope;
407 ep_table[1] = ep_table[3] = ((((j - i) & 0x78) | 4) * slope >> 8) & 0x1ff;
408 ep_table[2] = (t1 >> 8) & 0x1ff;
409 ep_table[4] = ((((j - i) + 0x80) | 4) * slope >> 8) & 0x1ff;
410 ep_table[5] = ((t1 + t0) >> 8) & 0x1ff;
411 ep_table[6] = (t2 >> 8) & 0x1ff;
412 ep_table[7] = ((t2 + t0) >> 8) & 0x1ff;
413 }
414
415 if( nch == 3 )
416 {
417 #define ICV_PUT_POINT(x, y) \
418 { \
419 uchar* tptr = ptr + (x)*3 + (y)*step; \
420 _cb = tptr[0]; \
421 _cb += ((cb - _cb)*a + 127)>> 8;\
422 _cb += ((cb - _cb)*a + 127)>> 8;\
423 _cg = tptr[1]; \
424 _cg += ((cg - _cg)*a + 127)>> 8;\
425 _cg += ((cg - _cg)*a + 127)>> 8;\
426 _cr = tptr[2]; \
427 _cr += ((cr - _cr)*a + 127)>> 8;\
428 _cr += ((cr - _cr)*a + 127)>> 8;\
429 tptr[0] = (uchar)_cb; \
430 tptr[1] = (uchar)_cg; \
431 tptr[2] = (uchar)_cr; \
432 }
433 if( ax > ay )
434 {
435 int x = (int)(pt1.x >> XY_SHIFT);
436
437 for( ; ecount >= 0; x++, pt1.y += y_step, scount++, ecount-- )
438 {
439 if( (unsigned)x >= (unsigned)size0.width )
440 continue;
441 int y = (int)((pt1.y >> XY_SHIFT) - 1);
442
443 int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
444 (((ecount >= 2) + 1) & (ecount | 2))];
445 int a, dist = (pt1.y >> (XY_SHIFT - 5)) & 31;
446
447 a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff;
448 if( (unsigned)y < (unsigned)size0.height )
449 ICV_PUT_POINT(x, y)
450
451 a = (ep_corr * FilterTable[dist] >> 8) & 0xff;
452 if( (unsigned)(y+1) < (unsigned)size0.height )
453 ICV_PUT_POINT(x, y+1)
454
455 a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff;
456 if( (unsigned)(y+2) < (unsigned)size0.height )
457 ICV_PUT_POINT(x, y+2)
458 }
459 }
460 else
461 {
462 int y = (int)(pt1.y >> XY_SHIFT);
463
464 for( ; ecount >= 0; y++, pt1.x += x_step, scount++, ecount-- )
465 {
466 if( (unsigned)y >= (unsigned)size0.height )
467 continue;
468 int x = (int)((pt1.x >> XY_SHIFT) - 1);
469 int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
470 (((ecount >= 2) + 1) & (ecount | 2))];
471 int a, dist = (pt1.x >> (XY_SHIFT - 5)) & 31;
472
473 a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff;
474 if( (unsigned)x < (unsigned)size0.width )
475 ICV_PUT_POINT(x, y)
476
477 a = (ep_corr * FilterTable[dist] >> 8) & 0xff;
478 if( (unsigned)(x+1) < (unsigned)size0.width )
479 ICV_PUT_POINT(x+1, y)
480
481 a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff;
482 if( (unsigned)(x+2) < (unsigned)size0.width )
483 ICV_PUT_POINT(x+2, y)
484 }
485 }
486 #undef ICV_PUT_POINT
487 }
488 else if(nch == 1)
489 {
490 #define ICV_PUT_POINT(x, y) \
491 { \
492 uchar* tptr = ptr + (x) + (y) * step; \
493 _cb = tptr[0]; \
494 _cb += ((cb - _cb)*a + 127)>> 8;\
495 _cb += ((cb - _cb)*a + 127)>> 8;\
496 tptr[0] = (uchar)_cb; \
497 }
498
499 if( ax > ay )
500 {
501 int x = (int)(pt1.x >> XY_SHIFT);
502
503 for( ; ecount >= 0; x++, pt1.y += y_step, scount++, ecount-- )
504 {
505 if( (unsigned)x >= (unsigned)size0.width )
506 continue;
507 int y = (int)((pt1.y >> XY_SHIFT) - 1);
508
509 int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
510 (((ecount >= 2) + 1) & (ecount | 2))];
511 int a, dist = (pt1.y >> (XY_SHIFT - 5)) & 31;
512
513 a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff;
514 if( (unsigned)y < (unsigned)size0.height )
515 ICV_PUT_POINT(x, y)
516
517 a = (ep_corr * FilterTable[dist] >> 8) & 0xff;
518 if( (unsigned)(y+1) < (unsigned)size0.height )
519 ICV_PUT_POINT(x, y+1)
520
521 a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff;
522 if( (unsigned)(y+2) < (unsigned)size0.height )
523 ICV_PUT_POINT(x, y+2)
524 }
525 }
526 else
527 {
528 int y = (int)(pt1.y >> XY_SHIFT);
529
530 for( ; ecount >= 0; y++, pt1.x += x_step, scount++, ecount-- )
531 {
532 if( (unsigned)y >= (unsigned)size0.height )
533 continue;
534 int x = (int)((pt1.x >> XY_SHIFT) - 1);
535 int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
536 (((ecount >= 2) + 1) & (ecount | 2))];
537 int a, dist = (pt1.x >> (XY_SHIFT - 5)) & 31;
538
539 a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff;
540 if( (unsigned)x < (unsigned)size0.width )
541 ICV_PUT_POINT(x, y)
542
543 a = (ep_corr * FilterTable[dist] >> 8) & 0xff;
544 if( (unsigned)(x+1) < (unsigned)size0.width )
545 ICV_PUT_POINT(x+1, y)
546
547 a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff;
548 if( (unsigned)(x+2) < (unsigned)size0.width )
549 ICV_PUT_POINT(x+2, y)
550 }
551 }
552 #undef ICV_PUT_POINT
553 }
554 else
555 {
556 #define ICV_PUT_POINT(x, y) \
557 { \
558 uchar* tptr = ptr + (x)*4 + (y)*step; \
559 _cb = tptr[0]; \
560 _cb += ((cb - _cb)*a + 127)>> 8;\
561 _cb += ((cb - _cb)*a + 127)>> 8;\
562 _cg = tptr[1]; \
563 _cg += ((cg - _cg)*a + 127)>> 8;\
564 _cg += ((cg - _cg)*a + 127)>> 8;\
565 _cr = tptr[2]; \
566 _cr += ((cr - _cr)*a + 127)>> 8;\
567 _cr += ((cr - _cr)*a + 127)>> 8;\
568 _ca = tptr[3]; \
569 _ca += ((ca - _ca)*a + 127)>> 8;\
570 _ca += ((ca - _ca)*a + 127)>> 8;\
571 tptr[0] = (uchar)_cb; \
572 tptr[1] = (uchar)_cg; \
573 tptr[2] = (uchar)_cr; \
574 tptr[3] = (uchar)_ca; \
575 }
576 if( ax > ay )
577 {
578 int x = (int)(pt1.x >> XY_SHIFT);
579
580 for( ; ecount >= 0; x++, pt1.y += y_step, scount++, ecount-- )
581 {
582 if( (unsigned)x >= (unsigned)size0.width )
583 continue;
584 int y = (int)((pt1.y >> XY_SHIFT) - 1);
585
586 int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
587 (((ecount >= 2) + 1) & (ecount | 2))];
588 int a, dist = (pt1.y >> (XY_SHIFT - 5)) & 31;
589
590 a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff;
591 if( (unsigned)y < (unsigned)size0.height )
592 ICV_PUT_POINT(x, y)
593
594 a = (ep_corr * FilterTable[dist] >> 8) & 0xff;
595 if( (unsigned)(y+1) < (unsigned)size0.height )
596 ICV_PUT_POINT(x, y+1)
597
598 a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff;
599 if( (unsigned)(y+2) < (unsigned)size0.height )
600 ICV_PUT_POINT(x, y+2)
601 }
602 }
603 else
604 {
605 int y = (int)(pt1.y >> XY_SHIFT);
606
607 for( ; ecount >= 0; y++, pt1.x += x_step, scount++, ecount-- )
608 {
609 if( (unsigned)y >= (unsigned)size0.height )
610 continue;
611 int x = (int)((pt1.x >> XY_SHIFT) - 1);
612 int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 +
613 (((ecount >= 2) + 1) & (ecount | 2))];
614 int a, dist = (pt1.x >> (XY_SHIFT - 5)) & 31;
615
616 a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff;
617 if( (unsigned)x < (unsigned)size0.width )
618 ICV_PUT_POINT(x, y)
619
620 a = (ep_corr * FilterTable[dist] >> 8) & 0xff;
621 if( (unsigned)(x+1) < (unsigned)size0.width )
622 ICV_PUT_POINT(x+1, y)
623
624 a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff;
625 if( (unsigned)(x+2) < (unsigned)size0.width )
626 ICV_PUT_POINT(x+2, y)
627 }
628 }
629 #undef ICV_PUT_POINT
630 }
631}
632
633
634static void
635Line2( Mat& img, Point2l pt1, Point2l pt2, const void* color)
636{
637 int64 dx, dy;
638 int ecount;
639 int64 ax, ay;
640 int64 i, j;
641 int x, y;
642 int64 x_step, y_step;
643 int cb = ((uchar*)color)[0];
644 int cg = ((uchar*)color)[1];
645 int cr = ((uchar*)color)[2];
646 int pix_size = (int)img.elemSize();
647 uchar *ptr = img.ptr(), *tptr;
648 size_t step = img.step;
649 Size size = img.size();
650
651 //CV_Assert( img && (nch == 1 || nch == 3) && img.depth() == CV_8U );
652
653 Size2l sizeScaled(((int64)size.width) << XY_SHIFT, ((int64)size.height) << XY_SHIFT);
654 if( !clipLine( img_size: sizeScaled, pt1, pt2 ))
655 return;
656
657 dx = pt2.x - pt1.x;
658 dy = pt2.y - pt1.y;
659
660 j = dx < 0 ? -1 : 0;
661 ax = (dx ^ j) - j;
662 i = dy < 0 ? -1 : 0;
663 ay = (dy ^ i) - i;
664
665 if( ax > ay )
666 {
667 dy = (dy ^ j) - j;
668 pt1.x ^= pt2.x & j;
669 pt2.x ^= pt1.x & j;
670 pt1.x ^= pt2.x & j;
671 pt1.y ^= pt2.y & j;
672 pt2.y ^= pt1.y & j;
673 pt1.y ^= pt2.y & j;
674
675 x_step = XY_ONE;
676 y_step = dy * (1 << XY_SHIFT) / (ax | 1);
677 ecount = (int)((pt2.x - pt1.x) >> XY_SHIFT);
678 }
679 else
680 {
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 = dx * (1 << XY_SHIFT) / (ay | 1);
690 y_step = XY_ONE;
691 ecount = (int)((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((int)((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT),
711 (int)((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((int)(pt1.x), (int)(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((int)(pt1.x >> XY_SHIFT), (int)(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((int)((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT),
752 (int)((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((int)(pt1.x), (int)(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((int)(pt1.x >> XY_SHIFT), (int)(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((int)((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT),
794 (int)((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((int)(pt1.x), (int)(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((int)(pt1.x >> XY_SHIFT), (int)(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
830static 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
910static void
911sincos( 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*/
921void ellipse2Poly( Point center, Size axes, int angle,
922 int arcStart, int arcEnd,
923 int delta, CV_OUT std::vector<Point>& pts )
924{
925 std::vector<Point2d> _pts;
926 ellipse2Poly(center: Point2d(center.x, center.y), axes: Size2d(axes.width, axes.height), angle,
927 arcStart, arcEnd, delta, pts&: _pts);
928 Point prevPt(INT_MIN, INT_MIN);
929 pts.resize(new_size: 0);
930 for (unsigned int i = 0; i < _pts.size(); ++i)
931 {
932 Point pt;
933 pt.x = cvRound(value: _pts[i].x);
934 pt.y = cvRound(value: _pts[i].y);
935 if (pt != prevPt) {
936 pts.push_back(x: pt);
937 prevPt = pt;
938 }
939 }
940
941 // If there are no points, it's a zero-size polygon
942 CV_Assert( !pts.empty() );
943 if (pts.size() == 1) {
944 pts.assign(n: 2, val: center);
945 }
946}
947
948void ellipse2Poly( Point2d center, Size2d axes, int angle,
949 int arc_start, int arc_end,
950 int delta, std::vector<Point2d>& pts )
951{
952 CV_INSTRUMENT_REGION();
953 CV_Assert(0 < delta && delta <= 180);
954
955 float alpha, beta;
956 int i;
957
958 while( angle < 0 )
959 angle += 360;
960 while( angle > 360 )
961 angle -= 360;
962
963 if( arc_start > arc_end )
964 {
965 i = arc_start;
966 arc_start = arc_end;
967 arc_end = i;
968 }
969 while( arc_start < 0 )
970 {
971 arc_start += 360;
972 arc_end += 360;
973 }
974 while( arc_end > 360 )
975 {
976 arc_end -= 360;
977 arc_start -= 360;
978 }
979 if( arc_end - arc_start > 360 )
980 {
981 arc_start = 0;
982 arc_end = 360;
983 }
984 sincos( angle, cosval&: alpha, sinval&: beta );
985 pts.resize(new_size: 0);
986
987 for( i = arc_start; i < arc_end + delta; i += delta )
988 {
989 double x, y;
990 angle = i;
991 if( angle > arc_end )
992 angle = arc_end;
993 if( angle < 0 )
994 angle += 360;
995
996 x = axes.width * SinTable[450-angle];
997 y = axes.height * SinTable[angle];
998 Point2d pt;
999 pt.x = center.x + x * alpha - y * beta;
1000 pt.y = center.y + x * beta + y * alpha;
1001 pts.push_back(x: pt);
1002 }
1003
1004 // If there are no points, it's a zero-size polygon
1005 CV_Assert( !pts.empty() );
1006 if( pts.size() == 1) {
1007 pts.assign(n: 2,val: center);
1008 }
1009}
1010
1011
1012static void
1013EllipseEx( Mat& img, Point2l center, Size2l axes,
1014 int angle, int arc_start, int arc_end,
1015 const void* color, int thickness, int line_type )
1016{
1017 axes.width = std::abs(i: axes.width), axes.height = std::abs(i: axes.height);
1018 int delta = (int)((std::max(a: axes.width,b: axes.height)+(XY_ONE>>1))>>XY_SHIFT);
1019 delta = delta < 3 ? 90 : delta < 10 ? 30 : delta < 15 ? 18 : 5;
1020
1021 std::vector<Point2d> _v;
1022 ellipse2Poly( center: Point2d((double)center.x, (double)center.y), axes: Size2d((double)axes.width, (double)axes.height), angle, arc_start, arc_end, delta, pts&: _v );
1023
1024 std::vector<Point2l> v;
1025 Point2l prevPt(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF);
1026 for (unsigned int i = 0; i < _v.size(); ++i)
1027 {
1028 Point2l pt;
1029 pt.x = (int64)cvRound(value: _v[i].x / static_cast<double>(XY_ONE)) << XY_SHIFT;
1030 pt.y = (int64)cvRound(value: _v[i].y / static_cast<double>(XY_ONE)) << XY_SHIFT;
1031 pt.x += cvRound(value: _v[i].x - pt.x);
1032 pt.y += cvRound(value: _v[i].y - pt.y);
1033 if (pt != prevPt) {
1034 v.push_back(x: pt);
1035 prevPt = pt;
1036 }
1037 }
1038
1039 // If there are no points, it's a zero-size polygon
1040 if (v.size() <= 1) {
1041 v.assign(n: 2, val: center);
1042 }
1043
1044 if( thickness >= 0 )
1045 PolyLine( img, v: &v[0], npts: (int)v.size(), closed: false, color, thickness, line_type, shift: XY_SHIFT );
1046 else if( arc_end - arc_start >= 360 )
1047 FillConvexPoly( img, v: &v[0], npts: (int)v.size(), color, line_type, shift: XY_SHIFT );
1048 else
1049 {
1050 v.push_back(x: center);
1051 std::vector<PolyEdge> edges;
1052 CollectPolyEdges( img, v: &v[0], npts: (int)v.size(), edges, color, line_type, shift: XY_SHIFT );
1053 FillEdgeCollection( img, edges, color );
1054 }
1055}
1056
1057
1058/****************************************************************************************\
1059* Polygons filling *
1060\****************************************************************************************/
1061
1062static inline void ICV_HLINE_X(uchar* ptr, int64_t xl, int64_t xr, const uchar* color, int pix_size)
1063{
1064 uchar* hline_min_ptr = (uchar*)(ptr) + (xl)*(pix_size);
1065 uchar* hline_end_ptr = (uchar*)(ptr) + (xr+1)*(pix_size);
1066 uchar* hline_ptr = hline_min_ptr;
1067 if (pix_size == 1)
1068 memset(s: hline_min_ptr, c: *color, n: hline_end_ptr-hline_min_ptr);
1069 else//if (pix_size != 1)
1070 {
1071 if (hline_min_ptr < hline_end_ptr)
1072 {
1073 memcpy(dest: hline_ptr, src: color, n: pix_size);
1074 hline_ptr += pix_size;
1075 }//end if (hline_min_ptr < hline_end_ptr)
1076 size_t sizeToCopy = pix_size;
1077 while(hline_ptr < hline_end_ptr)
1078 {
1079 memcpy(dest: hline_ptr, src: hline_min_ptr, n: sizeToCopy);
1080 hline_ptr += sizeToCopy;
1081 sizeToCopy = std::min(a: 2*sizeToCopy, b: static_cast<size_t>(hline_end_ptr-hline_ptr));
1082 }//end while(hline_ptr < hline_end_ptr)
1083 }//end if (pix_size != 1)
1084}
1085//end ICV_HLINE_X()
1086
1087static inline void ICV_HLINE(uchar* ptr, int64_t xl, int64_t xr, const void* color, int pix_size)
1088{
1089 ICV_HLINE_X(ptr, xl, xr, color: reinterpret_cast<const uchar*>(color), pix_size);
1090}
1091//end ICV_HLINE()
1092
1093/* filling convex polygon. v - array of vertices, ntps - number of points */
1094static void
1095FillConvexPoly( Mat& img, const Point2l* v, int npts, const void* color, int line_type, int shift )
1096{
1097 struct
1098 {
1099 int idx, di;
1100 int64 x, dx;
1101 int ye;
1102 }
1103 edge[2];
1104
1105 int delta = 1 << shift >> 1;
1106 int i, y, imin = 0;
1107 int edges = npts;
1108 int64 xmin, xmax, ymin, ymax;
1109 uchar* ptr = img.ptr();
1110 Size size = img.size();
1111 int pix_size = (int)img.elemSize();
1112 Point2l p0;
1113 int delta1, delta2;
1114
1115 if( line_type < cv::LINE_AA )
1116 delta1 = delta2 = XY_ONE >> 1;
1117 else
1118 delta1 = XY_ONE - 1, delta2 = 0;
1119
1120 p0 = v[npts - 1];
1121 p0.x <<= XY_SHIFT - shift;
1122 p0.y <<= XY_SHIFT - shift;
1123
1124 CV_Assert( 0 <= shift && shift <= XY_SHIFT );
1125 xmin = xmax = v[0].x;
1126 ymin = ymax = v[0].y;
1127
1128 for( i = 0; i < npts; i++ )
1129 {
1130 Point2l p = v[i];
1131 if( p.y < ymin )
1132 {
1133 ymin = p.y;
1134 imin = i;
1135 }
1136
1137 ymax = std::max( a: ymax, b: p.y );
1138 xmax = std::max( a: xmax, b: p.x );
1139 xmin = MIN( xmin, p.x );
1140
1141 p.x <<= XY_SHIFT - shift;
1142 p.y <<= XY_SHIFT - shift;
1143
1144 if( line_type <= 8 )
1145 {
1146 if( shift == 0 )
1147 {
1148 Point pt0, pt1;
1149 pt0.x = (int)(p0.x >> XY_SHIFT);
1150 pt0.y = (int)(p0.y >> XY_SHIFT);
1151 pt1.x = (int)(p.x >> XY_SHIFT);
1152 pt1.y = (int)(p.y >> XY_SHIFT);
1153 Line( img, pt1: pt0, pt2: pt1, color: color, connectivity: line_type );
1154 }
1155 else
1156 Line2( img, pt1: p0, pt2: p, color );
1157 }
1158 else
1159 LineAA( img, pt1: p0, pt2: p, color );
1160 p0 = p;
1161 }
1162
1163 xmin = (xmin + delta) >> shift;
1164 xmax = (xmax + delta) >> shift;
1165 ymin = (ymin + delta) >> shift;
1166 ymax = (ymax + delta) >> shift;
1167
1168 if( npts < 3 || (int)xmax < 0 || (int)ymax < 0 || (int)xmin >= size.width || (int)ymin >= size.height )
1169 return;
1170
1171 ymax = MIN( ymax, size.height - 1 );
1172 edge[0].idx = edge[1].idx = imin;
1173
1174 edge[0].ye = edge[1].ye = y = (int)ymin;
1175 edge[0].di = 1;
1176 edge[1].di = npts - 1;
1177
1178 edge[0].x = edge[1].x = -XY_ONE;
1179 edge[0].dx = edge[1].dx = 0;
1180
1181 ptr += (int64_t)img.step*y;
1182
1183 do
1184 {
1185 if( line_type < cv::LINE_AA || y < (int)ymax || y == (int)ymin )
1186 {
1187 for( i = 0; i < 2; i++ )
1188 {
1189 if( y >= edge[i].ye )
1190 {
1191 int idx0 = edge[i].idx, di = edge[i].di;
1192 int idx = idx0 + di;
1193 if (idx >= npts) idx -= npts;
1194 int ty = 0;
1195
1196 for (; edges-- > 0; )
1197 {
1198 ty = (int)((v[idx].y + delta) >> shift);
1199 if (ty > y)
1200 {
1201 int64 xs = v[idx0].x;
1202 int64 xe = v[idx].x;
1203 if (shift != XY_SHIFT)
1204 {
1205 xs <<= XY_SHIFT - shift;
1206 xe <<= XY_SHIFT - shift;
1207 }
1208
1209 edge[i].ye = ty;
1210 edge[i].dx = ((xe - xs)*2 + ((int64_t)ty - y)) / (2 * ((int64_t)ty - y));
1211 edge[i].x = xs;
1212 edge[i].idx = idx;
1213 break;
1214 }
1215 idx0 = idx;
1216 idx += di;
1217 if (idx >= npts) idx -= npts;
1218 }
1219 }
1220 }
1221 }
1222
1223 if (edges < 0)
1224 break;
1225
1226 if (y >= 0)
1227 {
1228 int left = 0, right = 1;
1229 if (edge[0].x > edge[1].x)
1230 {
1231 left = 1, right = 0;
1232 }
1233
1234 int xx1 = (int)((edge[left].x + delta1) >> XY_SHIFT);
1235 int xx2 = (int)((edge[right].x + delta2) >> XY_SHIFT);
1236
1237 if( xx2 >= 0 && xx1 < size.width )
1238 {
1239 if( xx1 < 0 )
1240 xx1 = 0;
1241 if( xx2 >= size.width )
1242 xx2 = size.width - 1;
1243 ICV_HLINE( ptr, xl: xx1, xr: xx2, color, pix_size );
1244 }
1245 }
1246 else
1247 {
1248 // TODO optimize scan for negative y
1249 }
1250
1251 edge[0].x += edge[0].dx;
1252 edge[1].x += edge[1].dx;
1253 ptr += img.step;
1254 }
1255 while( ++y <= (int)ymax );
1256}
1257
1258
1259/******** Arbitrary polygon **********/
1260
1261static void
1262CollectPolyEdges( Mat& img, const Point2l* v, int count, std::vector<PolyEdge>& edges,
1263 const void* color, int line_type, int shift, Point offset )
1264{
1265 int i, delta = offset.y + ((1 << shift) >> 1);
1266 Point2l pt0 = v[count-1], pt1;
1267 pt0.x = (pt0.x + offset.x) << (XY_SHIFT - shift);
1268 pt0.y = (pt0.y + delta) >> shift;
1269
1270 edges.reserve( n: edges.size() + count );
1271
1272 for( i = 0; i < count; i++, pt0 = pt1 )
1273 {
1274 Point2l t0, t1;
1275 PolyEdge edge;
1276
1277 pt1 = v[i];
1278 pt1.x = (pt1.x + offset.x) << (XY_SHIFT - shift);
1279 pt1.y = (pt1.y + delta) >> shift;
1280
1281 Point2l pt0c(pt0), pt1c(pt1);
1282
1283 if (line_type < cv::LINE_AA)
1284 {
1285 t0.y = pt0.y; t1.y = pt1.y;
1286 t0.x = (pt0.x + (XY_ONE >> 1)) >> XY_SHIFT;
1287 t1.x = (pt1.x + (XY_ONE >> 1)) >> XY_SHIFT;
1288 Line(img, pt1: t0, pt2: t1, color: color, connectivity: line_type);
1289
1290 // use clipped endpoints to create a more accurate PolyEdge
1291 if ((unsigned)t0.x >= (unsigned)(img.cols) ||
1292 (unsigned)t1.x >= (unsigned)(img.cols) ||
1293 (unsigned)t0.y >= (unsigned)(img.rows) ||
1294 (unsigned)t1.y >= (unsigned)(img.rows))
1295 {
1296 clipLine(img_size: img.size(), pt1&: t0, pt2&: t1);
1297
1298 if (t0.y != t1.y)
1299 {
1300 pt0c.y = t0.y; pt1c.y = t1.y;
1301 }
1302 }
1303
1304 pt0c.x = (int64)(t0.x) << XY_SHIFT;
1305 pt1c.x = (int64)(t1.x) << XY_SHIFT;
1306 }
1307 else
1308 {
1309 t0.x = pt0.x; t1.x = pt1.x;
1310 t0.y = pt0.y << XY_SHIFT;
1311 t1.y = pt1.y << XY_SHIFT;
1312 LineAA(img, pt1: t0, pt2: t1, color);
1313 }
1314
1315 if (pt0.y == pt1.y)
1316 continue;
1317
1318 edge.dx = (pt1c.x - pt0c.x) / (pt1c.y - pt0c.y);
1319 if (pt0.y < pt1.y)
1320 {
1321 edge.y0 = (int)(pt0.y);
1322 edge.y1 = (int)(pt1.y);
1323 edge.x = pt0c.x + (pt0.y - pt0c.y) * edge.dx; // correct starting point for clipped lines
1324 }
1325 else
1326 {
1327 edge.y0 = (int)(pt1.y);
1328 edge.y1 = (int)(pt0.y);
1329 edge.x = pt1c.x + (pt1.y - pt1c.y) * edge.dx; // correct starting point for clipped lines
1330 }
1331 edges.push_back(x: edge);
1332 }
1333}
1334
1335struct CmpEdges
1336{
1337 bool operator ()(const PolyEdge& e1, const PolyEdge& e2)
1338 {
1339 return e1.y0 - e2.y0 ? e1.y0 < e2.y0 :
1340 e1.x - e2.x ? e1.x < e2.x : e1.dx < e2.dx;
1341 }
1342};
1343
1344/**************** helper macros and functions for sequence/contour processing ***********/
1345
1346static void
1347FillEdgeCollection( Mat& img, std::vector<PolyEdge>& edges, const void* color )
1348{
1349 PolyEdge tmp;
1350 int i, y, total = (int)edges.size();
1351 Size size = img.size();
1352 PolyEdge* e;
1353 int y_max = INT_MIN, y_min = INT_MAX;
1354 int64 x_max = 0xFFFFFFFFFFFFFFFF, x_min = 0x7FFFFFFFFFFFFFFF;
1355 int pix_size = (int)img.elemSize();
1356 int delta = XY_ONE - 1;
1357
1358 if( total < 2 )
1359 return;
1360
1361 for( i = 0; i < total; i++ )
1362 {
1363 PolyEdge& e1 = edges[i];
1364 CV_Assert( e1.y0 < e1.y1 );
1365 // Determine x-coordinate of the end of the edge.
1366 // (This is not necessary x-coordinate of any vertex in the array.)
1367 int64 x1 = e1.x + (e1.y1 - e1.y0) * e1.dx;
1368 y_min = std::min( a: y_min, b: e1.y0 );
1369 y_max = std::max( a: y_max, b: e1.y1 );
1370 x_min = std::min( a: x_min, b: e1.x );
1371 x_max = std::max( a: x_max, b: e1.x );
1372 x_min = std::min( a: x_min, b: x1 );
1373 x_max = std::max( a: x_max, b: x1 );
1374 }
1375
1376 if( y_max < 0 || y_min >= size.height || x_max < 0 || x_min >= ((int64)size.width<<XY_SHIFT) )
1377 return;
1378
1379 std::sort( first: edges.begin(), last: edges.end(), comp: CmpEdges() );
1380
1381 // start drawing
1382 tmp.y0 = INT_MAX;
1383 edges.push_back(x: tmp); // after this point we do not add
1384 // any elements to edges, thus we can use pointers
1385 i = 0;
1386 tmp.next = 0;
1387 e = &edges[i];
1388 y_max = MIN( y_max, size.height );
1389
1390 for( y = e->y0; y < y_max; y++ )
1391 {
1392 PolyEdge *last, *prelast, *keep_prelast;
1393 int draw = 0;
1394 int clipline = y < 0;
1395
1396 prelast = &tmp;
1397 last = tmp.next;
1398 while( last || e->y0 == y )
1399 {
1400 if( last && last->y1 == y )
1401 {
1402 // exclude edge if y reaches its lower point
1403 prelast->next = last->next;
1404 last = last->next;
1405 continue;
1406 }
1407 keep_prelast = prelast;
1408 if( last && (e->y0 > y || last->x < e->x) )
1409 {
1410 // go to the next edge in active list
1411 prelast = last;
1412 last = last->next;
1413 }
1414 else if( i < total )
1415 {
1416 // insert new edge into active list if y reaches its upper point
1417 prelast->next = e;
1418 e->next = last;
1419 prelast = e;
1420 e = &edges[++i];
1421 }
1422 else
1423 break;
1424
1425 if( draw )
1426 {
1427 if( !clipline )
1428 {
1429 // convert x's from fixed-point to image coordinates
1430 uchar *timg = img.ptr(y);
1431 int x1, x2;
1432
1433 if (keep_prelast->x > prelast->x)
1434 {
1435 x1 = (int)((prelast->x + delta) >> XY_SHIFT);
1436 x2 = (int)(keep_prelast->x >> XY_SHIFT);
1437 }
1438 else
1439 {
1440 x1 = (int)((keep_prelast->x + delta) >> XY_SHIFT);
1441 x2 = (int)(prelast->x >> XY_SHIFT);
1442 }
1443
1444 // clip and draw the line
1445 if( x1 < size.width && x2 >= 0 )
1446 {
1447 if( x1 < 0 )
1448 x1 = 0;
1449 if( x2 >= size.width )
1450 x2 = size.width - 1;
1451 ICV_HLINE( ptr: timg, xl: x1, xr: x2, color, pix_size );
1452 }
1453 }
1454 keep_prelast->x += keep_prelast->dx;
1455 prelast->x += prelast->dx;
1456 }
1457 draw ^= 1;
1458 }
1459
1460 // sort edges (using bubble sort)
1461 keep_prelast = 0;
1462
1463 do
1464 {
1465 prelast = &tmp;
1466 last = tmp.next;
1467 PolyEdge *last_exchange = 0;
1468
1469 while( last != keep_prelast && last->next != 0 )
1470 {
1471 PolyEdge *te = last->next;
1472
1473 // swap edges
1474 if( last->x > te->x )
1475 {
1476 prelast->next = te;
1477 last->next = te->next;
1478 te->next = last;
1479 prelast = te;
1480 last_exchange = prelast;
1481 }
1482 else
1483 {
1484 prelast = last;
1485 last = te;
1486 }
1487 }
1488 if (last_exchange == NULL)
1489 break;
1490 keep_prelast = last_exchange;
1491 } while( keep_prelast != tmp.next && keep_prelast != &tmp );
1492 }
1493}
1494
1495
1496/* draws simple or filled circle */
1497static void
1498Circle( Mat& img, Point center, int radius, const void* color, int fill )
1499{
1500 Size size = img.size();
1501 size_t step = img.step;
1502 int pix_size = (int)img.elemSize();
1503 uchar* ptr = img.ptr();
1504 int64_t err = 0, dx = radius, dy = 0, plus = 1, minus = (radius << 1) - 1;
1505 int inside = center.x >= radius && center.x < size.width - radius &&
1506 center.y >= radius && center.y < size.height - radius;
1507
1508 #define ICV_PUT_POINT( ptr, x ) \
1509 memcpy( ptr + (x)*pix_size, color, pix_size );
1510
1511 while( dx >= dy )
1512 {
1513 int mask;
1514 int64_t y11 = center.y - dy, y12 = center.y + dy, y21 = center.y - dx, y22 = center.y + dx;
1515 int64_t x11 = center.x - dx, x12 = center.x + dx, x21 = center.x - dy, x22 = center.x + dy;
1516
1517 if( inside )
1518 {
1519 uchar *tptr0 = ptr + y11 * step;
1520 uchar *tptr1 = ptr + y12 * step;
1521
1522 if( !fill )
1523 {
1524 ICV_PUT_POINT( tptr0, x11 );
1525 ICV_PUT_POINT( tptr1, x11 );
1526 ICV_PUT_POINT( tptr0, x12 );
1527 ICV_PUT_POINT( tptr1, x12 );
1528 }
1529 else
1530 {
1531 ICV_HLINE( ptr: tptr0, xl: x11, xr: x12, color, pix_size );
1532 ICV_HLINE( ptr: tptr1, xl: x11, xr: x12, color, pix_size );
1533 }
1534
1535 tptr0 = ptr + y21 * step;
1536 tptr1 = ptr + y22 * step;
1537
1538 if( !fill )
1539 {
1540 ICV_PUT_POINT( tptr0, x21 );
1541 ICV_PUT_POINT( tptr1, x21 );
1542 ICV_PUT_POINT( tptr0, x22 );
1543 ICV_PUT_POINT( tptr1, x22 );
1544 }
1545 else
1546 {
1547 ICV_HLINE( ptr: tptr0, xl: x21, xr: x22, color, pix_size );
1548 ICV_HLINE( ptr: tptr1, xl: x21, xr: x22, color, pix_size );
1549 }
1550 }
1551 else if( x11 < size.width && x12 >= 0 && y21 < size.height && y22 >= 0)
1552 {
1553 if( fill )
1554 {
1555 x11 = std::max( a: x11, b: (int64_t)0 );
1556 x12 = MIN( x12, size.width - 1 );
1557 }
1558
1559 if( y11 >= 0 && y11 < size.height )
1560 {
1561 uchar *tptr = ptr + y11 * step;
1562
1563 if( !fill )
1564 {
1565 if( x11 >= 0 )
1566 ICV_PUT_POINT( tptr, x11 );
1567 if( x12 < size.width )
1568 ICV_PUT_POINT( tptr, x12 );
1569 }
1570 else
1571 ICV_HLINE( ptr: tptr, xl: x11, xr: x12, color, pix_size );
1572 }
1573
1574 if( y12 >= 0 && y12 < size.height )
1575 {
1576 uchar *tptr = ptr + y12 * step;
1577
1578 if( !fill )
1579 {
1580 if( x11 >= 0 )
1581 ICV_PUT_POINT( tptr, x11 );
1582 if( x12 < size.width )
1583 ICV_PUT_POINT( tptr, x12 );
1584 }
1585 else
1586 ICV_HLINE( ptr: tptr, xl: x11, xr: x12, color, pix_size );
1587 }
1588
1589 if( x21 < size.width && x22 >= 0 )
1590 {
1591 if( fill )
1592 {
1593 x21 = std::max( a: x21, b: (int64_t)0 );
1594 x22 = MIN( x22, size.width - 1 );
1595 }
1596
1597 if( y21 >= 0 && y21 < size.height )
1598 {
1599 uchar *tptr = ptr + y21 * step;
1600
1601 if( !fill )
1602 {
1603 if( x21 >= 0 )
1604 ICV_PUT_POINT( tptr, x21 );
1605 if( x22 < size.width )
1606 ICV_PUT_POINT( tptr, x22 );
1607 }
1608 else
1609 ICV_HLINE( ptr: tptr, xl: x21, xr: x22, color, pix_size );
1610 }
1611
1612 if( y22 >= 0 && y22 < size.height )
1613 {
1614 uchar *tptr = ptr + y22 * step;
1615
1616 if( !fill )
1617 {
1618 if( x21 >= 0 )
1619 ICV_PUT_POINT( tptr, x21 );
1620 if( x22 < size.width )
1621 ICV_PUT_POINT( tptr, x22 );
1622 }
1623 else
1624 ICV_HLINE( ptr: tptr, xl: x21, xr: x22, color, pix_size );
1625 }
1626 }
1627 }
1628 dy++;
1629 err += plus;
1630 plus += 2;
1631
1632 mask = (err <= 0) - 1;
1633
1634 err -= minus & mask;
1635 dx += mask;
1636 minus -= mask & 2;
1637 }
1638
1639 #undef ICV_PUT_POINT
1640}
1641
1642
1643static void
1644ThickLine( Mat& img, Point2l p0, Point2l p1, const void* color,
1645 int thickness, int line_type, int flags, int shift )
1646{
1647 static const double INV_XY_ONE = 1./static_cast<double>(XY_ONE);
1648
1649 p0.x <<= XY_SHIFT - shift;
1650 p0.y <<= XY_SHIFT - shift;
1651 p1.x <<= XY_SHIFT - shift;
1652 p1.y <<= XY_SHIFT - shift;
1653
1654 if( thickness <= 1 )
1655 {
1656 if( line_type < cv::LINE_AA )
1657 {
1658 if( line_type == 1 || line_type == 4 || shift == 0 )
1659 {
1660 p0.x = (p0.x + (XY_ONE>>1)) >> XY_SHIFT;
1661 p0.y = (p0.y + (XY_ONE>>1)) >> XY_SHIFT;
1662 p1.x = (p1.x + (XY_ONE>>1)) >> XY_SHIFT;
1663 p1.y = (p1.y + (XY_ONE>>1)) >> XY_SHIFT;
1664 Line( img, pt1: p0, pt2: p1, color: color, connectivity: line_type );
1665 }
1666 else
1667 Line2( img, pt1: p0, pt2: p1, color );
1668 }
1669 else
1670 LineAA( img, pt1: p0, pt2: p1, color );
1671 }
1672 else
1673 {
1674 Point2l pt[4], dp = Point2l(0,0);
1675 double dx = (p0.x - p1.x)*INV_XY_ONE, dy = (p1.y - p0.y)*INV_XY_ONE;
1676 double r = dx * dx + dy * dy;
1677 int i, oddThickness = thickness & 1;
1678 thickness <<= XY_SHIFT - 1;
1679
1680 if( fabs(x: r) > DBL_EPSILON )
1681 {
1682 r = (thickness + oddThickness*XY_ONE*0.5)/std::sqrt(x: r);
1683 dp.x = cvRound( value: dy * r );
1684 dp.y = cvRound( value: dx * r );
1685
1686 pt[0].x = p0.x + dp.x;
1687 pt[0].y = p0.y + dp.y;
1688 pt[1].x = p0.x - dp.x;
1689 pt[1].y = p0.y - dp.y;
1690 pt[2].x = p1.x - dp.x;
1691 pt[2].y = p1.y - dp.y;
1692 pt[3].x = p1.x + dp.x;
1693 pt[3].y = p1.y + dp.y;
1694
1695 FillConvexPoly( img, v: pt, npts: 4, color, line_type, shift: XY_SHIFT );
1696 }
1697
1698 for( i = 0; i < 2; i++ )
1699 {
1700 if( flags & (i+1) )
1701 {
1702 if( line_type < cv::LINE_AA )
1703 {
1704 Point center;
1705 center.x = (int)((p0.x + (XY_ONE>>1)) >> XY_SHIFT);
1706 center.y = (int)((p0.y + (XY_ONE>>1)) >> XY_SHIFT);
1707 Circle( img, center, radius: (thickness + (XY_ONE>>1)) >> XY_SHIFT, color, fill: 1 );
1708 }
1709 else
1710 {
1711 EllipseEx( img, center: p0, axes: Size2l(thickness, thickness),
1712 angle: 0, arc_start: 0, arc_end: 360, color, thickness: -1, line_type );
1713 }
1714 }
1715 p0 = p1;
1716 }
1717 }
1718}
1719
1720
1721static void
1722PolyLine( Mat& img, const Point2l* v, int count, bool is_closed,
1723 const void* color, int thickness,
1724 int line_type, int shift )
1725{
1726 if( !v || count <= 0 )
1727 return;
1728
1729 int i = is_closed ? count - 1 : 0;
1730 int flags = 2 + !is_closed;
1731 Point2l p0;
1732 CV_Assert( 0 <= shift && shift <= XY_SHIFT && thickness >= 0 );
1733
1734 p0 = v[i];
1735 for( i = !is_closed; i < count; i++ )
1736 {
1737 Point2l p = v[i];
1738 ThickLine( img, p0, p1: p, color, thickness, line_type, flags, shift );
1739 p0 = p;
1740 flags = 2;
1741 }
1742}
1743
1744/* ----------------------------------------------------------------------------------------- */
1745/* ADDING A SET OF PREDEFINED MARKERS WHICH COULD BE USED TO HIGHLIGHT POSITIONS IN AN IMAGE */
1746/* ----------------------------------------------------------------------------------------- */
1747
1748void drawMarker(InputOutputArray img, Point position, const Scalar& color, int markerType, int markerSize, int thickness, int line_type)
1749{
1750 switch(markerType)
1751 {
1752 // The cross marker case
1753 case MARKER_CROSS:
1754 line(img, pt1: Point(position.x-(markerSize/2), position.y), pt2: Point(position.x+(markerSize/2), position.y), color, thickness, lineType: line_type);
1755 line(img, pt1: Point(position.x, position.y-(markerSize/2)), pt2: Point(position.x, position.y+(markerSize/2)), color, thickness, lineType: line_type);
1756 break;
1757
1758 // The tilted cross marker case
1759 case MARKER_TILTED_CROSS:
1760 line(img, pt1: Point(position.x-(markerSize/2), position.y-(markerSize/2)), pt2: Point(position.x+(markerSize/2), position.y+(markerSize/2)), color, thickness, lineType: line_type);
1761 line(img, pt1: Point(position.x+(markerSize/2), position.y-(markerSize/2)), pt2: Point(position.x-(markerSize/2), position.y+(markerSize/2)), color, thickness, lineType: line_type);
1762 break;
1763
1764 // The star marker case
1765 case MARKER_STAR:
1766 line(img, pt1: Point(position.x-(markerSize/2), position.y), pt2: Point(position.x+(markerSize/2), position.y), color, thickness, lineType: line_type);
1767 line(img, pt1: Point(position.x, position.y-(markerSize/2)), pt2: Point(position.x, position.y+(markerSize/2)), color, thickness, lineType: line_type);
1768 line(img, pt1: Point(position.x-(markerSize/2), position.y-(markerSize/2)), pt2: Point(position.x+(markerSize/2), position.y+(markerSize/2)), color, thickness, lineType: line_type);
1769 line(img, pt1: Point(position.x+(markerSize/2), position.y-(markerSize/2)), pt2: Point(position.x-(markerSize/2), position.y+(markerSize/2)), color, thickness, lineType: line_type);
1770 break;
1771
1772 // The diamond marker case
1773 case MARKER_DIAMOND:
1774 line(img, pt1: Point(position.x, position.y-(markerSize/2)), pt2: Point(position.x+(markerSize/2), position.y), color, thickness, lineType: line_type);
1775 line(img, pt1: Point(position.x+(markerSize/2), position.y), pt2: Point(position.x, position.y+(markerSize/2)), color, thickness, lineType: line_type);
1776 line(img, pt1: Point(position.x, position.y+(markerSize/2)), pt2: Point(position.x-(markerSize/2), position.y), color, thickness, lineType: line_type);
1777 line(img, pt1: Point(position.x-(markerSize/2), position.y), pt2: Point(position.x, position.y-(markerSize/2)), color, thickness, lineType: line_type);
1778 break;
1779
1780 // The square marker case
1781 case MARKER_SQUARE:
1782 line(img, pt1: Point(position.x-(markerSize/2), position.y-(markerSize/2)), pt2: Point(position.x+(markerSize/2), position.y-(markerSize/2)), color, thickness, lineType: line_type);
1783 line(img, pt1: Point(position.x+(markerSize/2), position.y-(markerSize/2)), pt2: Point(position.x+(markerSize/2), position.y+(markerSize/2)), color, thickness, lineType: line_type);
1784 line(img, pt1: Point(position.x+(markerSize/2), position.y+(markerSize/2)), pt2: Point(position.x-(markerSize/2), position.y+(markerSize/2)), color, thickness, lineType: line_type);
1785 line(img, pt1: Point(position.x-(markerSize/2), position.y+(markerSize/2)), pt2: Point(position.x-(markerSize/2), position.y-(markerSize/2)), color, thickness, lineType: line_type);
1786 break;
1787
1788 // The triangle up marker case
1789 case MARKER_TRIANGLE_UP:
1790 line(img, pt1: Point(position.x-(markerSize/2), position.y+(markerSize/2)), pt2: Point(position.x+(markerSize/2), position.y+(markerSize/2)), color, thickness, lineType: line_type);
1791 line(img, pt1: Point(position.x+(markerSize/2), position.y+(markerSize/2)), pt2: Point(position.x, position.y-(markerSize/2)), color, thickness, lineType: line_type);
1792 line(img, pt1: Point(position.x, position.y-(markerSize/2)), pt2: Point(position.x-(markerSize/2), position.y+(markerSize/2)), color, thickness, lineType: line_type);
1793 break;
1794
1795 // The triangle down marker case
1796 case MARKER_TRIANGLE_DOWN:
1797 line(img, pt1: Point(position.x-(markerSize/2), position.y-(markerSize/2)), pt2: Point(position.x+(markerSize/2), position.y-(markerSize/2)), color, thickness, lineType: line_type);
1798 line(img, pt1: Point(position.x+(markerSize/2), position.y-(markerSize/2)), pt2: Point(position.x, position.y+(markerSize/2)), color, thickness, lineType: line_type);
1799 line(img, pt1: Point(position.x, position.y+(markerSize/2)), pt2: Point(position.x-(markerSize/2), position.y-(markerSize/2)), color, thickness, lineType: line_type);
1800 break;
1801
1802 // If any number that doesn't exist is entered as marker type, draw a cross marker, to avoid crashes
1803 default:
1804 drawMarker(img, position, color, markerType: MARKER_CROSS, markerSize, thickness, line_type);
1805 break;
1806 }
1807}
1808
1809/****************************************************************************************\
1810* External functions *
1811\****************************************************************************************/
1812
1813void line( InputOutputArray _img, Point pt1, Point pt2, const Scalar& color,
1814 int thickness, int line_type, int shift )
1815{
1816 CV_INSTRUMENT_REGION();
1817
1818 Mat img = _img.getMat();
1819
1820 if( line_type == cv::LINE_AA && img.depth() != CV_8U )
1821 line_type = 8;
1822
1823 CV_Assert( 0 < thickness && thickness <= MAX_THICKNESS );
1824 CV_Assert( 0 <= shift && shift <= XY_SHIFT );
1825
1826 double buf[4];
1827 scalarToRawData( s: color, buf, type: img.type(), unroll_to: 0 );
1828 ThickLine( img, p0: pt1, p1: pt2, color: buf, thickness, line_type, flags: 3, shift );
1829}
1830
1831void arrowedLine(InputOutputArray img, Point pt1, Point pt2, const Scalar& color,
1832 int thickness, int line_type, int shift, double tipLength)
1833{
1834 CV_INSTRUMENT_REGION();
1835
1836 const double tipSize = norm(pt: pt1-pt2)*tipLength; // Factor to normalize the size of the tip depending on the length of the arrow
1837
1838 line(img: img, pt1, pt2, color, thickness, line_type, shift);
1839
1840 const double angle = atan2( y: (double) pt1.y - pt2.y, x: (double) pt1.x - pt2.x );
1841
1842 Point p(cvRound(value: pt2.x + tipSize * cos(x: angle + CV_PI / 4)),
1843 cvRound(value: pt2.y + tipSize * sin(x: angle + CV_PI / 4)));
1844 line(img: img, pt1: p, pt2, color, thickness, line_type, shift);
1845
1846 p.x = cvRound(value: pt2.x + tipSize * cos(x: angle - CV_PI / 4));
1847 p.y = cvRound(value: pt2.y + tipSize * sin(x: angle - CV_PI / 4));
1848 line(img: img, pt1: p, pt2, color, thickness, line_type, shift);
1849}
1850
1851void rectangle( InputOutputArray _img, Point pt1, Point pt2,
1852 const Scalar& color, int thickness,
1853 int lineType, int shift )
1854{
1855 CV_INSTRUMENT_REGION();
1856
1857 Mat img = _img.getMat();
1858
1859 if( lineType == cv::LINE_AA && img.depth() != CV_8U )
1860 lineType = 8;
1861
1862 CV_Assert( thickness <= MAX_THICKNESS );
1863 CV_Assert( 0 <= shift && shift <= XY_SHIFT );
1864
1865 double buf[4];
1866 scalarToRawData(s: color, buf, type: img.type(), unroll_to: 0);
1867
1868 Point2l pt[4];
1869
1870 pt[0] = pt1;
1871 pt[1].x = pt2.x;
1872 pt[1].y = pt1.y;
1873 pt[2] = pt2;
1874 pt[3].x = pt1.x;
1875 pt[3].y = pt2.y;
1876
1877 if( thickness >= 0 )
1878 PolyLine( img, v: pt, count: 4, is_closed: true, color: buf, thickness, line_type: lineType, shift );
1879 else
1880 FillConvexPoly( img, v: pt, npts: 4, color: buf, line_type: lineType, shift );
1881}
1882
1883
1884void rectangle( InputOutputArray img, Rect rec,
1885 const Scalar& color, int thickness,
1886 int lineType, int shift )
1887{
1888 CV_INSTRUMENT_REGION();
1889
1890 CV_Assert( 0 <= shift && shift <= XY_SHIFT );
1891
1892 // Crop the rectangle to right around the mat.
1893 rec &= Rect(-(1 << shift), -(1 << shift), ((img.cols() + 2) << shift),
1894 ((img.rows() + 2) << shift));
1895
1896 if( !rec.empty() )
1897 rectangle( img: img, pt1: rec.tl(), pt2: rec.br() - Point(1<<shift,1<<shift),
1898 color, thickness, lineType, shift );
1899}
1900
1901
1902void circle( InputOutputArray _img, Point center, int radius,
1903 const Scalar& color, int thickness, int line_type, int shift )
1904{
1905 CV_INSTRUMENT_REGION();
1906
1907 Mat img = _img.getMat();
1908
1909 if( line_type == cv::LINE_AA && img.depth() != CV_8U )
1910 line_type = 8;
1911
1912 CV_Assert( radius >= 0 && thickness <= MAX_THICKNESS &&
1913 0 <= shift && shift <= XY_SHIFT );
1914
1915 double buf[4];
1916 scalarToRawData(s: color, buf, type: img.type(), unroll_to: 0);
1917
1918 if( thickness > 1 || line_type != LINE_8 || shift > 0 )
1919 {
1920 Point2l _center(center);
1921 int64 _radius(radius);
1922 _center.x <<= XY_SHIFT - shift;
1923 _center.y <<= XY_SHIFT - shift;
1924 _radius <<= XY_SHIFT - shift;
1925 EllipseEx( img, center: _center, axes: Size2l(_radius, _radius),
1926 angle: 0, arc_start: 0, arc_end: 360, color: buf, thickness, line_type );
1927 }
1928 else
1929 Circle( img, center, radius, color: buf, fill: thickness < 0 );
1930}
1931
1932
1933void ellipse( InputOutputArray _img, Point center, Size axes,
1934 double angle, double start_angle, double end_angle,
1935 const Scalar& color, int thickness, int line_type, int shift )
1936{
1937 CV_INSTRUMENT_REGION();
1938
1939 Mat img = _img.getMat();
1940
1941 if( line_type == cv::LINE_AA && img.depth() != CV_8U )
1942 line_type = 8;
1943
1944 CV_Assert( axes.width >= 0 && axes.height >= 0 &&
1945 thickness <= MAX_THICKNESS && 0 <= shift && shift <= XY_SHIFT );
1946
1947 double buf[4];
1948 scalarToRawData(s: color, buf, type: img.type(), unroll_to: 0);
1949
1950 int _angle = cvRound(value: angle);
1951 int _start_angle = cvRound(value: start_angle);
1952 int _end_angle = cvRound(value: end_angle);
1953 Point2l _center(center);
1954 Size2l _axes(axes);
1955 _center.x <<= XY_SHIFT - shift;
1956 _center.y <<= XY_SHIFT - shift;
1957 _axes.width <<= XY_SHIFT - shift;
1958 _axes.height <<= XY_SHIFT - shift;
1959
1960 EllipseEx( img, center: _center, axes: _axes, angle: _angle, arc_start: _start_angle,
1961 arc_end: _end_angle, color: buf, thickness, line_type );
1962}
1963
1964void ellipse(InputOutputArray _img, const RotatedRect& box, const Scalar& color,
1965 int thickness, int lineType)
1966{
1967 CV_INSTRUMENT_REGION();
1968
1969 Mat img = _img.getMat();
1970
1971 if( lineType == cv::LINE_AA && img.depth() != CV_8U )
1972 lineType = 8;
1973
1974 CV_Assert( box.size.width >= 0 && box.size.height >= 0 &&
1975 thickness <= MAX_THICKNESS );
1976
1977 double buf[4];
1978 scalarToRawData(s: color, buf, type: img.type(), unroll_to: 0);
1979
1980 int _angle = cvRound(value: box.angle);
1981 Point2l center(cvRound(value: box.center.x),
1982 cvRound(value: box.center.y));
1983 center.x = (center.x << XY_SHIFT) + cvRound(value: (box.center.x - center.x)*static_cast<float>(XY_ONE));
1984 center.y = (center.y << XY_SHIFT) + cvRound(value: (box.center.y - center.y)*static_cast<float>(XY_ONE));
1985 Size2l axes(cvRound(value: box.size.width),
1986 cvRound(value: box.size.height));
1987 axes.width = (axes.width << (XY_SHIFT - 1)) + cvRound(value: (box.size.width - axes.width)*(XY_ONE>>1));
1988 axes.height = (axes.height << (XY_SHIFT - 1)) + cvRound(value: (box.size.height - axes.height)*(XY_ONE>>1));
1989 EllipseEx( img, center, axes, angle: _angle, arc_start: 0, arc_end: 360, color: buf, thickness, line_type: lineType );
1990}
1991
1992void fillConvexPoly( InputOutputArray _img, const Point* pts, int npts,
1993 const Scalar& color, int line_type, int shift )
1994{
1995 CV_INSTRUMENT_REGION();
1996
1997 Mat img = _img.getMat();
1998
1999 if( !pts || npts <= 0 )
2000 return;
2001
2002 if( line_type == cv::LINE_AA && img.depth() != CV_8U )
2003 line_type = 8;
2004
2005 double buf[4];
2006 CV_Assert( 0 <= shift && shift <= XY_SHIFT );
2007 scalarToRawData(s: color, buf, type: img.type(), unroll_to: 0);
2008 std::vector<Point2l> _pts(pts, pts + npts);
2009 FillConvexPoly( img, v: _pts.data(), npts, color: buf, line_type, shift );
2010}
2011
2012void fillPoly( InputOutputArray _img, const Point** pts, const int* npts, int ncontours,
2013 const Scalar& color, int line_type,
2014 int shift, Point offset )
2015{
2016 CV_INSTRUMENT_REGION();
2017
2018 Mat img = _img.getMat();
2019
2020 if( line_type == cv::LINE_AA && img.depth() != CV_8U )
2021 line_type = 8;
2022
2023 CV_Assert( pts && npts && ncontours >= 0 && 0 <= shift && shift <= XY_SHIFT );
2024
2025 double buf[4];
2026 scalarToRawData(s: color, buf, type: img.type(), unroll_to: 0);
2027
2028 std::vector<PolyEdge> edges;
2029
2030 int i, total = 0;
2031 for( i = 0; i < ncontours; i++ )
2032 total += npts[i];
2033
2034 edges.reserve( n: total + 1 );
2035 for (i = 0; i < ncontours; i++)
2036 {
2037 if (npts[i] > 0 && pts[i])
2038 {
2039 std::vector<Point2l> _pts(pts[i], pts[i] + npts[i]);
2040 CollectPolyEdges(img, v: _pts.data(), count: npts[i], edges, color: buf, line_type, shift, offset);
2041 }
2042 }
2043
2044 FillEdgeCollection(img, edges, color: buf);
2045}
2046
2047void polylines( InputOutputArray _img, const Point* const* pts, const int* npts, int ncontours, bool isClosed,
2048 const Scalar& color, int thickness, int line_type, int shift )
2049{
2050 CV_INSTRUMENT_REGION();
2051
2052 Mat img = _img.getMat();
2053
2054 if( line_type == cv::LINE_AA && img.depth() != CV_8U )
2055 line_type = 8;
2056
2057 CV_Assert( pts && npts && ncontours >= 0 &&
2058 0 <= thickness && thickness <= MAX_THICKNESS &&
2059 0 <= shift && shift <= XY_SHIFT );
2060
2061 double buf[4];
2062 scalarToRawData( s: color, buf, type: img.type(), unroll_to: 0 );
2063
2064 for( int i = 0; i < ncontours; i++ )
2065 {
2066 std::vector<Point2l> _pts(pts[i], pts[i]+npts[i]);
2067 PolyLine( img, v: _pts.data(), count: npts[i], is_closed: isClosed, color: buf, thickness, line_type, shift );
2068 }
2069}
2070
2071
2072enum { FONT_SIZE_SHIFT=8, FONT_ITALIC_ALPHA=(1 << 8),
2073 FONT_ITALIC_DIGIT=(2 << 8), FONT_ITALIC_PUNCT=(4 << 8),
2074 FONT_ITALIC_BRACES=(8 << 8), FONT_HAVE_GREEK=(16 << 8),
2075 FONT_HAVE_CYRILLIC=(32 << 8) };
2076
2077static const int HersheyPlain[] = {
2078(5 + 4*16) + FONT_HAVE_GREEK,
2079199, 214, 217, 233, 219, 197, 234, 216, 221, 222, 228, 225, 211, 224, 210, 220,
2080200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 212, 213, 191, 226, 192,
2081215, 190, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
208214, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 193, 84,
2083194, 85, 86, 87, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
2084112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
2085195, 223, 196, 88 };
2086
2087static const int HersheyPlainItalic[] = {
2088(5 + 4*16) + FONT_ITALIC_ALPHA + FONT_HAVE_GREEK,
2089199, 214, 217, 233, 219, 197, 234, 216, 221, 222, 228, 225, 211, 224, 210, 220,
2090200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 212, 213, 191, 226, 192,
2091215, 190, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
209264, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 193, 84,
2093194, 85, 86, 87, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161,
2094162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176,
2095195, 223, 196, 88 };
2096
2097static const int HersheyComplexSmall[] = {
2098(6 + 7*16) + FONT_HAVE_GREEK,
20991199, 1214, 1217, 1275, 1274, 1271, 1272, 1216, 1221, 1222, 1219, 1232, 1211, 1231, 1210, 1220,
21001200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1212, 2213, 1241, 1238, 1242,
21011215, 1273, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013,
21021014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1223, 1084,
21031224, 1247, 586, 1249, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111,
21041112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126,
21051225, 1229, 1226, 1246 };
2106
2107static const int HersheyComplexSmallItalic[] = {
2108(6 + 7*16) + FONT_ITALIC_ALPHA + FONT_HAVE_GREEK,
21091199, 1214, 1217, 1275, 1274, 1271, 1272, 1216, 1221, 1222, 1219, 1232, 1211, 1231, 1210, 1220,
21101200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1212, 1213, 1241, 1238, 1242,
21111215, 1273, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063,
21121064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1223, 1084,
21131224, 1247, 586, 1249, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161,
21141162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176,
21151225, 1229, 1226, 1246 };
2116
2117static const int HersheySimplex[] = {
2118(9 + 12*16) + FONT_HAVE_GREEK,
21192199, 714, 717, 733, 719, 697, 734, 716, 721, 722, 728, 725, 711, 724, 710, 720,
2120700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 712, 713, 691, 726, 692,
2121715, 690, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513,
2122514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 693, 584,
2123694, 2247, 586, 2249, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611,
2124612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626,
2125695, 723, 696, 2246 };
2126
2127static const int HersheyDuplex[] = {
2128(9 + 12*16) + FONT_HAVE_GREEK,
21292199, 2714, 2728, 2732, 2719, 2733, 2718, 2727, 2721, 2722, 2723, 2725, 2711, 2724, 2710, 2720,
21302700, 2701, 2702, 2703, 2704, 2705, 2706, 2707, 2708, 2709, 2712, 2713, 2730, 2726, 2731,
21312715, 2734, 2501, 2502, 2503, 2504, 2505, 2506, 2507, 2508, 2509, 2510, 2511, 2512, 2513,
21322514, 2515, 2516, 2517, 2518, 2519, 2520, 2521, 2522, 2523, 2524, 2525, 2526, 2223, 2084,
21332224, 2247, 587, 2249, 2601, 2602, 2603, 2604, 2605, 2606, 2607, 2608, 2609, 2610, 2611,
21342612, 2613, 2614, 2615, 2616, 2617, 2618, 2619, 2620, 2621, 2622, 2623, 2624, 2625, 2626,
21352225, 2229, 2226, 2246 };
2136
2137static const int HersheyComplex[] = {
2138(9 + 12*16) + FONT_HAVE_GREEK + FONT_HAVE_CYRILLIC,
21392199, 2214, 2217, 2275, 2274, 2271, 2272, 2216, 2221, 2222, 2219, 2232, 2211, 2231, 2210, 2220,
21402200, 2201, 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, 2212, 2213, 2241, 2238, 2242,
21412215, 2273, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013,
21422014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2223, 2084,
21432224, 2247, 587, 2249, 2101, 2102, 2103, 2104, 2105, 2106, 2107, 2108, 2109, 2110, 2111,
21442112, 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, 2121, 2122, 2123, 2124, 2125, 2126,
21452225, 2229, 2226, 2246, 2801, 2802, 2803, 2804, 2805, 2806, 2807, 2808, 2809, 2810, 2811,
21462812, 2813, 2814, 2815, 2816, 2817, 2818, 2819, 2820, 2821, 2822, 2823, 2824, 2825, 2826,
21472827, 2828, 2829, 2830, 2831, 2832, 2901, 2902, 2903, 2904, 2905, 2906, 2907, 2908, 2909,
21482910, 2911, 2912, 2913, 2914, 2915, 2916, 2917, 2918, 2919, 2920, 2921, 2922, 2923, 2924,
21492925, 2926, 2927, 2928, 2929, 2930, 2931, 2932};
2150
2151static const int HersheyComplexItalic[] = {
2152(9 + 12*16) + FONT_ITALIC_ALPHA + FONT_ITALIC_DIGIT + FONT_ITALIC_PUNCT +
2153FONT_HAVE_GREEK + FONT_HAVE_CYRILLIC,
21542199, 2764, 2778, 2782, 2769, 2783, 2768, 2777, 2771, 2772, 2219, 2232, 2211, 2231, 2210, 2220,
21552750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2212, 2213, 2241, 2238, 2242,
21562765, 2273, 2051, 2052, 2053, 2054, 2055, 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063,
21572064, 2065, 2066, 2067, 2068, 2069, 2070, 2071, 2072, 2073, 2074, 2075, 2076, 2223, 2084,
21582224, 2247, 587, 2249, 2151, 2152, 2153, 2154, 2155, 2156, 2157, 2158, 2159, 2160, 2161,
21592162, 2163, 2164, 2165, 2166, 2167, 2168, 2169, 2170, 2171, 2172, 2173, 2174, 2175, 2176,
21602225, 2229, 2226, 2246 };
2161
2162static const int HersheyTriplex[] = {
2163(9 + 12*16) + FONT_HAVE_GREEK,
21642199, 3214, 3228, 3232, 3219, 3233, 3218, 3227, 3221, 3222, 3223, 3225, 3211, 3224, 3210, 3220,
21653200, 3201, 3202, 3203, 3204, 3205, 3206, 3207, 3208, 3209, 3212, 3213, 3230, 3226, 3231,
21663215, 3234, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3011, 3012, 3013,
21672014, 3015, 3016, 3017, 3018, 3019, 3020, 3021, 3022, 3023, 3024, 3025, 3026, 2223, 2084,
21682224, 2247, 587, 2249, 3101, 3102, 3103, 3104, 3105, 3106, 3107, 3108, 3109, 3110, 3111,
21693112, 3113, 3114, 3115, 3116, 3117, 3118, 3119, 3120, 3121, 3122, 3123, 3124, 3125, 3126,
21702225, 2229, 2226, 2246 };
2171
2172static const int HersheyTriplexItalic[] = {
2173(9 + 12*16) + FONT_ITALIC_ALPHA + FONT_ITALIC_DIGIT +
2174FONT_ITALIC_PUNCT + FONT_HAVE_GREEK,
21752199, 3264, 3278, 3282, 3269, 3233, 3268, 3277, 3271, 3272, 3223, 3225, 3261, 3224, 3260, 3270,
21763250, 3251, 3252, 3253, 3254, 3255, 3256, 3257, 3258, 3259, 3262, 3263, 3230, 3226, 3231,
21773265, 3234, 3051, 3052, 3053, 3054, 3055, 3056, 3057, 3058, 3059, 3060, 3061, 3062, 3063,
21782064, 3065, 3066, 3067, 3068, 3069, 3070, 3071, 3072, 3073, 3074, 3075, 3076, 2223, 2084,
21792224, 2247, 587, 2249, 3151, 3152, 3153, 3154, 3155, 3156, 3157, 3158, 3159, 3160, 3161,
21803162, 3163, 3164, 3165, 3166, 3167, 3168, 3169, 3170, 3171, 3172, 3173, 3174, 3175, 3176,
21812225, 2229, 2226, 2246 };
2182
2183static const int HersheyScriptSimplex[] = {
2184(9 + 12*16) + FONT_ITALIC_ALPHA + FONT_HAVE_GREEK,
21852199, 714, 717, 733, 719, 697, 734, 716, 721, 722, 728, 725, 711, 724, 710, 720,
2186700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 712, 713, 691, 726, 692,
2187715, 690, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563,
2188564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 693, 584,
2189694, 2247, 586, 2249, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661,
2190662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676,
2191695, 723, 696, 2246 };
2192
2193static const int HersheyScriptComplex[] = {
2194(9 + 12*16) + FONT_ITALIC_ALPHA + FONT_ITALIC_DIGIT + FONT_ITALIC_PUNCT + FONT_HAVE_GREEK,
21952199, 2764, 2778, 2782, 2769, 2783, 2768, 2777, 2771, 2772, 2219, 2232, 2211, 2231, 2210, 2220,
21962750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2212, 2213, 2241, 2238, 2242,
21972215, 2273, 2551, 2552, 2553, 2554, 2555, 2556, 2557, 2558, 2559, 2560, 2561, 2562, 2563,
21982564, 2565, 2566, 2567, 2568, 2569, 2570, 2571, 2572, 2573, 2574, 2575, 2576, 2223, 2084,
21992224, 2247, 586, 2249, 2651, 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, 2660, 2661,
22002662, 2663, 2664, 2665, 2666, 2667, 2668, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2676,
22012225, 2229, 2226, 2246 };
2202
2203
2204static const int* getFontData(int fontFace)
2205{
2206 bool isItalic = (fontFace & FONT_ITALIC) != 0;
2207 const int* ascii = 0;
2208
2209 switch( fontFace & 15 )
2210 {
2211 case FONT_HERSHEY_SIMPLEX:
2212 ascii = HersheySimplex;
2213 break;
2214 case FONT_HERSHEY_PLAIN:
2215 ascii = !isItalic ? HersheyPlain : HersheyPlainItalic;
2216 break;
2217 case FONT_HERSHEY_DUPLEX:
2218 ascii = HersheyDuplex;
2219 break;
2220 case FONT_HERSHEY_COMPLEX:
2221 ascii = !isItalic ? HersheyComplex : HersheyComplexItalic;
2222 break;
2223 case FONT_HERSHEY_TRIPLEX:
2224 ascii = !isItalic ? HersheyTriplex : HersheyTriplexItalic;
2225 break;
2226 case FONT_HERSHEY_COMPLEX_SMALL:
2227 ascii = !isItalic ? HersheyComplexSmall : HersheyComplexSmallItalic;
2228 break;
2229 case FONT_HERSHEY_SCRIPT_SIMPLEX:
2230 ascii = HersheyScriptSimplex;
2231 break;
2232 case FONT_HERSHEY_SCRIPT_COMPLEX:
2233 ascii = HersheyScriptComplex;
2234 break;
2235 default:
2236 CV_Error( cv::Error::StsOutOfRange, "Unknown font type" );
2237 }
2238 return ascii;
2239}
2240
2241inline void readCheck(int &c, int &i, const String &text, int fontFace)
2242{
2243
2244 int leftBoundary = ' ', rightBoundary = 127;
2245
2246 if(c >= 0x80 && fontFace == FONT_HERSHEY_COMPLEX)
2247 {
2248 if(c == 0xD0 && (uchar)text[i + 1] >= 0x90 && (uchar)text[i + 1] <= 0xBF)
2249 {
2250 c = (uchar)text[++i] - 17;
2251 leftBoundary = 127;
2252 rightBoundary = 175;
2253 }
2254 else if(c == 0xD1 && (uchar)text[i + 1] >= 0x80 && (uchar)text[i + 1] <= 0x8F)
2255 {
2256 c = (uchar)text[++i] + 47;
2257 leftBoundary = 175;
2258 rightBoundary = 191;
2259 }
2260 else
2261 {
2262 if(c >= 0xC0 && text[i+1] != 0) //2 bytes utf
2263 i++;
2264
2265 if(c >= 0xE0 && text[i+1] != 0) //3 bytes utf
2266 i++;
2267
2268 if(c >= 0xF0 && text[i+1] != 0) //4 bytes utf
2269 i++;
2270
2271 if(c >= 0xF8 && text[i+1] != 0) //5 bytes utf
2272 i++;
2273
2274 if(c >= 0xFC && text[i+1] != 0) //6 bytes utf
2275 i++;
2276
2277 c = '?';
2278 }
2279 }
2280
2281 if(c >= rightBoundary || c < leftBoundary)
2282 c = '?';
2283}
2284
2285extern const char* g_HersheyGlyphs[];
2286
2287void putText( InputOutputArray _img, const String& text, Point org,
2288 int fontFace, double fontScale, Scalar color,
2289 int thickness, int line_type, bool bottomLeftOrigin )
2290
2291{
2292 CV_INSTRUMENT_REGION();
2293
2294 if ( text.empty() )
2295 {
2296 return;
2297 }
2298 Mat img = _img.getMat();
2299 const int* ascii = getFontData(fontFace);
2300
2301 double buf[4];
2302 scalarToRawData(s: color, buf, type: img.type(), unroll_to: 0);
2303
2304 int base_line = -(ascii[0] & 15);
2305 int hscale = cvRound(value: fontScale * static_cast<double>(XY_ONE)), vscale = hscale;
2306
2307 if( line_type == cv::LINE_AA && img.depth() != CV_8U )
2308 line_type = 8;
2309
2310 if( bottomLeftOrigin )
2311 vscale = -vscale;
2312
2313 int64 view_x = (int64)org.x << XY_SHIFT;
2314 int64 view_y = ((int64)org.y << XY_SHIFT) + base_line*vscale;
2315 std::vector<Point2l> pts;
2316 pts.reserve(n: 1 << 10);
2317 const char **faces = cv::g_HersheyGlyphs;
2318
2319 for( int i = 0; i < (int)text.size(); i++ )
2320 {
2321 int c = (uchar)text[i];
2322 Point2l p;
2323
2324 readCheck(c, i, text, fontFace);
2325
2326 const char* ptr = faces[ascii[(c-' ')+1]];
2327 p.x = (uchar)ptr[0] - 'R';
2328 p.y = (uchar)ptr[1] - 'R';
2329 int64 dx = p.y*hscale;
2330 view_x -= p.x*hscale;
2331 pts.resize(new_size: 0);
2332
2333 for( ptr += 2;; )
2334 {
2335 if( *ptr == ' ' || !*ptr )
2336 {
2337 if( pts.size() > 1 )
2338 PolyLine( img, v: &pts[0], count: (int)pts.size(), is_closed: false, color: buf, thickness, line_type, shift: XY_SHIFT );
2339 if( !*ptr++ )
2340 break;
2341 pts.resize(new_size: 0);
2342 }
2343 else
2344 {
2345 p.x = (uchar)ptr[0] - 'R';
2346 p.y = (uchar)ptr[1] - 'R';
2347 ptr += 2;
2348 pts.push_back(x: Point2l(p.x*hscale + view_x, p.y*vscale + view_y));
2349 }
2350 }
2351 view_x += dx;
2352 }
2353}
2354
2355Size getTextSize( const String& text, int fontFace, double fontScale, int thickness, int* _base_line)
2356{
2357 Size size;
2358 double view_x = 0;
2359 const char **faces = cv::g_HersheyGlyphs;
2360 const int* ascii = getFontData(fontFace);
2361
2362 int base_line = (ascii[0] & 15);
2363 int cap_line = (ascii[0] >> 4) & 15;
2364 size.height = cvRound(value: (cap_line + base_line)*fontScale + (thickness+1)/2);
2365
2366 for( int i = 0; i < (int)text.size(); i++ )
2367 {
2368 int c = (uchar)text[i];
2369 Point p;
2370
2371 readCheck(c, i, text, fontFace);
2372
2373 const char* ptr = faces[ascii[(c-' ')+1]];
2374 p.x = (uchar)ptr[0] - 'R';
2375 p.y = (uchar)ptr[1] - 'R';
2376 view_x += (p.y - p.x)*fontScale;
2377 }
2378
2379 size.width = cvRound(value: view_x + thickness);
2380 if( _base_line )
2381 *_base_line = cvRound(value: base_line*fontScale + thickness*0.5);
2382 return size;
2383}
2384
2385double getFontScaleFromHeight(const int fontFace, const int pixelHeight, const int thickness)
2386{
2387 // By https://stackoverflow.com/a/27898487/1531708
2388 const int* ascii = getFontData(fontFace);
2389
2390 int base_line = (ascii[0] & 15);
2391 int cap_line = (ascii[0] >> 4) & 15;
2392
2393 return static_cast<double>(pixelHeight - static_cast<double>((thickness + 1)) / 2.0) / static_cast<double>(cap_line + base_line);
2394}
2395
2396}
2397
2398void cv::fillConvexPoly(InputOutputArray img, InputArray _points,
2399 const Scalar& color, int lineType, int shift)
2400{
2401 CV_INSTRUMENT_REGION();
2402
2403 Mat points = _points.getMat();
2404 CV_Assert(points.checkVector(2, CV_32S) >= 0);
2405 fillConvexPoly(img: img, pts: points.ptr<Point>(), npts: points.rows*points.cols*points.channels()/2, color, line_type: lineType, shift);
2406}
2407
2408void cv::fillPoly(InputOutputArray img, InputArrayOfArrays pts,
2409 const Scalar& color, int lineType, int shift, Point offset)
2410{
2411 CV_INSTRUMENT_REGION();
2412
2413 bool manyContours = pts.kind() == _InputArray::STD_VECTOR_VECTOR ||
2414 pts.kind() == _InputArray::STD_VECTOR_MAT;
2415 int i, ncontours = manyContours ? (int)pts.total() : 1;
2416 if( ncontours == 0 )
2417 return;
2418 AutoBuffer<Point*> _ptsptr(ncontours);
2419 AutoBuffer<int> _npts(ncontours);
2420 Point** ptsptr = _ptsptr.data();
2421 int* npts = _npts.data();
2422
2423 for( i = 0; i < ncontours; i++ )
2424 {
2425 Mat p = pts.getMat(i: manyContours ? i : -1);
2426 CV_Assert(p.checkVector(2, CV_32S) > 0);
2427 ptsptr[i] = p.ptr<Point>();
2428 npts[i] = p.rows*p.cols*p.channels()/2;
2429 }
2430 fillPoly(img: img, pts: (const Point**)ptsptr, npts, ncontours: (int)ncontours, color, line_type: lineType, shift, offset);
2431}
2432
2433void cv::polylines(InputOutputArray img, InputArrayOfArrays pts,
2434 bool isClosed, const Scalar& color,
2435 int thickness, int lineType, int shift)
2436{
2437 CV_INSTRUMENT_REGION();
2438
2439 bool manyContours = pts.kind() == _InputArray::STD_VECTOR_VECTOR ||
2440 pts.kind() == _InputArray::STD_VECTOR_MAT;
2441 int i, ncontours = manyContours ? (int)pts.total() : 1;
2442 if( ncontours == 0 )
2443 return;
2444 AutoBuffer<Point*> _ptsptr(ncontours);
2445 AutoBuffer<int> _npts(ncontours);
2446 Point** ptsptr = _ptsptr.data();
2447 int* npts = _npts.data();
2448
2449 for( i = 0; i < ncontours; i++ )
2450 {
2451 Mat p = pts.getMat(i: manyContours ? i : -1);
2452 if( p.total() == 0 )
2453 {
2454 ptsptr[i] = NULL;
2455 npts[i] = 0;
2456 continue;
2457 }
2458 CV_Assert(p.checkVector(2, CV_32S) >= 0);
2459 ptsptr[i] = p.ptr<Point>();
2460 npts[i] = p.rows*p.cols*p.channels()/2;
2461 }
2462 polylines(img: img, pts: (const Point**)ptsptr, npts, ncontours: (int)ncontours, isClosed, color, thickness, line_type: lineType, shift);
2463}
2464
2465
2466void cv::drawContours( InputOutputArray _image, InputArrayOfArrays _contours,
2467 int contourIdx, const Scalar& color, int thickness,
2468 int lineType, InputArray _hierarchy,
2469 int maxLevel, Point offset )
2470{
2471 CV_INSTRUMENT_REGION();
2472 CV_Assert( thickness <= MAX_THICKNESS );
2473 const size_t ncontours = _contours.total();
2474 if (!ncontours)
2475 return;
2476 CV_Assert(ncontours <= (size_t)std::numeric_limits<int>::max());
2477 if (lineType == cv::LINE_AA && _image.depth() != CV_8U)
2478 lineType = 8;
2479 Mat image = _image.getMat();
2480 Mat_<Vec4i> hierarchy = _hierarchy.getMat();
2481
2482 int i = 0, end = (int)ncontours;
2483 if (contourIdx >= 0)
2484 {
2485 i = contourIdx;
2486 end = i + 1;
2487 }
2488 std::vector<int> indexesToFill;
2489 if (hierarchy.empty() || maxLevel == 0)
2490 {
2491 indexesToFill.resize(new_size: end - i);
2492 std::iota(first: indexesToFill.begin(), last: indexesToFill.end(), value: i);
2493 }
2494 else
2495 {
2496 std::stack<int> indexes;
2497 for (; i != end; ++i)
2498 {
2499 // either all from the top level or a single contour
2500 if (hierarchy(i)[3] < 0 || contourIdx >= 0)
2501 indexes.push(x: i);
2502 }
2503 while (!indexes.empty())
2504 {
2505 // get current element
2506 const int cur = indexes.top();
2507 indexes.pop();
2508
2509 // check current element depth
2510 int curLevel = -1;
2511 int par = cur;
2512 while (par >= 0)
2513 {
2514 par = hierarchy(par)[3]; // parent
2515 ++curLevel;
2516 }
2517 if (curLevel <= maxLevel)
2518 {
2519 indexesToFill.push_back(x: cur);
2520 }
2521
2522 int next = hierarchy(cur)[2]; // first child
2523 while (next > 0)
2524 {
2525 indexes.push(x: next);
2526 next = hierarchy(next)[0]; // next sibling
2527 }
2528 }
2529 }
2530 std::vector<Mat> contoursToFill;
2531 contoursToFill.reserve(n: indexesToFill.size());
2532 for (const int& idx : indexesToFill)
2533 contoursToFill.emplace_back(args: _contours.getMat(i: idx));
2534
2535 if (thickness < 0)
2536 fillPoly(img: image, pts: contoursToFill, color, lineType, shift: 0, offset);
2537 else
2538 {
2539 double color_buf[4]{};
2540 scalarToRawData(s: color, buf: color_buf, type: _image.type(), unroll_to: 0);
2541 for (const Mat& cnt : contoursToFill)
2542 {
2543 if (cnt.empty())
2544 continue;
2545 const int npoints = cnt.checkVector(elemChannels: 2, CV_32S);
2546 CV_Assert(npoints > 0);
2547 for (int j = 0; j < npoints; ++j)
2548 {
2549 const bool isLastIter = j == npoints - 1;
2550 const Point pt1 = cnt.at<Point>(i0: j);
2551 const Point pt2 = cnt.at<Point>(i0: isLastIter ? 0 : j + 1);
2552 cv::ThickLine(img&: image, p0: pt1 + offset, p1: pt2 + offset, color: color_buf, thickness, line_type: lineType, flags: 2, shift: 0);
2553 }
2554 }
2555 }
2556}
2557
2558
2559static const int CodeDeltas[8][2] =
2560{ {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1} };
2561
2562CV_IMPL void
2563cvDrawContours( void* _img, CvSeq* contour,
2564 CvScalar _externalColor, CvScalar _holeColor,
2565 int maxLevel, int thickness,
2566 int line_type, CvPoint _offset )
2567{
2568 CvSeq *contour0 = contour, *h_next = 0;
2569 CvTreeNodeIterator iterator;
2570 std::vector<cv::PolyEdge> edges;
2571 std::vector<cv::Point2l> pts;
2572 cv::Scalar externalColor = _externalColor, holeColor = _holeColor;
2573 cv::Mat img = cv::cvarrToMat(arr: _img);
2574 cv::Point offset = _offset;
2575 double ext_buf[4], hole_buf[4];
2576
2577 if( line_type == cv::LINE_AA && img.depth() != CV_8U )
2578 line_type = 8;
2579
2580 if( !contour )
2581 return;
2582
2583 CV_Assert( thickness <= MAX_THICKNESS );
2584
2585 scalarToRawData( s: externalColor, buf: ext_buf, type: img.type(), unroll_to: 0 );
2586 scalarToRawData( s: holeColor, buf: hole_buf, type: img.type(), unroll_to: 0 );
2587
2588 maxLevel = MAX(maxLevel, INT_MIN+2);
2589 maxLevel = MIN(maxLevel, INT_MAX-1);
2590
2591 if( maxLevel < 0 )
2592 {
2593 h_next = contour->h_next;
2594 contour->h_next = 0;
2595 maxLevel = -maxLevel+1;
2596 }
2597
2598 cvInitTreeNodeIterator( tree_iterator: &iterator, first: contour, max_level: maxLevel );
2599 while( (contour = (CvSeq*)cvNextTreeNode( tree_iterator: &iterator )) != 0 )
2600 {
2601 CvSeqReader reader;
2602 int i, count = contour->total;
2603 int elem_type = CV_MAT_TYPE(contour->flags);
2604 void* clr = (contour->flags & CV_SEQ_FLAG_HOLE) == 0 ? ext_buf : hole_buf;
2605
2606 cvStartReadSeq( seq: contour, reader: &reader, reverse: 0 );
2607 CV_Assert(reader.ptr != NULL);
2608 if( thickness < 0 )
2609 pts.resize(new_size: 0);
2610
2611 if( CV_IS_SEQ_CHAIN_CONTOUR( contour ))
2612 {
2613 cv::Point pt = ((CvChain*)contour)->origin;
2614 cv::Point prev_pt = pt;
2615 char prev_code = reader.ptr ? reader.ptr[0] : '\0';
2616
2617 prev_pt += offset;
2618
2619 for( i = 0; i < count; i++ )
2620 {
2621 char code;
2622 CV_READ_SEQ_ELEM( code, reader );
2623
2624 CV_Assert( (code & ~7) == 0 );
2625
2626 if( code != prev_code )
2627 {
2628 prev_code = code;
2629 if( thickness >= 0 )
2630 cv::ThickLine( img, p0: prev_pt, p1: pt, color: clr, thickness, line_type, flags: 2, shift: 0 );
2631 else
2632 pts.push_back(x: pt);
2633 prev_pt = pt;
2634 }
2635
2636 pt.x += CodeDeltas[(int)code][0];
2637 pt.y += CodeDeltas[(int)code][1];
2638 }
2639
2640 if( thickness >= 0 )
2641 cv::ThickLine( img, p0: prev_pt,
2642 p1: cv::Point(((CvChain*)contour)->origin) + offset,
2643 color: clr, thickness, line_type, flags: 2, shift: 0 );
2644 else
2645 cv::CollectPolyEdges(img, v: &pts[0], count: (int)pts.size(),
2646 edges, color: ext_buf, line_type, shift: 0, offset);
2647 }
2648 else if( CV_IS_SEQ_POLYLINE( contour ))
2649 {
2650 CV_Assert( elem_type == CV_32SC2 );
2651 cv::Point pt1, pt2;
2652 int shift = 0;
2653
2654 count -= !CV_IS_SEQ_CLOSED(contour);
2655 { CvPoint pt_ = CV_STRUCT_INITIALIZER; CV_READ_SEQ_ELEM(pt_, reader); pt1 = pt_; }
2656 pt1 += offset;
2657 if( thickness < 0 )
2658 pts.push_back(x: pt1);
2659
2660 for( i = 0; i < count; i++ )
2661 {
2662 { CvPoint pt_ = CV_STRUCT_INITIALIZER; CV_READ_SEQ_ELEM(pt_, reader); pt2 = pt_; }
2663 pt2 += offset;
2664 if( thickness >= 0 )
2665 cv::ThickLine( img, p0: pt1, p1: pt2, color: clr, thickness, line_type, flags: 2, shift );
2666 else
2667 pts.push_back(x: pt2);
2668 pt1 = pt2;
2669 }
2670 if( thickness < 0 )
2671 cv::CollectPolyEdges( img, v: &pts[0], count: (int)pts.size(),
2672 edges, color: ext_buf, line_type, shift: 0, offset: cv::Point() );
2673 }
2674 }
2675
2676 if( thickness < 0 )
2677 cv::FillEdgeCollection( img, edges, color: ext_buf );
2678
2679 if( h_next && contour0 )
2680 contour0->h_next = h_next;
2681}
2682
2683CV_IMPL int
2684cvClipLine( CvSize size, CvPoint* pt1, CvPoint* pt2 )
2685{
2686 CV_Assert( pt1 && pt2 );
2687 return cv::clipLine( img_size: size, pt1&: *(cv::Point*)pt1, pt2&: *(cv::Point*)pt2 );
2688}
2689
2690
2691CV_IMPL int
2692cvEllipse2Poly( CvPoint center, CvSize axes, int angle,
2693 int arc_start, int arc_end, CvPoint* _pts, int delta )
2694{
2695 std::vector<cv::Point> pts;
2696 cv::ellipse2Poly( Point(center), Size(axes), angle, arcStart: arc_start, arcEnd: arc_end, delta, pts );
2697 memcpy( dest: _pts, src: &pts[0], n: pts.size()*sizeof(_pts[0]) );
2698 return (int)pts.size();
2699}
2700
2701CV_IMPL CvScalar
2702cvColorToScalar( double packed_color, int type )
2703{
2704 cv::Scalar scalar;
2705
2706 if( CV_MAT_DEPTH( type ) == CV_8U )
2707 {
2708 int icolor = cvRound( value: packed_color );
2709 if( CV_MAT_CN( type ) > 1 )
2710 {
2711 scalar.val[0] = icolor & 255;
2712 scalar.val[1] = (icolor >> 8) & 255;
2713 scalar.val[2] = (icolor >> 16) & 255;
2714 scalar.val[3] = (icolor >> 24) & 255;
2715 }
2716 else
2717 {
2718 scalar.val[0] = cv::saturate_cast<uchar>( v: icolor );
2719 scalar.val[1] = scalar.val[2] = scalar.val[3] = 0;
2720 }
2721 }
2722 else if( CV_MAT_DEPTH( type ) == CV_8S )
2723 {
2724 int icolor = cvRound( value: packed_color );
2725 if( CV_MAT_CN( type ) > 1 )
2726 {
2727 scalar.val[0] = (char)icolor;
2728 scalar.val[1] = (char)(icolor >> 8);
2729 scalar.val[2] = (char)(icolor >> 16);
2730 scalar.val[3] = (char)(icolor >> 24);
2731 }
2732 else
2733 {
2734 scalar.val[0] = cv::saturate_cast<schar>( v: icolor );
2735 scalar.val[1] = scalar.val[2] = scalar.val[3] = 0;
2736 }
2737 }
2738 else
2739 {
2740 int cn = CV_MAT_CN( type );
2741 switch( cn )
2742 {
2743 case 1:
2744 scalar.val[0] = packed_color;
2745 scalar.val[1] = scalar.val[2] = scalar.val[3] = 0;
2746 break;
2747 case 2:
2748 scalar.val[0] = scalar.val[1] = packed_color;
2749 scalar.val[2] = scalar.val[3] = 0;
2750 break;
2751 case 3:
2752 scalar.val[0] = scalar.val[1] = scalar.val[2] = packed_color;
2753 scalar.val[3] = 0;
2754 break;
2755 default:
2756 scalar.val[0] = scalar.val[1] =
2757 scalar.val[2] = scalar.val[3] = packed_color;
2758 break;
2759 }
2760 }
2761
2762 return cvScalar(s: scalar);
2763}
2764
2765CV_IMPL int
2766cvInitLineIterator( const CvArr* img, CvPoint pt1, CvPoint pt2,
2767 CvLineIterator* iterator, int connectivity,
2768 int left_to_right )
2769{
2770 CV_Assert( iterator != 0 );
2771 cv::LineIterator li(cv::cvarrToMat(arr: img), pt1, pt2, connectivity, left_to_right!=0);
2772
2773 iterator->err = li.err;
2774 iterator->minus_delta = li.minusDelta;
2775 iterator->plus_delta = li.plusDelta;
2776 iterator->minus_step = li.minusStep;
2777 iterator->plus_step = li.plusStep;
2778 iterator->ptr = li.ptr;
2779
2780 return li.count;
2781}
2782
2783CV_IMPL void
2784cvLine( CvArr* _img, CvPoint pt1, CvPoint pt2, CvScalar color,
2785 int thickness, int line_type, int shift )
2786{
2787 cv::Mat img = cv::cvarrToMat(arr: _img);
2788 cv::line( img: img, pt1, pt2, color, thickness, line_type, shift );
2789}
2790
2791CV_IMPL void
2792cvRectangle( CvArr* _img, CvPoint pt1, CvPoint pt2,
2793 CvScalar color, int thickness,
2794 int line_type, int shift )
2795{
2796 cv::Mat img = cv::cvarrToMat(arr: _img);
2797 cv::rectangle( img: img, pt1, pt2, color, thickness, lineType: line_type, shift );
2798}
2799
2800CV_IMPL void
2801cvRectangleR( CvArr* _img, CvRect rec,
2802 CvScalar color, int thickness,
2803 int line_type, int shift )
2804{
2805 cv::Mat img = cv::cvarrToMat(arr: _img);
2806 cv::rectangle( img, rec, color, thickness, lineType: line_type, shift );
2807}
2808
2809CV_IMPL void
2810cvCircle( CvArr* _img, CvPoint center, int radius,
2811 CvScalar color, int thickness, int line_type, int shift )
2812{
2813 cv::Mat img = cv::cvarrToMat(arr: _img);
2814 cv::circle( img: img, center, radius, color, thickness, line_type, shift );
2815}
2816
2817CV_IMPL void
2818cvEllipse( CvArr* _img, CvPoint center, CvSize axes,
2819 double angle, double start_angle, double end_angle,
2820 CvScalar color, int thickness, int line_type, int shift )
2821{
2822 cv::Mat img = cv::cvarrToMat(arr: _img);
2823 cv::ellipse( img: img, center, axes, angle, start_angle, end_angle,
2824 color, thickness, line_type, shift );
2825}
2826
2827CV_IMPL void
2828cvFillConvexPoly( CvArr* _img, const CvPoint *pts, int npts,
2829 CvScalar color, int line_type, int shift )
2830{
2831 cv::Mat img = cv::cvarrToMat(arr: _img);
2832 cv::fillConvexPoly( img: img, pts: (const cv::Point*)pts, npts,
2833 color, line_type, shift );
2834}
2835
2836CV_IMPL void
2837cvFillPoly( CvArr* _img, CvPoint **pts, const int *npts, int ncontours,
2838 CvScalar color, int line_type, int shift )
2839{
2840 cv::Mat img = cv::cvarrToMat(arr: _img);
2841
2842 cv::fillPoly( img: img, pts: (const cv::Point**)pts, npts, ncontours, color, line_type, shift );
2843}
2844
2845CV_IMPL void
2846cvPolyLine( CvArr* _img, CvPoint **pts, const int *npts,
2847 int ncontours, int closed, CvScalar color,
2848 int thickness, int line_type, int shift )
2849{
2850 cv::Mat img = cv::cvarrToMat(arr: _img);
2851
2852 cv::polylines( img: img, pts: (const cv::Point**)pts, npts, ncontours,
2853 isClosed: closed != 0, color, thickness, line_type, shift );
2854}
2855
2856CV_IMPL void
2857cvPutText( CvArr* _img, const char *text, CvPoint org, const CvFont *_font, CvScalar color )
2858{
2859 cv::Mat img = cv::cvarrToMat(arr: _img);
2860 CV_Assert( text != 0 && _font != 0);
2861 cv::putText( img: img, text, org, fontFace: _font->font_face, fontScale: (_font->hscale+_font->vscale)*0.5,
2862 color, thickness: _font->thickness, line_type: _font->line_type,
2863 CV_IS_IMAGE(_img) && ((IplImage*)_img)->origin != 0 );
2864}
2865
2866
2867CV_IMPL void
2868cvInitFont( CvFont *font, int font_face, double hscale, double vscale,
2869 double shear, int thickness, int line_type )
2870{
2871 CV_Assert( font != 0 && hscale > 0 && vscale > 0 && thickness >= 0 );
2872
2873 font->ascii = cv::getFontData(fontFace: font_face);
2874 font->font_face = font_face;
2875 font->hscale = (float)hscale;
2876 font->vscale = (float)vscale;
2877 font->thickness = thickness;
2878 font->shear = (float)shear;
2879 font->greek = font->cyrillic = 0;
2880 font->line_type = line_type;
2881}
2882
2883CV_IMPL void
2884cvGetTextSize( const char *text, const CvFont *_font, CvSize *_size, int *_base_line )
2885{
2886 CV_Assert(text != 0 && _font != 0);
2887 cv::Size size = cv::getTextSize( text, fontFace: _font->font_face, fontScale: (_font->hscale + _font->vscale)*0.5,
2888 thickness: _font->thickness, _base_line );
2889 if( _size )
2890 *_size = cvSize(sz: size);
2891}
2892
2893/* End of file. */
2894

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of opencv/modules/imgproc/src/drawing.cpp