1 /*M/////////////////////////////////////////////////////////////////////////////////////// 2 // 3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 4 // 5 // By downloading, copying, installing or using the software you agree to this license. 6 // If you do not agree to this license, do not download, install, 7 // copy or use the software. 8 // 9 // 10 // Intel License Agreement 11 // For Open Source Computer Vision Library 12 // 13 // Copyright (C) 2000, Intel Corporation, all rights reserved. 14 // Third party copyrights are property of their respective owners. 15 // 16 // Redistribution and use in source and binary forms, with or without modification, 17 // are permitted provided that the following conditions are met: 18 // 19 // * Redistribution's of source code must retain the above copyright notice, 20 // this list of conditions and the following disclaimer. 21 // 22 // * Redistribution's in binary form must reproduce the above copyright notice, 23 // this list of conditions and the following disclaimer in the documentation 24 // and/or other materials provided with the distribution. 25 // 26 // * The name of Intel Corporation may not be used to endorse or promote products 27 // derived from this software without specific prior written permission. 28 // 29 // This software is provided by the copyright holders and contributors "as is" and 30 // any express or implied warranties, including, but not limited to, the implied 31 // warranties of merchantability and fitness for a particular purpose are disclaimed. 32 // In no event shall the Intel Corporation or contributors be liable for any direct, 33 // indirect, incidental, special, exemplary, or consequential damages 34 // (including, but not limited to, procurement of substitute goods or services; 35 // loss of use, data, or profits; or business interruption) however caused 36 // and on any theory of liability, whether in contract, strict liability, 37 // or tort (including negligence or otherwise) arising in any way out of 38 // the use of this software, even if advised of the possibility of such damage. 39 // 40 //M*/ 41 #include "_cxcore.h" 42 43 #define ICV_FREE_PTR(storage) \ 44 ((schar*)(storage)->top + (storage)->block_size - (storage)->free_space) 45 46 #define ICV_ALIGNED_SEQ_BLOCK_SIZE \ 47 (int)cvAlign(sizeof(CvSeqBlock), CV_STRUCT_ALIGN) 48 49 CV_INLINE int 50 cvAlignLeft( int size, int align ) 51 { 52 return size & -align; 53 } 54 55 #define CV_GET_LAST_ELEM( seq, block ) \ 56 ((block)->data + ((block)->count - 1)*((seq)->elem_size)) 57 58 #define CV_SWAP_ELEMS(a,b,elem_size) \ 59 { \ 60 int k; \ 61 for( k = 0; k < elem_size; k++ ) \ 62 { \ 63 char t0 = (a)[k]; \ 64 char t1 = (b)[k]; \ 65 (a)[k] = t1; \ 66 (b)[k] = t0; \ 67 } \ 68 } 69 70 #define ICV_SHIFT_TAB_MAX 32 71 static const schar icvPower2ShiftTab[] = 72 { 73 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4, 74 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5 75 }; 76 77 /****************************************************************************************\ 78 * Functions for manipulating memory storage - list of memory blocks * 79 \****************************************************************************************/ 80 81 /* Initialize allocated storage: */ 82 static void 83 icvInitMemStorage( CvMemStorage* storage, int block_size ) 84 { 85 CV_FUNCNAME( "icvInitMemStorage " ); 86 87 __BEGIN__; 88 89 if( !storage ) 90 CV_ERROR( CV_StsNullPtr, "" ); 91 92 if( block_size <= 0 ) 93 block_size = CV_STORAGE_BLOCK_SIZE; 94 95 block_size = cvAlign( block_size, CV_STRUCT_ALIGN ); 96 assert( sizeof(CvMemBlock) % CV_STRUCT_ALIGN == 0 ); 97 98 memset( storage, 0, sizeof( *storage )); 99 storage->signature = CV_STORAGE_MAGIC_VAL; 100 storage->block_size = block_size; 101 102 __END__; 103 } 104 105 106 /* Create root memory storage: */ 107 CV_IMPL CvMemStorage* 108 cvCreateMemStorage( int block_size ) 109 { 110 CvMemStorage *storage = 0; 111 112 CV_FUNCNAME( "cvCreateMemStorage" ); 113 114 __BEGIN__; 115 116 CV_CALL( storage = (CvMemStorage *)cvAlloc( sizeof( CvMemStorage ))); 117 CV_CALL( icvInitMemStorage( storage, block_size )); 118 119 __END__; 120 121 if( cvGetErrStatus() < 0 ) 122 cvFree( &storage ); 123 124 return storage; 125 } 126 127 128 /* Create child memory storage: */ 129 CV_IMPL CvMemStorage * 130 cvCreateChildMemStorage( CvMemStorage * parent ) 131 { 132 CvMemStorage *storage = 0; 133 CV_FUNCNAME( "cvCreateChildMemStorage" ); 134 135 __BEGIN__; 136 137 if( !parent ) 138 CV_ERROR( CV_StsNullPtr, "" ); 139 140 CV_CALL( storage = cvCreateMemStorage(parent->block_size)); 141 storage->parent = parent; 142 143 __END__; 144 145 if( cvGetErrStatus() < 0 ) 146 cvFree( &storage ); 147 148 return storage; 149 } 150 151 152 /* Release all blocks of the storage (or return them to parent, if any): */ 153 static void 154 icvDestroyMemStorage( CvMemStorage* storage ) 155 { 156 CV_FUNCNAME( "icvDestroyMemStorage" ); 157 158 __BEGIN__; 159 160 int k = 0; 161 162 CvMemBlock *block; 163 CvMemBlock *dst_top = 0; 164 165 if( !storage ) 166 CV_ERROR( CV_StsNullPtr, "" ); 167 168 if( storage->parent ) 169 dst_top = storage->parent->top; 170 171 for( block = storage->bottom; block != 0; k++ ) 172 { 173 CvMemBlock *temp = block; 174 175 block = block->next; 176 if( storage->parent ) 177 { 178 if( dst_top ) 179 { 180 temp->prev = dst_top; 181 temp->next = dst_top->next; 182 if( temp->next ) 183 temp->next->prev = temp; 184 dst_top = dst_top->next = temp; 185 } 186 else 187 { 188 dst_top = storage->parent->bottom = storage->parent->top = temp; 189 temp->prev = temp->next = 0; 190 storage->free_space = storage->block_size - sizeof( *temp ); 191 } 192 } 193 else 194 { 195 cvFree( &temp ); 196 } 197 } 198 199 storage->top = storage->bottom = 0; 200 storage->free_space = 0; 201 202 __END__; 203 } 204 205 206 /* Release memory storage: */ 207 CV_IMPL void 208 cvReleaseMemStorage( CvMemStorage** storage ) 209 { 210 CvMemStorage *st; 211 CV_FUNCNAME( "cvReleaseMemStorage" ); 212 213 __BEGIN__; 214 215 if( !storage ) 216 CV_ERROR( CV_StsNullPtr, "" ); 217 218 st = *storage; 219 *storage = 0; 220 221 if( st ) 222 { 223 CV_CALL( icvDestroyMemStorage( st )); 224 cvFree( &st ); 225 } 226 227 __END__; 228 } 229 230 231 /* Clears memory storage (return blocks to the parent, if any): */ 232 CV_IMPL void 233 cvClearMemStorage( CvMemStorage * storage ) 234 { 235 CV_FUNCNAME( "cvClearMemStorage" ); 236 237 __BEGIN__; 238 239 if( !storage ) 240 CV_ERROR( CV_StsNullPtr, "" ); 241 242 if( storage->parent ) 243 { 244 icvDestroyMemStorage( storage ); 245 } 246 else 247 { 248 storage->top = storage->bottom; 249 storage->free_space = storage->bottom ? storage->block_size - sizeof(CvMemBlock) : 0; 250 } 251 252 __END__; 253 } 254 255 256 /* Moves stack pointer to next block. 257 If no blocks, allocate new one and link it to the storage: */ 258 static void 259 icvGoNextMemBlock( CvMemStorage * storage ) 260 { 261 CV_FUNCNAME( "icvGoNextMemBlock" ); 262 263 __BEGIN__; 264 265 if( !storage ) 266 CV_ERROR( CV_StsNullPtr, "" ); 267 268 if( !storage->top || !storage->top->next ) 269 { 270 CvMemBlock *block; 271 272 if( !(storage->parent) ) 273 { 274 CV_CALL( block = (CvMemBlock *)cvAlloc( storage->block_size )); 275 } 276 else 277 { 278 CvMemStorage *parent = storage->parent; 279 CvMemStoragePos parent_pos; 280 281 cvSaveMemStoragePos( parent, &parent_pos ); 282 CV_CALL( icvGoNextMemBlock( parent )); 283 284 block = parent->top; 285 cvRestoreMemStoragePos( parent, &parent_pos ); 286 287 if( block == parent->top ) /* the single allocated block */ 288 { 289 assert( parent->bottom == block ); 290 parent->top = parent->bottom = 0; 291 parent->free_space = 0; 292 } 293 else 294 { 295 /* cut the block from the parent's list of blocks */ 296 parent->top->next = block->next; 297 if( block->next ) 298 block->next->prev = parent->top; 299 } 300 } 301 302 /* link block */ 303 block->next = 0; 304 block->prev = storage->top; 305 306 if( storage->top ) 307 storage->top->next = block; 308 else 309 storage->top = storage->bottom = block; 310 } 311 312 if( storage->top->next ) 313 storage->top = storage->top->next; 314 storage->free_space = storage->block_size - sizeof(CvMemBlock); 315 assert( storage->free_space % CV_STRUCT_ALIGN == 0 ); 316 317 __END__; 318 } 319 320 321 /* Remember memory storage position: */ 322 CV_IMPL void 323 cvSaveMemStoragePos( const CvMemStorage * storage, CvMemStoragePos * pos ) 324 { 325 CV_FUNCNAME( "cvSaveMemStoragePos" ); 326 327 __BEGIN__; 328 329 if( !storage || !pos ) 330 CV_ERROR( CV_StsNullPtr, "" ); 331 332 pos->top = storage->top; 333 pos->free_space = storage->free_space; 334 335 __END__; 336 } 337 338 339 /* Restore memory storage position: */ 340 CV_IMPL void 341 cvRestoreMemStoragePos( CvMemStorage * storage, CvMemStoragePos * pos ) 342 { 343 CV_FUNCNAME( "cvRestoreMemStoragePos" ); 344 345 __BEGIN__; 346 347 if( !storage || !pos ) 348 CV_ERROR( CV_StsNullPtr, "" ); 349 if( pos->free_space > storage->block_size ) 350 CV_ERROR( CV_StsBadSize, "" ); 351 352 /* 353 // this breaks icvGoNextMemBlock, so comment it off for now 354 if( storage->parent && (!pos->top || pos->top->next) ) 355 { 356 CvMemBlock* save_bottom; 357 if( !pos->top ) 358 save_bottom = 0; 359 else 360 { 361 save_bottom = storage->bottom; 362 storage->bottom = pos->top->next; 363 pos->top->next = 0; 364 storage->bottom->prev = 0; 365 } 366 icvDestroyMemStorage( storage ); 367 storage->bottom = save_bottom; 368 }*/ 369 370 storage->top = pos->top; 371 storage->free_space = pos->free_space; 372 373 if( !storage->top ) 374 { 375 storage->top = storage->bottom; 376 storage->free_space = storage->top ? storage->block_size - sizeof(CvMemBlock) : 0; 377 } 378 379 __END__; 380 } 381 382 383 /* Allocate continuous buffer of the specified size in the storage: */ 384 CV_IMPL void* 385 cvMemStorageAlloc( CvMemStorage* storage, size_t size ) 386 { 387 schar *ptr = 0; 388 389 CV_FUNCNAME( "cvMemStorageAlloc" ); 390 391 __BEGIN__; 392 393 if( !storage ) 394 CV_ERROR( CV_StsNullPtr, "NULL storage pointer" ); 395 396 if( size > INT_MAX ) 397 CV_ERROR( CV_StsOutOfRange, "Too large memory block is requested" ); 398 399 assert( storage->free_space % CV_STRUCT_ALIGN == 0 ); 400 401 if( (size_t)storage->free_space < size ) 402 { 403 size_t max_free_space = cvAlignLeft(storage->block_size - sizeof(CvMemBlock), CV_STRUCT_ALIGN); 404 if( max_free_space < size ) 405 CV_ERROR( CV_StsOutOfRange, "requested size is negative or too big" ); 406 407 CV_CALL( icvGoNextMemBlock( storage )); 408 } 409 410 ptr = ICV_FREE_PTR(storage); 411 assert( (size_t)ptr % CV_STRUCT_ALIGN == 0 ); 412 storage->free_space = cvAlignLeft(storage->free_space - (int)size, CV_STRUCT_ALIGN ); 413 414 __END__; 415 416 return ptr; 417 } 418 419 420 CV_IMPL CvString 421 cvMemStorageAllocString( CvMemStorage* storage, const char* ptr, int len ) 422 { 423 CvString str; 424 CV_FUNCNAME( "cvMemStorageAllocString" ); 425 426 __BEGIN__; 427 428 str.len = len >= 0 ? len : (int)strlen(ptr); 429 CV_CALL( str.ptr = (char*)cvMemStorageAlloc( storage, str.len + 1 )); 430 memcpy( str.ptr, ptr, str.len ); 431 str.ptr[str.len] = '\0'; 432 433 __END__; 434 435 return str; 436 } 437 438 439 /****************************************************************************************\ 440 * Sequence implementation * 441 \****************************************************************************************/ 442 443 /* Create empty sequence: */ 444 CV_IMPL CvSeq * 445 cvCreateSeq( int seq_flags, int header_size, int elem_size, CvMemStorage * storage ) 446 { 447 CvSeq *seq = 0; 448 449 CV_FUNCNAME( "cvCreateSeq" ); 450 451 __BEGIN__; 452 453 if( !storage ) 454 CV_ERROR( CV_StsNullPtr, "" ); 455 if( header_size < (int)sizeof( CvSeq ) || elem_size <= 0 ) 456 CV_ERROR( CV_StsBadSize, "" ); 457 458 /* allocate sequence header */ 459 CV_CALL( seq = (CvSeq*)cvMemStorageAlloc( storage, header_size )); 460 memset( seq, 0, header_size ); 461 462 seq->header_size = header_size; 463 seq->flags = (seq_flags & ~CV_MAGIC_MASK) | CV_SEQ_MAGIC_VAL; 464 { 465 int elemtype = CV_MAT_TYPE(seq_flags); 466 int typesize = CV_ELEM_SIZE(elemtype); 467 468 if( elemtype != CV_SEQ_ELTYPE_GENERIC && 469 typesize != 0 && typesize != elem_size ) 470 CV_ERROR( CV_StsBadSize, 471 "Specified element size doesn't match to the size of the specified element type " 472 "(try to use 0 for element type)" ); 473 } 474 seq->elem_size = elem_size; 475 seq->storage = storage; 476 477 CV_CALL( cvSetSeqBlockSize( seq, (1 << 10)/elem_size )); 478 479 __END__; 480 481 return seq; 482 } 483 484 485 /* adjusts <delta_elems> field of sequence. It determines how much the sequence 486 grows if there are no free space inside the sequence buffers */ 487 CV_IMPL void 488 cvSetSeqBlockSize( CvSeq *seq, int delta_elements ) 489 { 490 int elem_size; 491 int useful_block_size; 492 493 CV_FUNCNAME( "cvSetSeqBlockSize" ); 494 495 __BEGIN__; 496 497 if( !seq || !seq->storage ) 498 CV_ERROR( CV_StsNullPtr, "" ); 499 if( delta_elements < 0 ) 500 CV_ERROR( CV_StsOutOfRange, "" ); 501 502 useful_block_size = cvAlignLeft(seq->storage->block_size - sizeof(CvMemBlock) - 503 sizeof(CvSeqBlock), CV_STRUCT_ALIGN); 504 elem_size = seq->elem_size; 505 506 if( delta_elements == 0 ) 507 { 508 delta_elements = (1 << 10) / elem_size; 509 delta_elements = MAX( delta_elements, 1 ); 510 } 511 if( delta_elements * elem_size > useful_block_size ) 512 { 513 delta_elements = useful_block_size / elem_size; 514 if( delta_elements == 0 ) 515 CV_ERROR( CV_StsOutOfRange, "Storage block size is too small " 516 "to fit the sequence elements" ); 517 } 518 519 seq->delta_elems = delta_elements; 520 521 __END__; 522 } 523 524 525 /* Find a sequence element by its index: */ 526 CV_IMPL schar* 527 cvGetSeqElem( const CvSeq *seq, int index ) 528 { 529 CvSeqBlock *block; 530 int count, total = seq->total; 531 532 if( (unsigned)index >= (unsigned)total ) 533 { 534 index += index < 0 ? total : 0; 535 index -= index >= total ? total : 0; 536 if( (unsigned)index >= (unsigned)total ) 537 return 0; 538 } 539 540 block = seq->first; 541 if( index + index <= total ) 542 { 543 while( index >= (count = block->count) ) 544 { 545 block = block->next; 546 index -= count; 547 } 548 } 549 else 550 { 551 do 552 { 553 block = block->prev; 554 total -= block->count; 555 } 556 while( index < total ); 557 index -= total; 558 } 559 560 return block->data + index * seq->elem_size; 561 } 562 563 564 /* Calculate index of a sequence element: */ 565 CV_IMPL int 566 cvSeqElemIdx( const CvSeq* seq, const void* _element, CvSeqBlock** _block ) 567 { 568 const schar *element = (const schar *)_element; 569 int elem_size; 570 int id = -1; 571 CvSeqBlock *first_block; 572 CvSeqBlock *block; 573 574 CV_FUNCNAME( "cvSeqElemIdx" ); 575 576 __BEGIN__; 577 578 if( !seq || !element ) 579 CV_ERROR( CV_StsNullPtr, "" ); 580 581 block = first_block = seq->first; 582 elem_size = seq->elem_size; 583 584 for( ;; ) 585 { 586 if( (unsigned)(element - block->data) < (unsigned) (block->count * elem_size) ) 587 { 588 if( _block ) 589 *_block = block; 590 if( elem_size <= ICV_SHIFT_TAB_MAX && (id = icvPower2ShiftTab[elem_size - 1]) >= 0 ) 591 id = (int)((size_t)(element - block->data) >> id); 592 else 593 id = (int)((size_t)(element - block->data) / elem_size); 594 id += block->start_index - seq->first->start_index; 595 break; 596 } 597 block = block->next; 598 if( block == first_block ) 599 break; 600 } 601 602 __END__; 603 604 return id; 605 } 606 607 608 CV_IMPL int 609 cvSliceLength( CvSlice slice, const CvSeq* seq ) 610 { 611 int total = seq->total; 612 int length = slice.end_index - slice.start_index; 613 614 if( length != 0 ) 615 { 616 if( slice.start_index < 0 ) 617 slice.start_index += total; 618 if( slice.end_index <= 0 ) 619 slice.end_index += total; 620 621 length = slice.end_index - slice.start_index; 622 } 623 624 if( length < 0 ) 625 { 626 length += total; 627 /*if( length < 0 ) 628 length += total;*/ 629 } 630 else if( length > total ) 631 length = total; 632 633 return length; 634 } 635 636 637 /* Copy all sequence elements into single continuous array: */ 638 CV_IMPL void* 639 cvCvtSeqToArray( const CvSeq *seq, void *array, CvSlice slice ) 640 { 641 CV_FUNCNAME( "cvCvtSeqToArray" ); 642 643 __BEGIN__; 644 645 int elem_size, total; 646 CvSeqReader reader; 647 char *dst = (char*)array; 648 649 if( !seq || !array ) 650 CV_ERROR( CV_StsNullPtr, "" ); 651 652 elem_size = seq->elem_size; 653 total = cvSliceLength( slice, seq )*elem_size; 654 655 if( total == 0 ) 656 EXIT; 657 658 cvStartReadSeq( seq, &reader, 0 ); 659 CV_CALL( cvSetSeqReaderPos( &reader, slice.start_index, 0 )); 660 661 do 662 { 663 int count = (int)(reader.block_max - reader.ptr); 664 if( count > total ) 665 count = total; 666 667 memcpy( dst, reader.ptr, count ); 668 dst += count; 669 reader.block = reader.block->next; 670 reader.ptr = reader.block->data; 671 reader.block_max = reader.ptr + reader.block->count*elem_size; 672 total -= count; 673 } 674 while( total > 0 ); 675 676 __END__; 677 678 return array; 679 } 680 681 682 /* Construct a sequence from an array without copying any data. 683 NB: The resultant sequence cannot grow beyond its initial size: */ 684 CV_IMPL CvSeq* 685 cvMakeSeqHeaderForArray( int seq_flags, int header_size, int elem_size, 686 void *array, int total, CvSeq *seq, CvSeqBlock * block ) 687 { 688 CvSeq* result = 0; 689 690 CV_FUNCNAME( "cvMakeSeqHeaderForArray" ); 691 692 __BEGIN__; 693 694 if( elem_size <= 0 || header_size < (int)sizeof( CvSeq ) || total < 0 ) 695 CV_ERROR( CV_StsBadSize, "" ); 696 697 if( !seq || ((!array || !block) && total > 0) ) 698 CV_ERROR( CV_StsNullPtr, "" ); 699 700 memset( seq, 0, header_size ); 701 702 seq->header_size = header_size; 703 seq->flags = (seq_flags & ~CV_MAGIC_MASK) | CV_SEQ_MAGIC_VAL; 704 { 705 int elemtype = CV_MAT_TYPE(seq_flags); 706 int typesize = CV_ELEM_SIZE(elemtype); 707 708 if( elemtype != CV_SEQ_ELTYPE_GENERIC && 709 typesize != 0 && typesize != elem_size ) 710 CV_ERROR( CV_StsBadSize, 711 "Element size doesn't match to the size of predefined element type " 712 "(try to use 0 for sequence element type)" ); 713 } 714 seq->elem_size = elem_size; 715 seq->total = total; 716 seq->block_max = seq->ptr = (schar *) array + total * elem_size; 717 718 if( total > 0 ) 719 { 720 seq->first = block; 721 block->prev = block->next = block; 722 block->start_index = 0; 723 block->count = total; 724 block->data = (schar *) array; 725 } 726 727 result = seq; 728 729 __END__; 730 731 return result; 732 } 733 734 735 /* The function allocates space for at least one more sequence element. 736 If there are free sequence blocks (seq->free_blocks != 0) 737 they are reused, otherwise the space is allocated in the storage: */ 738 static void 739 icvGrowSeq( CvSeq *seq, int in_front_of ) 740 { 741 CV_FUNCNAME( "icvGrowSeq" ); 742 743 __BEGIN__; 744 745 CvSeqBlock *block; 746 747 if( !seq ) 748 CV_ERROR( CV_StsNullPtr, "" ); 749 block = seq->free_blocks; 750 751 if( !block ) 752 { 753 int elem_size = seq->elem_size; 754 int delta_elems = seq->delta_elems; 755 CvMemStorage *storage = seq->storage; 756 757 if( seq->total >= delta_elems*4 ) 758 cvSetSeqBlockSize( seq, delta_elems*2 ); 759 760 if( !storage ) 761 CV_ERROR( CV_StsNullPtr, "The sequence has NULL storage pointer" ); 762 763 /* If there is a free space just after last allocated block 764 and it is big enough then enlarge the last block. 765 This can happen only if the new block is added to the end of sequence: */ 766 if( (unsigned)(ICV_FREE_PTR(storage) - seq->block_max) < CV_STRUCT_ALIGN && 767 storage->free_space >= seq->elem_size && !in_front_of ) 768 { 769 int delta = storage->free_space / elem_size; 770 771 delta = MIN( delta, delta_elems ) * elem_size; 772 seq->block_max += delta; 773 storage->free_space = cvAlignLeft((int)(((schar*)storage->top + storage->block_size) - 774 seq->block_max), CV_STRUCT_ALIGN ); 775 EXIT; 776 } 777 else 778 { 779 int delta = elem_size * delta_elems + ICV_ALIGNED_SEQ_BLOCK_SIZE; 780 781 /* Try to allocate <delta_elements> elements: */ 782 if( storage->free_space < delta ) 783 { 784 int small_block_size = MAX(1, delta_elems/3)*elem_size + 785 ICV_ALIGNED_SEQ_BLOCK_SIZE; 786 /* try to allocate smaller part */ 787 if( storage->free_space >= small_block_size + CV_STRUCT_ALIGN ) 788 { 789 delta = (storage->free_space - ICV_ALIGNED_SEQ_BLOCK_SIZE)/seq->elem_size; 790 delta = delta*seq->elem_size + ICV_ALIGNED_SEQ_BLOCK_SIZE; 791 } 792 else 793 { 794 CV_CALL( icvGoNextMemBlock( storage )); 795 assert( storage->free_space >= delta ); 796 } 797 } 798 799 CV_CALL( block = (CvSeqBlock*)cvMemStorageAlloc( storage, delta )); 800 block->data = (schar*)cvAlignPtr( block + 1, CV_STRUCT_ALIGN ); 801 block->count = delta - ICV_ALIGNED_SEQ_BLOCK_SIZE; 802 block->prev = block->next = 0; 803 } 804 } 805 else 806 { 807 seq->free_blocks = block->next; 808 } 809 810 if( !(seq->first) ) 811 { 812 seq->first = block; 813 block->prev = block->next = block; 814 } 815 else 816 { 817 block->prev = seq->first->prev; 818 block->next = seq->first; 819 block->prev->next = block->next->prev = block; 820 } 821 822 /* For free blocks the <count> field means 823 * total number of bytes in the block. 824 * 825 * For used blocks it means current number 826 * of sequence elements in the block: 827 */ 828 assert( block->count % seq->elem_size == 0 && block->count > 0 ); 829 830 if( !in_front_of ) 831 { 832 seq->ptr = block->data; 833 seq->block_max = block->data + block->count; 834 block->start_index = block == block->prev ? 0 : 835 block->prev->start_index + block->prev->count; 836 } 837 else 838 { 839 int delta = block->count / seq->elem_size; 840 block->data += block->count; 841 842 if( block != block->prev ) 843 { 844 assert( seq->first->start_index == 0 ); 845 seq->first = block; 846 } 847 else 848 { 849 seq->block_max = seq->ptr = block->data; 850 } 851 852 block->start_index = 0; 853 854 for( ;; ) 855 { 856 block->start_index += delta; 857 block = block->next; 858 if( block == seq->first ) 859 break; 860 } 861 } 862 863 block->count = 0; 864 865 __END__; 866 } 867 868 /* Recycle a sequence block: */ 869 static void 870 icvFreeSeqBlock( CvSeq *seq, int in_front_of ) 871 { 872 /*CV_FUNCNAME( "icvFreeSeqBlock" );*/ 873 874 __BEGIN__; 875 876 CvSeqBlock *block = seq->first; 877 878 assert( (in_front_of ? block : block->prev)->count == 0 ); 879 880 if( block == block->prev ) /* single block case */ 881 { 882 block->count = (int)(seq->block_max - block->data) + block->start_index * seq->elem_size; 883 block->data = seq->block_max - block->count; 884 seq->first = 0; 885 seq->ptr = seq->block_max = 0; 886 seq->total = 0; 887 } 888 else 889 { 890 if( !in_front_of ) 891 { 892 block = block->prev; 893 assert( seq->ptr == block->data ); 894 895 block->count = (int)(seq->block_max - seq->ptr); 896 seq->block_max = seq->ptr = block->prev->data + 897 block->prev->count * seq->elem_size; 898 } 899 else 900 { 901 int delta = block->start_index; 902 903 block->count = delta * seq->elem_size; 904 block->data -= block->count; 905 906 /* Update start indices of sequence blocks: */ 907 for( ;; ) 908 { 909 block->start_index -= delta; 910 block = block->next; 911 if( block == seq->first ) 912 break; 913 } 914 915 seq->first = block->next; 916 } 917 918 block->prev->next = block->next; 919 block->next->prev = block->prev; 920 } 921 922 assert( block->count > 0 && block->count % seq->elem_size == 0 ); 923 block->next = seq->free_blocks; 924 seq->free_blocks = block; 925 926 __END__; 927 } 928 929 930 /****************************************************************************************\ 931 * Sequence Writer implementation * 932 \****************************************************************************************/ 933 934 /* Initialize sequence writer: */ 935 CV_IMPL void 936 cvStartAppendToSeq( CvSeq *seq, CvSeqWriter * writer ) 937 { 938 CV_FUNCNAME( "cvStartAppendToSeq" ); 939 940 __BEGIN__; 941 942 if( !seq || !writer ) 943 CV_ERROR( CV_StsNullPtr, "" ); 944 945 memset( writer, 0, sizeof( *writer )); 946 writer->header_size = sizeof( CvSeqWriter ); 947 948 writer->seq = seq; 949 writer->block = seq->first ? seq->first->prev : 0; 950 writer->ptr = seq->ptr; 951 writer->block_max = seq->block_max; 952 953 __END__; 954 } 955 956 957 /* Initialize sequence writer: */ 958 CV_IMPL void 959 cvStartWriteSeq( int seq_flags, int header_size, 960 int elem_size, CvMemStorage * storage, CvSeqWriter * writer ) 961 { 962 CvSeq *seq = 0; 963 964 CV_FUNCNAME( "cvStartWriteSeq" ); 965 966 __BEGIN__; 967 968 if( !storage || !writer ) 969 CV_ERROR( CV_StsNullPtr, "" ); 970 971 CV_CALL( seq = cvCreateSeq( seq_flags, header_size, elem_size, storage )); 972 cvStartAppendToSeq( seq, writer ); 973 974 __END__; 975 } 976 977 978 /* Update sequence header: */ 979 CV_IMPL void 980 cvFlushSeqWriter( CvSeqWriter * writer ) 981 { 982 CvSeq *seq = 0; 983 984 CV_FUNCNAME( "cvFlushSeqWriter" ); 985 986 __BEGIN__; 987 988 if( !writer ) 989 CV_ERROR( CV_StsNullPtr, "" ); 990 991 seq = writer->seq; 992 seq->ptr = writer->ptr; 993 994 if( writer->block ) 995 { 996 int total = 0; 997 CvSeqBlock *first_block = writer->seq->first; 998 CvSeqBlock *block = first_block; 999 1000 writer->block->count = (int)((writer->ptr - writer->block->data) / seq->elem_size); 1001 assert( writer->block->count > 0 ); 1002 1003 do 1004 { 1005 total += block->count; 1006 block = block->next; 1007 } 1008 while( block != first_block ); 1009 1010 writer->seq->total = total; 1011 } 1012 1013 __END__; 1014 } 1015 1016 1017 /* Calls icvFlushSeqWriter and finishes writing process: */ 1018 CV_IMPL CvSeq * 1019 cvEndWriteSeq( CvSeqWriter * writer ) 1020 { 1021 CvSeq *seq = 0; 1022 1023 CV_FUNCNAME( "cvEndWriteSeq" ); 1024 1025 __BEGIN__; 1026 1027 if( !writer ) 1028 CV_ERROR( CV_StsNullPtr, "" ); 1029 1030 CV_CALL( cvFlushSeqWriter( writer )); 1031 seq = writer->seq; 1032 1033 /* Truncate the last block: */ 1034 if( writer->block && writer->seq->storage ) 1035 { 1036 CvMemStorage *storage = seq->storage; 1037 schar *storage_block_max = (schar *) storage->top + storage->block_size; 1038 1039 assert( writer->block->count > 0 ); 1040 1041 if( (unsigned)((storage_block_max - storage->free_space) 1042 - seq->block_max) < CV_STRUCT_ALIGN ) 1043 { 1044 storage->free_space = cvAlignLeft((int)(storage_block_max - seq->ptr), CV_STRUCT_ALIGN); 1045 seq->block_max = seq->ptr; 1046 } 1047 } 1048 1049 writer->ptr = 0; 1050 1051 __END__; 1052 1053 return seq; 1054 } 1055 1056 1057 /* Create new sequence block: */ 1058 CV_IMPL void 1059 cvCreateSeqBlock( CvSeqWriter * writer ) 1060 { 1061 CV_FUNCNAME( "cvCreateSeqBlock" ); 1062 1063 __BEGIN__; 1064 1065 CvSeq *seq; 1066 1067 if( !writer || !writer->seq ) 1068 CV_ERROR( CV_StsNullPtr, "" ); 1069 1070 seq = writer->seq; 1071 1072 cvFlushSeqWriter( writer ); 1073 1074 CV_CALL( icvGrowSeq( seq, 0 )); 1075 1076 writer->block = seq->first->prev; 1077 writer->ptr = seq->ptr; 1078 writer->block_max = seq->block_max; 1079 1080 __END__; 1081 } 1082 1083 1084 /****************************************************************************************\ 1085 * Sequence Reader implementation * 1086 \****************************************************************************************/ 1087 1088 /* Initialize sequence reader: */ 1089 CV_IMPL void 1090 cvStartReadSeq( const CvSeq *seq, CvSeqReader * reader, int reverse ) 1091 { 1092 CvSeqBlock *first_block; 1093 CvSeqBlock *last_block; 1094 1095 CV_FUNCNAME( "cvStartReadSeq" ); 1096 1097 if( reader ) 1098 { 1099 reader->seq = 0; 1100 reader->block = 0; 1101 reader->ptr = reader->block_max = reader->block_min = 0; 1102 } 1103 1104 __BEGIN__; 1105 1106 if( !seq || !reader ) 1107 CV_ERROR( CV_StsNullPtr, "" ); 1108 1109 reader->header_size = sizeof( CvSeqReader ); 1110 reader->seq = (CvSeq*)seq; 1111 1112 first_block = seq->first; 1113 1114 if( first_block ) 1115 { 1116 last_block = first_block->prev; 1117 reader->ptr = first_block->data; 1118 reader->prev_elem = CV_GET_LAST_ELEM( seq, last_block ); 1119 reader->delta_index = seq->first->start_index; 1120 1121 if( reverse ) 1122 { 1123 schar *temp = reader->ptr; 1124 1125 reader->ptr = reader->prev_elem; 1126 reader->prev_elem = temp; 1127 1128 reader->block = last_block; 1129 } 1130 else 1131 { 1132 reader->block = first_block; 1133 } 1134 1135 reader->block_min = reader->block->data; 1136 reader->block_max = reader->block_min + reader->block->count * seq->elem_size; 1137 } 1138 else 1139 { 1140 reader->delta_index = 0; 1141 reader->block = 0; 1142 1143 reader->ptr = reader->prev_elem = reader->block_min = reader->block_max = 0; 1144 } 1145 1146 __END__; 1147 } 1148 1149 1150 /* Change the current reading block 1151 * to the previous or to the next: 1152 */ 1153 CV_IMPL void 1154 cvChangeSeqBlock( void* _reader, int direction ) 1155 { 1156 CV_FUNCNAME( "cvChangeSeqBlock" ); 1157 1158 __BEGIN__; 1159 1160 CvSeqReader* reader = (CvSeqReader*)_reader; 1161 1162 if( !reader ) 1163 CV_ERROR( CV_StsNullPtr, "" ); 1164 1165 if( direction > 0 ) 1166 { 1167 reader->block = reader->block->next; 1168 reader->ptr = reader->block->data; 1169 } 1170 else 1171 { 1172 reader->block = reader->block->prev; 1173 reader->ptr = CV_GET_LAST_ELEM( reader->seq, reader->block ); 1174 } 1175 reader->block_min = reader->block->data; 1176 reader->block_max = reader->block_min + reader->block->count * reader->seq->elem_size; 1177 1178 __END__; 1179 } 1180 1181 1182 /* Return the current reader position: */ 1183 CV_IMPL int 1184 cvGetSeqReaderPos( CvSeqReader* reader ) 1185 { 1186 int elem_size; 1187 int index = -1; 1188 1189 CV_FUNCNAME( "cvGetSeqReaderPos" ); 1190 1191 __BEGIN__; 1192 1193 if( !reader || !reader->ptr ) 1194 CV_ERROR( CV_StsNullPtr, "" ); 1195 1196 elem_size = reader->seq->elem_size; 1197 if( elem_size <= ICV_SHIFT_TAB_MAX && (index = icvPower2ShiftTab[elem_size - 1]) >= 0 ) 1198 index = (int)((reader->ptr - reader->block_min) >> index); 1199 else 1200 index = (int)((reader->ptr - reader->block_min) / elem_size); 1201 1202 index += reader->block->start_index - reader->delta_index; 1203 1204 __END__; 1205 1206 return index; 1207 } 1208 1209 1210 /* Set reader position to given position, 1211 * either absolute or relative to the 1212 * current one: 1213 */ 1214 CV_IMPL void 1215 cvSetSeqReaderPos( CvSeqReader* reader, int index, int is_relative ) 1216 { 1217 CV_FUNCNAME( "cvSetSeqReaderPos" ); 1218 1219 __BEGIN__; 1220 1221 CvSeqBlock *block; 1222 int elem_size, count, total; 1223 1224 if( !reader || !reader->seq ) 1225 CV_ERROR( CV_StsNullPtr, "" ); 1226 1227 total = reader->seq->total; 1228 elem_size = reader->seq->elem_size; 1229 1230 if( !is_relative ) 1231 { 1232 if( index < 0 ) 1233 { 1234 if( index < -total ) 1235 CV_ERROR( CV_StsOutOfRange, "" ); 1236 index += total; 1237 } 1238 else if( index >= total ) 1239 { 1240 index -= total; 1241 if( index >= total ) 1242 CV_ERROR( CV_StsOutOfRange, "" ); 1243 } 1244 1245 block = reader->seq->first; 1246 if( index >= (count = block->count) ) 1247 { 1248 if( index + index <= total ) 1249 { 1250 do 1251 { 1252 block = block->next; 1253 index -= count; 1254 } 1255 while( index >= (count = block->count) ); 1256 } 1257 else 1258 { 1259 do 1260 { 1261 block = block->prev; 1262 total -= block->count; 1263 } 1264 while( index < total ); 1265 index -= total; 1266 } 1267 } 1268 reader->ptr = block->data + index * elem_size; 1269 if( reader->block != block ) 1270 { 1271 reader->block = block; 1272 reader->block_min = block->data; 1273 reader->block_max = block->data + block->count * elem_size; 1274 } 1275 } 1276 else 1277 { 1278 schar* ptr = reader->ptr; 1279 index *= elem_size; 1280 block = reader->block; 1281 1282 if( index > 0 ) 1283 { 1284 while( ptr + index >= reader->block_max ) 1285 { 1286 int delta = (int)(reader->block_max - ptr); 1287 index -= delta; 1288 reader->block = block = block->next; 1289 reader->block_min = ptr = block->data; 1290 reader->block_max = block->data + block->count*elem_size; 1291 } 1292 reader->ptr = ptr + index; 1293 } 1294 else 1295 { 1296 while( ptr + index < reader->block_min ) 1297 { 1298 int delta = (int)(ptr - reader->block_min); 1299 index += delta; 1300 reader->block = block = block->prev; 1301 reader->block_min = block->data; 1302 reader->block_max = ptr = block->data + block->count*elem_size; 1303 } 1304 reader->ptr = ptr + index; 1305 } 1306 } 1307 1308 __END__; 1309 } 1310 1311 1312 /* Push element onto the sequence: */ 1313 CV_IMPL schar* 1314 cvSeqPush( CvSeq *seq, void *element ) 1315 { 1316 schar *ptr = 0; 1317 size_t elem_size; 1318 1319 CV_FUNCNAME( "cvSeqPush" ); 1320 1321 __BEGIN__; 1322 1323 if( !seq ) 1324 CV_ERROR( CV_StsNullPtr, "" ); 1325 1326 elem_size = seq->elem_size; 1327 ptr = seq->ptr; 1328 1329 if( ptr >= seq->block_max ) 1330 { 1331 CV_CALL( icvGrowSeq( seq, 0 )); 1332 1333 ptr = seq->ptr; 1334 assert( ptr + elem_size <= seq->block_max /*&& ptr == seq->block_min */ ); 1335 } 1336 1337 if( element ) 1338 CV_MEMCPY_AUTO( ptr, element, elem_size ); 1339 seq->first->prev->count++; 1340 seq->total++; 1341 seq->ptr = ptr + elem_size; 1342 1343 __END__; 1344 1345 return ptr; 1346 } 1347 1348 1349 /* Pop last element off of the sequence: */ 1350 CV_IMPL void 1351 cvSeqPop( CvSeq *seq, void *element ) 1352 { 1353 schar *ptr; 1354 int elem_size; 1355 1356 CV_FUNCNAME( "cvSeqPop" ); 1357 1358 __BEGIN__; 1359 1360 if( !seq ) 1361 CV_ERROR( CV_StsNullPtr, "" ); 1362 if( seq->total <= 0 ) 1363 CV_ERROR( CV_StsBadSize, "" ); 1364 1365 elem_size = seq->elem_size; 1366 seq->ptr = ptr = seq->ptr - elem_size; 1367 1368 if( element ) 1369 CV_MEMCPY_AUTO( element, ptr, elem_size ); 1370 seq->ptr = ptr; 1371 seq->total--; 1372 1373 if( --(seq->first->prev->count) == 0 ) 1374 { 1375 icvFreeSeqBlock( seq, 0 ); 1376 assert( seq->ptr == seq->block_max ); 1377 } 1378 1379 __END__; 1380 } 1381 1382 1383 /* Push element onto the front of the sequence: */ 1384 CV_IMPL schar* 1385 cvSeqPushFront( CvSeq *seq, void *element ) 1386 { 1387 schar* ptr = 0; 1388 int elem_size; 1389 CvSeqBlock *block; 1390 1391 CV_FUNCNAME( "cvSeqPushFront" ); 1392 1393 __BEGIN__; 1394 1395 if( !seq ) 1396 CV_ERROR( CV_StsNullPtr, "" ); 1397 1398 elem_size = seq->elem_size; 1399 block = seq->first; 1400 1401 if( !block || block->start_index == 0 ) 1402 { 1403 CV_CALL( icvGrowSeq( seq, 1 )); 1404 1405 block = seq->first; 1406 assert( block->start_index > 0 ); 1407 } 1408 1409 ptr = block->data -= elem_size; 1410 1411 if( element ) 1412 CV_MEMCPY_AUTO( ptr, element, elem_size ); 1413 block->count++; 1414 block->start_index--; 1415 seq->total++; 1416 1417 __END__; 1418 1419 return ptr; 1420 } 1421 1422 1423 /* Shift out first element of the sequence: */ 1424 CV_IMPL void 1425 cvSeqPopFront( CvSeq *seq, void *element ) 1426 { 1427 int elem_size; 1428 CvSeqBlock *block; 1429 1430 CV_FUNCNAME( "cvSeqPopFront" ); 1431 1432 __BEGIN__; 1433 1434 if( !seq ) 1435 CV_ERROR( CV_StsNullPtr, "" ); 1436 if( seq->total <= 0 ) 1437 CV_ERROR( CV_StsBadSize, "" ); 1438 1439 elem_size = seq->elem_size; 1440 block = seq->first; 1441 1442 if( element ) 1443 CV_MEMCPY_AUTO( element, block->data, elem_size ); 1444 block->data += elem_size; 1445 block->start_index++; 1446 seq->total--; 1447 1448 if( --(block->count) == 0 ) 1449 { 1450 icvFreeSeqBlock( seq, 1 ); 1451 } 1452 1453 __END__; 1454 } 1455 1456 /* Insert new element in middle of sequence: */ 1457 CV_IMPL schar* 1458 cvSeqInsert( CvSeq *seq, int before_index, void *element ) 1459 { 1460 int elem_size; 1461 int block_size; 1462 CvSeqBlock *block; 1463 int delta_index; 1464 int total; 1465 schar* ret_ptr = 0; 1466 1467 CV_FUNCNAME( "cvSeqInsert" ); 1468 1469 __BEGIN__; 1470 1471 if( !seq ) 1472 CV_ERROR( CV_StsNullPtr, "" ); 1473 1474 total = seq->total; 1475 before_index += before_index < 0 ? total : 0; 1476 before_index -= before_index > total ? total : 0; 1477 1478 if( (unsigned)before_index > (unsigned)total ) 1479 CV_ERROR( CV_StsOutOfRange, "" ); 1480 1481 if( before_index == total ) 1482 { 1483 CV_CALL( ret_ptr = cvSeqPush( seq, element )); 1484 } 1485 else if( before_index == 0 ) 1486 { 1487 CV_CALL( ret_ptr = cvSeqPushFront( seq, element )); 1488 } 1489 else 1490 { 1491 elem_size = seq->elem_size; 1492 1493 if( before_index >= total >> 1 ) 1494 { 1495 schar *ptr = seq->ptr + elem_size; 1496 1497 if( ptr > seq->block_max ) 1498 { 1499 CV_CALL( icvGrowSeq( seq, 0 )); 1500 1501 ptr = seq->ptr + elem_size; 1502 assert( ptr <= seq->block_max ); 1503 } 1504 1505 delta_index = seq->first->start_index; 1506 block = seq->first->prev; 1507 block->count++; 1508 block_size = (int)(ptr - block->data); 1509 1510 while( before_index < block->start_index - delta_index ) 1511 { 1512 CvSeqBlock *prev_block = block->prev; 1513 1514 memmove( block->data + elem_size, block->data, block_size - elem_size ); 1515 block_size = prev_block->count * elem_size; 1516 memcpy( block->data, prev_block->data + block_size - elem_size, elem_size ); 1517 block = prev_block; 1518 1519 /* Check that we don't fall into an infinite loop: */ 1520 assert( block != seq->first->prev ); 1521 } 1522 1523 before_index = (before_index - block->start_index + delta_index) * elem_size; 1524 memmove( block->data + before_index + elem_size, block->data + before_index, 1525 block_size - before_index - elem_size ); 1526 1527 ret_ptr = block->data + before_index; 1528 1529 if( element ) 1530 memcpy( ret_ptr, element, elem_size ); 1531 seq->ptr = ptr; 1532 } 1533 else 1534 { 1535 block = seq->first; 1536 1537 if( block->start_index == 0 ) 1538 { 1539 CV_CALL( icvGrowSeq( seq, 1 )); 1540 1541 block = seq->first; 1542 } 1543 1544 delta_index = block->start_index; 1545 block->count++; 1546 block->start_index--; 1547 block->data -= elem_size; 1548 1549 while( before_index > block->start_index - delta_index + block->count ) 1550 { 1551 CvSeqBlock *next_block = block->next; 1552 1553 block_size = block->count * elem_size; 1554 memmove( block->data, block->data + elem_size, block_size - elem_size ); 1555 memcpy( block->data + block_size - elem_size, next_block->data, elem_size ); 1556 block = next_block; 1557 1558 /* Check that we don't fall into an infinite loop: */ 1559 assert( block != seq->first ); 1560 } 1561 1562 before_index = (before_index - block->start_index + delta_index) * elem_size; 1563 memmove( block->data, block->data + elem_size, before_index - elem_size ); 1564 1565 ret_ptr = block->data + before_index - elem_size; 1566 1567 if( element ) 1568 memcpy( ret_ptr, element, elem_size ); 1569 } 1570 1571 seq->total = total + 1; 1572 } 1573 1574 __END__; 1575 1576 return ret_ptr; 1577 } 1578 1579 1580 /* Removes element from sequence: */ 1581 CV_IMPL void 1582 cvSeqRemove( CvSeq *seq, int index ) 1583 { 1584 schar *ptr; 1585 int elem_size; 1586 int block_size; 1587 CvSeqBlock *block; 1588 int delta_index; 1589 int total, front = 0; 1590 1591 CV_FUNCNAME( "cvSeqRemove" ); 1592 1593 __BEGIN__; 1594 1595 if( !seq ) 1596 CV_ERROR( CV_StsNullPtr, "" ); 1597 1598 total = seq->total; 1599 1600 index += index < 0 ? total : 0; 1601 index -= index >= total ? total : 0; 1602 1603 if( (unsigned) index >= (unsigned) total ) 1604 CV_ERROR( CV_StsOutOfRange, "Invalid index" ); 1605 1606 if( index == total - 1 ) 1607 { 1608 cvSeqPop( seq, 0 ); 1609 } 1610 else if( index == 0 ) 1611 { 1612 cvSeqPopFront( seq, 0 ); 1613 } 1614 else 1615 { 1616 block = seq->first; 1617 elem_size = seq->elem_size; 1618 delta_index = block->start_index; 1619 while( block->start_index - delta_index + block->count <= index ) 1620 block = block->next; 1621 1622 ptr = block->data + (index - block->start_index + delta_index) * elem_size; 1623 1624 front = index < total >> 1; 1625 if( !front ) 1626 { 1627 block_size = block->count * elem_size - (int)(ptr - block->data); 1628 1629 while( block != seq->first->prev ) /* while not the last block */ 1630 { 1631 CvSeqBlock *next_block = block->next; 1632 1633 memmove( ptr, ptr + elem_size, block_size - elem_size ); 1634 memcpy( ptr + block_size - elem_size, next_block->data, elem_size ); 1635 block = next_block; 1636 ptr = block->data; 1637 block_size = block->count * elem_size; 1638 } 1639 1640 memmove( ptr, ptr + elem_size, block_size - elem_size ); 1641 seq->ptr -= elem_size; 1642 } 1643 else 1644 { 1645 ptr += elem_size; 1646 block_size = (int)(ptr - block->data); 1647 1648 while( block != seq->first ) 1649 { 1650 CvSeqBlock *prev_block = block->prev; 1651 1652 memmove( block->data + elem_size, block->data, block_size - elem_size ); 1653 block_size = prev_block->count * elem_size; 1654 memcpy( block->data, prev_block->data + block_size - elem_size, elem_size ); 1655 block = prev_block; 1656 } 1657 1658 memmove( block->data + elem_size, block->data, block_size - elem_size ); 1659 block->data += elem_size; 1660 block->start_index++; 1661 } 1662 1663 seq->total = total - 1; 1664 if( --block->count == 0 ) 1665 icvFreeSeqBlock( seq, front ); 1666 } 1667 1668 __END__; 1669 } 1670 1671 1672 /* Add several elements to the beginning or end of a sequence: */ 1673 CV_IMPL void 1674 cvSeqPushMulti( CvSeq *seq, void *_elements, int count, int front ) 1675 { 1676 char *elements = (char *) _elements; 1677 1678 CV_FUNCNAME( "cvSeqPushMulti" ); 1679 1680 __BEGIN__; 1681 int elem_size; 1682 1683 if( !seq ) 1684 CV_ERROR( CV_StsNullPtr, "NULL sequence pointer" ); 1685 if( count < 0 ) 1686 CV_ERROR( CV_StsBadSize, "number of removed elements is negative" ); 1687 1688 elem_size = seq->elem_size; 1689 1690 if( !front ) 1691 { 1692 while( count > 0 ) 1693 { 1694 int delta = (int)((seq->block_max - seq->ptr) / elem_size); 1695 1696 delta = MIN( delta, count ); 1697 if( delta > 0 ) 1698 { 1699 seq->first->prev->count += delta; 1700 seq->total += delta; 1701 count -= delta; 1702 delta *= elem_size; 1703 if( elements ) 1704 { 1705 memcpy( seq->ptr, elements, delta ); 1706 elements += delta; 1707 } 1708 seq->ptr += delta; 1709 } 1710 1711 if( count > 0 ) 1712 CV_CALL( icvGrowSeq( seq, 0 )); 1713 } 1714 } 1715 else 1716 { 1717 CvSeqBlock* block = seq->first; 1718 1719 while( count > 0 ) 1720 { 1721 int delta; 1722 1723 if( !block || block->start_index == 0 ) 1724 { 1725 CV_CALL( icvGrowSeq( seq, 1 )); 1726 1727 block = seq->first; 1728 assert( block->start_index > 0 ); 1729 } 1730 1731 delta = MIN( block->start_index, count ); 1732 count -= delta; 1733 block->start_index -= delta; 1734 block->count += delta; 1735 seq->total += delta; 1736 delta *= elem_size; 1737 block->data -= delta; 1738 1739 if( elements ) 1740 memcpy( block->data, elements + count*elem_size, delta ); 1741 } 1742 } 1743 1744 __END__; 1745 } 1746 1747 1748 /* Remove several elements from the end of sequence: */ 1749 CV_IMPL void 1750 cvSeqPopMulti( CvSeq *seq, void *_elements, int count, int front ) 1751 { 1752 char *elements = (char *) _elements; 1753 1754 CV_FUNCNAME( "cvSeqPopMulti" ); 1755 1756 __BEGIN__; 1757 1758 if( !seq ) 1759 CV_ERROR( CV_StsNullPtr, "NULL sequence pointer" ); 1760 if( count < 0 ) 1761 CV_ERROR( CV_StsBadSize, "number of removed elements is negative" ); 1762 1763 count = MIN( count, seq->total ); 1764 1765 if( !front ) 1766 { 1767 if( elements ) 1768 elements += count * seq->elem_size; 1769 1770 while( count > 0 ) 1771 { 1772 int delta = seq->first->prev->count; 1773 1774 delta = MIN( delta, count ); 1775 assert( delta > 0 ); 1776 1777 seq->first->prev->count -= delta; 1778 seq->total -= delta; 1779 count -= delta; 1780 delta *= seq->elem_size; 1781 seq->ptr -= delta; 1782 1783 if( elements ) 1784 { 1785 elements -= delta; 1786 memcpy( elements, seq->ptr, delta ); 1787 } 1788 1789 if( seq->first->prev->count == 0 ) 1790 icvFreeSeqBlock( seq, 0 ); 1791 } 1792 } 1793 else 1794 { 1795 while( count > 0 ) 1796 { 1797 int delta = seq->first->count; 1798 1799 delta = MIN( delta, count ); 1800 assert( delta > 0 ); 1801 1802 seq->first->count -= delta; 1803 seq->total -= delta; 1804 count -= delta; 1805 seq->first->start_index += delta; 1806 delta *= seq->elem_size; 1807 1808 if( elements ) 1809 { 1810 memcpy( elements, seq->first->data, delta ); 1811 elements += delta; 1812 } 1813 1814 seq->first->data += delta; 1815 if( seq->first->count == 0 ) 1816 icvFreeSeqBlock( seq, 1 ); 1817 } 1818 } 1819 1820 __END__; 1821 } 1822 1823 1824 /* Remove all elements from a sequence: */ 1825 CV_IMPL void 1826 cvClearSeq( CvSeq *seq ) 1827 { 1828 CV_FUNCNAME( "cvClearSeq" ); 1829 1830 __BEGIN__; 1831 1832 if( !seq ) 1833 CV_ERROR( CV_StsNullPtr, "" ); 1834 cvSeqPopMulti( seq, 0, seq->total ); 1835 1836 __END__; 1837 } 1838 1839 1840 CV_IMPL CvSeq* 1841 cvSeqSlice( const CvSeq* seq, CvSlice slice, CvMemStorage* storage, int copy_data ) 1842 { 1843 CvSeq* subseq = 0; 1844 1845 CV_FUNCNAME("cvSeqSlice"); 1846 1847 __BEGIN__; 1848 1849 int elem_size, count, length; 1850 CvSeqReader reader; 1851 CvSeqBlock *block, *first_block = 0, *last_block = 0; 1852 1853 if( !CV_IS_SEQ(seq) ) 1854 CV_ERROR( CV_StsBadArg, "Invalid sequence header" ); 1855 1856 if( !storage ) 1857 { 1858 storage = seq->storage; 1859 if( !storage ) 1860 CV_ERROR( CV_StsNullPtr, "NULL storage pointer" ); 1861 } 1862 1863 elem_size = seq->elem_size; 1864 length = cvSliceLength( slice, seq ); 1865 if( slice.start_index < 0 ) 1866 slice.start_index += seq->total; 1867 else if( slice.start_index >= seq->total ) 1868 slice.start_index -= seq->total; 1869 if( (unsigned)length > (unsigned)seq->total || 1870 ((unsigned)slice.start_index >= (unsigned)seq->total && length != 0) ) 1871 CV_ERROR( CV_StsOutOfRange, "Bad sequence slice" ); 1872 1873 CV_CALL( subseq = cvCreateSeq( seq->flags, seq->header_size, elem_size, storage )); 1874 1875 if( length > 0 ) 1876 { 1877 cvStartReadSeq( seq, &reader, 0 ); 1878 cvSetSeqReaderPos( &reader, slice.start_index, 0 ); 1879 count = (int)((reader.block_max - reader.ptr)/elem_size); 1880 1881 do 1882 { 1883 int bl = MIN( count, length ); 1884 1885 if( !copy_data ) 1886 { 1887 block = (CvSeqBlock*)cvMemStorageAlloc( storage, sizeof(*block) ); 1888 if( !first_block ) 1889 { 1890 first_block = subseq->first = block->prev = block->next = block; 1891 block->start_index = 0; 1892 } 1893 else 1894 { 1895 block->prev = last_block; 1896 block->next = first_block; 1897 last_block->next = first_block->prev = block; 1898 block->start_index = last_block->start_index + last_block->count; 1899 } 1900 last_block = block; 1901 block->data = reader.ptr; 1902 block->count = bl; 1903 subseq->total += bl; 1904 } 1905 else 1906 cvSeqPushMulti( subseq, reader.ptr, bl, 0 ); 1907 length -= bl; 1908 reader.block = reader.block->next; 1909 reader.ptr = reader.block->data; 1910 count = reader.block->count; 1911 } 1912 while( length > 0 ); 1913 } 1914 1915 __END__; 1916 1917 return subseq; 1918 } 1919 1920 1921 // Remove slice from the middle of the sequence. 1922 // !!! TODO !!! Implement more efficient algorithm 1923 CV_IMPL void 1924 cvSeqRemoveSlice( CvSeq* seq, CvSlice slice ) 1925 { 1926 CV_FUNCNAME("cvSeqRemoveSlice"); 1927 1928 __BEGIN__; 1929 1930 int total, length; 1931 1932 if( !CV_IS_SEQ(seq) ) 1933 CV_ERROR( CV_StsBadArg, "Invalid sequence header" ); 1934 1935 length = cvSliceLength( slice, seq ); 1936 total = seq->total; 1937 1938 if( slice.start_index < 0 ) 1939 slice.start_index += total; 1940 else if( slice.start_index >= total ) 1941 slice.start_index -= total; 1942 1943 if( (unsigned)slice.start_index >= (unsigned)total ) 1944 CV_ERROR( CV_StsOutOfRange, "start slice index is out of range" ); 1945 1946 slice.end_index = slice.start_index + length; 1947 1948 if( slice.end_index < total ) 1949 { 1950 CvSeqReader reader_to, reader_from; 1951 int elem_size = seq->elem_size; 1952 1953 cvStartReadSeq( seq, &reader_to ); 1954 cvStartReadSeq( seq, &reader_from ); 1955 1956 if( slice.start_index > total - slice.end_index ) 1957 { 1958 int i, count = seq->total - slice.end_index; 1959 cvSetSeqReaderPos( &reader_to, slice.start_index ); 1960 cvSetSeqReaderPos( &reader_from, slice.end_index ); 1961 1962 for( i = 0; i < count; i++ ) 1963 { 1964 CV_MEMCPY_AUTO( reader_to.ptr, reader_from.ptr, elem_size ); 1965 CV_NEXT_SEQ_ELEM( elem_size, reader_to ); 1966 CV_NEXT_SEQ_ELEM( elem_size, reader_from ); 1967 } 1968 1969 cvSeqPopMulti( seq, 0, slice.end_index - slice.start_index ); 1970 } 1971 else 1972 { 1973 int i, count = slice.start_index; 1974 cvSetSeqReaderPos( &reader_to, slice.end_index ); 1975 cvSetSeqReaderPos( &reader_from, slice.start_index ); 1976 1977 for( i = 0; i < count; i++ ) 1978 { 1979 CV_PREV_SEQ_ELEM( elem_size, reader_to ); 1980 CV_PREV_SEQ_ELEM( elem_size, reader_from ); 1981 1982 CV_MEMCPY_AUTO( reader_to.ptr, reader_from.ptr, elem_size ); 1983 } 1984 1985 cvSeqPopMulti( seq, 0, slice.end_index - slice.start_index, 1 ); 1986 } 1987 } 1988 else 1989 { 1990 cvSeqPopMulti( seq, 0, total - slice.start_index ); 1991 cvSeqPopMulti( seq, 0, slice.end_index - total, 1 ); 1992 } 1993 1994 __END__; 1995 } 1996 1997 1998 // Insert a sequence into the middle of another sequence: 1999 // !!! TODO !!! Implement more efficient algorithm 2000 CV_IMPL void 2001 cvSeqInsertSlice( CvSeq* seq, int index, const CvArr* from_arr ) 2002 { 2003 CvSeqReader reader_to, reader_from; 2004 int i, elem_size, total, from_total; 2005 2006 CV_FUNCNAME("cvSeqInsertSlice"); 2007 2008 __BEGIN__; 2009 2010 CvSeq from_header, *from = (CvSeq*)from_arr; 2011 CvSeqBlock block; 2012 2013 if( !CV_IS_SEQ(seq) ) 2014 CV_ERROR( CV_StsBadArg, "Invalid destination sequence header" ); 2015 2016 if( !CV_IS_SEQ(from)) 2017 { 2018 CvMat* mat = (CvMat*)from; 2019 if( !CV_IS_MAT(mat)) 2020 CV_ERROR( CV_StsBadArg, "Source is not a sequence nor matrix" ); 2021 2022 if( !CV_IS_MAT_CONT(mat->type) || (mat->rows != 1 && mat->cols != 1) ) 2023 CV_ERROR( CV_StsBadArg, "The source array must be 1d coninuous vector" ); 2024 2025 CV_CALL( from = cvMakeSeqHeaderForArray( CV_SEQ_KIND_GENERIC, sizeof(from_header), 2026 CV_ELEM_SIZE(mat->type), 2027 mat->data.ptr, mat->cols + mat->rows - 1, 2028 &from_header, &block )); 2029 } 2030 2031 if( seq->elem_size != from->elem_size ) 2032 CV_ERROR( CV_StsUnmatchedSizes, 2033 "Source and destination sequence element sizes are different." ); 2034 2035 from_total = from->total; 2036 2037 if( from_total == 0 ) 2038 EXIT; 2039 2040 total = seq->total; 2041 index += index < 0 ? total : 0; 2042 index -= index > total ? total : 0; 2043 2044 if( (unsigned)index > (unsigned)total ) 2045 CV_ERROR( CV_StsOutOfRange, "" ); 2046 2047 elem_size = seq->elem_size; 2048 2049 if( index < (total >> 1) ) 2050 { 2051 cvSeqPushMulti( seq, 0, from_total, 1 ); 2052 2053 cvStartReadSeq( seq, &reader_to ); 2054 cvStartReadSeq( seq, &reader_from ); 2055 cvSetSeqReaderPos( &reader_from, from_total ); 2056 2057 for( i = 0; i < index; i++ ) 2058 { 2059 CV_MEMCPY_AUTO( reader_to.ptr, reader_from.ptr, elem_size ); 2060 CV_NEXT_SEQ_ELEM( elem_size, reader_to ); 2061 CV_NEXT_SEQ_ELEM( elem_size, reader_from ); 2062 } 2063 } 2064 else 2065 { 2066 cvSeqPushMulti( seq, 0, from_total ); 2067 2068 cvStartReadSeq( seq, &reader_to ); 2069 cvStartReadSeq( seq, &reader_from ); 2070 cvSetSeqReaderPos( &reader_from, total ); 2071 cvSetSeqReaderPos( &reader_to, seq->total ); 2072 2073 for( i = 0; i < total - index; i++ ) 2074 { 2075 CV_PREV_SEQ_ELEM( elem_size, reader_to ); 2076 CV_PREV_SEQ_ELEM( elem_size, reader_from ); 2077 CV_MEMCPY_AUTO( reader_to.ptr, reader_from.ptr, elem_size ); 2078 } 2079 } 2080 2081 cvStartReadSeq( from, &reader_from ); 2082 cvSetSeqReaderPos( &reader_to, index ); 2083 2084 for( i = 0; i < from_total; i++ ) 2085 { 2086 CV_MEMCPY_AUTO( reader_to.ptr, reader_from.ptr, elem_size ); 2087 CV_NEXT_SEQ_ELEM( elem_size, reader_to ); 2088 CV_NEXT_SEQ_ELEM( elem_size, reader_from ); 2089 } 2090 2091 __END__; 2092 } 2093 2094 // Sort the sequence using user-specified comparison function. 2095 // The semantics is similar to qsort() function. 2096 // The code is based on BSD system qsort(): 2097 // * Copyright (c) 1992, 1993 2098 // * The Regents of the University of California. All rights reserved. 2099 // * 2100 // * Redistribution and use in source and binary forms, with or without 2101 // * modification, are permitted provided that the following conditions 2102 // * are met: 2103 // * 1. Redistributions of source code must retain the above copyright 2104 // * notice, this list of conditions and the following disclaimer. 2105 // * 2. Redistributions in binary form must reproduce the above copyright 2106 // * notice, this list of conditions and the following disclaimer in the 2107 // * documentation and/or other materials provided with the distribution. 2108 // * 3. All advertising materials mentioning features or use of this software 2109 // * must display the following acknowledgement: 2110 // * This product includes software developed by the University of 2111 // * California, Berkeley and its contributors. 2112 // * 4. Neither the name of the University nor the names of its contributors 2113 // * may be used to endorse or promote products derived from this software 2114 // * without specific prior written permission. 2115 // * 2116 // * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2117 // * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2118 // * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2119 // * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2120 // * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2121 // * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2122 // * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2123 // * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2124 // * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2125 // * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2126 // * SUCH DAMAGE. 2127 2128 typedef struct CvSeqReaderPos 2129 { 2130 CvSeqBlock* block; 2131 schar* ptr; 2132 schar* block_min; 2133 schar* block_max; 2134 } 2135 CvSeqReaderPos; 2136 2137 #define CV_SAVE_READER_POS( reader, pos ) \ 2138 { \ 2139 (pos).block = (reader).block; \ 2140 (pos).ptr = (reader).ptr; \ 2141 (pos).block_min = (reader).block_min; \ 2142 (pos).block_max = (reader).block_max; \ 2143 } 2144 2145 #define CV_RESTORE_READER_POS( reader, pos )\ 2146 { \ 2147 (reader).block = (pos).block; \ 2148 (reader).ptr = (pos).ptr; \ 2149 (reader).block_min = (pos).block_min; \ 2150 (reader).block_max = (pos).block_max; \ 2151 } 2152 2153 inline schar* 2154 icvMed3( schar* a, schar* b, schar* c, CvCmpFunc cmp_func, void* aux ) 2155 { 2156 return cmp_func(a, b, aux) < 0 ? 2157 (cmp_func(b, c, aux) < 0 ? b : cmp_func(a, c, aux) < 0 ? c : a) 2158 :(cmp_func(b, c, aux) > 0 ? b : cmp_func(a, c, aux) < 0 ? a : c); 2159 } 2160 2161 CV_IMPL void 2162 cvSeqSort( CvSeq* seq, CvCmpFunc cmp_func, void* aux ) 2163 { 2164 int elem_size; 2165 int isort_thresh = 7; 2166 CvSeqReader left, right; 2167 int sp = 0; 2168 2169 struct 2170 { 2171 CvSeqReaderPos lb; 2172 CvSeqReaderPos ub; 2173 } 2174 stack[48]; 2175 2176 CV_FUNCNAME( "cvSeqSort" ); 2177 2178 __BEGIN__; 2179 2180 if( !CV_IS_SEQ(seq) ) 2181 CV_ERROR( !seq ? CV_StsNullPtr : CV_StsBadArg, "Bad input sequence" ); 2182 2183 if( !cmp_func ) 2184 CV_ERROR( CV_StsNullPtr, "Null compare function" ); 2185 2186 if( seq->total <= 1 ) 2187 EXIT; 2188 2189 elem_size = seq->elem_size; 2190 isort_thresh *= elem_size; 2191 2192 cvStartReadSeq( seq, &left, 0 ); 2193 right = left; 2194 CV_SAVE_READER_POS( left, stack[0].lb ); 2195 CV_PREV_SEQ_ELEM( elem_size, right ); 2196 CV_SAVE_READER_POS( right, stack[0].ub ); 2197 2198 while( sp >= 0 ) 2199 { 2200 CV_RESTORE_READER_POS( left, stack[sp].lb ); 2201 CV_RESTORE_READER_POS( right, stack[sp].ub ); 2202 sp--; 2203 2204 for(;;) 2205 { 2206 int i, n, m; 2207 CvSeqReader ptr, ptr2; 2208 2209 if( left.block == right.block ) 2210 n = (int)(right.ptr - left.ptr) + elem_size; 2211 else 2212 { 2213 n = cvGetSeqReaderPos( &right ); 2214 n = (n - cvGetSeqReaderPos( &left ) + 1)*elem_size; 2215 } 2216 2217 if( n <= isort_thresh ) 2218 { 2219 insert_sort: 2220 ptr = ptr2 = left; 2221 CV_NEXT_SEQ_ELEM( elem_size, ptr ); 2222 CV_NEXT_SEQ_ELEM( elem_size, right ); 2223 while( ptr.ptr != right.ptr ) 2224 { 2225 ptr2.ptr = ptr.ptr; 2226 if( ptr2.block != ptr.block ) 2227 { 2228 ptr2.block = ptr.block; 2229 ptr2.block_min = ptr.block_min; 2230 ptr2.block_max = ptr.block_max; 2231 } 2232 while( ptr2.ptr != left.ptr ) 2233 { 2234 schar* cur = ptr2.ptr; 2235 CV_PREV_SEQ_ELEM( elem_size, ptr2 ); 2236 if( cmp_func( ptr2.ptr, cur, aux ) <= 0 ) 2237 break; 2238 CV_SWAP_ELEMS( ptr2.ptr, cur, elem_size ); 2239 } 2240 CV_NEXT_SEQ_ELEM( elem_size, ptr ); 2241 } 2242 break; 2243 } 2244 else 2245 { 2246 CvSeqReader left0, left1, right0, right1; 2247 CvSeqReader tmp0, tmp1; 2248 schar *m1, *m2, *m3, *pivot; 2249 int swap_cnt = 0; 2250 int l, l0, l1, r, r0, r1; 2251 2252 left0 = tmp0 = left; 2253 right0 = right1 = right; 2254 n /= elem_size; 2255 2256 if( n > 40 ) 2257 { 2258 int d = n / 8; 2259 schar *p1, *p2, *p3; 2260 p1 = tmp0.ptr; 2261 cvSetSeqReaderPos( &tmp0, d, 1 ); 2262 p2 = tmp0.ptr; 2263 cvSetSeqReaderPos( &tmp0, d, 1 ); 2264 p3 = tmp0.ptr; 2265 m1 = icvMed3( p1, p2, p3, cmp_func, aux ); 2266 cvSetSeqReaderPos( &tmp0, (n/2) - d*3, 1 ); 2267 p1 = tmp0.ptr; 2268 cvSetSeqReaderPos( &tmp0, d, 1 ); 2269 p2 = tmp0.ptr; 2270 cvSetSeqReaderPos( &tmp0, d, 1 ); 2271 p3 = tmp0.ptr; 2272 m2 = icvMed3( p1, p2, p3, cmp_func, aux ); 2273 cvSetSeqReaderPos( &tmp0, n - 1 - d*3 - n/2, 1 ); 2274 p1 = tmp0.ptr; 2275 cvSetSeqReaderPos( &tmp0, d, 1 ); 2276 p2 = tmp0.ptr; 2277 cvSetSeqReaderPos( &tmp0, d, 1 ); 2278 p3 = tmp0.ptr; 2279 m3 = icvMed3( p1, p2, p3, cmp_func, aux ); 2280 } 2281 else 2282 { 2283 m1 = tmp0.ptr; 2284 cvSetSeqReaderPos( &tmp0, n/2, 1 ); 2285 m2 = tmp0.ptr; 2286 cvSetSeqReaderPos( &tmp0, n - 1 - n/2, 1 ); 2287 m3 = tmp0.ptr; 2288 } 2289 2290 pivot = icvMed3( m1, m2, m3, cmp_func, aux ); 2291 left = left0; 2292 if( pivot != left.ptr ) 2293 { 2294 CV_SWAP_ELEMS( pivot, left.ptr, elem_size ); 2295 pivot = left.ptr; 2296 } 2297 CV_NEXT_SEQ_ELEM( elem_size, left ); 2298 left1 = left; 2299 2300 for(;;) 2301 { 2302 while( left.ptr != right.ptr && (r = cmp_func(left.ptr, pivot, aux)) <= 0 ) 2303 { 2304 if( r == 0 ) 2305 { 2306 if( left1.ptr != left.ptr ) 2307 CV_SWAP_ELEMS( left1.ptr, left.ptr, elem_size ); 2308 swap_cnt = 1; 2309 CV_NEXT_SEQ_ELEM( elem_size, left1 ); 2310 } 2311 CV_NEXT_SEQ_ELEM( elem_size, left ); 2312 } 2313 2314 while( left.ptr != right.ptr && (r = cmp_func(right.ptr,pivot, aux)) >= 0 ) 2315 { 2316 if( r == 0 ) 2317 { 2318 if( right1.ptr != right.ptr ) 2319 CV_SWAP_ELEMS( right1.ptr, right.ptr, elem_size ); 2320 swap_cnt = 1; 2321 CV_PREV_SEQ_ELEM( elem_size, right1 ); 2322 } 2323 CV_PREV_SEQ_ELEM( elem_size, right ); 2324 } 2325 2326 if( left.ptr == right.ptr ) 2327 { 2328 r = cmp_func(left.ptr, pivot, aux); 2329 if( r == 0 ) 2330 { 2331 if( left1.ptr != left.ptr ) 2332 CV_SWAP_ELEMS( left1.ptr, left.ptr, elem_size ); 2333 swap_cnt = 1; 2334 CV_NEXT_SEQ_ELEM( elem_size, left1 ); 2335 } 2336 if( r <= 0 ) 2337 { 2338 CV_NEXT_SEQ_ELEM( elem_size, left ); 2339 } 2340 else 2341 { 2342 CV_PREV_SEQ_ELEM( elem_size, right ); 2343 } 2344 break; 2345 } 2346 2347 CV_SWAP_ELEMS( left.ptr, right.ptr, elem_size ); 2348 CV_NEXT_SEQ_ELEM( elem_size, left ); 2349 r = left.ptr == right.ptr; 2350 CV_PREV_SEQ_ELEM( elem_size, right ); 2351 swap_cnt = 1; 2352 if( r ) 2353 break; 2354 } 2355 2356 if( swap_cnt == 0 ) 2357 { 2358 left = left0, right = right0; 2359 goto insert_sort; 2360 } 2361 2362 l = cvGetSeqReaderPos( &left ); 2363 if( l == 0 ) 2364 l = seq->total; 2365 l0 = cvGetSeqReaderPos( &left0 ); 2366 l1 = cvGetSeqReaderPos( &left1 ); 2367 if( l1 == 0 ) 2368 l1 = seq->total; 2369 2370 n = MIN( l - l1, l1 - l0 ); 2371 if( n > 0 ) 2372 { 2373 tmp0 = left0; 2374 tmp1 = left; 2375 cvSetSeqReaderPos( &tmp1, 0-n, 1 ); 2376 for( i = 0; i < n; i++ ) 2377 { 2378 CV_SWAP_ELEMS( tmp0.ptr, tmp1.ptr, elem_size ); 2379 CV_NEXT_SEQ_ELEM( elem_size, tmp0 ); 2380 CV_NEXT_SEQ_ELEM( elem_size, tmp1 ); 2381 } 2382 } 2383 2384 r = cvGetSeqReaderPos( &right ); 2385 r0 = cvGetSeqReaderPos( &right0 ); 2386 r1 = cvGetSeqReaderPos( &right1 ); 2387 m = MIN( r0 - r1, r1 - r ); 2388 if( m > 0 ) 2389 { 2390 tmp0 = left; 2391 tmp1 = right0; 2392 cvSetSeqReaderPos( &tmp1, 1-m, 1 ); 2393 for( i = 0; i < m; i++ ) 2394 { 2395 CV_SWAP_ELEMS( tmp0.ptr, tmp1.ptr, elem_size ); 2396 CV_NEXT_SEQ_ELEM( elem_size, tmp0 ); 2397 CV_NEXT_SEQ_ELEM( elem_size, tmp1 ); 2398 } 2399 } 2400 2401 n = l - l1; 2402 m = r1 - r; 2403 if( n > 1 ) 2404 { 2405 if( m > 1 ) 2406 { 2407 if( n > m ) 2408 { 2409 sp++; 2410 CV_SAVE_READER_POS( left0, stack[sp].lb ); 2411 cvSetSeqReaderPos( &left0, n - 1, 1 ); 2412 CV_SAVE_READER_POS( left0, stack[sp].ub ); 2413 left = right = right0; 2414 cvSetSeqReaderPos( &left, 1 - m, 1 ); 2415 } 2416 else 2417 { 2418 sp++; 2419 CV_SAVE_READER_POS( right0, stack[sp].ub ); 2420 cvSetSeqReaderPos( &right0, 1 - m, 1 ); 2421 CV_SAVE_READER_POS( right0, stack[sp].lb ); 2422 left = right = left0; 2423 cvSetSeqReaderPos( &right, n - 1, 1 ); 2424 } 2425 } 2426 else 2427 { 2428 left = right = left0; 2429 cvSetSeqReaderPos( &right, n - 1, 1 ); 2430 } 2431 } 2432 else if( m > 1 ) 2433 { 2434 left = right = right0; 2435 cvSetSeqReaderPos( &left, 1 - m, 1 ); 2436 } 2437 else 2438 break; 2439 } 2440 } 2441 } 2442 2443 __END__; 2444 } 2445 2446 2447 CV_IMPL schar* 2448 cvSeqSearch( CvSeq* seq, const void* _elem, CvCmpFunc cmp_func, 2449 int is_sorted, int* _idx, void* userdata ) 2450 { 2451 schar* result = 0; 2452 const schar* elem = (const schar*)_elem; 2453 int idx = -1; 2454 2455 CV_FUNCNAME("cvSeqSearch"); 2456 2457 __BEGIN__; 2458 2459 int elem_size, i, j, total; 2460 2461 if( !CV_IS_SEQ(seq) ) 2462 CV_ERROR( !seq ? CV_StsNullPtr : CV_StsBadArg, "Bad input sequence" ); 2463 2464 if( !elem ) 2465 CV_ERROR( CV_StsNullPtr, "Null element pointer" ); 2466 2467 elem_size = seq->elem_size; 2468 total = seq->total; 2469 2470 if( total == 0 ) 2471 EXIT; 2472 2473 if( !is_sorted ) 2474 { 2475 CvSeqReader reader; 2476 cvStartReadSeq( seq, &reader, 0 ); 2477 2478 if( cmp_func ) 2479 { 2480 for( i = 0; i < total; i++ ) 2481 { 2482 if( cmp_func( elem, reader.ptr, userdata ) == 0 ) 2483 break; 2484 CV_NEXT_SEQ_ELEM( elem_size, reader ); 2485 } 2486 } 2487 else if( (elem_size & (sizeof(int)-1)) == 0 ) 2488 { 2489 for( i = 0; i < total; i++ ) 2490 { 2491 for( j = 0; j < elem_size; j += sizeof(int) ) 2492 { 2493 if( *(const int*)(reader.ptr + j) != *(const int*)(elem + j) ) 2494 break; 2495 } 2496 if( j == elem_size ) 2497 break; 2498 CV_NEXT_SEQ_ELEM( elem_size, reader ); 2499 } 2500 } 2501 else 2502 { 2503 for( i = 0; i < total; i++ ) 2504 { 2505 for( j = 0; j < elem_size; j++ ) 2506 { 2507 if( reader.ptr[j] != elem[j] ) 2508 break; 2509 } 2510 if( j == elem_size ) 2511 break; 2512 CV_NEXT_SEQ_ELEM( elem_size, reader ); 2513 } 2514 } 2515 2516 idx = i; 2517 if( i < total ) 2518 result = reader.ptr; 2519 } 2520 else 2521 { 2522 if( !cmp_func ) 2523 CV_ERROR( CV_StsNullPtr, "Null compare function" ); 2524 2525 i = 0, j = total; 2526 2527 while( j > i ) 2528 { 2529 int k = (i+j)>>1, code; 2530 schar* ptr = cvGetSeqElem( seq, k ); 2531 code = cmp_func( elem, ptr, userdata ); 2532 if( !code ) 2533 { 2534 result = ptr; 2535 idx = k; 2536 EXIT; 2537 } 2538 if( code < 0 ) 2539 j = k; 2540 else 2541 i = k+1; 2542 } 2543 idx = j; 2544 } 2545 2546 __END__; 2547 2548 if( _idx ) 2549 *_idx = idx; 2550 2551 return result; 2552 } 2553 2554 2555 CV_IMPL void 2556 cvSeqInvert( CvSeq* seq ) 2557 { 2558 CV_FUNCNAME( "cvSeqInvert" ); 2559 2560 __BEGIN__; 2561 2562 CvSeqReader left_reader, right_reader; 2563 int elem_size; 2564 int i, count; 2565 2566 CV_CALL( cvStartReadSeq( seq, &left_reader, 0 )); 2567 CV_CALL( cvStartReadSeq( seq, &right_reader, 1 )); 2568 elem_size = seq->elem_size; 2569 count = seq->total >> 1; 2570 2571 for( i = 0; i < count; i++ ) 2572 { 2573 CV_SWAP_ELEMS( left_reader.ptr, right_reader.ptr, elem_size ); 2574 CV_NEXT_SEQ_ELEM( elem_size, left_reader ); 2575 CV_PREV_SEQ_ELEM( elem_size, right_reader ); 2576 } 2577 2578 __END__; 2579 } 2580 2581 2582 typedef struct CvPTreeNode 2583 { 2584 struct CvPTreeNode* parent; 2585 schar* element; 2586 int rank; 2587 } 2588 CvPTreeNode; 2589 2590 2591 // This function splits the input sequence or set into one or more equivalence classes. 2592 // is_equal(a,b,...) returns non-zero if the two sequence elements 2593 // belong to the same class. The function returns sequence of integers - 2594 // 0-based class indexes for each element. 2595 // 2596 // The algorithm is described in "Introduction to Algorithms" 2597 // by Cormen, Leiserson and Rivest, chapter "Data structures for disjoint sets" 2598 CV_IMPL int 2599 cvSeqPartition( const CvSeq* seq, CvMemStorage* storage, CvSeq** labels, 2600 CvCmpFunc is_equal, void* userdata ) 2601 { 2602 CvSeq* result = 0; 2603 CvMemStorage* temp_storage = 0; 2604 int class_idx = 0; 2605 2606 CV_FUNCNAME( "cvSeqPartition" ); 2607 2608 __BEGIN__; 2609 2610 CvSeqWriter writer; 2611 CvSeqReader reader, reader0; 2612 CvSeq* nodes; 2613 int i, j; 2614 int is_set; 2615 2616 if( !labels ) 2617 CV_ERROR( CV_StsNullPtr, "" ); 2618 2619 if( !seq || !is_equal ) 2620 CV_ERROR( CV_StsNullPtr, "" ); 2621 2622 if( !storage ) 2623 storage = seq->storage; 2624 2625 if( !storage ) 2626 CV_ERROR( CV_StsNullPtr, "" ); 2627 2628 is_set = CV_IS_SET(seq); 2629 2630 temp_storage = cvCreateChildMemStorage( storage ); 2631 2632 nodes = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPTreeNode), temp_storage ); 2633 2634 cvStartReadSeq( seq, &reader ); 2635 memset( &writer, 0, sizeof(writer)); 2636 cvStartAppendToSeq( nodes, &writer ); 2637 2638 // Initial O(N) pass. Make a forest of single-vertex trees. 2639 for( i = 0; i < seq->total; i++ ) 2640 { 2641 CvPTreeNode node = { 0, 0, 0 }; 2642 if( !is_set || CV_IS_SET_ELEM( reader.ptr )) 2643 node.element = reader.ptr; 2644 CV_WRITE_SEQ_ELEM( node, writer ); 2645 CV_NEXT_SEQ_ELEM( seq->elem_size, reader ); 2646 } 2647 2648 cvEndWriteSeq( &writer ); 2649 2650 // Because in the next loop we will iterate 2651 // through all the sequence nodes each time, 2652 // we do not need to initialize reader every time: 2653 cvStartReadSeq( nodes, &reader ); 2654 cvStartReadSeq( nodes, &reader0 ); 2655 2656 // The main O(N^2) pass. Merge connected components. 2657 for( i = 0; i < nodes->total; i++ ) 2658 { 2659 CvPTreeNode* node = (CvPTreeNode*)(reader0.ptr); 2660 CvPTreeNode* root = node; 2661 CV_NEXT_SEQ_ELEM( nodes->elem_size, reader0 ); 2662 2663 if( !node->element ) 2664 continue; 2665 2666 // find root 2667 while( root->parent ) 2668 root = root->parent; 2669 2670 for( j = 0; j < nodes->total; j++ ) 2671 { 2672 CvPTreeNode* node2 = (CvPTreeNode*)reader.ptr; 2673 2674 if( node2->element && node2 != node && 2675 is_equal( node->element, node2->element, userdata )) 2676 { 2677 CvPTreeNode* root2 = node2; 2678 2679 // unite both trees 2680 while( root2->parent ) 2681 root2 = root2->parent; 2682 2683 if( root2 != root ) 2684 { 2685 if( root->rank > root2->rank ) 2686 root2->parent = root; 2687 else 2688 { 2689 root->parent = root2; 2690 root2->rank += root->rank == root2->rank; 2691 root = root2; 2692 } 2693 assert( root->parent == 0 ); 2694 2695 // Compress path from node2 to the root: 2696 while( node2->parent ) 2697 { 2698 CvPTreeNode* temp = node2; 2699 node2 = node2->parent; 2700 temp->parent = root; 2701 } 2702 2703 // Compress path from node to the root: 2704 node2 = node; 2705 while( node2->parent ) 2706 { 2707 CvPTreeNode* temp = node2; 2708 node2 = node2->parent; 2709 temp->parent = root; 2710 } 2711 } 2712 } 2713 2714 CV_NEXT_SEQ_ELEM( sizeof(*node), reader ); 2715 } 2716 } 2717 2718 // Final O(N) pass (Enumerate classes) 2719 // Reuse reader one more time 2720 result = cvCreateSeq( 0, sizeof(CvSeq), sizeof(int), storage ); 2721 cvStartAppendToSeq( result, &writer ); 2722 2723 for( i = 0; i < nodes->total; i++ ) 2724 { 2725 CvPTreeNode* node = (CvPTreeNode*)reader.ptr; 2726 int idx = -1; 2727 2728 if( node->element ) 2729 { 2730 while( node->parent ) 2731 node = node->parent; 2732 if( node->rank >= 0 ) 2733 node->rank = ~class_idx++; 2734 idx = ~node->rank; 2735 } 2736 2737 CV_NEXT_SEQ_ELEM( sizeof(*node), reader ); 2738 CV_WRITE_SEQ_ELEM( idx, writer ); 2739 } 2740 2741 cvEndWriteSeq( &writer ); 2742 2743 __END__; 2744 2745 if( labels ) 2746 *labels = result; 2747 2748 cvReleaseMemStorage( &temp_storage ); 2749 return class_idx; 2750 } 2751 2752 2753 /****************************************************************************************\ 2754 * Set implementation * 2755 \****************************************************************************************/ 2756 2757 /* Creates empty set: */ 2758 CV_IMPL CvSet* 2759 cvCreateSet( int set_flags, int header_size, int elem_size, CvMemStorage * storage ) 2760 { 2761 CvSet *set = 0; 2762 2763 CV_FUNCNAME( "cvCreateSet" ); 2764 2765 __BEGIN__; 2766 2767 if( !storage ) 2768 CV_ERROR( CV_StsNullPtr, "" ); 2769 if( header_size < (int)sizeof( CvSet ) || 2770 elem_size < (int)sizeof(void*)*2 || 2771 (elem_size & (sizeof(void*)-1)) != 0 ) 2772 CV_ERROR( CV_StsBadSize, "" ); 2773 2774 set = (CvSet*) cvCreateSeq( set_flags, header_size, elem_size, storage ); 2775 set->flags = (set->flags & ~CV_MAGIC_MASK) | CV_SET_MAGIC_VAL; 2776 2777 __END__; 2778 2779 return set; 2780 } 2781 2782 2783 /* Add new element to the set: */ 2784 CV_IMPL int 2785 cvSetAdd( CvSet* set, CvSetElem* element, CvSetElem** inserted_element ) 2786 { 2787 int id = -1; 2788 2789 CV_FUNCNAME( "cvSetAdd" ); 2790 2791 __BEGIN__; 2792 2793 CvSetElem *free_elem; 2794 2795 if( !set ) 2796 CV_ERROR( CV_StsNullPtr, "" ); 2797 2798 if( !(set->free_elems) ) 2799 { 2800 int count = set->total; 2801 int elem_size = set->elem_size; 2802 schar *ptr; 2803 CV_CALL( icvGrowSeq( (CvSeq *) set, 0 )); 2804 2805 set->free_elems = (CvSetElem*) (ptr = set->ptr); 2806 for( ; ptr + elem_size <= set->block_max; ptr += elem_size, count++ ) 2807 { 2808 ((CvSetElem*)ptr)->flags = count | CV_SET_ELEM_FREE_FLAG; 2809 ((CvSetElem*)ptr)->next_free = (CvSetElem*)(ptr + elem_size); 2810 } 2811 assert( count <= CV_SET_ELEM_IDX_MASK+1 ); 2812 ((CvSetElem*)(ptr - elem_size))->next_free = 0; 2813 set->first->prev->count += count - set->total; 2814 set->total = count; 2815 set->ptr = set->block_max; 2816 } 2817 2818 free_elem = set->free_elems; 2819 set->free_elems = free_elem->next_free; 2820 2821 id = free_elem->flags & CV_SET_ELEM_IDX_MASK; 2822 if( element ) 2823 CV_MEMCPY_INT( free_elem, element, (size_t)set->elem_size/sizeof(int) ); 2824 2825 free_elem->flags = id; 2826 set->active_count++; 2827 2828 if( inserted_element ) 2829 *inserted_element = free_elem; 2830 2831 __END__; 2832 2833 return id; 2834 } 2835 2836 2837 /* Remove element from a set given element index: */ 2838 CV_IMPL void 2839 cvSetRemove( CvSet* set, int index ) 2840 { 2841 CV_FUNCNAME( "cvSetRemove" ); 2842 2843 __BEGIN__; 2844 2845 CvSetElem* elem = cvGetSetElem( set, index ); 2846 if( elem ) 2847 cvSetRemoveByPtr( set, elem ); 2848 else if( !set ) 2849 CV_ERROR( CV_StsNullPtr, "" ); 2850 2851 __END__; 2852 } 2853 2854 2855 /* Remove all elements from a set: */ 2856 CV_IMPL void 2857 cvClearSet( CvSet* set ) 2858 { 2859 CV_FUNCNAME( "cvClearSet" ); 2860 2861 __BEGIN__; 2862 2863 CV_CALL( cvClearSeq( (CvSeq*)set )); 2864 set->free_elems = 0; 2865 set->active_count = 0; 2866 2867 __END__; 2868 } 2869 2870 2871 /****************************************************************************************\ 2872 * Graph implementation * 2873 \****************************************************************************************/ 2874 2875 /* Create a new graph: */ 2876 CV_IMPL CvGraph * 2877 cvCreateGraph( int graph_type, int header_size, 2878 int vtx_size, int edge_size, CvMemStorage * storage ) 2879 { 2880 CvGraph *graph = 0; 2881 CvSet *edges = 0; 2882 2883 CV_FUNCNAME( "cvCleateGraph" ); 2884 2885 __BEGIN__; 2886 2887 CvSet *vertices = 0; 2888 2889 if( header_size < (int) sizeof( CvGraph ) 2890 || edge_size < (int) sizeof( CvGraphEdge ) 2891 || vtx_size < (int) sizeof( CvGraphVtx ) 2892 ){ 2893 CV_ERROR( CV_StsBadSize, "" ); 2894 } 2895 2896 CV_CALL( vertices = cvCreateSet( graph_type, header_size, vtx_size, storage )); 2897 CV_CALL( edges = cvCreateSet( CV_SEQ_KIND_GENERIC | CV_SEQ_ELTYPE_GRAPH_EDGE, 2898 sizeof( CvSet ), edge_size, storage )); 2899 2900 graph = (CvGraph*)vertices; 2901 graph->edges = edges; 2902 2903 __END__; 2904 2905 return graph; 2906 } 2907 2908 2909 /* Remove all vertices and edges from a graph: */ 2910 CV_IMPL void 2911 cvClearGraph( CvGraph * graph ) 2912 { 2913 CV_FUNCNAME( "cvClearGraph" ); 2914 2915 __BEGIN__; 2916 2917 if( !graph ) 2918 CV_ERROR( CV_StsNullPtr, "" ); 2919 2920 cvClearSet( graph->edges ); 2921 cvClearSet( (CvSet*)graph ); 2922 2923 __END__; 2924 } 2925 2926 2927 /* Add a vertex to a graph: */ 2928 CV_IMPL int 2929 cvGraphAddVtx( CvGraph* graph, const CvGraphVtx* _vertex, CvGraphVtx** _inserted_vertex ) 2930 { 2931 CvGraphVtx *vertex = 0; 2932 int index = -1; 2933 2934 CV_FUNCNAME( "cvGraphAddVtx" ); 2935 2936 __BEGIN__; 2937 2938 if( !graph ) 2939 CV_ERROR( CV_StsNullPtr, "" ); 2940 2941 vertex = (CvGraphVtx*)cvSetNew((CvSet*)graph); 2942 if( vertex ) 2943 { 2944 if( _vertex ) 2945 CV_MEMCPY_INT( vertex + 1, _vertex + 1, 2946 (size_t)(graph->elem_size - sizeof(CvGraphVtx))/sizeof(int) ); 2947 vertex->first = 0; 2948 index = vertex->flags; 2949 } 2950 2951 if( _inserted_vertex ) 2952 *_inserted_vertex = vertex; 2953 2954 __END__; 2955 2956 return index; 2957 } 2958 2959 2960 /* Remove a vertex from the graph together with its incident edges: */ 2961 CV_IMPL int 2962 cvGraphRemoveVtxByPtr( CvGraph* graph, CvGraphVtx* vtx ) 2963 { 2964 int count = -1; 2965 2966 CV_FUNCNAME( "cvGraphRemoveVtxByPtr" ); 2967 2968 __BEGIN__; 2969 2970 if( !graph || !vtx ) 2971 CV_ERROR( CV_StsNullPtr, "" ); 2972 2973 if( !CV_IS_SET_ELEM(vtx)) 2974 CV_ERROR( CV_StsBadArg, "The vertex does not belong to the graph" ); 2975 2976 count = graph->edges->active_count; 2977 for( ;; ) 2978 { 2979 CvGraphEdge *edge = vtx->first; 2980 if( !edge ) 2981 break; 2982 cvGraphRemoveEdgeByPtr( graph, edge->vtx[0], edge->vtx[1] ); 2983 } 2984 count -= graph->edges->active_count; 2985 cvSetRemoveByPtr( (CvSet*)graph, vtx ); 2986 2987 __END__; 2988 2989 return count; 2990 } 2991 2992 2993 /* Remove a vertex from the graph together with its incident edges: */ 2994 CV_IMPL int 2995 cvGraphRemoveVtx( CvGraph* graph, int index ) 2996 { 2997 int count = -1; 2998 CvGraphVtx *vtx = 0; 2999 3000 CV_FUNCNAME( "cvGraphRemoveVtx" ); 3001 3002 __BEGIN__; 3003 3004 if( !graph ) 3005 CV_ERROR( CV_StsNullPtr, "" ); 3006 3007 vtx = cvGetGraphVtx( graph, index ); 3008 if( !vtx ) 3009 CV_ERROR( CV_StsBadArg, "The vertex is not found" ); 3010 3011 count = graph->edges->active_count; 3012 for( ;; ) 3013 { 3014 CvGraphEdge *edge = vtx->first; 3015 count++; 3016 3017 if( !edge ) 3018 break; 3019 cvGraphRemoveEdgeByPtr( graph, edge->vtx[0], edge->vtx[1] ); 3020 } 3021 count -= graph->edges->active_count; 3022 cvSetRemoveByPtr( (CvSet*)graph, vtx ); 3023 3024 __END__; 3025 3026 return count; 3027 } 3028 3029 3030 /* Find a graph edge given pointers to the ending vertices: */ 3031 CV_IMPL CvGraphEdge* 3032 cvFindGraphEdgeByPtr( const CvGraph* graph, 3033 const CvGraphVtx* start_vtx, 3034 const CvGraphVtx* end_vtx ) 3035 { 3036 CvGraphEdge *edge = 0; 3037 CV_FUNCNAME( "cvFindGraphEdgeByPtr" ); 3038 3039 __BEGIN__; 3040 3041 int ofs = 0; 3042 3043 if( !graph || !start_vtx || !end_vtx ) 3044 CV_ERROR( CV_StsNullPtr, "" ); 3045 3046 if( start_vtx == end_vtx ) 3047 EXIT; 3048 3049 if( !CV_IS_GRAPH_ORIENTED( graph ) && 3050 (start_vtx->flags & CV_SET_ELEM_IDX_MASK) > (end_vtx->flags & CV_SET_ELEM_IDX_MASK) ) 3051 { 3052 const CvGraphVtx* t; 3053 CV_SWAP( start_vtx, end_vtx, t ); 3054 } 3055 3056 edge = start_vtx->first; 3057 for( ; edge; edge = edge->next[ofs] ) 3058 { 3059 ofs = start_vtx == edge->vtx[1]; 3060 assert( ofs == 1 || start_vtx == edge->vtx[0] ); 3061 if( edge->vtx[1] == end_vtx ) 3062 break; 3063 } 3064 3065 __END__; 3066 3067 return edge; 3068 } 3069 3070 3071 /* Find an edge in the graph given indices of the ending vertices: */ 3072 CV_IMPL CvGraphEdge * 3073 cvFindGraphEdge( const CvGraph* graph, int start_idx, int end_idx ) 3074 { 3075 CvGraphEdge *edge = 0; 3076 CvGraphVtx *start_vtx; 3077 CvGraphVtx *end_vtx; 3078 3079 CV_FUNCNAME( "cvFindGraphEdge" ); 3080 3081 __BEGIN__; 3082 3083 if( !graph ) 3084 CV_ERROR( CV_StsNullPtr, "graph pointer is NULL" ); 3085 3086 start_vtx = cvGetGraphVtx( graph, start_idx ); 3087 end_vtx = cvGetGraphVtx( graph, end_idx ); 3088 3089 edge = cvFindGraphEdgeByPtr( graph, start_vtx, end_vtx ); 3090 3091 __END__; 3092 3093 return edge; 3094 } 3095 3096 3097 /* Given two vertices, return the edge 3098 * connecting them, creating it if it 3099 * did not already exist: 3100 */ 3101 CV_IMPL int 3102 cvGraphAddEdgeByPtr( CvGraph* graph, 3103 CvGraphVtx* start_vtx, CvGraphVtx* end_vtx, 3104 const CvGraphEdge* _edge, 3105 CvGraphEdge ** _inserted_edge ) 3106 { 3107 CvGraphEdge *edge = 0; 3108 int result = -1; 3109 3110 CV_FUNCNAME( "cvGraphAddEdgeByPtr" ); 3111 3112 __BEGIN__; 3113 3114 int delta; 3115 3116 if( !graph ) 3117 CV_ERROR( CV_StsNullPtr, "graph pointer is NULL" ); 3118 3119 if( !CV_IS_GRAPH_ORIENTED( graph ) && 3120 (start_vtx->flags & CV_SET_ELEM_IDX_MASK) > (end_vtx->flags & CV_SET_ELEM_IDX_MASK) ) 3121 { 3122 CvGraphVtx* t; 3123 CV_SWAP( start_vtx, end_vtx, t ); 3124 } 3125 3126 CV_CALL( edge = cvFindGraphEdgeByPtr( graph, start_vtx, end_vtx )); 3127 if( edge ) 3128 { 3129 result = 0; 3130 EXIT; 3131 } 3132 3133 if( start_vtx == end_vtx ) 3134 CV_ERROR( start_vtx ? CV_StsBadArg : CV_StsNullPtr, 3135 "vertex pointers coinside (or set to NULL)" ); 3136 3137 CV_CALL( edge = (CvGraphEdge*)cvSetNew( (CvSet*)(graph->edges) )); 3138 assert( edge->flags >= 0 ); 3139 3140 edge->vtx[0] = start_vtx; 3141 edge->vtx[1] = end_vtx; 3142 edge->next[0] = start_vtx->first; 3143 edge->next[1] = end_vtx->first; 3144 start_vtx->first = end_vtx->first = edge; 3145 3146 delta = (graph->edges->elem_size - sizeof(*edge))/sizeof(int); 3147 if( _edge ) 3148 { 3149 if( delta > 0 ) 3150 CV_MEMCPY_INT( edge + 1, _edge + 1, delta ); 3151 edge->weight = _edge->weight; 3152 } 3153 else 3154 { 3155 if( delta > 0 ) 3156 CV_ZERO_INT( edge + 1, delta ); 3157 edge->weight = 1.f; 3158 } 3159 3160 result = 1; 3161 3162 __END__; 3163 3164 if( _inserted_edge ) 3165 *_inserted_edge = edge; 3166 3167 return result; 3168 } 3169 3170 /* Given two vertices, return the edge 3171 * connecting them, creating it if it 3172 * did not already exist: 3173 */ 3174 CV_IMPL int 3175 cvGraphAddEdge( CvGraph* graph, 3176 int start_idx, int end_idx, 3177 const CvGraphEdge* _edge, 3178 CvGraphEdge ** _inserted_edge ) 3179 { 3180 CvGraphVtx *start_vtx; 3181 CvGraphVtx *end_vtx; 3182 int result = -1; 3183 3184 CV_FUNCNAME( "cvGraphAddEdge" ); 3185 3186 __BEGIN__; 3187 3188 if( !graph ) 3189 CV_ERROR( CV_StsNullPtr, "" ); 3190 3191 start_vtx = cvGetGraphVtx( graph, start_idx ); 3192 end_vtx = cvGetGraphVtx( graph, end_idx ); 3193 3194 result = cvGraphAddEdgeByPtr( graph, start_vtx, end_vtx, _edge, _inserted_edge ); 3195 3196 __END__; 3197 3198 return result; 3199 } 3200 3201 3202 /* Remove the graph edge connecting two given vertices: */ 3203 CV_IMPL void 3204 cvGraphRemoveEdgeByPtr( CvGraph* graph, CvGraphVtx* start_vtx, CvGraphVtx* end_vtx ) 3205 { 3206 CV_FUNCNAME( "cvGraphRemoveEdgeByPtr" ); 3207 3208 __BEGIN__; 3209 3210 int ofs, prev_ofs; 3211 CvGraphEdge *edge, *next_edge, *prev_edge; 3212 3213 if( !graph || !start_vtx || !end_vtx ) 3214 CV_ERROR( CV_StsNullPtr, "" ); 3215 3216 if( start_vtx == end_vtx ) 3217 EXIT; 3218 3219 if( !CV_IS_GRAPH_ORIENTED( graph ) && 3220 (start_vtx->flags & CV_SET_ELEM_IDX_MASK) > (end_vtx->flags & CV_SET_ELEM_IDX_MASK) ) 3221 { 3222 CvGraphVtx* t; 3223 CV_SWAP( start_vtx, end_vtx, t ); 3224 } 3225 3226 for( ofs = prev_ofs = 0, prev_edge = 0, edge = start_vtx->first; edge != 0; 3227 prev_ofs = ofs, prev_edge = edge, edge = edge->next[ofs] ) 3228 { 3229 ofs = start_vtx == edge->vtx[1]; 3230 assert( ofs == 1 || start_vtx == edge->vtx[0] ); 3231 if( edge->vtx[1] == end_vtx ) 3232 break; 3233 } 3234 3235 if( !edge ) 3236 EXIT; 3237 3238 next_edge = edge->next[ofs]; 3239 if( prev_edge ) 3240 prev_edge->next[prev_ofs] = next_edge; 3241 else 3242 start_vtx->first = next_edge; 3243 3244 for( ofs = prev_ofs = 0, prev_edge = 0, edge = end_vtx->first; edge != 0; 3245 prev_ofs = ofs, prev_edge = edge, edge = edge->next[ofs] ) 3246 { 3247 ofs = end_vtx == edge->vtx[1]; 3248 assert( ofs == 1 || end_vtx == edge->vtx[0] ); 3249 if( edge->vtx[0] == start_vtx ) 3250 break; 3251 } 3252 3253 assert( edge != 0 ); 3254 3255 next_edge = edge->next[ofs]; 3256 if( prev_edge ) 3257 prev_edge->next[prev_ofs] = next_edge; 3258 else 3259 end_vtx->first = next_edge; 3260 3261 cvSetRemoveByPtr( graph->edges, edge ); 3262 3263 __END__; 3264 } 3265 3266 3267 /* Remove the graph edge connecting two given vertices: */ 3268 CV_IMPL void 3269 cvGraphRemoveEdge( CvGraph* graph, int start_idx, int end_idx ) 3270 { 3271 CvGraphVtx *start_vtx; 3272 CvGraphVtx *end_vtx; 3273 3274 CV_FUNCNAME( "cvGraphRemoveEdge" ); 3275 3276 __BEGIN__; 3277 3278 if( !graph ) 3279 CV_ERROR( CV_StsNullPtr, "" ); 3280 3281 start_vtx = cvGetGraphVtx( graph, start_idx ); 3282 end_vtx = cvGetGraphVtx( graph, end_idx ); 3283 3284 cvGraphRemoveEdgeByPtr( graph, start_vtx, end_vtx ); 3285 3286 __END__; 3287 } 3288 3289 3290 /* Count number of edges incident to a given vertex: */ 3291 CV_IMPL int 3292 cvGraphVtxDegreeByPtr( const CvGraph* graph, const CvGraphVtx* vertex ) 3293 { 3294 CvGraphEdge *edge; 3295 int count = -1; 3296 3297 CV_FUNCNAME( "cvGraphVtxDegreeByPtr" ); 3298 3299 __BEGIN__; 3300 3301 if( !graph || !vertex ) 3302 CV_ERROR( CV_StsNullPtr, "" ); 3303 3304 for( edge = vertex->first, count = 0; edge; ) 3305 { 3306 count++; 3307 edge = CV_NEXT_GRAPH_EDGE( edge, vertex ); 3308 } 3309 3310 __END__; 3311 3312 return count; 3313 } 3314 3315 3316 /* Count number of edges incident to a given vertex: */ 3317 CV_IMPL int 3318 cvGraphVtxDegree( const CvGraph* graph, int vtx_idx ) 3319 { 3320 CvGraphVtx *vertex; 3321 CvGraphEdge *edge; 3322 int count = -1; 3323 3324 CV_FUNCNAME( "cvGraphVtxDegree" ); 3325 3326 __BEGIN__; 3327 3328 if( !graph ) 3329 CV_ERROR( CV_StsNullPtr, "" ); 3330 3331 vertex = cvGetGraphVtx( graph, vtx_idx ); 3332 if( !vertex ) 3333 CV_ERROR( CV_StsObjectNotFound, "" ); 3334 3335 for( edge = vertex->first, count = 0; edge; ) 3336 { 3337 count++; 3338 edge = CV_NEXT_GRAPH_EDGE( edge, vertex ); 3339 } 3340 3341 __END__; 3342 3343 return count; 3344 } 3345 3346 3347 typedef struct CvGraphItem 3348 { 3349 CvGraphVtx* vtx; 3350 CvGraphEdge* edge; 3351 } 3352 CvGraphItem; 3353 3354 3355 static void 3356 icvSeqElemsClearFlags( CvSeq* seq, int offset, int clear_mask ) 3357 { 3358 CV_FUNCNAME("icvStartScanGraph"); 3359 3360 __BEGIN__; 3361 3362 CvSeqReader reader; 3363 int i, total, elem_size; 3364 3365 if( !seq ) 3366 CV_ERROR( CV_StsNullPtr, "" ); 3367 3368 elem_size = seq->elem_size; 3369 total = seq->total; 3370 3371 if( (unsigned)offset > (unsigned)elem_size ) 3372 CV_ERROR( CV_StsBadArg, "" ); 3373 3374 CV_CALL( cvStartReadSeq( seq, &reader )); 3375 3376 for( i = 0; i < total; i++ ) 3377 { 3378 int* flag_ptr = (int*)(reader.ptr + offset); 3379 *flag_ptr &= ~clear_mask; 3380 3381 CV_NEXT_SEQ_ELEM( elem_size, reader ); 3382 } 3383 3384 __END__; 3385 } 3386 3387 3388 static schar* 3389 icvSeqFindNextElem( CvSeq* seq, int offset, int mask, 3390 int value, int* start_index ) 3391 { 3392 schar* elem_ptr = 0; 3393 3394 CV_FUNCNAME("icvStartScanGraph"); 3395 3396 __BEGIN__; 3397 3398 CvSeqReader reader; 3399 int total, elem_size, index; 3400 3401 if( !seq || !start_index ) 3402 CV_ERROR( CV_StsNullPtr, "" ); 3403 3404 elem_size = seq->elem_size; 3405 total = seq->total; 3406 index = *start_index; 3407 3408 if( (unsigned)offset > (unsigned)elem_size ) 3409 CV_ERROR( CV_StsBadArg, "" ); 3410 3411 if( total == 0 ) 3412 EXIT; 3413 3414 if( (unsigned)index >= (unsigned)total ) 3415 { 3416 index %= total; 3417 index += index < 0 ? total : 0; 3418 } 3419 3420 CV_CALL( cvStartReadSeq( seq, &reader )); 3421 3422 if( index != 0 ) 3423 CV_CALL( cvSetSeqReaderPos( &reader, index )); 3424 3425 for( index = 0; index < total; index++ ) 3426 { 3427 int* flag_ptr = (int*)(reader.ptr + offset); 3428 if( (*flag_ptr & mask) == value ) 3429 break; 3430 3431 CV_NEXT_SEQ_ELEM( elem_size, reader ); 3432 } 3433 3434 if( index < total ) 3435 { 3436 elem_ptr = reader.ptr; 3437 *start_index = index; 3438 } 3439 3440 __END__; 3441 3442 return elem_ptr; 3443 } 3444 3445 #define CV_FIELD_OFFSET( field, structtype ) ((int)(size_t)&((structtype*)0)->field) 3446 3447 CV_IMPL CvGraphScanner* 3448 cvCreateGraphScanner( CvGraph* graph, CvGraphVtx* vtx, int mask ) 3449 { 3450 CvGraphScanner* scanner = 0; 3451 CvMemStorage* child_storage = 0; 3452 3453 CV_FUNCNAME("cvCreateGraphScanner"); 3454 3455 __BEGIN__; 3456 3457 if( !graph ) 3458 CV_ERROR( CV_StsNullPtr, "Null graph pointer" ); 3459 3460 CV_ASSERT( graph->storage != 0 ); 3461 3462 CV_CALL( scanner = (CvGraphScanner*)cvAlloc( sizeof(*scanner) )); 3463 memset( scanner, 0, sizeof(*scanner)); 3464 3465 scanner->graph = graph; 3466 scanner->mask = mask; 3467 scanner->vtx = vtx; 3468 scanner->index = vtx == 0 ? 0 : -1; 3469 3470 CV_CALL( child_storage = cvCreateChildMemStorage( graph->storage )); 3471 3472 CV_CALL( scanner->stack = cvCreateSeq( 0, sizeof(CvSet), 3473 sizeof(CvGraphItem), child_storage )); 3474 3475 CV_CALL( icvSeqElemsClearFlags( (CvSeq*)graph, 3476 CV_FIELD_OFFSET( flags, CvGraphVtx), 3477 CV_GRAPH_ITEM_VISITED_FLAG| 3478 CV_GRAPH_SEARCH_TREE_NODE_FLAG )); 3479 3480 CV_CALL( icvSeqElemsClearFlags( (CvSeq*)(graph->edges), 3481 CV_FIELD_OFFSET( flags, CvGraphEdge), 3482 CV_GRAPH_ITEM_VISITED_FLAG )); 3483 3484 __END__; 3485 3486 if( cvGetErrStatus() < 0 ) 3487 { 3488 cvReleaseMemStorage( &child_storage ); 3489 cvFree( &scanner ); 3490 } 3491 3492 return scanner; 3493 } 3494 3495 3496 CV_IMPL void 3497 cvReleaseGraphScanner( CvGraphScanner** scanner ) 3498 { 3499 CV_FUNCNAME("cvReleaseGraphScanner"); 3500 3501 __BEGIN__; 3502 3503 if( !scanner ) 3504 CV_ERROR( CV_StsNullPtr, "Null double pointer to graph scanner" ); 3505 3506 if( *scanner ) 3507 { 3508 if( (*scanner)->stack ) 3509 CV_CALL( cvReleaseMemStorage( &((*scanner)->stack->storage))); 3510 cvFree( scanner ); 3511 } 3512 3513 __END__; 3514 } 3515 3516 3517 CV_IMPL int 3518 cvNextGraphItem( CvGraphScanner* scanner ) 3519 { 3520 int code = -1; 3521 3522 CV_FUNCNAME("cvNextGraphItem"); 3523 3524 __BEGIN__; 3525 3526 CvGraphVtx* vtx; 3527 CvGraphVtx* dst; 3528 CvGraphEdge* edge; 3529 CvGraphItem item; 3530 3531 if( !scanner || !(scanner->stack)) 3532 CV_ERROR( CV_StsNullPtr, "Null graph scanner" ); 3533 3534 dst = scanner->dst; 3535 vtx = scanner->vtx; 3536 edge = scanner->edge; 3537 3538 for(;;) 3539 { 3540 for(;;) 3541 { 3542 if( dst && !CV_IS_GRAPH_VERTEX_VISITED(dst) ) 3543 { 3544 scanner->vtx = vtx = dst; 3545 edge = vtx->first; 3546 dst->flags |= CV_GRAPH_ITEM_VISITED_FLAG; 3547 3548 if((scanner->mask & CV_GRAPH_VERTEX)) 3549 { 3550 scanner->vtx = vtx; 3551 scanner->edge = vtx->first; 3552 scanner->dst = 0; 3553 code = CV_GRAPH_VERTEX; 3554 EXIT; 3555 } 3556 } 3557 3558 while( edge ) 3559 { 3560 dst = edge->vtx[vtx == edge->vtx[0]]; 3561 3562 if( !CV_IS_GRAPH_EDGE_VISITED(edge) ) 3563 { 3564 // Check that the edge is outgoing: 3565 if( !CV_IS_GRAPH_ORIENTED( scanner->graph ) || dst != edge->vtx[0] ) 3566 { 3567 edge->flags |= CV_GRAPH_ITEM_VISITED_FLAG; 3568 3569 if( !CV_IS_GRAPH_VERTEX_VISITED(dst) ) 3570 { 3571 item.vtx = vtx; 3572 item.edge = edge; 3573 3574 vtx->flags |= CV_GRAPH_SEARCH_TREE_NODE_FLAG; 3575 3576 cvSeqPush( scanner->stack, &item ); 3577 3578 if( scanner->mask & CV_GRAPH_TREE_EDGE ) 3579 { 3580 code = CV_GRAPH_TREE_EDGE; 3581 scanner->vtx = vtx; 3582 scanner->dst = dst; 3583 scanner->edge = edge; 3584 EXIT; 3585 } 3586 break; 3587 } 3588 else 3589 { 3590 if( scanner->mask & (CV_GRAPH_BACK_EDGE| 3591 CV_GRAPH_CROSS_EDGE| 3592 CV_GRAPH_FORWARD_EDGE) ) 3593 { 3594 code = (dst->flags & CV_GRAPH_SEARCH_TREE_NODE_FLAG) ? 3595 CV_GRAPH_BACK_EDGE : 3596 (edge->flags & CV_GRAPH_FORWARD_EDGE_FLAG) ? 3597 CV_GRAPH_FORWARD_EDGE : CV_GRAPH_CROSS_EDGE; 3598 edge->flags &= ~CV_GRAPH_FORWARD_EDGE_FLAG; 3599 if( scanner->mask & code ) 3600 { 3601 scanner->vtx = vtx; 3602 scanner->dst = dst; 3603 scanner->edge = edge; 3604 EXIT; 3605 } 3606 } 3607 } 3608 } 3609 else if( (dst->flags & (CV_GRAPH_ITEM_VISITED_FLAG| 3610 CV_GRAPH_SEARCH_TREE_NODE_FLAG)) == 3611 (CV_GRAPH_ITEM_VISITED_FLAG| 3612 CV_GRAPH_SEARCH_TREE_NODE_FLAG)) 3613 { 3614 edge->flags |= CV_GRAPH_FORWARD_EDGE_FLAG; 3615 } 3616 } 3617 3618 edge = CV_NEXT_GRAPH_EDGE( edge, vtx ); 3619 } 3620 3621 if( !edge ) /* need to backtrack */ 3622 { 3623 if( scanner->stack->total == 0 ) 3624 { 3625 if( scanner->index >= 0 ) 3626 vtx = 0; 3627 else 3628 scanner->index = 0; 3629 break; 3630 } 3631 cvSeqPop( scanner->stack, &item ); 3632 vtx = item.vtx; 3633 vtx->flags &= ~CV_GRAPH_SEARCH_TREE_NODE_FLAG; 3634 edge = item.edge; 3635 dst = 0; 3636 3637 if( scanner->mask & CV_GRAPH_BACKTRACKING ) 3638 { 3639 scanner->vtx = vtx; 3640 scanner->edge = edge; 3641 scanner->dst = edge->vtx[vtx == edge->vtx[0]]; 3642 code = CV_GRAPH_BACKTRACKING; 3643 EXIT; 3644 } 3645 } 3646 } 3647 3648 if( !vtx ) 3649 { 3650 vtx = (CvGraphVtx*)icvSeqFindNextElem( (CvSeq*)(scanner->graph), 3651 CV_FIELD_OFFSET( flags, CvGraphVtx ), CV_GRAPH_ITEM_VISITED_FLAG|INT_MIN, 3652 0, &(scanner->index) ); 3653 3654 if( !vtx ) 3655 { 3656 code = CV_GRAPH_OVER; 3657 break; 3658 } 3659 } 3660 3661 dst = vtx; 3662 if( scanner->mask & CV_GRAPH_NEW_TREE ) 3663 { 3664 scanner->dst = dst; 3665 scanner->edge = 0; 3666 scanner->vtx = 0; 3667 code = CV_GRAPH_NEW_TREE; 3668 break; 3669 } 3670 } 3671 3672 __END__; 3673 3674 return code; 3675 } 3676 3677 3678 CV_IMPL CvGraph* 3679 cvCloneGraph( const CvGraph* graph, CvMemStorage* storage ) 3680 { 3681 int* flag_buffer = 0; 3682 CvGraphVtx** ptr_buffer = 0; 3683 CvGraph* result = 0; 3684 3685 CV_FUNCNAME( "cvCloneGraph" ); 3686 3687 __BEGIN__; 3688 3689 int i, k; 3690 int vtx_size, edge_size; 3691 CvSeqReader reader; 3692 3693 if( !CV_IS_GRAPH(graph)) 3694 CV_ERROR( CV_StsBadArg, "Invalid graph pointer" ); 3695 3696 if( !storage ) 3697 storage = graph->storage; 3698 3699 if( !storage ) 3700 CV_ERROR( CV_StsNullPtr, "NULL storage pointer" ); 3701 3702 vtx_size = graph->elem_size; 3703 edge_size = graph->edges->elem_size; 3704 3705 CV_CALL( flag_buffer = (int*)cvAlloc( graph->total*sizeof(flag_buffer[0]))); 3706 CV_CALL( ptr_buffer = (CvGraphVtx**)cvAlloc( graph->total*sizeof(ptr_buffer[0]))); 3707 CV_CALL( result = cvCreateGraph( graph->flags, graph->header_size, 3708 vtx_size, edge_size, storage )); 3709 memcpy( result + sizeof(CvGraph), graph + sizeof(CvGraph), 3710 graph->header_size - sizeof(CvGraph)); 3711 3712 // Pass 1. Save flags, copy vertices: 3713 cvStartReadSeq( (CvSeq*)graph, &reader ); 3714 for( i = 0, k = 0; i < graph->total; i++ ) 3715 { 3716 if( CV_IS_SET_ELEM( reader.ptr )) 3717 { 3718 CvGraphVtx* vtx = (CvGraphVtx*)reader.ptr; 3719 CvGraphVtx* dstvtx = 0; 3720 CV_CALL( cvGraphAddVtx( result, vtx, &dstvtx )); 3721 flag_buffer[k] = dstvtx->flags = vtx->flags; 3722 vtx->flags = k; 3723 ptr_buffer[k++] = dstvtx; 3724 } 3725 CV_NEXT_SEQ_ELEM( vtx_size, reader ); 3726 } 3727 3728 // Pass 2. Copy edges: 3729 cvStartReadSeq( (CvSeq*)graph->edges, &reader ); 3730 for( i = 0; i < graph->edges->total; i++ ) 3731 { 3732 if( CV_IS_SET_ELEM( reader.ptr )) 3733 { 3734 CvGraphEdge* edge = (CvGraphEdge*)reader.ptr; 3735 CvGraphEdge* dstedge = 0; 3736 CvGraphVtx* new_org = ptr_buffer[edge->vtx[0]->flags]; 3737 CvGraphVtx* new_dst = ptr_buffer[edge->vtx[1]->flags]; 3738 CV_CALL( cvGraphAddEdgeByPtr( result, new_org, new_dst, edge, &dstedge )); 3739 dstedge->flags = edge->flags; 3740 } 3741 CV_NEXT_SEQ_ELEM( edge_size, reader ); 3742 } 3743 3744 // Pass 3. Restore flags: 3745 cvStartReadSeq( (CvSeq*)graph, &reader ); 3746 for( i = 0, k = 0; i < graph->edges->total; i++ ) 3747 { 3748 if( CV_IS_SET_ELEM( reader.ptr )) 3749 { 3750 CvGraphVtx* vtx = (CvGraphVtx*)reader.ptr; 3751 vtx->flags = flag_buffer[k++]; 3752 } 3753 CV_NEXT_SEQ_ELEM( vtx_size, reader ); 3754 } 3755 3756 __END__; 3757 3758 cvFree( &flag_buffer ); 3759 cvFree( &ptr_buffer ); 3760 3761 if( cvGetErrStatus() < 0 ) 3762 result = 0; 3763 3764 return result; 3765 } 3766 3767 3768 /****************************************************************************************\ 3769 * Working with sequence tree * 3770 \****************************************************************************************/ 3771 3772 // Gather pointers to all the sequences, accessible from the <first>, to the single sequence. 3773 CV_IMPL CvSeq* 3774 cvTreeToNodeSeq( const void* first, int header_size, CvMemStorage* storage ) 3775 { 3776 CvSeq* allseq = 0; 3777 3778 CV_FUNCNAME("cvTreeToNodeSeq"); 3779 3780 __BEGIN__; 3781 3782 CvTreeNodeIterator iterator; 3783 3784 if( !storage ) 3785 CV_ERROR( CV_StsNullPtr, "NULL storage pointer" ); 3786 3787 CV_CALL( allseq = cvCreateSeq( 0, header_size, sizeof(first), storage )); 3788 3789 if( first ) 3790 { 3791 CV_CALL( cvInitTreeNodeIterator( &iterator, first, INT_MAX )); 3792 3793 for(;;) 3794 { 3795 void* node = cvNextTreeNode( &iterator ); 3796 if( !node ) 3797 break; 3798 cvSeqPush( allseq, &node ); 3799 } 3800 } 3801 3802 __END__; 3803 3804 return allseq; 3805 } 3806 3807 3808 typedef struct CvTreeNode 3809 { 3810 int flags; /* micsellaneous flags */ 3811 int header_size; /* size of sequence header */ 3812 struct CvTreeNode* h_prev; /* previous sequence */ 3813 struct CvTreeNode* h_next; /* next sequence */ 3814 struct CvTreeNode* v_prev; /* 2nd previous sequence */ 3815 struct CvTreeNode* v_next; /* 2nd next sequence */ 3816 } 3817 CvTreeNode; 3818 3819 3820 3821 // Insert contour into tree given certain parent sequence. 3822 // If parent is equal to frame (the most external contour), 3823 // then added contour will have null pointer to parent: 3824 CV_IMPL void 3825 cvInsertNodeIntoTree( void* _node, void* _parent, void* _frame ) 3826 { 3827 CV_FUNCNAME( "cvInsertNodeIntoTree" ); 3828 3829 __BEGIN__; 3830 3831 CvTreeNode* node = (CvTreeNode*)_node; 3832 CvTreeNode* parent = (CvTreeNode*)_parent; 3833 3834 if( !node || !parent ) 3835 CV_ERROR( CV_StsNullPtr, "" ); 3836 3837 node->v_prev = _parent != _frame ? parent : 0; 3838 node->h_next = parent->v_next; 3839 3840 assert( parent->v_next != node ); 3841 3842 if( parent->v_next ) 3843 parent->v_next->h_prev = node; 3844 parent->v_next = node; 3845 3846 __END__; 3847 } 3848 3849 3850 // Remove contour from tree, together with the contour's children: 3851 CV_IMPL void 3852 cvRemoveNodeFromTree( void* _node, void* _frame ) 3853 { 3854 CV_FUNCNAME( "cvRemoveNodeFromTree" ); 3855 3856 __BEGIN__; 3857 3858 CvTreeNode* node = (CvTreeNode*)_node; 3859 CvTreeNode* frame = (CvTreeNode*)_frame; 3860 3861 if( !node ) 3862 CV_ERROR_FROM_CODE( CV_StsNullPtr ); 3863 3864 if( node == frame ) 3865 CV_ERROR( CV_StsBadArg, "frame node could not be deleted" ); 3866 3867 if( node->h_next ) 3868 node->h_next->h_prev = node->h_prev; 3869 3870 if( node->h_prev ) 3871 node->h_prev->h_next = node->h_next; 3872 else 3873 { 3874 CvTreeNode* parent = node->v_prev; 3875 if( !parent ) 3876 parent = frame; 3877 3878 if( parent ) 3879 { 3880 assert( parent->v_next == node ); 3881 parent->v_next = node->h_next; 3882 } 3883 } 3884 3885 __END__; 3886 } 3887 3888 3889 CV_IMPL void 3890 cvInitTreeNodeIterator( CvTreeNodeIterator* treeIterator, 3891 const void* first, int max_level ) 3892 { 3893 CV_FUNCNAME("icvInitTreeNodeIterator"); 3894 3895 __BEGIN__; 3896 3897 if( !treeIterator || !first ) 3898 CV_ERROR( CV_StsNullPtr, "" ); 3899 3900 if( max_level < 0 ) 3901 CV_ERROR( CV_StsOutOfRange, "" ); 3902 3903 treeIterator->node = (void*)first; 3904 treeIterator->level = 0; 3905 treeIterator->max_level = max_level; 3906 3907 __END__; 3908 } 3909 3910 3911 CV_IMPL void* 3912 cvNextTreeNode( CvTreeNodeIterator* treeIterator ) 3913 { 3914 CvTreeNode* prevNode = 0; 3915 3916 CV_FUNCNAME("cvNextTreeNode"); 3917 3918 __BEGIN__; 3919 3920 CvTreeNode* node; 3921 int level; 3922 3923 if( !treeIterator ) 3924 CV_ERROR( CV_StsNullPtr, "NULL iterator pointer" ); 3925 3926 prevNode = node = (CvTreeNode*)treeIterator->node; 3927 level = treeIterator->level; 3928 3929 if( node ) 3930 { 3931 if( node->v_next && level+1 < treeIterator->max_level ) 3932 { 3933 node = node->v_next; 3934 level++; 3935 } 3936 else 3937 { 3938 while( node->h_next == 0 ) 3939 { 3940 node = node->v_prev; 3941 if( --level < 0 ) 3942 { 3943 node = 0; 3944 break; 3945 } 3946 } 3947 node = node && treeIterator->max_level != 0 ? node->h_next : 0; 3948 } 3949 } 3950 3951 treeIterator->node = node; 3952 treeIterator->level = level; 3953 3954 __END__; 3955 3956 return prevNode; 3957 } 3958 3959 3960 CV_IMPL void* 3961 cvPrevTreeNode( CvTreeNodeIterator* treeIterator ) 3962 { 3963 CvTreeNode* prevNode = 0; 3964 3965 CV_FUNCNAME("cvPrevTreeNode"); 3966 3967 __BEGIN__; 3968 3969 CvTreeNode* node; 3970 int level; 3971 3972 if( !treeIterator ) 3973 CV_ERROR( CV_StsNullPtr, "" ); 3974 3975 prevNode = node = (CvTreeNode*)treeIterator->node; 3976 level = treeIterator->level; 3977 3978 if( node ) 3979 { 3980 if( !node->h_prev ) 3981 { 3982 node = node->v_prev; 3983 if( --level < 0 ) 3984 node = 0; 3985 } 3986 else 3987 { 3988 node = node->h_prev; 3989 3990 while( node->v_next && level < treeIterator->max_level ) 3991 { 3992 node = node->v_next; 3993 level++; 3994 3995 while( node->h_next ) 3996 node = node->h_next; 3997 } 3998 } 3999 } 4000 4001 treeIterator->node = node; 4002 treeIterator->level = level; 4003 4004 __END__; 4005 4006 return prevNode; 4007 } 4008 4009 /* End of file. */ 4010