/***************************************************************************** # 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. # #*****************************************************************************/ #include "compareContigs.h" #include "extendAlignmentBanded.h" #include "extendAlignment.h" #include "getAlignmentBanded.h" #include "contig.h" #include using namespace std; #include #include "guiCompareContigs.h" #include "numutil.h" #include "scaleTickSizes.h" #include "consed.h" #include "makeUpper.h" #include "paddedPieceOfRead.h" #include "bIsAPad.h" #include "compareContigsTypes.h" #include "translateRWCString.h" #include "contigwin.h" #include "getAlignment.h" #include "please_wait.h" #include "consedParameters.h" #include "popupErrorMessage.h" #include "colormode.h" #include "bGuiGetAnswerYesNo.h" #include #include "seqMatch.h" // const int nWindowSize = 10000; const int nGapPenalty = 4; const int nMatchBoost = 1; const int nMismatchPenalty = 2; const int nGuiCompareContigsWindowSize = 80; const int nIndicationThatAlignmentExtendsFurther = 10; const int nContextBases = 30; inline RWCString soMakeStringFromChar( const char c ) { RWCString soTemp( (char) c ); return( soTemp ); } compareContigs :: compareContigs(ContigWin* pContigWin, const int nConsPos1 ) : pContigWin1_( pContigWin ), pContigWin2_(0), pNewContigWin_( 0 ), pContig2_(0), bAlignmentExists_( false ), nAlignmentWindowLeftEdgeZeroBasedPos_( 0 ), pNewContig_( NULL ), bContig1ComplementedWRTAlignedReadsWindow_( false ), bContig2ComplementedWRTAlignedReadsWindow_( false ) { pContig1_ = pContigWin->pGetContig(); nContig1LeftEdgeConsensusPosition_ = nConsPos1 - nGuiCompareContigsWindowSize/2; if (nContig1LeftEdgeConsensusPosition_ < pContig1_->nGetStartConsensusIndex() ) nContig1LeftEdgeConsensusPosition_ = pContig1_->nGetStartConsensusIndex(); pGuiCompareContigs_ = new guiCompareContigs( this ); setScrollBarForNewContig( eContig1 ); pGuiCompareContigs_->setContigName( eContig1, pContig1_->soGetName() ); setTopContigCursorByConsensusPosition( eContig1, nConsPos1 ); } compareContigs :: compareContigs() : pContigWin1_( 0 ), pContigWin2_( 0 ), pNewContigWin_( 0 ), pContig1_( 0 ), pContig2_( 0 ), bAlignmentExists_( false ), nAlignmentWindowLeftEdgeZeroBasedPos_( 0 ), pNewContig_( 0 ) {} compareContigs :: ~compareContigs() { assert( ConsEd::pGetConsEd()->bFoundAndDeletedThisCompareContigsFromList( this ) ); delete pGuiCompareContigs_; } void compareContigs :: addSecondContig( ContigWin* pContigWin, const int nConsPos2 ) { pContigWin2_ = pContigWin; pContig2_ = pContigWin2_->pGetContig(); nContig2LeftEdgeConsensusPosition_ = nConsPos2 - nGuiCompareContigsWindowSize / 2; if ( nContig2LeftEdgeConsensusPosition_ < pContig2_->nGetStartConsensusIndex() ) nContig2LeftEdgeConsensusPosition_ = pContig2_->nGetStartConsensusIndex(); setScrollBarForNewContig( eContig2 ); pGuiCompareContigs_->setContigName( eContig2, pContig2_->soGetName() ); drawScaleAndBases( eContig2 ); setTopContigCursorByConsensusPosition( eContig2, nConsPos2 ); pGuiCompareContigs_->raiseWindow(); } // this entry point is *not* used by assemblyView--that uses // popupForAssemblyView and does not use nPinnedConsPos1_ or // nPinnedConsPos2_ since there is no pineed bases in that case void compareContigs :: doCompareContigs() { compareContigsCursor& curTopContig1 = curGetCompareContigsTopContigCursor( eContig1 ); compareContigsCursor& curTopContig2 = curGetCompareContigsTopContigCursor( eContig2 ); if (!curTopContig1.bIsValid() || !curTopContig2.bIsValid() ) { GuiApp::popupErrorMessage( "you must set the cursor on each contig to specify the bases to be pinned together" ); return; } nPinnedConsPos1_ = curTopContig1.nPosition_; nPinnedConsPos2_ = curTopContig2.nPosition_; // check that the cursors are not on pads if ( pContig1_->ntGetCons( nPinnedConsPos1_ ).bIsPad() || pContig2_->ntGetCons( nPinnedConsPos2_ ).bIsPad() ) { popupErrorMessage("both cursors must be set on bases--not pads" ); return; } // these are in the coordinates of the aligned reads window (without // taking into account any complementing with the compare contigs window int nUnpaddedPinned1 = pContig1_->nUnpaddedIndex( nPinnedConsPos1_ ); int nUnpaddedPinned2 = pContig2_->nUnpaddedIndex( nPinnedConsPos2_ ); PleaseWait* pPleaseWait = new PleaseWait( pGuiCompareContigs_->widPopupShell_ ); // calculate how far we should get sequence to the right. // We will do this as follows: // -------------- // --------------------- // ^ ^ ^ // P A B // where P is where it is pinned. We will extend to A since // that is where the shortest contig ends. int nUnpaddedBasesToRight1; int nUnpaddedBasesToRight2; if ( bContig1ComplementedWRTAlignedReadsWindow_ ) nUnpaddedBasesToRight1 = nUnpaddedPinned1 - 1; else nUnpaddedBasesToRight1 = pContig1_->nGetUnpaddedEndIndex() - nUnpaddedPinned1; if ( bContig2ComplementedWRTAlignedReadsWindow_ ) nUnpaddedBasesToRight2 = nUnpaddedPinned2 - 1; else nUnpaddedBasesToRight2 = pContig2_->nGetUnpaddedEndIndex() - nUnpaddedPinned2; bool bShortestToRightIsContig1Not2; int nUnpaddedOverlappingBasesToRight; if ( nUnpaddedBasesToRight1 < nUnpaddedBasesToRight2 ) { bShortestToRightIsContig1Not2 = true; nUnpaddedOverlappingBasesToRight = nUnpaddedBasesToRight1; } else { bShortestToRightIsContig1Not2 = false; nUnpaddedOverlappingBasesToRight = nUnpaddedBasesToRight2; } int nALittleMoreThanUnpaddedOverlappingBasesToRight = nUnpaddedOverlappingBasesToRight + pCP->nCompareContigsBandSize_; RWCString soUnpaddedConsensus1ToRight; RWCString soUnpaddedConsensus2ToRight; // in the case of complemented contigs, left means lower // positions, so must add 1 instead of - 1 int nUnpaddedStart1 = ( bContig1ComplementedWRTAlignedReadsWindow_ ? nUnpaddedPinned1 - 1 : nUnpaddedPinned1 + 1 ); int nUnpaddedStart2 = ( bContig2ComplementedWRTAlignedReadsWindow_ ? nUnpaddedPinned2 - 1 : nUnpaddedPinned2 + 1 ); pContig1_->getPartOfUnpaddedConsensusForCompareContigs( nUnpaddedStart1, nALittleMoreThanUnpaddedOverlappingBasesToRight, soUnpaddedConsensus1ToRight, bContig1ComplementedWRTAlignedReadsWindow_, false ); // bToLeftNotToRight pContig2_->getPartOfUnpaddedConsensusForCompareContigs( nUnpaddedStart2, nALittleMoreThanUnpaddedOverlappingBasesToRight, soUnpaddedConsensus2ToRight, bContig2ComplementedWRTAlignedReadsWindow_, false ); // bToLeftNotToRight RWCString soAlignmentRightTop; RWCString soAlignmentRightMid; RWCString soAlignmentRightBot; int nBestAlignEnd1; int nBestAlignEnd2; int nBestScore; if ( soUnpaddedConsensus1ToRight.length() == 0 || soUnpaddedConsensus2ToRight.length() == 0 ) { // case in which the user clicked on the rightmost base soAlignmentRightTop = ""; soAlignmentRightMid = ""; soAlignmentRightBot = ""; nBestAlignEnd1 = 0; nBestAlignEnd2 = 0; nBestScore = 0; } else { cerr << "extending alignment to right..."; cerr.flush(); if ( pCP->bCompareContigsUseBandedRatherThanFullSmithWaterman_ ) { extendAlignmentBanded( soUnpaddedConsensus1ToRight.data(), soUnpaddedConsensus2ToRight.data(), soUnpaddedConsensus1ToRight.length(), soUnpaddedConsensus2ToRight.length(), &nBestAlignEnd1, &nBestAlignEnd2, &nBestScore, nGapPenalty, nMatchBoost, nMismatchPenalty, pCP->nCompareContigsBandSize_ ); } else { extendAlignment( soUnpaddedConsensus1ToRight.data(), soUnpaddedConsensus2ToRight.data(), soUnpaddedConsensus1ToRight.length(), soUnpaddedConsensus2ToRight.length(), &nBestAlignEnd1, &nBestAlignEnd2, &nBestScore, nGapPenalty, nMatchBoost, nMismatchPenalty ); } cerr << "done" << endl; cerr.flush(); soUnpaddedConsensus1ToRight.truncate( nBestAlignEnd1 ); soUnpaddedConsensus2ToRight.truncate( nBestAlignEnd2 ); // handle case in which the extendAlignment refuses to extend // the alignment even one base if ( soUnpaddedConsensus1ToRight.length() > 0 ) { int nScore; cerr << "computing alignment to right..."; cerr.flush(); if ( pCP->bCompareContigsUseBandedRatherThanFullSmithWaterman_ ) { getAlignmentBanded( soUnpaddedConsensus1ToRight.data(), soUnpaddedConsensus2ToRight.data(), soUnpaddedConsensus1ToRight.length(), soUnpaddedConsensus2ToRight.length(), nGapPenalty, nMatchBoost, nMismatchPenalty, pCP->nCompareContigsBandSize_, soAlignmentRightTop, soAlignmentRightMid, soAlignmentRightBot, nScore ); assert( soAlignmentRightTop.length() == soAlignmentRightMid.length() ); assert( soAlignmentRightTop.length() == soAlignmentRightBot.length() ); assert( nScore == nBestScore ); } else { getAlignment( soUnpaddedConsensus1ToRight.data(), soUnpaddedConsensus2ToRight.data(), nGapPenalty, nMatchBoost, // match boost nMismatchPenalty, // mismatch penalty soAlignmentRightTop, soAlignmentRightBot, nScore); assert( nScore == nBestScore ); soAlignmentRightMid = ""; int n; for( n = 0; n < soAlignmentRightTop.length(); ++n ) { if ( soAlignmentRightTop[n] == soAlignmentRightBot[n] ) soAlignmentRightMid += " "; else soAlignmentRightMid += "X"; } } cerr << "done" << endl; cerr.flush(); } else { // case in which the alignment fails to extend even 1 base soAlignmentRightTop = ""; soAlignmentRightMid = ""; soAlignmentRightBot = ""; nBestAlignEnd1 = 0; nBestAlignEnd2 = 0; nBestScore = 0; } } // save these for later int nUnpaddedRightEndOfAlignment1 = pContig1_->nUnpaddedIndex( nPinnedConsPos1_ ) + ( bContig1ComplementedWRTAlignedReadsWindow_ ? - nBestAlignEnd1 : nBestAlignEnd1 ); // If nBestAlignEnd1 is 0, then there is no alignment. // If nBestAlignEnd1 is 1, then there is a null at position 1, but // position 0 is present, so must add 1 to get unpadded position int nUnpaddedRightEndOfAlignment2 = pContig2_->nUnpaddedIndex( nPinnedConsPos2_ ) + ( bContig2ComplementedWRTAlignedReadsWindow_ ? -nBestAlignEnd2 : nBestAlignEnd2 ); // EXTENDING LEFT // now extend alignment from the left of the pinned location // ------------------------- // ------------- // ^ ^ ^ // A B P // where P is where they are pinned. We will extend to B since // that is where the overlap ends. int nUnpaddedBasesToLeft1; int nUnpaddedBasesToLeft2; if ( bContig1ComplementedWRTAlignedReadsWindow_ ) nUnpaddedBasesToLeft1 = pContig1_->nGetUnpaddedEndIndex() - nUnpaddedPinned1; else nUnpaddedBasesToLeft1 = nUnpaddedPinned1 - 1; if ( bContig2ComplementedWRTAlignedReadsWindow_ ) nUnpaddedBasesToLeft2 = pContig2_->nGetUnpaddedEndIndex() - nUnpaddedPinned2; else nUnpaddedBasesToLeft2 = nUnpaddedPinned2 - 1; bool bShortestToLeftIsContig1Not2; int nUnpaddedOverlappingBasesToLeft; if ( nUnpaddedBasesToLeft1 < nUnpaddedBasesToLeft2 ) { bShortestToLeftIsContig1Not2 = true; nUnpaddedOverlappingBasesToLeft = nUnpaddedBasesToLeft1; } else { bShortestToLeftIsContig1Not2 = false; nUnpaddedOverlappingBasesToLeft = nUnpaddedBasesToLeft2; } int nALittleMoreThanUnpaddedOverlappingBasesToLeft = nUnpaddedOverlappingBasesToLeft + pCP->nCompareContigsBandSize_; RWCString soUnpaddedConsensus1ToLeft; RWCString soUnpaddedConsensus2ToLeft; // in the case of complemented contigs, left means lower // positions, so much subtract 1 instead of adding nUnpaddedStart1 = ( bContig1ComplementedWRTAlignedReadsWindow_ ? nUnpaddedPinned1 + 1 : nUnpaddedPinned1 - 1 ); nUnpaddedStart2 = ( bContig2ComplementedWRTAlignedReadsWindow_ ? nUnpaddedPinned2 + 1 : nUnpaddedPinned2 - 1 ); pContig1_->getPartOfUnpaddedConsensusForCompareContigs( nUnpaddedStart1, nALittleMoreThanUnpaddedOverlappingBasesToLeft, soUnpaddedConsensus1ToLeft, bContig1ComplementedWRTAlignedReadsWindow_, true ); // bToLeftNotRight pContig2_->getPartOfUnpaddedConsensusForCompareContigs( nUnpaddedStart2, nALittleMoreThanUnpaddedOverlappingBasesToLeft, soUnpaddedConsensus2ToLeft, bContig2ComplementedWRTAlignedReadsWindow_, true ); // bToLeftNotRight RWCString soAlignmentLeftTop; RWCString soAlignmentLeftMid; RWCString soAlignmentLeftBot; if ( soUnpaddedConsensus1ToLeft.length() == 0 || soUnpaddedConsensus2ToLeft.length() == 0 ) { // case in which the user clicked on the leftmost base of // one of the contigs soAlignmentLeftTop = ""; soAlignmentLeftMid = ""; soAlignmentLeftBot = ""; nBestAlignEnd1 = 0; nBestAlignEnd2 = 0; nBestScore = 0; } else { cerr << "extending alignment to left..."; cerr.flush(); if ( pCP->bCompareContigsUseBandedRatherThanFullSmithWaterman_ ) { extendAlignmentBanded( soUnpaddedConsensus1ToLeft.data(), soUnpaddedConsensus2ToLeft.data(), soUnpaddedConsensus1ToLeft.length(), soUnpaddedConsensus2ToLeft.length(), &nBestAlignEnd1, &nBestAlignEnd2, &nBestScore, nGapPenalty, nMatchBoost, nMismatchPenalty, pCP->nCompareContigsBandSize_ ); } else { extendAlignment( soUnpaddedConsensus1ToLeft.data(), soUnpaddedConsensus2ToLeft.data(), soUnpaddedConsensus1ToLeft.length(), soUnpaddedConsensus2ToLeft.length(), &nBestAlignEnd1, &nBestAlignEnd2, &nBestScore, nGapPenalty, nMatchBoost, nMismatchPenalty); } cerr << "done" << endl; cerr.flush(); soUnpaddedConsensus1ToLeft.truncate( nBestAlignEnd1 ); soUnpaddedConsensus2ToLeft.truncate( nBestAlignEnd2 ); // handle case in which the extendAlignment decides that // any extension gives a negative score if ( soUnpaddedConsensus1ToLeft.length() > 0 ) { int nScore; cerr << "computing alignment to left..."; cerr.flush(); if ( pCP->bCompareContigsUseBandedRatherThanFullSmithWaterman_ ) { getAlignmentBanded( soUnpaddedConsensus1ToLeft.data(), soUnpaddedConsensus2ToLeft.data(), soUnpaddedConsensus1ToLeft.length(), soUnpaddedConsensus2ToLeft.length(), nGapPenalty, nMatchBoost, nMismatchPenalty, pCP->nCompareContigsBandSize_, soAlignmentLeftTop, soAlignmentLeftMid, soAlignmentLeftBot, nScore ); assert( soAlignmentLeftTop.length() == soAlignmentLeftMid.length() ); assert( soAlignmentLeftTop.length() == soAlignmentLeftBot.length() ); assert( nScore == nBestScore ); } else { getAlignment( soUnpaddedConsensus1ToLeft.data(), soUnpaddedConsensus2ToLeft.data(), nGapPenalty, // gap penalty nMatchBoost, // match boost nMismatchPenalty, // mismatch penalty soAlignmentLeftTop, soAlignmentLeftBot, nScore ); assert( nScore == nBestScore ); soAlignmentLeftMid = ""; for( int n = 0; n < soAlignmentLeftTop.length(); ++n ) { if (soAlignmentLeftTop[n] == soAlignmentLeftBot[n] ) soAlignmentLeftMid += " "; else soAlignmentLeftMid += "X"; } } cerr << "done" << endl; cerr.flush(); } else { soAlignmentLeftTop = ""; soAlignmentLeftMid = ""; soAlignmentLeftBot = ""; nBestAlignEnd1 = 0; nBestAlignEnd2 = 0; nBestScore = 0; } } // save for paddedPieceOfRead int nUnpaddedLeftEndOfAlignment1 = pContig1_->nUnpaddedIndex( nPinnedConsPos1_ ) + ( bContig1ComplementedWRTAlignedReadsWindow_ ? nBestAlignEnd1 : -nBestAlignEnd1 ); int nUnpaddedLeftEndOfAlignment2 = pContig2_->nUnpaddedIndex( nPinnedConsPos2_ ) + ( bContig2ComplementedWRTAlignedReadsWindow_ ? nBestAlignEnd2 : -nBestAlignEnd2 ); // first put in the alignment of the bases to the left of the pinned bases // The order of these must be reversed. assert( soAlignmentLeftTop.length() == soAlignmentLeftMid.length() ); assert( soAlignmentLeftTop.length() == soAlignmentLeftBot.length() ); int nLengthOfAlignmentWithContext = soAlignmentLeftTop.length() + 1 + // pinned base soAlignmentRightTop.length() + 2*nContextBases; RWCString soAlignmentTop( (size_t) nLengthOfAlignmentWithContext ); RWCString soAlignmentMid( (size_t) nLengthOfAlignmentWithContext ); RWCString soAlignmentBot( (size_t) nLengthOfAlignmentWithContext ); int nLengthLeft = soAlignmentLeftTop.length(); // handle case of no extension if (nLengthLeft > 0 ) { soAlignmentTop.nCurrentLength_ = nLengthLeft; soAlignmentMid.nCurrentLength_ = nLengthLeft; soAlignmentBot.nCurrentLength_ = nLengthLeft; // notice that soAlignmentLeft is being flipped for( int n = 0; n < nLengthLeft; ++n ) { soAlignmentTop[n] = soAlignmentLeftTop[ nLengthLeft - n - 1 ]; soAlignmentMid[n] = soAlignmentLeftMid[ nLengthLeft - n - 1 ]; soAlignmentBot[n] = soAlignmentLeftBot[ nLengthLeft - n - 1 ]; } } // now handle the pinned bases in the middle char cPinnedBase1 = toupper( pContig1_->ntideGet( nPinnedConsPos1_ ).cGetBase() ); char cPinnedBase2 = toupper( pContig2_->ntideGet( nPinnedConsPos2_ ).cGetBase() ); if ( bContig1ComplementedWRTAlignedReadsWindow_ ) cPinnedBase1 = cComplementBase( cPinnedBase1 ); if ( bContig2ComplementedWRTAlignedReadsWindow_ ) cPinnedBase2 = cComplementBase( cPinnedBase2 ); soAlignmentTop.append( cPinnedBase1 ); soAlignmentMid.append( "P" ); soAlignmentBot.append( cPinnedBase2 ); // now add the alignment from the bases on the right soAlignmentTop += soAlignmentRightTop; soAlignmentMid += soAlignmentRightMid; soAlignmentBot += soAlignmentRightBot; // now add context bases on both sides addContext( eContig1, soAlignmentTop, nUnpaddedLeftEndOfAlignment1, nUnpaddedRightEndOfAlignment1 ); addContext( eContig2, soAlignmentBot, nUnpaddedLeftEndOfAlignment2, nUnpaddedRightEndOfAlignment2 ); RWCString soQuestionMarks( (size_t) nContextBases ); soQuestionMarks.appendLotsOfCopies( '?', nContextBases ); soAlignmentMid = soQuestionMarks + soAlignmentMid + soQuestionMarks; assert( soAlignmentTop.length() == soAlignmentMid.length() ); assert( soAlignmentTop.length() == soAlignmentBot.length() ); // nContextBases is a constant. But since we add blanks in the // case in which the alignment extends to the very beginning of the // sequence, there are still nContextBases context bases (blanks) // at the beginning before the alignment starts. int nPaddedAlignmentStart = nContextBases; int nPaddedAlignmentEnd = soAlignmentTop.length() - nContextBases - 1; // correct since soAlignmentTop.length() - 1 is the last position. int nZeroBasedPinned1 = soAlignmentLeftTop.length() + nContextBases; int nZeroBasedPinned2 = soAlignmentLeftBot.length() + nContextBases; pPaddedPieceOfReadTop_ = new paddedPieceOfRead( "compareContigs::pPaddedPieceOfReadTop_", soAlignmentTop, nZeroBasedPinned1, nPinnedConsPos1_, pContig1_, nUnpaddedLeftEndOfAlignment1, nUnpaddedRightEndOfAlignment1, nPaddedAlignmentStart, nPaddedAlignmentEnd, bContig1ComplementedWRTAlignedReadsWindow_ ); soAlignmentMiddleLine_ = soAlignmentMid; // redundant since soAlignmentTop.length() == soAlignmentBot.length() // nPaddedAlignmentStart = nContextBases; // nPaddedAlignmentEnd = soAlignmentBot.length() - nContextBases - 1; pPaddedPieceOfReadBot_ = new paddedPieceOfRead( "compareContigs::pPaddedPieceOfReadBot_", soAlignmentBot, nZeroBasedPinned2, nPinnedConsPos2_, pContig2_, nUnpaddedLeftEndOfAlignment2, nUnpaddedRightEndOfAlignment2, nPaddedAlignmentStart, nPaddedAlignmentEnd, bContig2ComplementedWRTAlignedReadsWindow_ ); printAlignment( soAlignmentTop, soAlignmentMid, soAlignmentBot ); bAlignmentExists_ = true; setAlignmentWindowScrollBarForNewAlignment(); drawAlignmentWindowScaleAndBases(); displayDiscrepancyNumberAndRate(); delete pPleaseWait; } void compareContigs :: printAlignment( const RWCString& soAlignmentTop, const RWCString& soAlignmentMid, const RWCString& soAlignmentBot ) { assert( soAlignmentTop.length() == soAlignmentMid.length() ); assert( soAlignmentTop.length() == soAlignmentBot.length() ); int nLengthOfAlignment = soAlignmentTop.length(); int nUnpaddedPos; for( int nOnceALine = 0; nOnceALine < nLengthOfAlignment; nOnceALine += 50 ) { nUnpaddedPos = pPaddedPieceOfReadTop_->nUnpaddedContigPosFromZeroBasedPaddedPos( nOnceALine ); printf("%-9d ", nUnpaddedPos ); int n; for( n = nOnceALine; n < nLengthOfAlignment && n < nOnceALine + 50; ++n ) { printf("%c", soAlignmentTop[ n ] ); } nUnpaddedPos = pPaddedPieceOfReadTop_->nUnpaddedContigPosFromZeroBasedPaddedPos( n - 1 ); printf(" %-9d\n", nUnpaddedPos ); printf(" " ); for( n = nOnceALine; n < nLengthOfAlignment && n < nOnceALine + 50; ++n ) { printf("%c", soAlignmentMid[ n ] ); } printf("\n"); nUnpaddedPos = pPaddedPieceOfReadBot_->nUnpaddedContigPosFromZeroBasedPaddedPos( nOnceALine ); printf("%-9d ", nUnpaddedPos ); for( n = nOnceALine; n < nLengthOfAlignment && n < nOnceALine + 50; ++n ) { printf("%c", soAlignmentBot[ n ] ); } nUnpaddedPos = pPaddedPieceOfReadBot_->nUnpaddedContigPosFromZeroBasedPaddedPos( n-1 ); printf(" %-9d\n", nUnpaddedPos ); printf("\n" ); } // for( nOnceALine = 0 ... } void compareContigs :: contigExposure( const compareContigsTypes eContig1OrContig2) { drawScaleAndBases( eContig1OrContig2 ); } void compareContigs :: alignmentWindowExposure( ) { drawAlignmentWindowScaleAndBases(); } void compareContigs :: drawScaleAndBases( const compareContigsTypes eContig1OrContig2 ) { if ( (eContig1OrContig2 == eContig1 ) && !pContig1_ ) return; // handle case in which the 2nd contig hasn't yet been chosen if ( (eContig1OrContig2 == eContig2 ) && !pContig2_ ) return; pGuiCompareContigs_->guiClearContigWindow( eContig1OrContig2 ); drawScale( eContig1OrContig2 ); drawContigBases( eContig1OrContig2 ); } void compareContigs :: drawScale( const compareContigsTypes eContig1OrContig2 ) { int nLeftEdgeConsPos = nGetLeftEdgeConsensusPosition( eContig1OrContig2 ); Contig* pContig = pGetContig( eContig1OrContig2 ); int nRightEdgeConsPos = nGetRightEdgeConsensusPosition( eContig1OrContig2 ); bool bComplementedWRTAlignedReadsWindow = ( eContig1OrContig2 == eContig1 ? bContig1ComplementedWRTAlignedReadsWindow_ : bContig2ComplementedWRTAlignedReadsWindow_ ); int nCon; int nCharScreenPosition; char szLabel[50]; int nLittleConsPos; int nBigConsPos; if ( bComplementedWRTAlignedReadsWindow ) { nLittleConsPos = nRightEdgeConsPos; nBigConsPos = nLeftEdgeConsPos; } else { nLittleConsPos = nLeftEdgeConsPos; nBigConsPos = nRightEdgeConsPos; } int nUnpadPos = pContig->nUnpaddedIndex( nLittleConsPos ); bool bFirstTimeThrough = true; for(nCon = nLittleConsPos; nCon <= nBigConsPos; ++nCon ) { // is the current consensus position a pad ? bool bConIsPad = pContig->ntGetCons(nCon).bIsPad(); // if not first time through, update the unpadded position if (! bFirstTimeThrough) { // if this consensus pos is not a base, increment unpadded pos if ( ! bConIsPad ) { nUnpadPos++; } } else { bFirstTimeThrough = false; } // screen position depends on all displayed bases, including pads nCharScreenPosition = nConsensusPositionToScreenChar( eContig1OrContig2, nCon ); // only draw a tickmark if the current consensus position // is not a pad if (! bConIsPad ) { // draw big ticks every 5 if (nUnpadPos % 5 == 0) { pGuiCompareContigs_->guiDrawScaleTick( eContig1OrContig2, eBigTick, nCharScreenPosition ); if (nUnpadPos % 10 == 0) { sprintf(szLabel, "%d", nUnpadPos ); pGuiCompareContigs_->guiDrawScaleNumber( eContig1OrContig2, nCharScreenPosition, szLabel ); } } else { pGuiCompareContigs_->guiDrawScaleTick( eContig1OrContig2, eLittleTick, nCharScreenPosition ); } } } pGuiCompareContigs_->guiDrawScaleHorizontalLine( eContig1OrContig2 ); } void compareContigs :: drawContigBases( const compareContigsTypes eContig1OrContig2 ) { // handle case in which 2nd contig hasn't yet been selected if ( eContig1OrContig2 == eContig1 ) { if (!pContig1_) return; } else { if (!pContig2_) return; } int nLeftEdgeConsensusPosition = (eContig1OrContig2 == eContig1) ? nContig1LeftEdgeConsensusPosition_ : nContig2LeftEdgeConsensusPosition_; Contig* pContig = (eContig1OrContig2 == eContig1) ? pContig1_ : pContig2_; bool bComplemented = ( eContig1OrContig2 == eContig1 ? bContig1ComplementedWRTAlignedReadsWindow_ : bContig2ComplementedWRTAlignedReadsWindow_ ); int nLengthToRight; if ( bComplemented ) nLengthToRight = nLeftEdgeConsensusPosition; else nLengthToRight = pContig->nGetPaddedConsLength() - nLeftEdgeConsensusPosition + 1; nLengthToRight = MIN( nLengthToRight, pGuiCompareContigs_->nScreenWidthInChars() ); if (nLengthToRight < 1 ) return; RWCString soPartOfContig; if ( bComplemented ) pContig->getPartOfComplementedConsensus( nLeftEdgeConsensusPosition, nLengthToRight, soPartOfContig ); else pContig->getPartOfConsensus( nLeftEdgeConsensusPosition, nLengthToRight, soPartOfContig ) ; pGuiCompareContigs_->guiDrawContigBases( eContig1OrContig2, soPartOfContig ); } void compareContigs :: drawAlignmentWindowBases( const compareContigsTypes eContig1OrContig2 ) { paddedPieceOfRead* pPaddedPieceOfRead = pGetPaddedPieceOfRead( eContig1OrContig2 ); compareContigsAlignmentWindowLineTypes eLine; Contig* pContig; if (eContig1OrContig2 == eContig1 ) { eLine = eLine1; pContig = pContig1_; } else { eLine = eLine3; pContig = pContig2_; } RWCString soBasesToDisplay; GuiColorText* pGuiColorTextOfBasesToDisplay = NULL; int nZeroBasedPosOfBasesToDisplay = -666; for( int nZeroBasedAlignPos = nAlignmentWindowLeftEdgeZeroBasedPos_; nZeroBasedAlignPos <= nGetRightEdgeAlignmentWindowZeroBasedPosition(); ++nZeroBasedAlignPos ) { char cBaseOrPad = pPaddedPieceOfRead->soBasesAndPads_[ nZeroBasedAlignPos ]; Quality qual = pPaddedPieceOfRead->aBaseAndPadQualities_[ nZeroBasedAlignPos ]; if ( qual > pCP->nQualityThresholdForLowConsensusQuality_ ) cBaseOrPad = toupper( cBaseOrPad ); else cBaseOrPad = tolower( cBaseOrPad ); // the point of most of the code below is to determine // the value of this. GuiColorText* pGuiColorTextOfBase = NULL; if ( cBaseOrPad == ' ' ) { // special case: the alignment extends to the beginning (or end) // of the sequence so the context bases (the 3 unaligned bases that // are added to the beginning or end of the alignment) are blank // In this case, what should the GuiColorText be? White, I guess. pGuiColorTextOfBase = GAPP->pColorMeansQuality_->pColor40_97_; } else { Quality qual = pPaddedPieceOfRead->aBaseAndPadQualities_[ nZeroBasedAlignPos ]; pGuiColorTextOfBase = GAPP->pColorMeansQuality_->pGuiColorTextGetBackgroundAgree( qual ); } // group similar bases together to display at once if ( pGuiColorTextOfBasesToDisplay == NULL ) { pGuiColorTextOfBasesToDisplay = pGuiColorTextOfBase; soBasesToDisplay.append( cBaseOrPad ); nZeroBasedPosOfBasesToDisplay = nZeroBasedAlignPos; } else if ( pGuiColorTextOfBasesToDisplay == pGuiColorTextOfBase ) { soBasesToDisplay.append( cBaseOrPad ); } else { // we just changed quality. So print out what we have so far, // and then set up the soBasesToDisplay and pGuiColorTextOfBasesToDisplay for // the next group of bases/pads. pGuiCompareContigs_->guiDrawAlignmentWindowBases( eLine, nZeroBasedPosOfBasesToDisplay, soBasesToDisplay, pGuiColorTextOfBasesToDisplay ); // now consider the current base pGuiColorTextOfBasesToDisplay = pGuiColorTextOfBase; soBasesToDisplay = cBaseOrPad; nZeroBasedPosOfBasesToDisplay = nZeroBasedAlignPos; } } // for( int nZeroBasedAlignPos = nAlignmentWindowLeftEdgeZeroBasedPos_; // in the loop above, we only print out when the color changes. // So we are guaranteed to exit the loop with something still to print // out, unless the loop is not executed at all. pGuiCompareContigs_->guiDrawAlignmentWindowBases( eLine, nZeroBasedPosOfBasesToDisplay, soBasesToDisplay, pGuiColorTextOfBasesToDisplay ); } void compareContigs :: drawAlignmentWindowMiddleLine( ) { RWCString soMatchMarksToDisplay = soAlignmentMiddleLine_( nAlignmentWindowLeftEdgeZeroBasedPos_, nGetRightEdgeAlignmentWindowZeroBasedPosition() - nAlignmentWindowLeftEdgeZeroBasedPos_ + 1 ); pGuiCompareContigs_->guiDrawAlignmentWindowBases( eLine2, soMatchMarksToDisplay ); } void compareContigs :: displayDiscrepancyNumberAndRate() { int nNumberOfDiscrepancies = 0; int nNumberOfAlignedBases = 0; for( int n = 0; n < soAlignmentMiddleLine_.length(); ++n ) { if ( soAlignmentMiddleLine_[n] != '?' ) { ++nNumberOfAlignedBases; if ( soAlignmentMiddleLine_[n] == 'X' ) { ++nNumberOfDiscrepancies; } } } char szDiscrepancies[10]; sprintf( szDiscrepancies, "%d", nNumberOfDiscrepancies ); XtVaSetValues( pGuiCompareContigs_->widNumberOfDiscrepancies_, XmNvalue, szDiscrepancies, NULL ); char szDiscrepancyRate[10]; if ( nNumberOfAlignedBases == 0 ) { strcpy( szDiscrepancyRate, "?" ); } else { sprintf( szDiscrepancyRate, "%.4f", 100.0 * (double) nNumberOfDiscrepancies / (double) nNumberOfAlignedBases ); } XtVaSetValues( pGuiCompareContigs_->widDiscrepancyRate_, XmNvalue, szDiscrepancyRate, NULL ); } int compareContigs :: nGetRightEdgeConsensusPosition( const compareContigsTypes eContig1OrContig2 ) { int nLeftEdgeConsPos = (eContig1OrContig2 == eContig1 ) ? nContig1LeftEdgeConsensusPosition_ : nContig2LeftEdgeConsensusPosition_; int nScreenWidthInChars = pGuiCompareContigs_->nScreenWidthInChars(); bool bComplemented = ( eContig1OrContig2 == eContig1 ? bContig1ComplementedWRTAlignedReadsWindow_ : bContig2ComplementedWRTAlignedReadsWindow_ ); int nRightEdgeConsPos; if ( bComplemented ) { nRightEdgeConsPos = nLeftEdgeConsPos - nScreenWidthInChars + 1; } else { nRightEdgeConsPos = nLeftEdgeConsPos + nScreenWidthInChars - 1; } Contig* pContig = (eContig1OrContig2 == eContig1 ) ? pContig1_ : pContig2_; if ( bComplemented ) { if ( nRightEdgeConsPos < pContig->nGetStartConsensusIndex() ) nRightEdgeConsPos = pContig->nGetStartConsensusIndex(); } else { if (nRightEdgeConsPos > pContig->nGetEndConsensusIndex() ) nRightEdgeConsPos = pContig->nGetEndConsensusIndex(); } return( nRightEdgeConsPos ); } int compareContigs :: nGetRightEdgeAlignmentWindowZeroBasedPosition() { int nScreenWidthInChars = pGuiCompareContigs_->nScreenWidthInChars(); int nRightEdgeConsPos = nAlignmentWindowLeftEdgeZeroBasedPos_ + nScreenWidthInChars - 1; int nMaximumZeroBasedPos = pPaddedPieceOfReadTop_->nGetPaddedLength() - 1; if (nRightEdgeConsPos > nMaximumZeroBasedPos ) nRightEdgeConsPos = nMaximumZeroBasedPos; return( nRightEdgeConsPos ); } void compareContigs :: horizontalScrollBarMoved( const compareContigsWindowTypes eWindow, const int nNewScrollBarPosition ) { compareContigsTypes eContig1OrContig2; // set private member data to new scroll bar position // the slider position equals the position within the // entire displayable region of the contig - consensus based if (eWindow == eContig1Window ) { nContig1LeftEdgeConsensusPosition_ = nNewScrollBarPosition; if ( bContig1ComplementedWRTAlignedReadsWindow_ ) { // complement it nContig1LeftEdgeConsensusPosition_ = pContig1_->nGetEndConsensusIndex() - nContig1LeftEdgeConsensusPosition_ + 1; } drawScaleAndBases( eContig1 ); } else if (eWindow == eContig2Window ) { nContig2LeftEdgeConsensusPosition_ = nNewScrollBarPosition; if ( bContig2ComplementedWRTAlignedReadsWindow_ ) { nContig2LeftEdgeConsensusPosition_ = pContig2_->nGetEndConsensusIndex() - nContig2LeftEdgeConsensusPosition_ + 1; } drawScaleAndBases( eContig2 ); } else if (eWindow == eAlignmentWindow ) { nAlignmentWindowLeftEdgeZeroBasedPos_ = nNewScrollBarPosition; drawAlignmentWindowScaleAndBases(); } else assert( false ); } void compareContigs :: setScrollBarForNewContig( const compareContigsTypes eContig1OrContig2 ) { Contig* pContig = pGetContig( eContig1OrContig2 ); int nLeftEdgeConsensusPosition = nGetLeftEdgeConsensusPosition( eContig1OrContig2 ); int nScrollBarPosition = nGetScrollBarPositionFromLeftEdgeConsensusPosition( eContig1OrContig2, nLeftEdgeConsensusPosition ); assert( pContig ); pGuiCompareContigs_->guiResetScrollBar( nScrollBarPosition, // val pContig->nGetStartConsensusIndex(), // min pContig->nGetEndConsensusIndex(), // max pGuiCompareContigs_->nScreenWidthInCharsNotRoundedUp(), // size eGetCompareContigsWindowType( eContig1OrContig2) ); } void compareContigs :: setAlignmentWindowScrollBarForNewAlignment() { pGuiCompareContigs_->guiResetScrollBar( nAlignmentWindowLeftEdgeZeroBasedPos_, // val 0, // min // subtract 1 since max subscript is 1 less than // the length soAlignmentMiddleLine_.length() - 1, //max pGuiCompareContigs_->nScreenWidthInCharsNotRoundedUp(), // size eAlignmentWindow ); } void compareContigs :: drawAlignmentWindowScaleAndBases( ) { // handle case in which the alignment hasn't yet been done if ( !bAlignmentExists_ ) return; pGuiCompareContigs_->guiClearAlignmentWindow( ); drawAlignmentWindowScale( eContig1 ); drawAlignmentWindowBases( eContig1 ); drawAlignmentWindowMiddleLine(); drawAlignmentWindowBases( eContig2 ); drawAlignmentWindowScale( eContig2 ); } void compareContigs :: drawAlignmentWindowScale( const compareContigsTypes eContig1OrContig2 ) { int nCharScreenPosition; char szLabel[50]; int nRightEdgeZeroBasedPos = nGetRightEdgeAlignmentWindowZeroBasedPosition(); paddedPieceOfRead* pPaddedPieceOfRead = pGetPaddedPieceOfRead( eContig1OrContig2 ); bool bComplementedContig = bIsContigComplemented( eContig1OrContig2 ); int nUnpaddedPos; bool bFirstTimeThrough = true; for( int nZeroBasedPos = nAlignmentWindowLeftEdgeZeroBasedPos_; nZeroBasedPos <= nRightEdgeZeroBasedPos; ++nZeroBasedPos ) { bool bIsPad = bIsAPad( pPaddedPieceOfRead->soBasesAndPads_[ nZeroBasedPos ] ); if (bFirstTimeThrough ) { bFirstTimeThrough = false; nUnpaddedPos = pPaddedPieceOfRead->nUnpaddedContigPosFromZeroBasedPaddedPos( nZeroBasedPos ); } else { if ( !bIsPad ) { if ( bComplementedContig ) { --nUnpaddedPos; } else { ++nUnpaddedPos; } } } nCharScreenPosition = nAlignmentWindowZeroBasedPosToScreenChar( nZeroBasedPos ); if ( ! bIsPad ) { // draw big ticks every 5 if (nUnpaddedPos % 5 == 0) { pGuiCompareContigs_->guiDrawAlignmentWindowScaleTick( eContig1OrContig2, eBigTick, nCharScreenPosition ); if (nUnpaddedPos % 10 == 0) { sprintf(szLabel, "%d", nUnpaddedPos ); pGuiCompareContigs_->guiDrawAlignmentWindowScaleNumber( eContig1OrContig2, nCharScreenPosition, szLabel ); } } else { pGuiCompareContigs_->guiDrawAlignmentWindowScaleTick( eContig1OrContig2, eLittleTick, nCharScreenPosition ); } } // if ( ! bIsPad ) } // for( int nZero... pGuiCompareContigs_->guiDrawAlignmentWindowScaleHorizontalLine( eContig1OrContig2 ); } paddedPieceOfRead* compareContigs :: pGetPaddedPieceOfRead( const compareContigsTypes eContig1OrContig2 ) { if (eContig1OrContig2 == eContig1 ) return( pPaddedPieceOfReadTop_ ); else if ( eContig1OrContig2 == eContig2 ) return( pPaddedPieceOfReadBot_ ); else assert( false ); } int compareContigs :: nConsensusPositionToScreenChar( const compareContigsTypes eContig1OrContig2, const int nConsPos ) { int nLeftEdgeConsensusPosition = nGetLeftEdgeConsensusPosition( eContig1OrContig2 ); int nRightEdgeConsensusPosition = nGetRightEdgeConsensusPosition( eContig1OrContig2 ); bool bComplemented = ( eContig1OrContig2 == eContig1 ? bContig1ComplementedWRTAlignedReadsWindow_ : bContig2ComplementedWRTAlignedReadsWindow_ ); // if the consensus position is not on the screen, signal this if (! ( ( bComplemented && nLeftEdgeConsensusPosition >= nConsPos && nConsPos >= nRightEdgeConsensusPosition ) || ( !bComplemented && nLeftEdgeConsensusPosition <= nConsPos && nConsPos <= nRightEdgeConsensusPosition ) ) ) { return( -1 ); } int nScreenCharX; if ( bComplemented ) { nScreenCharX = nLeftEdgeConsensusPosition - nConsPos; } else { nScreenCharX = nConsPos - nLeftEdgeConsensusPosition; } return( nScreenCharX ); } void compareContigs :: drawTopContigWindowCursor( const bool bBlinkOn, const compareContigsTypes eContig1OrContig2 ) { // handle case in which 2nd contig hasn't yet been selected Contig* pContig = pGetContig( eContig1OrContig2 ); if ( eContig1OrContig2 == eContig1 ) { if (!pContig1_) return; } else { if (!pContig2_) return; } compareContigsCursor& curCompareContigsCursor = curGetCompareContigsTopContigCursor( eContig1OrContig2 ); if (! curCompareContigsCursor.bIsValid() ) return; int nCursorConsensusPosition = curCompareContigsCursor.nPosition_; int nScreenCharPosX = nConsensusPositionToScreenChar( eContig1OrContig2, nCursorConsensusPosition ); if ( nScreenCharPosX < 0 ) return; char cBase = pContig->ntGetCons( nCursorConsensusPosition ).cGetBase(); if ( bIsContigComplemented( eContig1OrContig2 ) ) { cBase = cComplementBase( cBase ); } pGuiCompareContigs_->guiDrawContigCursor( eContig1OrContig2, nScreenCharPosX, bBlinkOn, cBase ); } void compareContigs :: drawAlignmentWindowCursor(const bool bBlinkOn ) { if (! curAlignmentWindow_.bIsValid() ) return; if (! bVisibleOnAlignmentWindow( curAlignmentWindow_.nPosition_ ) ) return; int nScreenCharPosX = nAlignmentWindowZeroBasedPosToScreenChar( curAlignmentWindow_.nPosition_ ); paddedPieceOfRead* pPaddedPieceOfRead = pGetPaddedPieceOfRead( eContig1 ); GuiColorText* pGuiColorText = NULL; char cBase; getGuiColorTextAndBaseForCursor( curAlignmentWindow_.nPosition_, pPaddedPieceOfRead, bBlinkOn, cBase, pGuiColorText ); pGuiCompareContigs_->guiDrawAlignmentWindowCursor( eContig1, nScreenCharPosX, cBase, pGuiColorText ); pPaddedPieceOfRead = pGetPaddedPieceOfRead( eContig2 ); cBase = pPaddedPieceOfRead->soBasesAndPads_[ curAlignmentWindow_.nPosition_ ]; getGuiColorTextAndBaseForCursor( curAlignmentWindow_.nPosition_, pPaddedPieceOfRead, bBlinkOn, cBase, pGuiColorText ); pGuiCompareContigs_->guiDrawAlignmentWindowCursor( eContig2, nScreenCharPosX, cBase, pGuiColorText ); } bool compareContigs :: bVisibleOnAlignmentWindow( const int nZeroBasedPos ) { if ( (nAlignmentWindowLeftEdgeZeroBasedPos_ <= nZeroBasedPos ) && nZeroBasedPos <= nGetRightEdgeAlignmentWindowZeroBasedPosition() ) return( true ); else return( false ); } void compareContigs :: setAlignmentCursor( const int nScreenCharX ) { // handle case in which the user is clicking on a blank alignment area if (!bAlignmentExists_ ) return; if ( curAlignmentWindow_.bIsValid() ) drawAlignmentWindowCursor( false ); curAlignmentWindow_.nPosition_ = nScreenCharX + nAlignmentWindowLeftEdgeZeroBasedPos_; curAlignmentWindow_.bIsValid_ = true; drawAlignmentWindowCursor( true ); } void compareContigs :: setAlignmentCursorAtAlignmentPos( const int n0AlignmentPos ) { if ( !bAlignmentExists_ ) return; if ( curAlignmentWindow_.bIsValid() ) drawAlignmentWindowCursor( false ); curAlignmentWindow_.nPosition_ = n0AlignmentPos; curAlignmentWindow_.bIsValid_ = true; drawAlignmentWindowCursor( true ); } void compareContigs :: setTopContigCursorByScreenPos( const compareContigsTypes eContig1OrContig2, const int nScreenCharX ) { if (! pGetContig( eContig1OrContig2 ) ) return; int nConsPos = nScreenCharToConsensusPosition( eContig1OrContig2, nScreenCharX ); setTopContigCursorByConsensusPosition( eContig1OrContig2, nConsPos ); } void compareContigs :: setTopContigCursorByConsensusPosition( const compareContigsTypes eContig1OrContig2, const int nConsPos ) { compareContigsCursor& curCompareContigsCursor = curGetCompareContigsTopContigCursor( eContig1OrContig2 ); if (curCompareContigsCursor.bIsValid() ) drawTopContigWindowCursor( false, eContig1OrContig2 ); curCompareContigsCursor.nPosition_ = nConsPos; curCompareContigsCursor.bIsValid_ = true; drawTopContigWindowCursor( true, eContig1OrContig2 ); } void compareContigs :: blinkAllCursors( const bool bBlinkOn ) { drawTopContigWindowCursor( bBlinkOn, eContig1 ); drawTopContigWindowCursor( bBlinkOn, eContig2 ); drawAlignmentWindowCursor( bBlinkOn ); } void compareContigs :: scrollContigWin( const compareContigsTypes eContig1OrContig2 ) { if ( !curAlignmentWindow_.bIsValid() ) { GuiApp::popupErrorMessage( "You must first click to set the cursor" ); return; } int nZeroBased = curAlignmentWindow_.nPosition_; paddedPieceOfRead* pPaddedPieceOfRead = pGetPaddedPieceOfRead( eContig1OrContig2 ); int nUnpadded = pPaddedPieceOfRead->nUnpaddedContigPosFromZeroBasedPaddedPos( nZeroBased ); // catch case of the user putting the cursor on a space before or after // the alignment Contig* pContig = pGetContig( eContig1OrContig2 ); if ( !pContig ) { GuiApp::popupErrorMessage( "These contigs have been replaced by the new joined one--you cannot scroll them" ); return; } if ( ( nUnpadded < pContig->nGetUnpaddedStartIndex() ) || ( pContig->nGetUnpaddedEndIndex() < nUnpadded ) ) { GuiApp::popupErrorMessage( "This base of off the end of the contig" ); return; } int nConsPos = pGetContig( eContig1OrContig2 )->nPaddedIndexFast( nUnpadded ); ContigWin* pContigWin; if ( eContig1OrContig2 == eContig2 && pContig1_ == pContig2_ ) { // special case for showing a repeat within the same contig. // must get another aligned reads window. pContigWin = ConsEd::pGetConsEd()->pGetSecondContigWinByContig( pContig ); // usually will be null (the user will only have one Aligned Reads // Window up for this contig) so must create a new one. if ( !pContigWin ) { pContigWin = ConsEd::pGetConsEd()->pPutContigInAContigWin( pContig, nConsPos ); } } else { //normal case pContigWin = pGetContigWin( eContig1OrContig2 ); if ( !pContigWin ) { pContigWin = ConsEd::pGetConsEd()->pScrollExistingContigWinOrMakeNewContigWin( pGetContig( eContig1OrContig2 ), nConsPos ); } } pContigWin->scrollToConsensusPosInCenter( nConsPos ); pContigWin->moveCursorToConsPos( nConsPos ); } void compareContigs :: getGuiColorTextAndBaseForCursor( const int nZeroBasedAlignPos, paddedPieceOfRead* pPaddedPieceOfRead, const bool bBlinkOn, char& cBaseOrPad, GuiColorText*& pGuiColorTextOfBase ) { cBaseOrPad = pPaddedPieceOfRead->soBasesAndPads_[ nZeroBasedAlignPos ]; if ( cBaseOrPad == ' ' ) { // special case: the alignment extends to the beginning (or end) // of the sequence so the context bases (the 3 unaligned bases that // are added to the beginning or end of the alignment) are blank if ( bBlinkOn ) pGuiColorTextOfBase = pGuiCompareContigs_->pGuiColorTextCursor_; else pGuiColorTextOfBase = GAPP->pColorMeansQuality_->pColor40_97_; return; } // So the base is not a blank. // make the base upper or lower case as it should be Quality qual = pPaddedPieceOfRead->aBaseAndPadQualities_[ nZeroBasedAlignPos ]; if ( qual > pCP->nQualityThresholdForLowConsensusQuality_ ) cBaseOrPad = toupper( cBaseOrPad ); else cBaseOrPad = tolower( cBaseOrPad ); if ( bBlinkOn ) { // make the base with red background pGuiColorTextOfBase = pGuiCompareContigs_->pGuiColorTextCursor_; } else { // find the quality shade of the base in the consensus pGuiColorTextOfBase = GAPP->pColorMeansQuality_->pGuiColorTextGetBackgroundAgree( qual ); } } float compareContigs :: fGetEstimatedTimeToDoAlignment() { time_t timeStart = time( NULL ); char* szSeq1 = "gctgtttatagatcccacaaacagtaaacgcaggcttgactctcttccacggagcagctccgacatttgaaaacagttcttgagaatgcagctggccggagctgtttatagatcccacaaacagtaaacgcaggcttgactctcttccacggagcagctccgacatttgaaaacagttcttgagaatgcagctggccggagctgtttatagatcccacaaacagtaaacgcaggcttgactctcttccacggagcagctccgacatttgaaaacagttcttgagaatgcagctggccggagctgtttatagatcccacaaacagtaaacgcaggcttgactctcttccacggagcagctccgacatttgaaaacagttcttgagaatgcagctggccggagctgtttatagatcccacaaacagtaaacgcaggcttgactctcttccacggagcagctccgacatttgaaaacagttcttgagaatgca" "gctggccggagctgtttatagatcccacaaacagtaaacgcaggcttgactctcttccacggagcagctccgacatttgaaaacagttcttgagaatgcagctggccggagctgtttatagatcccacaaacagtaaacgcaggcttgactctcttccacggagcagctccgacatttgaaaacagttcttgagaatgcagctggccggagctgtttatagatcccacaaacagtaaacgcaggcttgactctcttccacggagcagctccgacatttgaaaacagttcttgagaatgcagctggccggagctgtttatagatcccacaaacagtaaacgcaggcttgactctcttccacggagcagctccgacatttgaaaacagttcttgagaatgcagctggccggagctgtttatagatcccacaaacagtaaacgcaggcttgactctcttccacggagcagctccgacatttgaaaacagttcttgagaatgcagctggccgga"; char* szSeq2 = "gctgtttatagatcccacaaacagtaaacgcaggcttgactctcttccacggagcagctccgacatttgaaaacagttcttgagaatgcagctggccggagctgtttatagatcccacaaacagtaaacgcaggcttgactctcttccacggagcagctccgacatttgaaaacagttcttgagaatgcagctggccggagctgtttatagatcccacaaacagtaaacgcaggcttgactctcttccacggagcagctccgacatttgaaaacagttcttgagaatgcagctggccggagctgtttatagatcccacaaacagtaaacgcaggcttgactctcttccacggagcagctccgacatttgaaaacagttcttgagaatgcagctggccggagctgtttatagatcccacaaacagtaaacgcaggcttgactctcttccacggagcagctccgacatttgaaaacagttcttgagaatgca" "gctggccggagctgtttatagatcccacaaacagtaaacgcaggcttgactctcttccacggagcagctccgacatttgaaaacagttcttgagaatgcagctggccggagctgtttatagatcccacaaacagtaaacgcaggcttgactctcttccacggagcagctccgacatttgaaaacagttcttgagaatgcagctggccggagctgtttatagatcccacaaacagtaaacgcaggcttgactctcttccacggagcagctccgacatttgaaaacagttcttgagaatgcagctggccggagctgtttatagatcccacaaacagtaaacgcaggcttgactctcttccacggagcagctccgacatttgaaaacagttcttgagaatgcagctggccggagctgtttatagatcccacaaacagtaaacgcaggcttgactctcttccacggagcagctccgacatttgaaaacagttcttgagaatgcagctggccgga"; makeUpper( szSeq1 ); makeUpper( szSeq2 ); int nSeq1Length = strlen( szSeq1 ); int nSeq2Length = strlen( szSeq2 ); int nBestAlignEnd1; int nBestAlignEnd2; int nBestScore; extendAlignment( szSeq1, szSeq2, nSeq1Length, nSeq2Length, &nBestAlignEnd1, &nBestAlignEnd2, &nBestScore, nGapPenalty, nMatchBoost, nMismatchPenalty ); szSeq1[ nBestAlignEnd1 ] = '\0'; szSeq2[ nBestAlignEnd2 ] = '\0'; int nScore; RWCString soAlignmentTop; RWCString soAlignmentMid; getAlignment( szSeq1, szSeq2, nGapPenalty, nMatchBoost, nMismatchPenalty, soAlignmentTop, soAlignmentMid, nScore ); assert( nScore == nBestScore ); time_t timeEnd = time( NULL ); double dTimeFor100BasesBy100Bases = difftime( timeEnd, timeStart ); cerr << "time to do an alignment of 100 by 100: " << dTimeFor100BasesBy100Bases << endl; int nUnpaddedPinned1 = pContig1_->nUnpaddedIndex( nPinnedConsPos1_ ); int nUnpaddedPinned2 = pContig2_->nUnpaddedIndex( nPinnedConsPos2_ ); int nUnpaddedBasesToRight1 = pContig1_->nGetUnpaddedEndIndex() - nUnpaddedPinned1 + 1; int nUnpaddedBasesToRight2 = pContig2_->nGetUnpaddedEndIndex() - nUnpaddedPinned2 + 1; bool bShortestToRightIsContig1Not2; int nUnpaddedOverlappingBasesToRight; if ( nUnpaddedBasesToRight1 < nUnpaddedBasesToRight2 ) { bShortestToRightIsContig1Not2 = true; nUnpaddedOverlappingBasesToRight = nUnpaddedBasesToRight1; } else { bShortestToRightIsContig1Not2 = false; nUnpaddedOverlappingBasesToRight = nUnpaddedBasesToRight2; } int nALittleMoreThanUnpaddedOverlappingBasesToRight = nUnpaddedOverlappingBasesToRight * 1.1; int nUnpaddedBasesToLeft1 = pContig1_->nUnpaddedIndex( nPinnedConsPos1_ ) - 1; int nUnpaddedBasesToLeft2 = pContig2_->nUnpaddedIndex( nPinnedConsPos2_ ) - 1; bool bShortestToLeftIsContig1Not2; int nUnpaddedOverlappingBasesToLeft; if ( nUnpaddedBasesToLeft1 < nUnpaddedBasesToLeft2 ) { bShortestToLeftIsContig1Not2 = true; nUnpaddedOverlappingBasesToLeft = nUnpaddedBasesToLeft1; } else { bShortestToLeftIsContig1Not2 = false; nUnpaddedOverlappingBasesToLeft = nUnpaddedBasesToLeft2; } int nALittleMoreThanUnpaddedOverlappingBasesToLeft = nUnpaddedOverlappingBasesToLeft * 1.1; float fEstimatedTime = ( (float) nALittleMoreThanUnpaddedOverlappingBasesToRight * nUnpaddedOverlappingBasesToRight + (float) nALittleMoreThanUnpaddedOverlappingBasesToLeft * nUnpaddedOverlappingBasesToLeft ) / ( nSeq1Length * nSeq2Length ); fEstimatedTime *= dTimeFor100BasesBy100Bases; return fEstimatedTime; } bool compareContigs :: bUserThoughtAlignmentWouldTakeTooLong() { float fEstimatedTime = fGetEstimatedTimeToDoAlignment(); cerr << "estimated time: " << fEstimatedTime << " seconds" << endl; if ( fEstimatedTime > 10.0 ) { RWCString soMessage( (size_t) 300 ); if ( fEstimatedTime > 60.0 ) { float fMinutes = fEstimatedTime / 60.0; soMessage.appendFormat( "Alignment will take %.1f minutes. Would you rather cancel?", fMinutes ); } else { soMessage.appendFormat( "Alignment will take %f seconds. Would you rather cancel?", fEstimatedTime ); } return( bGuiGetAnswerYesNo( soMessage ) ); } else return false; } // another entry point to compareContigs (after the ctor) void compareContigs :: popupForAssemblyView( seqMatch* pSeqMatch ) { pContig1_ = pSeqMatch->pContig_[0]; pContig2_ = pSeqMatch->pContig_[1]; // let's pin the start (left edge) of the two regions so that, if // the user wants to later push "Align", it will work rather than // forcing him to find bases himself to pin. nContig1LeftEdgeConsensusPosition_ = pContig1_->nPaddedIndexFast( pSeqMatch->nUnpaddedStartConsPos_[0] ); nContig2LeftEdgeConsensusPosition_ = pContig2_->nPaddedIndexFast( pSeqMatch->nUnpaddedStartConsPos_[1] ); bContig1ComplementedWRTAlignedReadsWindow_ = false; // if the match is a complemented match, complement the 2nd // sequence w.r.t. the pContig2_ contig bContig2ComplementedWRTAlignedReadsWindow_ = pSeqMatch->bComplemented_; pGuiCompareContigs_ = new guiCompareContigs( this ); setScrollBarForNewContig( eContig1 ); setScrollBarForNewContig( eContig2 ); pGuiCompareContigs_->setContigName( eContig1, pContig1_->soGetName() ); pGuiCompareContigs_->setContigName( eContig2, pContig2_->soGetName() ); drawScaleAndBases( eContig2); setTopContigCursorByConsensusPosition( eContig1, nContig1LeftEdgeConsensusPosition_ ); setTopContigCursorByConsensusPosition( eContig2, nContig2LeftEdgeConsensusPosition_ ); PleaseWait* pPleaseWait = new PleaseWait( pGuiCompareContigs_->widPopupShell_ ); alignKnownRegions( pSeqMatch->nUnpaddedStartConsPos_[0], pSeqMatch->nUnpaddedEndConsPos_[0], pSeqMatch->nUnpaddedStartConsPos_[1], pSeqMatch->nUnpaddedEndConsPos_[1], pSeqMatch->bComplemented_ ); delete pPleaseWait; } // this is just for assemblyView void compareContigs :: alignKnownRegions( const int nUnpaddedStart1, const int nUnpaddedEnd1, const int nUnpaddedStart2, const int nUnpaddedEnd2, const bool bComplemented ) { RWCString soRegionContig1( (size_t) ABS( nUnpaddedEnd1 - nUnpaddedStart1 ) + 1 ); RWCString soRegionContig2( (size_t) ABS( nUnpaddedEnd2 - nUnpaddedEnd2 ) + 1 ); pContig1_->appendPartOfUnpaddedConsensus( soRegionContig1, false, nUnpaddedStart1, nUnpaddedEnd1 ); pContig2_->appendPartOfUnpaddedConsensus( soRegionContig2, bComplemented, nUnpaddedStart2, nUnpaddedEnd2 ); RWCString soAlignmentTop; RWCString soAlignmentBot; int nScore; cerr << "computing alignment..."; cerr.flush(); if ( pCP->bCompareContigsUseBandedRatherThanFullSmithWaterman_ ) { getAlignmentBanded( soRegionContig1.data(), soRegionContig2.data(), soRegionContig1.length(), soRegionContig2.length(), nGapPenalty, nMatchBoost, nMismatchPenalty, pCP->nCompareContigsBandSize_, soAlignmentTop, soAlignmentMiddleLine_, soAlignmentBot, nScore ); assert( soAlignmentTop.length() == soAlignmentMiddleLine_.length() ); assert( soAlignmentTop.length() == soAlignmentBot.length() ); } else { getAlignment( soRegionContig1.data(), soRegionContig2.data(), nGapPenalty, nMatchBoost, nMismatchPenalty, soAlignmentTop, soAlignmentBot, nScore ); soAlignmentMiddleLine_ = ""; soAlignmentMiddleLine_.increaseMaxLength( soAlignmentTop.length() ); for( int n = 0; n < soAlignmentTop.length(); ++n ) { if ( soAlignmentTop[n] == soAlignmentBot[n] ) soAlignmentMiddleLine_ += " "; else soAlignmentMiddleLine_ += "X"; } } // if ( pCP->bCompareContigsUseBandedRatherThanFullSmithWaterman_ ) { else cerr << "done" << endl; cerr.flush(); // should show context bases addContext( eContig1, soAlignmentTop, nUnpaddedStart1, nUnpaddedEnd1 ); // the 2nd sequence is in soAlignmentBot addContext( eContig2, soAlignmentBot, nUnpaddedStart2, nUnpaddedEnd2 ); RWCString soQuestionMarks; soQuestionMarks.appendLotsOfCopies( '?', nContextBases ); soAlignmentMiddleLine_ = soQuestionMarks + soAlignmentMiddleLine_ + soQuestionMarks; assert( soAlignmentTop.length() == soAlignmentBot.length() ); assert( soAlignmentTop.length() == soAlignmentMiddleLine_.length() ); // make paddedPieceOfRead int nConsPosOfStartOfAlignment1 = pContig1_->nPaddedIndexFast( nUnpaddedStart1 ); int nConsPosOfStartOfAlignment2 = pContig2_->nPaddedIndexFast( nUnpaddedStart2 ); int nConsPosOfEndOfAlignment1 = pContig1_->nPaddedIndexFast( nUnpaddedEnd1 ); int nConsPosOfEndOfAlignment2 = pContig2_->nPaddedIndexFast( nUnpaddedEnd2 ); int nAlignmentStart = nContextBases; int nAlignmentEnd = soAlignmentTop.length() - 1 - nContextBases; // Note: since soAlignmentTop.length() == soAlignmentBottom.length(), // nAlignmentStart and nAlignmentEnd will be the same for // both paddedPieceOfRead's pPaddedPieceOfReadTop_ = new paddedPieceOfRead( "compareContigs::pPaddedPieceOfReadTop_", soAlignmentTop, nContextBases, nConsPosOfStartOfAlignment1, pContig1_, nUnpaddedStart1, nUnpaddedEnd1, nAlignmentStart, nAlignmentEnd, false ); // bComplemented pPaddedPieceOfReadBot_ = new paddedPieceOfRead( "compareContigs::pPaddedPieceOfReadBot_", soAlignmentBot, nContextBases, nConsPosOfStartOfAlignment2, pContig2_, nUnpaddedStart2, nUnpaddedEnd2, nAlignmentStart, nAlignmentEnd, bComplemented ); printAlignment( soAlignmentTop, soAlignmentMiddleLine_, soAlignmentBot ); bAlignmentExists_ = true; setAlignmentWindowScrollBarForNewAlignment(); drawAlignmentWindowScaleAndBases(); displayDiscrepancyNumberAndRate(); } void compareContigs :: addContext( const compareContigsTypes eContig1OrContig2, RWCString& soAlignment, const int nUnpaddedStart, const int nUnpaddedEnd ) { // nUnpaddedStart, nUnpaddedEnd are the positions of the alignment // contained in soAlignment int nUnpaddedStart1 = nUnpaddedStart; int nUnpaddedEnd1 = nUnpaddedEnd; if ( nUnpaddedStart1 > nUnpaddedEnd1 ) { int nTemp = nUnpaddedStart1; nUnpaddedStart1 = nUnpaddedEnd1; nUnpaddedEnd1 = nTemp; } Contig* pContig = pGetContig( eContig1OrContig2 ); bool bComplemented = bIsContigComplemented( eContig1OrContig2 ); int nContextRight = nUnpaddedStart1 - 1; int nContextLeft = nContextRight - nContextBases + 1; int nBlanksNeeded; RWCString soContextOnLeft( (size_t) nContextBases ); if ( bIntersect( pContig->nGetUnpaddedStartIndex(), pContig->nGetUnpaddedEndIndex(), nContextLeft, nContextRight, nContextLeft, nContextRight ) ) { pContig->appendPartOfUnpaddedConsensus( soContextOnLeft, bComplemented, nContextLeft, nContextRight ); nBlanksNeeded = nContextBases - ( ABS( nContextRight - nContextLeft ) + 1 ); } else nBlanksNeeded = nContextBases; if ( nBlanksNeeded > 0 ) { RWCString soBlanks; soBlanks.appendLotsOfCopies( ' ', nBlanksNeeded ); if ( bComplemented ) soContextOnLeft += soBlanks; else soContextOnLeft = soBlanks + soContextOnLeft; } // now work on context on right nContextLeft = nUnpaddedEnd1 + 1; nContextRight = nContextLeft + nContextBases - 1; RWCString soContextOnRight( (size_t) nContextBases ); if ( bIntersect( pContig->nGetUnpaddedStartIndex(), pContig->nGetUnpaddedEndIndex(), nContextLeft, nContextRight, nContextLeft, nContextRight ) ) { pContig->appendPartOfUnpaddedConsensus( soContextOnRight, bComplemented, nContextLeft, nContextRight ); nBlanksNeeded = nContextBases - ( ABS( nContextRight - nContextLeft ) + 1 ); } else nBlanksNeeded = nContextBases; // this could happend, for example, if the alignment goes to the // end of the sequence, so nContextLeft and nContextRight are // completely off the consensus (but just off of it) if ( nBlanksNeeded > 0 ) { RWCString soBlanks; soBlanks.appendLotsOfCopies( ' ', nBlanksNeeded ); if ( bComplemented ) soContextOnRight = soBlanks + soContextOnRight; else soContextOnRight = soContextOnRight + soBlanks; } // now put it all together if ( bComplemented ) soAlignment = soContextOnRight + soAlignment + soContextOnLeft; else soAlignment = soContextOnLeft + soAlignment + soContextOnRight; } void compareContigs :: complementContig( const compareContigsTypes eContig1OrContig2 ) { int nNewLeftEdgeConsensusPosition = nGetRightEdgeConsensusPosition( eContig1OrContig2 ); bool bComplemented = false; if ( eContig1OrContig2 == eContig1 ) { bContig1ComplementedWRTAlignedReadsWindow_ = !bContig1ComplementedWRTAlignedReadsWindow_; if ( bContig1ComplementedWRTAlignedReadsWindow_ ) bComplemented = true; } else { bContig2ComplementedWRTAlignedReadsWindow_ = !bContig2ComplementedWRTAlignedReadsWindow_; if ( bContig2ComplementedWRTAlignedReadsWindow_ ) bComplemented = true; } // figure out the new nContig(N)LeftEdgeConsensusPosition_ ( eContig1OrContig2 == eContig1 ? nContig1LeftEdgeConsensusPosition_ : nContig2LeftEdgeConsensusPosition_ ) = nNewLeftEdgeConsensusPosition; pGuiCompareContigs_->setComplementContigButton( eContig1OrContig2 ); int nNewScrollBarPosition = ( bComplemented ? pGetContig( eContig1OrContig2 )->nGetEndConsensusIndex() - nNewLeftEdgeConsensusPosition + 1 : nNewLeftEdgeConsensusPosition ); pGuiCompareContigs_->guiSetScrollBarPos( nNewScrollBarPosition, eGetCompareContigsWindowType( eContig1OrContig2 )); drawScaleAndBases( eContig1OrContig2 ); } int compareContigs :: nScreenCharToConsensusPosition( const compareContigsTypes eContig1OrContig2, const int nScreenChar ) { if ( bIsContigComplemented( eContig1OrContig2 ) ) { return( nGetLeftEdgeConsensusPosition( eContig1OrContig2 ) - nScreenChar ); } else { return( nScreenChar + nGetLeftEdgeConsensusPosition( eContig1OrContig2 ) ); } } int compareContigs :: nGetScrollBarPositionFromLeftEdgeConsensusPosition( const compareContigsTypes eContig1OrContig2, const int nLeftEdgeConsensusPosition ) { if ( bIsContigComplemented( eContig1OrContig2 ) ) { Contig* pContig = pGetContig( eContig1OrContig2 ); assert( pContig ); return( pContig->nGetEndConsensusIndex() - nLeftEdgeConsensusPosition + 1 ); } else { return( nLeftEdgeConsensusPosition ); } } void compareContigs :: prevNextDiscrepancy( const ePrevOrNextType ePrevOrNext ) { // find the cursor int n0LastAlignmentPosition; if ( !curAlignmentWindow_.bIsValid() ) { // find the first discrepancy n0LastAlignmentPosition = -1; } else { n0LastAlignmentPosition = curAlignmentWindow_.nPosition_; } // find discrepancies bool bFoundDiscrepancy = false; int n0FoundDiscrepancy; if ( ePrevOrNext == eNextDiscrepancy ) { // the +1 is so that we don't find the same discrepancy we are already on for( int n0 = n0LastAlignmentPosition + 1; n0 < soAlignmentMiddleLine_.length(); ++n0 ) { if ( soAlignmentMiddleLine_[n0] == 'X' || soAlignmentMiddleLine_[n0] == '*' ) { n0FoundDiscrepancy = n0; bFoundDiscrepancy = true; break; } } } else if ( ePrevOrNext == ePrevDiscrepancy ) { for( int n0 = n0LastAlignmentPosition - 1; n0 >= 0; --n0 ) { if ( soAlignmentMiddleLine_[n0] == 'X' || soAlignmentMiddleLine_[n0] == '*' ) { n0FoundDiscrepancy = n0; bFoundDiscrepancy = true; break; } } } else { assert( false ); } if ( !bFoundDiscrepancy ) { GuiApp::beep(); return; } // if reached here, we found another discrepancy. First put the cursor on it. But it might // not be on the screen, in which case we need to scroll. if ( !bVisibleOnAlignmentWindow( n0FoundDiscrepancy ) ) { // scroll so it is visible pGuiCompareContigs_->programMovesAlignmentWindowScrollBarInCenter( n0FoundDiscrepancy ); } setAlignmentCursorAtAlignmentPos( n0FoundDiscrepancy ); // now scroll both Aligned Reads windows scrollContigWin( eContig1 ); scrollContigWin( eContig2 ); }