import ResultPointCallback from './../../ResultPointCallback' ; import BitMatrix from './../../common/BitMatrix' ; import AlignmentPattern from './AlignmentPattern' ; import Exception from './../../Exception' ; /**
 * <p>This class attempts to find alignment patterns in a QR Code. Alignment patterns look like finder
 * patterns but are smaller and appear at regular intervals throughout the image.</p>
 *
 * <p>At the moment this only looks for the bottom-right alignment pattern.</p>
 *
 * <p>This is mostly a simplified copy of  FinderPatternFinder . It is copied,
 * pasted and stripped down here for maximum performance but does unfortunately duplicate
 * some code.</p>
 *
 * <p>This class is thread-safe but not reentrant. Each thread must allocate its own object.</p>
 *
 *  author Sean Owen
  export default class AlignmentPatternFinder { private possibleCenters : AlignmentPattern [ ] ; private crossCheckStateCount : Int32Array ; param image param startX param startY param width param height param moduleSize public constructor ( private image , private startX , private startY , private width , private height , private moduleSize , private resultPointCallback ) { this . possibleCenters = [ ] ; this . crossCheckStateCount = new Int32Array ( 3 ) ; } return { link throws public find ( ) { const startX = this . startX ; const height = this . height ; const width = this . width ; const maxJ = startX + width ; const middleI = this . startY + ( height / 2 ) ; const stateCount = new Int32Array ( 3 ) ; const image = this . image ; for ( let iGen = 0 ; iGen < height ; iGen ++ ) { const i = middleI + ( ( iGen & 0x01 ) == 0 ? Math . floor ( ( iGen + 1 ) / 2 ) : - Math . floor ( ( iGen + 1 ) / 2 ) ) ; stateCount [ 0 ] = 0 ; stateCount [ 1 ] = 0 ; stateCount [ 2 ] = 0 ; let j = startX ; while ( j < maxJ && ! image . get ( j , i ) ) { j ++ ; } let currentState = 0 ; while ( j < maxJ ) { if ( image . get ( j , i ) ) { if ( currentState === 1 ) { stateCount [ 1 ] ++ ; } else { if ( currentState === 2 ) { if ( this . foundPatternCross ( stateCount ) ) { const confirmed = this . handlePossibleCenter ( stateCount , i , j ) ; if ( confirmed !== null ) { return confirmed ; } } stateCount [ 0 ] = stateCount [ 2 ] ; stateCount [ 1 ] = 1 ; stateCount [ 2 ] = 0 ; currentState = 1 ; } else { stateCount [ ++ currentState ] ++ ; } } } else { if ( currentState === 1 ) { currentState ++ ; } stateCount [ currentState ] ++ ; } j ++ ; } if ( this . foundPatternCross ( stateCount ) ) { const confirmed = this . handlePossibleCenter ( stateCount , i , maxJ ) ; if ( confirmed !== null ) { return confirmed ; } } } if ( this . possibleCenters . length !== 0 ) { return this . possibleCenters [ 0 ] ; } throw new Exception ( Exception . NotFoundException ) ; } /**
     * Given a count of black/white/black pixels just seen and an end position,
     * figures the location of the center of this black/white/black run.
     */ private static centerFromEnd ( stateCount , end ) { return ( end - stateCount [ 2 ] ) - stateCount [ 1 ] / 2.0 ; } param stateCount return private foundPatternCross ( stateCount ) { const moduleSize = this . moduleSize ; const maxVariance = moduleSize / 2.0 ; for ( let i = 0 ; i < 3 ; i ++ ) { if ( Math . abs ( moduleSize - stateCount [ i ] ) >= maxVariance ) { return false ; } } return true ; } param startI param centerJ param maxCount return vertical center of alignment pattern, or  Float if not found
      private crossCheckVertical ( startI , centerJ , maxCount , originalStateCountTotal ) { const image = this . image ; const maxI = image . getHeight ( ) ; const stateCount = this . crossCheckStateCount ; stateCount [ 0 ] = 0 ; stateCount [ 1 ] = 0 ; stateCount [ 2 ] = 0 ; let i = startI ; while ( i >= 0 && image . get ( centerJ , i ) && stateCount [ 1 ] <= maxCount ) { stateCount [ 1 ] ++ ; i -- ; } if ( i < 0 || stateCount [ 1 ] > maxCount ) { return NaN ; } while ( i >= 0 && ! image . get ( centerJ , i ) && stateCount [ 0 ] <= maxCount ) { stateCount [ 0 ] ++ ; i -- ; } if ( stateCount [ 0 ] > maxCount ) { return NaN ; } i = startI + 1 ; while ( i < maxI && image . get ( centerJ , i ) && stateCount [ 1 ] <= maxCount ) { stateCount [ 1 ] ++ ; i ++ ; } if ( i == maxI || stateCount [ 1 ] > maxCount ) { return NaN ; } while ( i < maxI && ! image . get ( centerJ , i ) && stateCount [ 2 ] <= maxCount ) { stateCount [ 2 ] ++ ; i ++ ; } if ( stateCount [ 2 ] > maxCount ) { return NaN ; } const stateCountTotal = stateCount [ 0 ] + stateCount [ 1 ] + stateCount [ 2 ] ; if ( 5 * Math . abs ( stateCountTotal - originalStateCountTotal ) >= 2 * originalStateCountTotal ) { return NaN ; } return this . foundPatternCross ( stateCount ) ? AlignmentPatternFinder . centerFromEnd ( stateCount , i ) : NaN ; } param stateCount param i param j return { link private handlePossibleCenter ( stateCount , i , j ) { const stateCountTotal = stateCount [ 0 ] + stateCount [ 1 ] + stateCount [ 2 ] ; const centerJ = AlignmentPatternFinder . centerFromEnd ( stateCount , j ) ; const centerI = this . crossCheckVertical ( i , centerJ , 2 * stateCount [ 1 ] , stateCountTotal ) ; if ( ! isNaN ( centerI ) ) { const estimatedModuleSize = ( stateCount [ 0 ] + stateCount [ 1 ] + stateCount [ 2 ] ) / 3.0 ; for ( const center of this . possibleCenters ) { if ( center . aboutEquals ( estimatedModuleSize , centerI , centerJ ) ) { return center . combineEstimate ( centerI , centerJ , estimatedModuleSize ) ; } } const point = new AlignmentPattern ( centerJ , centerI , estimatedModuleSize ) ; this . possibleCenters . push ( point ) ; if ( this . resultPointCallback !== null && this . resultPointCallback !== undefined ) { this . resultPointCallback . foundPossibleResultPoint ( point ) ; } } return null ; } }