/***************************************************************************** # Copyright (C) 1994-2008 by David Gordon. # All rights reserved. # # This software is part of a beta-test version of the Consed/Autofinish # package. It should not be redistributed or # used for any commercial purpose, including commercially funded # sequencing, without written permission from the author and the # University of Washington. # # This software is provided ``AS IS'' and any express or implied # warranties, including, but not limited to, the implied warranties of # merchantability and fitness for a particular purpose, are disclaimed. # In no event shall the authors or the University of Washington be # liable for any direct, indirect, incidental, special, exemplary, or # consequential damages (including, but not limited to, procurement of # substitute goods or services; loss of use, data, or profits; or # business interruption) however caused and on any theory of liability, # whether in contract, strict liability, or tort (including negligence # or otherwise) arising in any way out of the use of this software, even # if advised of the possibility of such damage. # # Building Consed from source is error prone and not simple which is # why I provide executables. Due to time limitations I cannot # provide any assistance in building Consed. Even if you do not # modify the source, you may introduce errors due to using a # different version of the compiler, a different version of motif, # different versions of other libraries than I used, etc. For this # reason, if you discover Consed bugs, I can only offer help with # those bugs if you first reproduce those bugs with an executable # provided by me--not an executable you have built. # # Modifying Consed is also difficult. Although Consed is modular, # some modules are used by many other modules. Thus making a change # in one place can have unforeseen effects on many other features. # It may takes months for you to notice these other side-effects # which may not seen connected at all. It is not feasable for me to # provide help with modifying Consed sources because of the # potentially huge amount of time involved. # #*****************************************************************************/ // // gotoList.cpp // // implementation for gotoList.h // // chrisa 14-mar-95 // gordon rewritten // #include using namespace std; #include #include "gotoList.h" #include "contig.h" #include "locatedFragment.h" #include #include "abs.h" #include #include "bIsNumeric.h" #include "bIntervalsIntersect.h" gotoItem :: gotoItem( Contig* pContig, LocatedFragment* pLocFrag, // refers to cons rather than frag const int nStart, // starting index into sequence const int nEnd, // ending index into seq const int nUnpaddedStart, // same only for display const int nUnpaddedEnd, const RWCString& soDescription, // string describing the gotoItem // i.e. "Poor consensus quality" const bool bPrefixContigToDescription, void* pOtherData ) : pContig_( pContig ), pLocFrag_( pLocFrag ), nGotoItemStart_(nStart), nGotoItemEnd_(nEnd), nUnpaddedGotoItemStart_(nUnpaddedStart), nUnpaddedGotoItemEnd_(nUnpaddedEnd), soInitialDescription_( soDescription ), pOtherData_( pOtherData ) { if ( bPrefixContigToDescription ) setFullDescription(); else soFullDescription_ = soInitialDescription_; } // gotoItem ctor gotoItem :: gotoItem( gotoItem* pGotoItem ) { pContig_ = pGotoItem->pContig_; pLocFrag_ = pGotoItem->pLocFrag_; soFullDescription_ = pGotoItem->soFullDescription_; soInitialDescription_ = pGotoItem->soInitialDescription_; nUnpaddedGotoItemStart_ = pGotoItem->nUnpaddedGotoItemStart_; nUnpaddedGotoItemEnd_ = pGotoItem->nUnpaddedGotoItemEnd_; nGotoItemStart_ = pGotoItem->nGotoItemStart_; nGotoItemEnd_ = pGotoItem->nGotoItemEnd_; bIsConsensusGotoItem_ = pGotoItem->bIsConsensusGotoItem_; pOtherData_ = pGotoItem->pOtherData_; } void gotoItem :: setNewEnd( const int nConsPos, const int nUnpaddedConsPos ) { nGotoItemEnd_ = nConsPos; nUnpaddedGotoItemEnd_ = nUnpaddedConsPos; setFullDescription(); } void gotoItem :: setFullDescription() { char szTemp[1000]; if (!pContig_ ) { // one of those not in a contig (a singleton) if ( nGotoItemStart_ != nGotoItemEnd_ ) { sprintf( szTemp, " %7d-%-7d %s", nUnpaddedGotoItemStart_, nUnpaddedGotoItemEnd_, (char*) soInitialDescription_.data() ); } else { sprintf( szTemp, " %7d %s", nUnpaddedGotoItemStart_, (char*) soInitialDescription_.data() ); } } else { if (!pLocFrag_ ) { // just searching contigs if ( nGotoItemStart_ != nGotoItemEnd_ ) { sprintf( szTemp, "%-11s (consensus) %7d-%-7d %s", (char*) pContig_->soGetName().data(), nUnpaddedGotoItemStart_, nUnpaddedGotoItemEnd_, (char*) soInitialDescription_.data() ); } else { sprintf( szTemp, "%-11s (consensus) %7d %s", (char*) pContig_->soGetName().data(), nUnpaddedGotoItemStart_, (char*) soInitialDescription_.data() ); } } else { // found in read which is part of a contig if ( nGotoItemStart_ != nGotoItemEnd_ ) { sprintf( szTemp, "%-11s %-19s %7d-%-7d %s", (char*) pContig_->soGetName().data(), (char*) pLocFrag_->soGetFragmentName().data(), nUnpaddedGotoItemStart_, nUnpaddedGotoItemEnd_, (char*) soInitialDescription_.data() ); } else { sprintf( szTemp, "%-11s %-19s %7d %s", (char*) pContig_->soGetName().data(), (char*) pLocFrag_->soGetFragmentName().data(), nUnpaddedGotoItemStart_, (char*) soInitialDescription_.data() ); } } } soFullDescription_ = szTemp; } void gotoList :: sortByPosition() { if ( apGotoItem_.length() < 2 ) return; apGotoItem_.resort(); } void gotoList :: appendAnotherList( gotoList* pAnotherGotoList ) { for( int n = 0; n < pAnotherGotoList->nGetNumGotoItems(); ++n ) { addToList( pAnotherGotoList->pGetGotoItem( n ) ); } } static int cmpLength( const gotoItem** ppGotoItem1, const gotoItem** ppGotoItem2 ) { // this will make qsort sort the items in order of unpadded length, // largest first int nLength1 = ABS( (*ppGotoItem1)->nUnpaddedGotoItemEnd_ - (*ppGotoItem1)->nUnpaddedGotoItemStart_ ); int nLength2 = ABS( (*ppGotoItem2)->nUnpaddedGotoItemEnd_ - (*ppGotoItem2)->nUnpaddedGotoItemStart_ ); if ( nLength1 < nLength2 ) return( 1 ); else if ( nLength1 > nLength2 ) return( -1 ); else return( 0 ); } void gotoList :: sortByLength() { if ( apGotoItem_.length() < 2 ) return; // already sorted void* pArray = (void*) apGotoItem_.data(); size_t nNumberOfElementsInArray = apGotoItem_.length(); size_t nSizeOfAnElement = sizeof( gotoItem* ); qsort( pArray, nNumberOfElementsInArray, nSizeOfAnElement, ( ( int(*) ( const void*, const void*) ) cmpLength ) ); if ( ! bIsSortedByLength() ) { PANIC_OST( ost ) << "gotoList::sortByLength didn't work" << endl << ends; throw ProgramLogicError( ost.str().c_str() ); } } bool gotoList :: bIsSortedByLength() { bool bSorted = true; for( int nGotoItem = 0; nGotoItem <= ( apGotoItem_.length() - 2 ); ++nGotoItem ) { gotoItem* pGotoItem1 = apGotoItem_[ nGotoItem ]; gotoItem* pGotoItem2 = apGotoItem_[ nGotoItem + 1 ]; int nLength1 = ABS( pGotoItem1->nUnpaddedGotoItemEnd_ - pGotoItem1->nUnpaddedGotoItemStart_ ); int nLength2 = ABS( pGotoItem2->nUnpaddedGotoItemEnd_ - pGotoItem2->nUnpaddedGotoItemStart_ ); if ( nLength1 < nLength2 ) { bSorted = false; cout << "Elements " << nGotoItem << " and " << nGotoItem + 1 << " are out of order since lengths " << nLength1 << " and " << nLength2 << endl; } } return( bSorted ); } bool gotoItem :: operator<( const gotoItem& rGotoItem) const { if ( pContig_ && rGotoItem.pContig_ && ( pContig_ != rGotoItem.pContig_ ) ) { RWCString soContig1 = pContig_->soGetName(); RWCString soContig2 = rGotoItem.pContig_->soGetName(); if ( soContig1.length() > 6 && soContig1(0, 6 ) == "Contig" && soContig2.length() > 6 && soContig2(0, 6 ) == "Contig" ) { soContig1 = soContig1( 6, soContig1.length() - 6 ); soContig2 = soContig2( 6, soContig2.length() - 6 ); if ( bIsNumeric( soContig1 ) && bIsNumeric( soContig2 ) ) { int nContig1 = atoi( soContig1 ); int nContig2 = atoi( soContig2 ); if ( nContig1 < nContig2 ) return( true ); else return( false ); } } // if reached here, the contig names are not of the form // Contignn and Contigmm return( soContig1 < soContig2 ); } else { if ( nGotoItemStart_ < rGotoItem.nGotoItemStart_ ) return true; else return false; } } // I haven't really put much thought into the case in which the // gotoItems may overlap and include each other. This is really // just for low consensus quality items void gotoList :: consolidateGotoItems( const int nConsolidateIfLessThanOrEqualToThisDistance ) { if ( nGetNumGotoItems() < 2 ) return; // this assumes the gotoItems are sorted for( int nGotoItem = nGetNumGotoItems() - 1; nGotoItem >= 1; --nGotoItem ) { gotoItem* pGotoItemLeft = pGetGotoItem( nGotoItem - 1 ); gotoItem* pGotoItemRight = pGetGotoItem( nGotoItem ); if ( pGotoItemLeft->pContig_ == pGotoItemRight->pContig_ && pGotoItemLeft->pLocFrag_ == pGotoItemRight->pLocFrag_ ) { if ( !bIntervalsIntersect( pGotoItemLeft->nUnpaddedGotoItemStart_, pGotoItemLeft->nUnpaddedGotoItemEnd_, pGotoItemRight->nUnpaddedGotoItemStart_, pGotoItemRight->nUnpaddedGotoItemEnd_ ) ) { // ok, so how far apart are they? if ( ABS( pGotoItemRight->nUnpaddedGotoItemStart_ - pGotoItemLeft->nUnpaddedGotoItemEnd_ ) <= nConsolidateIfLessThanOrEqualToThisDistance ) { pGotoItemLeft->nUnpaddedGotoItemEnd_ = pGotoItemRight->nUnpaddedGotoItemEnd_; pGotoItemLeft->nGotoItemEnd_ = pGotoItemRight->nGotoItemEnd_; apGotoItem_.removeAt( nGotoItem ); delete pGotoItemRight; } } } } // for( int nGotoItem = nGetNumGotoItems() - 1; } // this assumes they are sorted by position void gotoList :: removeDuplicates() { if ( nGetNumGotoItems() <= 1 ) return; for( int nGotoItem = nGetNumGotoItems() - 2; nGotoItem >= 0; --nGotoItem ) { gotoItem* pGotoItem1 = pGetGotoItem( nGotoItem ); gotoItem* pGotoItem2 = pGetGotoItem( nGotoItem + 1 ); if ( pGotoItem1->nGotoItemStart_ == pGotoItem2->nGotoItemStart_ && pGotoItem1->nGotoItemEnd_ == pGotoItem2->nGotoItemEnd_ && pGotoItem1->pContig_ == pGotoItem2->pContig_ && pGotoItem1->pLocFrag_ == pGotoItem2->pLocFrag_ && pGotoItem1->soFullDescription_ == pGotoItem2->soFullDescription_ ) { // the soInitialDescription is only used in the ctor // same item. Delete the 2nd one. apGotoItem_.removeAt( nGotoItem + 1 ); } } }