text: /* The copyright in this software is being made available under the BSD
   * License, included below. This software may be subject to other third party
   * and contributor rights, including patent rights, and no such rights are
   * granted under this license.
   *
   * Copyright (c) 2010-2015, ITU/ISO/IEC
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are met:
   *
   *  * Redistributions of source code must retain the above copyright notice,
   *    this list of conditions and the following disclaimer.
   *  * Redistributions in binary form must reproduce the above copyright notice,
   *    this list of conditions and the following disclaimer in the documentation
   *    and/or other materials provided with the distribution.
   *  * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
   *    be used to endorse or promote products derived from this software without
   *    specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS
   * 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.
   */
  
  /** \file     TComDataCU.cpp
      \brief    CU data structure
      \todo     not all entities are documented
  */
  
  #include "TComDataCU.h"
  #include "TComTU.h"
  #include "TComPic.h"
  
  //! \ingroup TLibCommon
  //! \{
  
  // ====================================================================================================================
  // Constructor / destructor / create / destroy
  // ====================================================================================================================
  
  TComDataCU::TComDataCU()
  {
    m_pcPic              = NULL;
    m_pcSlice            = NULL;
    m_puhDepth           = NULL;
  
    m_skipFlag           = NULL;
  
    m_pePartSize         = NULL;
    m_pePredMode         = NULL;
    m_CUTransquantBypass = NULL;
    m_puhWidth           = NULL;
    m_puhHeight          = NULL;
    m_phQP               = NULL;
    m_ChromaQpAdj        = NULL;
    m_pbMergeFlag        = NULL;
    m_puhMergeIndex      = NULL;
    for(UInt i=0; i<MAX_NUM_CHANNEL_TYPE; i++)
    {
      m_puhIntraDir[i]     = NULL;
    }
    m_puhInterDir        = NULL;
    m_puhTrIdx           = NULL;
  
    for (UInt comp=0; comp<MAX_NUM_COMPONENT; comp++)
    {
      m_puhCbf[comp]                        = NULL;
      m_crossComponentPredictionAlpha[comp] = NULL;
      m_puhTransformSkip[comp]              = NULL;
      m_pcTrCoeff[comp]                     = NULL;
  #if ADAPTIVE_QP_SELECTION
      m_pcArlCoeff[comp]                    = NULL;
  #endif
      m_pcIPCMSample[comp]                  = NULL;
      m_explicitRdpcmMode[comp]             = NULL;
    }
  #if ADAPTIVE_QP_SELECTION
    m_ArlCoeffIsAliasedAllocation = false;
  #endif
    m_pbIPCMFlag         = NULL;
  
    m_pCtuAboveLeft      = NULL;
    m_pCtuAboveRight     = NULL;
    m_pCtuAbove          = NULL;
    m_pCtuLeft           = NULL;
  
    for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
    {
      m_apcCUColocated[i]  = NULL;
      m_apiMVPIdx[i]       = NULL;
      m_apiMVPNum[i]       = NULL;
    }
  
    m_bDecSubCu          = false;
  }
  
  TComDataCU::~TComDataCU()
  {
  }
  
  Void TComDataCU::create( ChromaFormat chromaFormatIDC, UInt uiNumPartition, UInt uiWidth, UInt uiHeight, Bool bDecSubCu, Int unitSize
  #if ADAPTIVE_QP_SELECTION
                          , TCoeff *pParentARLBuffer
  #endif
                          )
  {
    m_bDecSubCu = bDecSubCu;
  
    m_pcPic              = NULL;
    m_pcSlice            = NULL;
    m_uiNumPartition     = uiNumPartition;
    m_unitSize = unitSize;
  
    if ( !bDecSubCu )
    {
      m_phQP               = (Char*     )xMalloc(Char,     uiNumPartition);
      m_puhDepth           = (UChar*    )xMalloc(UChar,    uiNumPartition);
      m_puhWidth           = (UChar*    )xMalloc(UChar,    uiNumPartition);
      m_puhHeight          = (UChar*    )xMalloc(UChar,    uiNumPartition);
  
      m_ChromaQpAdj        = new UChar[ uiNumPartition ];
      m_skipFlag           = new Bool[ uiNumPartition ];
      m_pePartSize         = new Char[ uiNumPartition ];
      memset( m_pePartSize, NUMBER_OF_PART_SIZES,uiNumPartition * sizeof( *m_pePartSize ) );
      m_pePredMode         = new Char[ uiNumPartition ];
      m_CUTransquantBypass = new Bool[ uiNumPartition ];
  
      m_pbMergeFlag        = (Bool*  )xMalloc(Bool,   uiNumPartition);
      m_puhMergeIndex      = (UChar* )xMalloc(UChar,  uiNumPartition);
  
      for (UInt ch=0; ch<MAX_NUM_CHANNEL_TYPE; ch++)
      {
        m_puhIntraDir[ch] = (UChar* )xMalloc(UChar,  uiNumPartition);
      }
      m_puhInterDir        = (UChar* )xMalloc(UChar,  uiNumPartition);
  
      m_puhTrIdx           = (UChar* )xMalloc(UChar,  uiNumPartition);
  
      for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
      {
        const RefPicList rpl=RefPicList(i);
        m_apiMVPIdx[rpl]       = new Char[ uiNumPartition ];
        m_apiMVPNum[rpl]       = new Char[ uiNumPartition ];
        memset( m_apiMVPIdx[rpl], -1,uiNumPartition * sizeof( Char ) );
      }
  
      for (UInt comp=0; comp<MAX_NUM_COMPONENT; comp++)
      {
        const ComponentID compID = ComponentID(comp);
        const UInt chromaShift = getComponentScaleX(compID, chromaFormatIDC) + getComponentScaleY(compID, chromaFormatIDC);
        const UInt totalSize   = (uiWidth * uiHeight) >> chromaShift;
  
        m_crossComponentPredictionAlpha[compID] = (Char*  )xMalloc(Char,   uiNumPartition);
        m_puhTransformSkip[compID]              = (UChar* )xMalloc(UChar,  uiNumPartition);
        m_explicitRdpcmMode[compID]             = (UChar* )xMalloc(UChar,  uiNumPartition);
        m_puhCbf[compID]                        = (UChar* )xMalloc(UChar,  uiNumPartition);
        m_pcTrCoeff[compID]                     = (TCoeff*)xMalloc(TCoeff, totalSize);
        memset( m_pcTrCoeff[compID], 0, (totalSize * sizeof( TCoeff )) );
  
  #if ADAPTIVE_QP_SELECTION
        if( pParentARLBuffer != 0 )
        {
          m_pcArlCoeff[compID] = pParentARLBuffer;
          m_ArlCoeffIsAliasedAllocation = true;
          pParentARLBuffer += totalSize;
        }
        else
        {
          m_pcArlCoeff[compID] = (TCoeff*)xMalloc(TCoeff, totalSize);
          m_ArlCoeffIsAliasedAllocation = false;
        }
  #endif
        m_pcIPCMSample[compID] = (Pel*   )xMalloc(Pel , totalSize);
      }
  
      m_pbIPCMFlag         = (Bool*  )xMalloc(Bool, uiNumPartition);
  
      for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
      {
        m_acCUMvField[i].create( uiNumPartition );
      }
  
    }
    else
    {
      for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
      {
        m_acCUMvField[i].setNumPartition(uiNumPartition );
      }
    }
  
    // create motion vector fields
  
    m_pCtuAboveLeft      = NULL;
    m_pCtuAboveRight     = NULL;
    m_pCtuAbove          = NULL;
    m_pCtuLeft           = NULL;
  
    for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
    {
      m_apcCUColocated[i]  = NULL;
    }
  }
  
  Void TComDataCU::destroy()
  {
    // encoder-side buffer free
    if ( !m_bDecSubCu )
    {
      if ( m_phQP )
      {
        xFree(m_phQP);
        m_phQP = NULL;
      }
      if ( m_puhDepth )
      {
        xFree(m_puhDepth);
        m_puhDepth = NULL;
      }
      if ( m_puhWidth )
      {
        xFree(m_puhWidth);
        m_puhWidth = NULL;
      }
      if ( m_puhHeight )
      {
        xFree(m_puhHeight);
        m_puhHeight = NULL;
      }
  
      if ( m_skipFlag )
      {
        delete[] m_skipFlag;
        m_skipFlag = NULL;
      }
  
      if ( m_pePartSize )
      {
        delete[] m_pePartSize;
        m_pePartSize = NULL;
      }
      if ( m_pePredMode )
      {
        delete[] m_pePredMode;
        m_pePredMode = NULL;
      }
      if ( m_ChromaQpAdj )
      {
        delete[] m_ChromaQpAdj;
        m_ChromaQpAdj = NULL;
      }
      if ( m_CUTransquantBypass )
      {
        delete[] m_CUTransquantBypass;
        m_CUTransquantBypass = NULL;
      }
      if ( m_puhInterDir )
      {
        xFree(m_puhInterDir);
        m_puhInterDir = NULL;
      }
      if ( m_pbMergeFlag )
      {
        xFree(m_pbMergeFlag);
        m_pbMergeFlag = NULL;
      }
      if ( m_puhMergeIndex )
      {
        xFree(m_puhMergeIndex);
        m_puhMergeIndex  = NULL;
      }
  
      for (UInt ch=0; ch<MAX_NUM_CHANNEL_TYPE; ch++)
      {
        xFree(m_puhIntraDir[ch]);
        m_puhIntraDir[ch] = NULL;
      }
  
      if ( m_puhTrIdx )
      {
        xFree(m_puhTrIdx);
        m_puhTrIdx = NULL;
      }
  
      for (UInt comp=0; comp<MAX_NUM_COMPONENT; comp++)
      {
        if ( m_crossComponentPredictionAlpha[comp] )
        {
          xFree(m_crossComponentPredictionAlpha[comp]);
          m_crossComponentPredictionAlpha[comp] = NULL;
        }
        if ( m_puhTransformSkip[comp] )
        {
          xFree(m_puhTransformSkip[comp]);
          m_puhTransformSkip[comp] = NULL;
        }
        if ( m_puhCbf[comp] )
        {
          xFree(m_puhCbf[comp]);
          m_puhCbf[comp] = NULL;
        }
        if ( m_pcTrCoeff[comp] )
        {
          xFree(m_pcTrCoeff[comp]);
          m_pcTrCoeff[comp] = NULL;
        }
        if ( m_explicitRdpcmMode[comp] )
        {
          xFree(m_explicitRdpcmMode[comp]);
          m_explicitRdpcmMode[comp] = NULL;
        }
  
  #if ADAPTIVE_QP_SELECTION
        if (!m_ArlCoeffIsAliasedAllocation)
        {
          if ( m_pcArlCoeff[comp] )
          {
            xFree(m_pcArlCoeff[comp]);
            m_pcArlCoeff[comp] = NULL;
          }
        }
  #endif
  
        if ( m_pcIPCMSample[comp] )
        {
          xFree(m_pcIPCMSample[comp]);
          m_pcIPCMSample[comp] = NULL;
        }
      }
      if ( m_pbIPCMFlag )
      {
        xFree(m_pbIPCMFlag );
        m_pbIPCMFlag = NULL;
      }
  
      for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
      {
        const RefPicList rpl=RefPicList(i);
        if ( m_apiMVPIdx[rpl] )
        {
          delete[] m_apiMVPIdx[rpl];
          m_apiMVPIdx[rpl] = NULL;
        }
        if ( m_apiMVPNum[rpl] )
        {
          delete[] m_apiMVPNum[rpl];
          m_apiMVPNum[rpl] = NULL;
        }
      }
  
      for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
      {
        const RefPicList rpl=RefPicList(i);
        m_acCUMvField[rpl].destroy();
      }
    }
  
    m_pcPic              = NULL;
    m_pcSlice            = NULL;
  
    m_pCtuAboveLeft      = NULL;
    m_pCtuAboveRight     = NULL;
    m_pCtuAbove          = NULL;
    m_pCtuLeft           = NULL;
  
  
    for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
    {
      m_apcCUColocated[i]  = NULL;
    }
  
  }
  
  Bool TComDataCU::CUIsFromSameTile            ( const TComDataCU *pCU /* Can be NULL */) const
  {
    return pCU!=NULL &&
           pCU->getSlice() != NULL &&
           m_pcPic->getPicSym()->getTileIdxMap( pCU->getCtuRsAddr() ) == m_pcPic->getPicSym()->getTileIdxMap(getCtuRsAddr());
  }
  
  Bool TComDataCU::CUIsFromSameSliceAndTile    ( const TComDataCU *pCU /* Can be NULL */) const
  {
    return pCU!=NULL &&
           pCU->getSlice() != NULL &&
           pCU->getSlice()->getSliceCurStartCtuTsAddr() == getSlice()->getSliceCurStartCtuTsAddr() &&
           m_pcPic->getPicSym()->getTileIdxMap( pCU->getCtuRsAddr() ) == m_pcPic->getPicSym()->getTileIdxMap(getCtuRsAddr())
           ;
  }
  
  Bool TComDataCU::CUIsFromSameSliceTileAndWavefrontRow( const TComDataCU *pCU /* Can be NULL */) const
  {
    return CUIsFromSameSliceAndTile(pCU)
           && (!getSlice()->getPPS()->getEntropyCodingSyncEnabledFlag() || getPic()->getCtu(getCtuRsAddr())->getCUPelY() == getPic()->getCtu(pCU->getCtuRsAddr())->getCUPelY());
  }
  
  Bool TComDataCU::isLastSubCUOfCtu(const UInt absPartIdx)
  {
    const TComSPS &sps=*(getSlice()->getSPS());
  
    const UInt picWidth = sps.getPicWidthInLumaSamples();
    const UInt picHeight = sps.getPicHeightInLumaSamples();
    const UInt granularityWidth = sps.getMaxCUWidth();
  
    const UInt cuPosX = getCUPelX() + g_auiRasterToPelX[ g_auiZscanToRaster[absPartIdx] ];
    const UInt cuPosY = getCUPelY() + g_auiRasterToPelY[ g_auiZscanToRaster[absPartIdx] ];
  
    return (((cuPosX+getWidth( absPartIdx))%granularityWidth==0||(cuPosX+getWidth( absPartIdx)==picWidth ))
         && ((cuPosY+getHeight(absPartIdx))%granularityWidth==0||(cuPosY+getHeight(absPartIdx)==picHeight)));
  }
  
  // ====================================================================================================================
  // Public member functions
  // ====================================================================================================================
  
  // --------------------------------------------------------------------------------------------------------------------
  // Initialization
  // --------------------------------------------------------------------------------------------------------------------
  
  /**
   Initialize top-level CU: create internal buffers and set initial values before encoding the CTU.
   
   \param  pcPic       picture (TComPic) class pointer
   \param  ctuRsAddr   CTU address in raster scan order
   */
  Void TComDataCU::initCtu( TComPic* pcPic, UInt ctuRsAddr )
  {
  
    const UInt maxCUWidth = pcPic->getPicSym()->getSPS().getMaxCUWidth();
    const UInt maxCUHeight= pcPic->getPicSym()->getSPS().getMaxCUHeight();
    m_pcPic              = pcPic;
    m_pcSlice            = pcPic->getSlice(pcPic->getCurrSliceIdx());
    m_ctuRsAddr          = ctuRsAddr;
    m_uiCUPelX           = ( ctuRsAddr % pcPic->getFrameWidthInCtus() ) * maxCUWidth;
    m_uiCUPelY           = ( ctuRsAddr / pcPic->getFrameWidthInCtus() ) * maxCUHeight;
    m_absZIdxInCtu       = 0;
    m_dTotalCost         = MAX_DOUBLE;
    m_uiTotalDistortion  = 0;
    m_uiTotalBits        = 0;
    m_uiTotalBins        = 0;
    m_uiNumPartition     = pcPic->getNumPartitionsInCtu();
  
    memset( m_skipFlag          , false,                      m_uiNumPartition * sizeof( *m_skipFlag ) );
  
    memset( m_pePartSize        , NUMBER_OF_PART_SIZES,       m_uiNumPartition * sizeof( *m_pePartSize ) );
    memset( m_pePredMode        , NUMBER_OF_PREDICTION_MODES, m_uiNumPartition * sizeof( *m_pePredMode ) );
    memset( m_CUTransquantBypass, false,                      m_uiNumPartition * sizeof( *m_CUTransquantBypass) );
    memset( m_puhDepth          , 0,                          m_uiNumPartition * sizeof( *m_puhDepth ) );
    memset( m_puhTrIdx          , 0,                          m_uiNumPartition * sizeof( *m_puhTrIdx ) );
    memset( m_puhWidth          , maxCUWidth,                 m_uiNumPartition * sizeof( *m_puhWidth ) );
    memset( m_puhHeight         , maxCUHeight,                m_uiNumPartition * sizeof( *m_puhHeight ) );
    for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
    {
      const RefPicList rpl=RefPicList(i);
      memset( m_apiMVPIdx[rpl]  , -1,                         m_uiNumPartition * sizeof( *m_apiMVPIdx[rpl] ) );
      memset( m_apiMVPNum[rpl]  , -1,                         m_uiNumPartition * sizeof( *m_apiMVPNum[rpl] ) );
    }
    memset( m_phQP              , getSlice()->getSliceQp(),   m_uiNumPartition * sizeof( *m_phQP ) );
    memset( m_ChromaQpAdj       , 0,                          m_uiNumPartition * sizeof( *m_ChromaQpAdj ) );
    for(UInt comp=0; comp<MAX_NUM_COMPONENT; comp++)
    {
      memset( m_crossComponentPredictionAlpha[comp] , 0,                     m_uiNumPartition * sizeof( *m_crossComponentPredictionAlpha[comp] ) );
      memset( m_puhTransformSkip[comp]              , 0,                     m_uiNumPartition * sizeof( *m_puhTransformSkip[comp]) );
      memset( m_puhCbf[comp]                        , 0,                     m_uiNumPartition * sizeof( *m_puhCbf[comp] ) );
      memset( m_explicitRdpcmMode[comp]             , NUMBER_OF_RDPCM_MODES, m_uiNumPartition * sizeof( *m_explicitRdpcmMode[comp] ) );
    }
    memset( m_pbMergeFlag       , false,                    m_uiNumPartition * sizeof( *m_pbMergeFlag ) );
    memset( m_puhMergeIndex     , 0,                        m_uiNumPartition * sizeof( *m_puhMergeIndex ) );
    for (UInt ch=0; ch<MAX_NUM_CHANNEL_TYPE; ch++)
    {
      memset( m_puhIntraDir[ch] , ((ch==0) ? DC_IDX : 0),   m_uiNumPartition * sizeof( *(m_puhIntraDir[ch]) ) );
    }
    memset( m_puhInterDir       , 0,                        m_uiNumPartition * sizeof( *m_puhInterDir ) );
    memset( m_pbIPCMFlag        , false,                    m_uiNumPartition * sizeof( *m_pbIPCMFlag ) );
  
    const UInt numCoeffY    = maxCUWidth*maxCUHeight;
    for (UInt comp=0; comp<MAX_NUM_COMPONENT; comp++)
    {
      const UInt componentShift = m_pcPic->getComponentScaleX(ComponentID(comp)) + m_pcPic->getComponentScaleY(ComponentID(comp));
      memset( m_pcTrCoeff[comp], 0, sizeof(TCoeff)* numCoeffY>>componentShift );
  #if ADAPTIVE_QP_SELECTION
      memset( m_pcArlCoeff[comp], 0, sizeof(TCoeff)* numCoeffY>>componentShift );
  #endif
    }
  
    for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
    {
      m_acCUMvField[i].clearMvField();
    }
  
    // Setting neighbor CU
    m_pCtuLeft        = NULL;
    m_pCtuAbove       = NULL;
    m_pCtuAboveLeft   = NULL;
    m_pCtuAboveRight  = NULL;
  
  
    for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
    {
      m_apcCUColocated[i]  = NULL;
    }
  
    UInt frameWidthInCtus = pcPic->getFrameWidthInCtus();
    if ( m_ctuRsAddr % frameWidthInCtus )
    {
      m_pCtuLeft = pcPic->getCtu( m_ctuRsAddr - 1 );
    }
  
    if ( m_ctuRsAddr / frameWidthInCtus )
    {
      m_pCtuAbove = pcPic->getCtu( m_ctuRsAddr - frameWidthInCtus );
    }
  
    if ( m_pCtuLeft && m_pCtuAbove )
    {
      m_pCtuAboveLeft = pcPic->getCtu( m_ctuRsAddr - frameWidthInCtus - 1 );
    }
  
    if ( m_pCtuAbove && ( (m_ctuRsAddr%frameWidthInCtus) < (frameWidthInCtus-1) )  )
    {
      m_pCtuAboveRight = pcPic->getCtu( m_ctuRsAddr - frameWidthInCtus + 1 );
    }
  
    for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
    {
      const RefPicList rpl=RefPicList(i);
      if ( getSlice()->getNumRefIdx( rpl ) > 0 )
      {
        m_apcCUColocated[rpl] = getSlice()->getRefPic( rpl, 0)->getCtu( m_ctuRsAddr );
      }
    }
  }
  
  
  /** Initialize prediction data with enabling sub-CTU-level delta QP.
  *   - set CU width and CU height according to depth
  *   - set qp value according to input qp
  *   - set last-coded qp value according to input last-coded qp
  *
  * \param  uiDepth            depth of the current CU
  * \param  qp                 qp for the current CU
  * \param  bTransquantBypass  true for transquant bypass
  */
  Void TComDataCU::initEstData( const UInt uiDepth, const Int qp, const Bool bTransquantBypass )
  {
    m_dTotalCost         = MAX_DOUBLE;
    m_uiTotalDistortion  = 0;
    m_uiTotalBits        = 0;
    m_uiTotalBins        = 0;
  
    const UChar uhWidth  = getSlice()->getSPS()->getMaxCUWidth()  >> uiDepth;
    const UChar uhHeight = getSlice()->getSPS()->getMaxCUHeight() >> uiDepth;
  
    for (UInt ui = 0; ui < m_uiNumPartition; ui++)
    {
      for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
      {
        const RefPicList rpl=RefPicList(i);
        m_apiMVPIdx[rpl][ui]  = -1;
        m_apiMVPNum[rpl][ui]  = -1;
      }
      m_puhDepth  [ui]    = uiDepth;
      m_puhWidth  [ui]    = uhWidth;
      m_puhHeight [ui]    = uhHeight;
      m_puhTrIdx  [ui]    = 0;
      for(UInt comp=0; comp<MAX_NUM_COMPONENT; comp++)
      {
        m_crossComponentPredictionAlpha[comp][ui] = 0;
        m_puhTransformSkip             [comp][ui] = 0;
        m_explicitRdpcmMode            [comp][ui] = NUMBER_OF_RDPCM_MODES;
      }
      m_skipFlag[ui]      = false;
      m_pePartSize[ui]    = NUMBER_OF_PART_SIZES;
      m_pePredMode[ui]    = NUMBER_OF_PREDICTION_MODES;
      m_CUTransquantBypass[ui] = bTransquantBypass;
      m_pbIPCMFlag[ui]    = 0;
      m_phQP[ui]          = qp;
      m_ChromaQpAdj[ui]   = 0;
      m_pbMergeFlag[ui]   = 0;
      m_puhMergeIndex[ui] = 0;
  
      for (UInt ch=0; ch<MAX_NUM_CHANNEL_TYPE; ch++)
      {
        m_puhIntraDir[ch][ui] = ((ch==0) ? DC_IDX : 0);
      }
  
      m_puhInterDir[ui] = 0;
      for (UInt comp=0; comp<MAX_NUM_COMPONENT; comp++)
      {
        m_puhCbf[comp][ui] = 0;
      }
    }
  
    for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
    {
      m_acCUMvField[i].clearMvField();
    }
  
    const UInt numCoeffY = uhWidth*uhHeight;
  
    for (UInt comp=0; comp<MAX_NUM_COMPONENT; comp++)
    {
      const ComponentID component = ComponentID(comp);
      const UInt numCoeff = numCoeffY >> (getPic()->getComponentScaleX(component) + getPic()->getComponentScaleY(component));
      memset( m_pcTrCoeff[comp],    0, numCoeff * sizeof( TCoeff ) );
  #if ADAPTIVE_QP_SELECTION
      memset( m_pcArlCoeff[comp],   0, numCoeff * sizeof( TCoeff ) );
  #endif
      memset( m_pcIPCMSample[comp], 0, numCoeff * sizeof( Pel) );
    }
  }
  
  
  // initialize Sub partition
  Void TComDataCU::initSubCU( TComDataCU* pcCU, UInt uiPartUnitIdx, UInt uiDepth, Int qp )
  {
    assert( uiPartUnitIdx<4 );
  
    UInt uiPartOffset = ( pcCU->getTotalNumPart()>>2 )*uiPartUnitIdx;
  
    m_pcPic              = pcCU->getPic();
    m_pcSlice            = pcCU->getSlice();
    m_ctuRsAddr          = pcCU->getCtuRsAddr();
    m_absZIdxInCtu       = pcCU->getZorderIdxInCtu() + uiPartOffset;
  
    const UChar uhWidth  = getSlice()->getSPS()->getMaxCUWidth()  >> uiDepth;
    const UChar uhHeight = getSlice()->getSPS()->getMaxCUHeight() >> uiDepth;
  
    m_uiCUPelX           = pcCU->getCUPelX() + ( uhWidth )*( uiPartUnitIdx &  1 );
    m_uiCUPelY           = pcCU->getCUPelY() + ( uhHeight)*( uiPartUnitIdx >> 1 );
  
    m_dTotalCost         = MAX_DOUBLE;
    m_uiTotalDistortion  = 0;
    m_uiTotalBits        = 0;
    m_uiTotalBins        = 0;
    m_uiNumPartition     = pcCU->getTotalNumPart() >> 2;
  
    Int iSizeInUchar = sizeof( UChar  ) * m_uiNumPartition;
    Int iSizeInBool  = sizeof( Bool   ) * m_uiNumPartition;
    Int sizeInChar = sizeof( Char  ) * m_uiNumPartition;
  
    memset( m_phQP,              qp,  sizeInChar );
    memset( m_pbMergeFlag,        0, iSizeInBool  );
    memset( m_puhMergeIndex,      0, iSizeInUchar );
    for (UInt ch=0; ch<MAX_NUM_CHANNEL_TYPE; ch++)
    {
      memset( m_puhIntraDir[ch],  ((ch==0) ? DC_IDX : 0), iSizeInUchar );
    }
  
    memset( m_puhInterDir,        0, iSizeInUchar );
    memset( m_puhTrIdx,           0, iSizeInUchar );
  
    for(UInt comp=0; comp<MAX_NUM_COMPONENT; comp++)
    {
      memset( m_crossComponentPredictionAlpha[comp], 0, iSizeInUchar );
      memset( m_puhTransformSkip[comp],              0, iSizeInUchar );
      memset( m_puhCbf[comp],                        0, iSizeInUchar );
      memset( m_explicitRdpcmMode[comp],             NUMBER_OF_RDPCM_MODES, iSizeInUchar );
    }
  
    memset( m_puhDepth,     uiDepth, iSizeInUchar );
    memset( m_puhWidth,          uhWidth,  iSizeInUchar );
    memset( m_puhHeight,         uhHeight, iSizeInUchar );
    memset( m_pbIPCMFlag,        0, iSizeInBool  );
    for (UInt ui = 0; ui < m_uiNumPartition; ui++)
    {
      m_skipFlag[ui]   = false;
      m_pePartSize[ui] = NUMBER_OF_PART_SIZES;
      m_pePredMode[ui] = NUMBER_OF_PREDICTION_MODES;
      m_CUTransquantBypass[ui] = false;
      m_ChromaQpAdj[ui] = 0;
  
      for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
      {
        const RefPicList rpl=RefPicList(i);
        m_apiMVPIdx[rpl][ui] = -1;
        m_apiMVPNum[rpl][ui] = -1;
      }
    }
  
    const UInt numCoeffY    = uhWidth*uhHeight;
    for (UInt ch=0; ch<MAX_NUM_COMPONENT; ch++)
    {
      const UInt componentShift = m_pcPic->getComponentScaleX(ComponentID(ch)) + m_pcPic->getComponentScaleY(ComponentID(ch));
      memset( m_pcTrCoeff[ch],  0, sizeof(TCoeff)*(numCoeffY>>componentShift) );
  #if ADAPTIVE_QP_SELECTION
      memset( m_pcArlCoeff[ch], 0, sizeof(TCoeff)*(numCoeffY>>componentShift) );
  #endif
      memset( m_pcIPCMSample[ch], 0, sizeof(Pel)* (numCoeffY>>componentShift) );
    }
  
    for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
    {
      m_acCUMvField[i].clearMvField();
    }
  
    m_pCtuLeft        = pcCU->getCtuLeft();
    m_pCtuAbove       = pcCU->getCtuAbove();
    m_pCtuAboveLeft   = pcCU->getCtuAboveLeft();
    m_pCtuAboveRight  = pcCU->getCtuAboveRight();
  
    for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
    {
      m_apcCUColocated[i] = pcCU->getCUColocated(RefPicList(i));
    }
  }
  
  Void TComDataCU::setOutsideCUPart( UInt uiAbsPartIdx, UInt uiDepth )
  {
    const UInt     uiNumPartition = m_uiNumPartition >> (uiDepth << 1);
    const UInt     uiSizeInUchar  = sizeof( UChar  ) * uiNumPartition;
    const TComSPS &sps            = *(getSlice()->getSPS());
    const UChar    uhWidth        = sps.getMaxCUWidth()  >> uiDepth;
    const UChar    uhHeight       = sps.getMaxCUHeight() >> uiDepth;
    memset( m_puhDepth    + uiAbsPartIdx,     uiDepth,  uiSizeInUchar );
    memset( m_puhWidth    + uiAbsPartIdx,     uhWidth,  uiSizeInUchar );
    memset( m_puhHeight   + uiAbsPartIdx,     uhHeight, uiSizeInUchar );
  }
  
  // --------------------------------------------------------------------------------------------------------------------
  // Copy
  // --------------------------------------------------------------------------------------------------------------------
  
  Void TComDataCU::copySubCU( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth )
  {
    UInt uiPart = uiAbsPartIdx;
  
    m_pcPic              = pcCU->getPic();
    m_pcSlice            = pcCU->getSlice();
    m_ctuRsAddr          = pcCU->getCtuRsAddr();
    m_absZIdxInCtu       = uiAbsPartIdx;
  
    m_uiCUPelX           = pcCU->getCUPelX() + g_auiRasterToPelX[ g_auiZscanToRaster[uiAbsPartIdx] ];
    m_uiCUPelY           = pcCU->getCUPelY() + g_auiRasterToPelY[ g_auiZscanToRaster[uiAbsPartIdx] ];
  
    m_skipFlag=pcCU->getSkipFlag()          + uiPart;
  
    m_phQP=pcCU->getQP()                    + uiPart;
    m_ChromaQpAdj = pcCU->getChromaQpAdj()  + uiPart;
    m_pePartSize = pcCU->getPartitionSize() + uiPart;
    m_pePredMode=pcCU->getPredictionMode()  + uiPart;
    m_CUTransquantBypass  = pcCU->getCUTransquantBypass()+uiPart;
  
    m_pbMergeFlag         = pcCU->getMergeFlag()        + uiPart;
    m_puhMergeIndex       = pcCU->getMergeIndex()       + uiPart;
  
    for (UInt ch=0; ch<MAX_NUM_CHANNEL_TYPE; ch++)
    {
      m_puhIntraDir[ch]   = pcCU->getIntraDir(ChannelType(ch)) + uiPart;
    }
  
    m_puhInterDir         = pcCU->getInterDir()         + uiPart;
    m_puhTrIdx            = pcCU->getTransformIdx()     + uiPart;
  
    for(UInt comp=0; comp<MAX_NUM_COMPONENT; comp++)
    {
      m_crossComponentPredictionAlpha[comp] = pcCU->getCrossComponentPredictionAlpha(ComponentID(comp)) + uiPart;
      m_puhTransformSkip[comp]              = pcCU->getTransformSkip(ComponentID(comp))                 + uiPart;
      m_puhCbf[comp]                        = pcCU->getCbf(ComponentID(comp))                           + uiPart;
      m_explicitRdpcmMode[comp]             = pcCU->getExplicitRdpcmMode(ComponentID(comp))             + uiPart;
    }
  
    m_puhDepth=pcCU->getDepth()                     + uiPart;
    m_puhWidth=pcCU->getWidth()                     + uiPart;
    m_puhHeight=pcCU->getHeight()                   + uiPart;
  
    m_pbIPCMFlag         = pcCU->getIPCMFlag()        + uiPart;
  
    m_pCtuAboveLeft      = pcCU->getCtuAboveLeft();
    m_pCtuAboveRight     = pcCU->getCtuAboveRight();
    m_pCtuAbove          = pcCU->getCtuAbove();
    m_pCtuLeft           = pcCU->getCtuLeft();
  
    for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
    {
      const RefPicList rpl=RefPicList(i);
      m_apcCUColocated[rpl] = pcCU->getCUColocated(rpl);
      m_apiMVPIdx[rpl]=pcCU->getMVPIdx(rpl)  + uiPart;
      m_apiMVPNum[rpl]=pcCU->getMVPNum(rpl)  + uiPart;
    }
  
    for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
    {
      const RefPicList rpl=RefPicList(i);
      m_acCUMvField[rpl].linkToWithOffset( pcCU->getCUMvField(rpl), uiPart );
    }
  
    UInt uiMaxCuWidth=pcCU->getSlice()->getSPS()->getMaxCUWidth();
    UInt uiMaxCuHeight=pcCU->getSlice()->getSPS()->getMaxCUHeight();
  
    UInt uiCoffOffset = uiMaxCuWidth*uiMaxCuHeight*uiAbsPartIdx/pcCU->getPic()->getNumPartitionsInCtu();
  
    for (UInt ch=0; ch<MAX_NUM_COMPONENT; ch++)
    {
      const ComponentID component = ComponentID(ch);
      const UInt componentShift   = m_pcPic->getComponentScaleX(component) + m_pcPic->getComponentScaleY(component);
      const UInt offset           = uiCoffOffset >> componentShift;
      m_pcTrCoeff[ch] = pcCU->getCoeff(component) + offset;
  #if ADAPTIVE_QP_SELECTION
      m_pcArlCoeff[ch] = pcCU->getArlCoeff(component) + offset;
  #endif
      m_pcIPCMSample[ch] = pcCU->getPCMSample(component) + offset;
    }
  }
  
  // Copy inter prediction info from the biggest CU
  Void TComDataCU::copyInterPredInfoFrom    ( TComDataCU* pcCU, UInt uiAbsPartIdx, RefPicList eRefPicList )
  {
    m_pcPic              = pcCU->getPic();
    m_pcSlice            = pcCU->getSlice();
    m_ctuRsAddr          = pcCU->getCtuRsAddr();
    m_absZIdxInCtu       = uiAbsPartIdx;
  
    Int iRastPartIdx     = g_auiZscanToRaster[uiAbsPartIdx];
    m_uiCUPelX           = pcCU->getCUPelX() + m_pcPic->getMinCUWidth ()*( iRastPartIdx % m_pcPic->getNumPartInCtuWidth() );
    m_uiCUPelY           = pcCU->getCUPelY() + m_pcPic->getMinCUHeight()*( iRastPartIdx / m_pcPic->getNumPartInCtuWidth() );
  
    m_pCtuAboveLeft      = pcCU->getCtuAboveLeft();
    m_pCtuAboveRight     = pcCU->getCtuAboveRight();
    m_pCtuAbove          = pcCU->getCtuAbove();
    m_pCtuLeft           = pcCU->getCtuLeft();
  
    for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
    {
      m_apcCUColocated[i]  = pcCU->getCUColocated(RefPicList(i));
    }
  
    m_skipFlag           = pcCU->getSkipFlag ()             + uiAbsPartIdx;
  
    m_pePartSize         = pcCU->getPartitionSize ()        + uiAbsPartIdx;
    m_pePredMode         = pcCU->getPredictionMode()        + uiAbsPartIdx;
    m_ChromaQpAdj        = pcCU->getChromaQpAdj()           + uiAbsPartIdx;
    m_CUTransquantBypass = pcCU->getCUTransquantBypass()    + uiAbsPartIdx;
    m_puhInterDir        = pcCU->getInterDir      ()        + uiAbsPartIdx;
  
    m_puhDepth           = pcCU->getDepth ()                + uiAbsPartIdx;
    m_puhWidth           = pcCU->getWidth ()                + uiAbsPartIdx;
    m_puhHeight          = pcCU->getHeight()                + uiAbsPartIdx;
  
    m_pbMergeFlag        = pcCU->getMergeFlag()             + uiAbsPartIdx;
    m_puhMergeIndex      = pcCU->getMergeIndex()            + uiAbsPartIdx;
  
    m_apiMVPIdx[eRefPicList] = pcCU->getMVPIdx(eRefPicList) + uiAbsPartIdx;
    m_apiMVPNum[eRefPicList] = pcCU->getMVPNum(eRefPicList) + uiAbsPartIdx;
  
    m_acCUMvField[ eRefPicList ].linkToWithOffset( pcCU->getCUMvField(eRefPicList), uiAbsPartIdx );
  }
  
  // Copy small CU to bigger CU.
  // One of quarter parts overwritten by predicted sub part.
  Void TComDataCU::copyPartFrom( TComDataCU* pcCU, UInt uiPartUnitIdx, UInt uiDepth )
  {
    assert( uiPartUnitIdx<4 );
  
    m_dTotalCost         += pcCU->getTotalCost();
    m_uiTotalDistortion  += pcCU->getTotalDistortion();
    m_uiTotalBits        += pcCU->getTotalBits();
  
    UInt uiOffset         = pcCU->getTotalNumPart()*uiPartUnitIdx;
    const UInt numValidComp=pcCU->getPic()->getNumberValidComponents();
    const UInt numValidChan=pcCU->getPic()->getChromaFormat()==CHROMA_400 ? 1:2;
  
    UInt uiNumPartition = pcCU->getTotalNumPart();
    Int iSizeInUchar  = sizeof( UChar ) * uiNumPartition;
    Int iSizeInBool   = sizeof( Bool  ) * uiNumPartition;
  
    Int sizeInChar  = sizeof( Char ) * uiNumPartition;
    memcpy( m_skipFlag   + uiOffset, pcCU->getSkipFlag(),       sizeof( *m_skipFlag )   * uiNumPartition );
    memcpy( m_phQP       + uiOffset, pcCU->getQP(),             sizeInChar                        );
    memcpy( m_pePartSize + uiOffset, pcCU->getPartitionSize(),  sizeof( *m_pePartSize ) * uiNumPartition );
    memcpy( m_pePredMode + uiOffset, pcCU->getPredictionMode(), sizeof( *m_pePredMode ) * uiNumPartition );
    memcpy( m_ChromaQpAdj + uiOffset, pcCU->getChromaQpAdj(),   sizeof( *m_ChromaQpAdj ) * uiNumPartition );
    memcpy( m_CUTransquantBypass + uiOffset, pcCU->getCUTransquantBypass(), sizeof( *m_CUTransquantBypass ) * uiNumPartition );
    memcpy( m_pbMergeFlag         + uiOffset, pcCU->getMergeFlag(),         iSizeInBool  );
    memcpy( m_puhMergeIndex       + uiOffset, pcCU->getMergeIndex(),        iSizeInUchar );
  
    for (UInt ch=0; ch<numValidChan; ch++)
    {
      memcpy( m_puhIntraDir[ch]   + uiOffset, pcCU->getIntraDir(ChannelType(ch)), iSizeInUchar );
    }
  
    memcpy( m_puhInterDir         + uiOffset, pcCU->getInterDir(),          iSizeInUchar );
    memcpy( m_puhTrIdx            + uiOffset, pcCU->getTransformIdx(),      iSizeInUchar );
  
    for(UInt comp=0; comp<numValidComp; comp++)
    {
      memcpy( m_crossComponentPredictionAlpha[comp] + uiOffset, pcCU->getCrossComponentPredictionAlpha(ComponentID(comp)), iSizeInUchar );
      memcpy( m_puhTransformSkip[comp]              + uiOffset, pcCU->getTransformSkip(ComponentID(comp))                , iSizeInUchar );
      memcpy( m_puhCbf[comp]                        + uiOffset, pcCU->getCbf(ComponentID(comp))                          , iSizeInUchar );
      memcpy( m_explicitRdpcmMode[comp]             + uiOffset, pcCU->getExplicitRdpcmMode(ComponentID(comp))            , iSizeInUchar );
    }
  
    memcpy( m_puhDepth  + uiOffset, pcCU->getDepth(),  iSizeInUchar );
    memcpy( m_puhWidth  + uiOffset, pcCU->getWidth(),  iSizeInUchar );
    memcpy( m_puhHeight + uiOffset, pcCU->getHeight(), iSizeInUchar );
  
    memcpy( m_pbIPCMFlag + uiOffset, pcCU->getIPCMFlag(), iSizeInBool );
  
    m_pCtuAboveLeft      = pcCU->getCtuAboveLeft();
    m_pCtuAboveRight     = pcCU->getCtuAboveRight();
    m_pCtuAbove          = pcCU->getCtuAbove();
    m_pCtuLeft           = pcCU->getCtuLeft();
  
    for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
    {
      const RefPicList rpl=RefPicList(i);
      memcpy( m_apiMVPIdx[rpl] + uiOffset, pcCU->getMVPIdx(rpl), iSizeInUchar );
      memcpy( m_apiMVPNum[rpl] + uiOffset, pcCU->getMVPNum(rpl), iSizeInUchar );
      m_apcCUColocated[rpl] = pcCU->getCUColocated(rpl);
    }
  
    for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
    {
      const RefPicList rpl=RefPicList(i);
      m_acCUMvField[rpl].copyFrom( pcCU->getCUMvField( rpl ), pcCU->getTotalNumPart(), uiOffset );
    }
  
    const UInt numCoeffY = (pcCU->getSlice()->getSPS()->getMaxCUWidth()*pcCU->getSlice()->getSPS()->getMaxCUHeight()) >> (uiDepth<<1);
    const UInt offsetY   = uiPartUnitIdx*numCoeffY;
    for (UInt ch=0; ch<numValidComp; ch++)
    {
      const ComponentID component = ComponentID(ch);
      const UInt componentShift   = m_pcPic->getComponentScaleX(component) + m_pcPic->getComponentScaleY(component);
      const UInt offset           = offsetY>>componentShift;
      memcpy( m_pcTrCoeff [ch] + offset, pcCU->getCoeff(component),    sizeof(TCoeff)*(numCoeffY>>componentShift) );
  #if ADAPTIVE_QP_SELECTION
      memcpy( m_pcArlCoeff[ch] + offset, pcCU->getArlCoeff(component), sizeof(TCoeff)*(numCoeffY>>componentShift) );
  #endif
      memcpy( m_pcIPCMSample[ch] + offset, pcCU->getPCMSample(component), sizeof(Pel)*(numCoeffY>>componentShift) );
    }
  
    m_uiTotalBins += pcCU->getTotalBins();
  }
  
  // Copy current predicted part to a CU in picture.
  // It is used to predict for next part
  Void TComDataCU::copyToPic( UChar uhDepth )
  {
    TComDataCU* pCtu = m_pcPic->getCtu( m_ctuRsAddr );
    const UInt numValidComp=pCtu->getPic()->getNumberValidComponents();
    const UInt numValidChan=pCtu->getPic()->getChromaFormat()==CHROMA_400 ? 1:2;
  
    pCtu->getTotalCost()       = m_dTotalCost;
    pCtu->getTotalDistortion() = m_uiTotalDistortion;
    pCtu->getTotalBits()       = m_uiTotalBits;
  
    Int iSizeInUchar  = sizeof( UChar ) * m_uiNumPartition;
    Int iSizeInBool   = sizeof( Bool  ) * m_uiNumPartition;
    Int sizeInChar  = sizeof( Char ) * m_uiNumPartition;
  
    memcpy( pCtu->getSkipFlag() + m_absZIdxInCtu, m_skipFlag, sizeof( *m_skipFlag ) * m_uiNumPartition );
  
    memcpy( pCtu->getQP() + m_absZIdxInCtu, m_phQP, sizeInChar  );
  
    memcpy( pCtu->getPartitionSize()  + m_absZIdxInCtu, m_pePartSize, sizeof( *m_pePartSize ) * m_uiNumPartition );
    memcpy( pCtu->getPredictionMode() + m_absZIdxInCtu, m_pePredMode, sizeof( *m_pePredMode ) * m_uiNumPartition );
    memcpy( pCtu->getChromaQpAdj() + m_absZIdxInCtu, m_ChromaQpAdj, sizeof( *m_ChromaQpAdj ) * m_uiNumPartition );
    memcpy( pCtu->getCUTransquantBypass()+ m_absZIdxInCtu, m_CUTransquantBypass, sizeof( *m_CUTransquantBypass ) * m_uiNumPartition );
    memcpy( pCtu->getMergeFlag()         + m_absZIdxInCtu, m_pbMergeFlag,         iSizeInBool  );
    memcpy( pCtu->getMergeIndex()        + m_absZIdxInCtu, m_puhMergeIndex,       iSizeInUchar );
    for (UInt ch=0; ch<numValidChan; ch++)
    {
      memcpy( pCtu->getIntraDir(ChannelType(ch)) + m_absZIdxInCtu, m_puhIntraDir[ch], iSizeInUchar);
    }
  
    memcpy( pCtu->getInterDir()          + m_absZIdxInCtu, m_puhInterDir,         iSizeInUchar );
    memcpy( pCtu->getTransformIdx()      + m_absZIdxInCtu, m_puhTrIdx,            iSizeInUchar );
  
    for(UInt comp=0; comp<numValidComp; comp++)
    {
      memcpy( pCtu->getCrossComponentPredictionAlpha(ComponentID(comp)) + m_absZIdxInCtu, m_crossComponentPredictionAlpha[comp], iSizeInUchar );
      memcpy( pCtu->getTransformSkip(ComponentID(comp))                 + m_absZIdxInCtu, m_puhTransformSkip[comp],              iSizeInUchar );
      memcpy( pCtu->getCbf(ComponentID(comp))                           + m_absZIdxInCtu, m_puhCbf[comp],                        iSizeInUchar );
      memcpy( pCtu->getExplicitRdpcmMode(ComponentID(comp))             + m_absZIdxInCtu, m_explicitRdpcmMode[comp],             iSizeInUchar );
    }
  
    memcpy( pCtu->getDepth()  + m_absZIdxInCtu, m_puhDepth,  iSizeInUchar );
    memcpy( pCtu->getWidth()  + m_absZIdxInCtu, m_puhWidth,  iSizeInUchar );
    memcpy( pCtu->getHeight() + m_absZIdxInCtu, m_puhHeight, iSizeInUchar );
  
    for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
    {
      const RefPicList rpl=RefPicList(i);
      memcpy( pCtu->getMVPIdx(rpl) + m_absZIdxInCtu, m_apiMVPIdx[rpl], iSizeInUchar );
      memcpy( pCtu->getMVPNum(rpl) + m_absZIdxInCtu, m_apiMVPNum[rpl], iSizeInUchar );
    }
  
    for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
    {
      const RefPicList rpl=RefPicList(i);
      m_acCUMvField[rpl].copyTo( pCtu->getCUMvField( rpl ), m_absZIdxInCtu );
    }
  
    memcpy( pCtu->getIPCMFlag() + m_absZIdxInCtu, m_pbIPCMFlag,         iSizeInBool  );
  
    const UInt numCoeffY    = (pCtu->getSlice()->getSPS()->getMaxCUWidth()*pCtu->getSlice()->getSPS()->getMaxCUHeight())>>(uhDepth<<1);
    const UInt offsetY      = m_absZIdxInCtu*m_pcPic->getMinCUWidth()*m_pcPic->getMinCUHeight();
    for (UInt comp=0; comp<numValidComp; comp++)
    {
      const ComponentID component = ComponentID(comp);
      const UInt componentShift   = m_pcPic->getComponentScaleX(component) + m_pcPic->getComponentScaleY(component);
      memcpy( pCtu->getCoeff(component)   + (offsetY>>componentShift), m_pcTrCoeff[component], sizeof(TCoeff)*(numCoeffY>>componentShift) );
  #if ADAPTIVE_QP_SELECTION
      memcpy( pCtu->getArlCoeff(component) + (offsetY>>componentShift), m_pcArlCoeff[component], sizeof(TCoeff)*(numCoeffY>>componentShift) );
  #endif
      memcpy( pCtu->getPCMSample(component) + (offsetY>>componentShift), m_pcIPCMSample[component], sizeof(Pel)*(numCoeffY>>componentShift) );
    }
  
    pCtu->getTotalBins() = m_uiTotalBins;
  }
  
  // --------------------------------------------------------------------------------------------------------------------
  // Other public functions
  // --------------------------------------------------------------------------------------------------------------------
  
  TComDataCU* TComDataCU::getPULeft( UInt& uiLPartUnitIdx,
                                     UInt uiCurrPartUnitIdx,
                                     Bool bEnforceSliceRestriction,
                                     Bool bEnforceTileRestriction )
  {
    UInt uiAbsPartIdx       = g_auiZscanToRaster[uiCurrPartUnitIdx];
    UInt uiAbsZorderCUIdx   = g_auiZscanToRaster[m_absZIdxInCtu];
    const UInt numPartInCtuWidth = m_pcPic->getNumPartInCtuWidth();
  
    if ( !RasterAddress::isZeroCol( uiAbsPartIdx, numPartInCtuWidth ) )
    {
      uiLPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdx - 1 ];
      if ( RasterAddress::isEqualCol( uiAbsPartIdx, uiAbsZorderCUIdx, numPartInCtuWidth ) )
      {
        return m_pcPic->getCtu( getCtuRsAddr() );
      }
      else
      {
        uiLPartUnitIdx -= m_absZIdxInCtu;
        return this;
      }
    }
  
    uiLPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdx + numPartInCtuWidth - 1 ];
    if ( (bEnforceSliceRestriction && !CUIsFromSameSlice(m_pCtuLeft)) || (bEnforceTileRestriction && !CUIsFromSameTile(m_pCtuLeft)) )
    {
      return NULL;
    }
    return m_pCtuLeft;
  }
  
  
  TComDataCU* TComDataCU::getPUAbove( UInt& uiAPartUnitIdx,
                                      UInt uiCurrPartUnitIdx,
                                      Bool bEnforceSliceRestriction,
                                      Bool planarAtCtuBoundary,
                                      Bool bEnforceTileRestriction )
  {
    UInt uiAbsPartIdx       = g_auiZscanToRaster[uiCurrPartUnitIdx];
    UInt uiAbsZorderCUIdx   = g_auiZscanToRaster[m_absZIdxInCtu];
    const UInt numPartInCtuWidth = m_pcPic->getNumPartInCtuWidth();
  
    if ( !RasterAddress::isZeroRow( uiAbsPartIdx, numPartInCtuWidth ) )
    {
      uiAPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdx - numPartInCtuWidth ];
      if ( RasterAddress::isEqualRow( uiAbsPartIdx, uiAbsZorderCUIdx, numPartInCtuWidth ) )
      {
        return m_pcPic->getCtu( getCtuRsAddr() );
      }
      else
      {
        uiAPartUnitIdx -= m_absZIdxInCtu;
        return this;
      }
    }
  
    if(planarAtCtuBoundary)
    {
      return NULL;
    }
  
    uiAPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdx + m_pcPic->getNumPartitionsInCtu() - numPartInCtuWidth ];
  
    if ( (bEnforceSliceRestriction && !CUIsFromSameSlice(m_pCtuAbove)) || (bEnforceTileRestriction && !CUIsFromSameTile(m_pCtuAbove)) )
    {
      return NULL;
    }
    return m_pCtuAbove;
  }
  
  TComDataCU* TComDataCU::getPUAboveLeft( UInt& uiALPartUnitIdx, UInt uiCurrPartUnitIdx, Bool bEnforceSliceRestriction )
  {
    UInt uiAbsPartIdx       = g_auiZscanToRaster[uiCurrPartUnitIdx];
    UInt uiAbsZorderCUIdx   = g_auiZscanToRaster[m_absZIdxInCtu];
    const UInt numPartInCtuWidth = m_pcPic->getNumPartInCtuWidth();
  
    if ( !RasterAddress::isZeroCol( uiAbsPartIdx, numPartInCtuWidth ) )
    {
      if ( !RasterAddress::isZeroRow( uiAbsPartIdx, numPartInCtuWidth ) )
      {
        uiALPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdx - numPartInCtuWidth - 1 ];
        if ( RasterAddress::isEqualRowOrCol( uiAbsPartIdx, uiAbsZorderCUIdx, numPartInCtuWidth ) )
        {
          return m_pcPic->getCtu( getCtuRsAddr() );
        }
        else
        {
          uiALPartUnitIdx -= m_absZIdxInCtu;
          return this;
        }
      }
      uiALPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdx + getPic()->getNumPartitionsInCtu() - numPartInCtuWidth - 1 ];
      if ( bEnforceSliceRestriction && !CUIsFromSameSliceAndTile(m_pCtuAbove) )
      {
        return NULL;
      }
      return m_pCtuAbove;
    }
  
    if ( !RasterAddress::isZeroRow( uiAbsPartIdx, numPartInCtuWidth ) )
    {
      uiALPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdx - 1 ];
      if ( bEnforceSliceRestriction && !CUIsFromSameSliceAndTile(m_pCtuLeft) )
      {
        return NULL;
      }
      return m_pCtuLeft;
    }
  
    uiALPartUnitIdx = g_auiRasterToZscan[ m_pcPic->getNumPartitionsInCtu() - 1 ];
    if ( bEnforceSliceRestriction && !CUIsFromSameSliceAndTile(m_pCtuAboveLeft) )
    {
      return NULL;
    }
    return m_pCtuAboveLeft;
  }
  
  TComDataCU* TComDataCU::getPUAboveRight( UInt& uiARPartUnitIdx, UInt uiCurrPartUnitIdx, Bool bEnforceSliceRestriction )
  {
    UInt uiAbsPartIdxRT     = g_auiZscanToRaster[uiCurrPartUnitIdx];
    UInt uiAbsZorderCUIdx   = g_auiZscanToRaster[ m_absZIdxInCtu ] + m_puhWidth[0] / m_pcPic->getMinCUWidth() - 1;
    const UInt numPartInCtuWidth = m_pcPic->getNumPartInCtuWidth();
  
    if( ( m_pcPic->getCtu(m_ctuRsAddr)->getCUPelX() + g_auiRasterToPelX[uiAbsPartIdxRT] + m_pcPic->getMinCUWidth() ) >= m_pcSlice->getSPS()->getPicWidthInLumaSamples() )
    {
      uiARPartUnitIdx = MAX_UINT;
      return NULL;
    }
  
    if ( RasterAddress::lessThanCol( uiAbsPartIdxRT, numPartInCtuWidth - 1, numPartInCtuWidth ) )
    {
      if ( !RasterAddress::isZeroRow( uiAbsPartIdxRT, numPartInCtuWidth ) )
      {
        if ( uiCurrPartUnitIdx > g_auiRasterToZscan[ uiAbsPartIdxRT - numPartInCtuWidth + 1 ] )
        {
          uiARPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdxRT - numPartInCtuWidth + 1 ];
          if ( RasterAddress::isEqualRowOrCol( uiAbsPartIdxRT, uiAbsZorderCUIdx, numPartInCtuWidth ) )
          {
            return m_pcPic->getCtu( getCtuRsAddr() );
          }
          else
          {
            uiARPartUnitIdx -= m_absZIdxInCtu;
            return this;
          }
        }
        uiARPartUnitIdx = MAX_UINT;
        return NULL;
      }
      uiARPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdxRT + m_pcPic->getNumPartitionsInCtu() - numPartInCtuWidth + 1 ];
  
      if ( bEnforceSliceRestriction && !CUIsFromSameSliceAndTile(m_pCtuAbove) )
      {
        return NULL;
      }
      return m_pCtuAbove;
    }
  
    if ( !RasterAddress::isZeroRow( uiAbsPartIdxRT, numPartInCtuWidth ) )
    {
      uiARPartUnitIdx = MAX_UINT;
      return NULL;
    }
  
    uiARPartUnitIdx = g_auiRasterToZscan[ m_pcPic->getNumPartitionsInCtu() - numPartInCtuWidth ];
  
    if ( bEnforceSliceRestriction && !CUIsFromSameSliceAndTile(m_pCtuAboveRight) )
    {
      return NULL;
    }
    return m_pCtuAboveRight;
  }
  
  TComDataCU* TComDataCU::getPUBelowLeft( UInt& uiBLPartUnitIdx, UInt uiCurrPartUnitIdx, Bool bEnforceSliceRestriction )
  {
    UInt uiAbsPartIdxLB     = g_auiZscanToRaster[uiCurrPartUnitIdx];
    const UInt numPartInCtuWidth = m_pcPic->getNumPartInCtuWidth();
    UInt uiAbsZorderCUIdxLB = g_auiZscanToRaster[ m_absZIdxInCtu ] + (m_puhHeight[0] / m_pcPic->getMinCUHeight() - 1)*numPartInCtuWidth;
  
    if( ( m_pcPic->getCtu(m_ctuRsAddr)->getCUPelY() + g_auiRasterToPelY[uiAbsPartIdxLB] + m_pcPic->getMinCUHeight() ) >= m_pcSlice->getSPS()->getPicHeightInLumaSamples() )
    {
      uiBLPartUnitIdx = MAX_UINT;
      return NULL;
    }
  
    if ( RasterAddress::lessThanRow( uiAbsPartIdxLB, m_pcPic->getNumPartInCtuHeight() - 1, numPartInCtuWidth ) )
    {
      if ( !RasterAddress::isZeroCol( uiAbsPartIdxLB, numPartInCtuWidth ) )
      {
        if ( uiCurrPartUnitIdx > g_auiRasterToZscan[ uiAbsPartIdxLB + numPartInCtuWidth - 1 ] )
        {
          uiBLPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdxLB + numPartInCtuWidth - 1 ];
          if ( RasterAddress::isEqualRowOrCol( uiAbsPartIdxLB, uiAbsZorderCUIdxLB, numPartInCtuWidth ) )
          {
            return m_pcPic->getCtu( getCtuRsAddr() );
          }
          else
          {
            uiBLPartUnitIdx -= m_absZIdxInCtu;
            return this;
          }
        }
        uiBLPartUnitIdx = MAX_UINT;
        return NULL;
      }
      uiBLPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdxLB + numPartInCtuWidth*2 - 1 ];
      if ( bEnforceSliceRestriction && !CUIsFromSameSliceAndTile(m_pCtuLeft) )
      {
        return NULL;
      }
      return m_pCtuLeft;
    }
  
    uiBLPartUnitIdx = MAX_UINT;
    return NULL;
  }
  
  TComDataCU* TComDataCU::getPUBelowLeftAdi(UInt& uiBLPartUnitIdx,  UInt uiCurrPartUnitIdx, UInt uiPartUnitOffset, Bool bEnforceSliceRestriction)
  {
    UInt uiAbsPartIdxLB     = g_auiZscanToRaster[uiCurrPartUnitIdx];
    const UInt numPartInCtuWidth = m_pcPic->getNumPartInCtuWidth();
    UInt uiAbsZorderCUIdxLB = g_auiZscanToRaster[ m_absZIdxInCtu ] + ((m_puhHeight[0] / m_pcPic->getMinCUHeight()) - 1)*numPartInCtuWidth;
  
    if( ( m_pcPic->getCtu(m_ctuRsAddr)->getCUPelY() + g_auiRasterToPelY[uiAbsPartIdxLB] + (m_pcPic->getPicSym()->getMinCUHeight() * uiPartUnitOffset)) >= m_pcSlice->getSPS()->getPicHeightInLumaSamples())
    {
      uiBLPartUnitIdx = MAX_UINT;
      return NULL;
    }
  
    if ( RasterAddress::lessThanRow( uiAbsPartIdxLB, m_pcPic->getNumPartInCtuHeight() - uiPartUnitOffset, numPartInCtuWidth ) )
    {
      if ( !RasterAddress::isZeroCol( uiAbsPartIdxLB, numPartInCtuWidth ) )
      {
        if ( uiCurrPartUnitIdx > g_auiRasterToZscan[ uiAbsPartIdxLB + uiPartUnitOffset * numPartInCtuWidth - 1 ] )
        {
          uiBLPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdxLB + uiPartUnitOffset * numPartInCtuWidth - 1 ];
          if ( RasterAddress::isEqualRowOrCol( uiAbsPartIdxLB, uiAbsZorderCUIdxLB, numPartInCtuWidth ) )
          {
            return m_pcPic->getCtu( getCtuRsAddr() );
          }
          else
          {
            uiBLPartUnitIdx -= m_absZIdxInCtu;
            return this;
          }
        }
        uiBLPartUnitIdx = MAX_UINT;
        return NULL;
      }
      uiBLPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdxLB + (1+uiPartUnitOffset) * numPartInCtuWidth - 1 ];
      if ( bEnforceSliceRestriction && !CUIsFromSameSliceAndTile(m_pCtuLeft) )
      {
        return NULL;
      }
      return m_pCtuLeft;
    }
  
    uiBLPartUnitIdx = MAX_UINT;
    return NULL;
  }
  
  TComDataCU* TComDataCU::getPUAboveRightAdi(UInt&  uiARPartUnitIdx, UInt uiCurrPartUnitIdx, UInt uiPartUnitOffset, Bool bEnforceSliceRestriction)
  {
    UInt uiAbsPartIdxRT     = g_auiZscanToRaster[uiCurrPartUnitIdx];
    UInt uiAbsZorderCUIdx   = g_auiZscanToRaster[ m_absZIdxInCtu ] + (m_puhWidth[0] / m_pcPic->getMinCUWidth()) - 1;
    const UInt numPartInCtuWidth = m_pcPic->getNumPartInCtuWidth();
  
    if( ( m_pcPic->getCtu(m_ctuRsAddr)->getCUPelX() + g_auiRasterToPelX[uiAbsPartIdxRT] + (m_pcPic->getPicSym()->getMinCUHeight() * uiPartUnitOffset)) >= m_pcSlice->getSPS()->getPicWidthInLumaSamples() )
    {
      uiARPartUnitIdx = MAX_UINT;
      return NULL;
    }
  
    if ( RasterAddress::lessThanCol( uiAbsPartIdxRT, numPartInCtuWidth - uiPartUnitOffset, numPartInCtuWidth ) )
    {
      if ( !RasterAddress::isZeroRow( uiAbsPartIdxRT, numPartInCtuWidth ) )
      {
        if ( uiCurrPartUnitIdx > g_auiRasterToZscan[ uiAbsPartIdxRT - numPartInCtuWidth + uiPartUnitOffset ] )
        {
          uiARPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdxRT - numPartInCtuWidth + uiPartUnitOffset ];
          if ( RasterAddress::isEqualRowOrCol( uiAbsPartIdxRT, uiAbsZorderCUIdx, numPartInCtuWidth ) )
          {
            return m_pcPic->getCtu( getCtuRsAddr() );
          }
          else
          {
            uiARPartUnitIdx -= m_absZIdxInCtu;
            return this;
          }
        }
        uiARPartUnitIdx = MAX_UINT;
        return NULL;
      }
  
      uiARPartUnitIdx = g_auiRasterToZscan[ uiAbsPartIdxRT + m_pcPic->getNumPartitionsInCtu() - numPartInCtuWidth + uiPartUnitOffset ];
      if ( bEnforceSliceRestriction && !CUIsFromSameSliceAndTile(m_pCtuAbove) )
      {
        return NULL;
      }
      return m_pCtuAbove;
    }
  
    if ( !RasterAddress::isZeroRow( uiAbsPartIdxRT, numPartInCtuWidth ) )
    {
      uiARPartUnitIdx = MAX_UINT;
      return NULL;
    }
  
    uiARPartUnitIdx = g_auiRasterToZscan[ m_pcPic->getNumPartitionsInCtu() - numPartInCtuWidth + uiPartUnitOffset-1 ];
    if ( bEnforceSliceRestriction && !CUIsFromSameSliceAndTile(m_pCtuAboveRight) )
    {
      return NULL;
    }
    return m_pCtuAboveRight;
  }
  
  /** Get left QpMinCu
  *\param   uiLPartUnitIdx
  *\param   uiCurrAbsIdxInCtu
  *\returns TComDataCU*   point of TComDataCU of left QpMinCu
  */
  TComDataCU* TComDataCU::getQpMinCuLeft( UInt& uiLPartUnitIdx, UInt uiCurrAbsIdxInCtu )
  {
    const UInt numPartInCtuWidth = m_pcPic->getNumPartInCtuWidth();
    const UInt maxCUDepth        = getSlice()->getSPS()->getMaxTotalCUDepth();
    const UInt maxCuDQPDepth     = getSlice()->getPPS()->getMaxCuDQPDepth();
    const UInt doubleDepthDifference = ((maxCUDepth - maxCuDQPDepth)<<1);
    UInt absZorderQpMinCUIdx = (uiCurrAbsIdxInCtu>>doubleDepthDifference)<<doubleDepthDifference;
    UInt absRorderQpMinCUIdx = g_auiZscanToRaster[absZorderQpMinCUIdx];
  
    // check for left CTU boundary
    if ( RasterAddress::isZeroCol(absRorderQpMinCUIdx, numPartInCtuWidth) )
    {
      return NULL;
    }
  
    // get index of left-CU relative to top-left corner of current quantization group
    uiLPartUnitIdx = g_auiRasterToZscan[absRorderQpMinCUIdx - 1];
  
    // return pointer to current CTU
    return m_pcPic->getCtu( getCtuRsAddr() );
  }
  
  /** Get Above QpMinCu
  *\param   uiAPartUnitIdx
  *\param   uiCurrAbsIdxInCtu
  *\returns TComDataCU*   point of TComDataCU of above QpMinCu
  */
  TComDataCU* TComDataCU::getQpMinCuAbove( UInt& uiAPartUnitIdx, UInt uiCurrAbsIdxInCtu )
  {
    const UInt numPartInCtuWidth = m_pcPic->getNumPartInCtuWidth();
    const UInt maxCUDepth        = getSlice()->getSPS()->getMaxTotalCUDepth();
    const UInt maxCuDQPDepth     = getSlice()->getPPS()->getMaxCuDQPDepth();
    const UInt doubleDepthDifference = ((maxCUDepth - maxCuDQPDepth)<<1);
    UInt absZorderQpMinCUIdx = (uiCurrAbsIdxInCtu>>doubleDepthDifference)<<doubleDepthDifference;
    UInt absRorderQpMinCUIdx = g_auiZscanToRaster[absZorderQpMinCUIdx];
  
    // check for top CTU boundary
    if ( RasterAddress::isZeroRow( absRorderQpMinCUIdx, numPartInCtuWidth) )
    {
      return NULL;
    }
  
    // get index of top-CU relative to top-left corner of current quantization group
    uiAPartUnitIdx = g_auiRasterToZscan[absRorderQpMinCUIdx - numPartInCtuWidth];
  
    // return pointer to current CTU
    return m_pcPic->getCtu( getCtuRsAddr() );
  }
  
  
  
  /** Get reference QP from left QpMinCu or latest coded QP
  *\param   uiCurrAbsIdxInCtu
  *\returns Char   reference QP value
  */
  Char TComDataCU::getRefQP( UInt uiCurrAbsIdxInCtu )
  {
    UInt lPartIdx = MAX_UINT;
    UInt aPartIdx = MAX_UINT;
    TComDataCU* cULeft  = getQpMinCuLeft ( lPartIdx, m_absZIdxInCtu + uiCurrAbsIdxInCtu );
    TComDataCU* cUAbove = getQpMinCuAbove( aPartIdx, m_absZIdxInCtu + uiCurrAbsIdxInCtu );
    return (((cULeft? cULeft->getQP( lPartIdx ): getLastCodedQP( uiCurrAbsIdxInCtu )) + (cUAbove? cUAbove->getQP( aPartIdx ): getLastCodedQP( uiCurrAbsIdxInCtu )) + 1) >> 1);
  }
  
  Int TComDataCU::getLastValidPartIdx( Int iAbsPartIdx )
  {
    Int iLastValidPartIdx = iAbsPartIdx-1;
    while ( iLastValidPartIdx >= 0
         && getPredictionMode( iLastValidPartIdx ) == NUMBER_OF_PREDICTION_MODES )
    {
      UInt uiDepth = getDepth( iLastValidPartIdx );
      iLastValidPartIdx -= m_uiNumPartition>>(uiDepth<<1);
    }
    return iLastValidPartIdx;
  }
  
  Char TComDataCU::getLastCodedQP( UInt uiAbsPartIdx )
  {
    UInt uiQUPartIdxMask = ~((1<<((getSlice()->getSPS()->getMaxTotalCUDepth() - getSlice()->getPPS()->getMaxCuDQPDepth())<<1))-1);
    Int iLastValidPartIdx = getLastValidPartIdx( uiAbsPartIdx&uiQUPartIdxMask ); // A idx will be invalid if it is off the right or bottom edge of the picture.
    // If this CU is in the first CTU of the slice and there is no valid part before this one, use slice QP
    if ( getPic()->getPicSym()->getCtuTsToRsAddrMap(getSlice()->getSliceCurStartCtuTsAddr()) == getCtuRsAddr() && Int(getZorderIdxInCtu())+iLastValidPartIdx<0)
    {
      return getSlice()->getSliceQp();
    }
    else if ( iLastValidPartIdx >= 0 )
    {
      // If there is a valid part within the current Sub-CU, use it
      return getQP( iLastValidPartIdx );
    }
    else
    {
      if ( getZorderIdxInCtu() > 0 )
      {
        // If this wasn't the first sub-cu within the Ctu, explore the CTU itself.
        return getPic()->getCtu( getCtuRsAddr() )->getLastCodedQP( getZorderIdxInCtu() ); // TODO - remove this recursion
      }
      else if ( getPic()->getPicSym()->getCtuRsToTsAddrMap(getCtuRsAddr()) > 0
        && CUIsFromSameSliceTileAndWavefrontRow(getPic()->getCtu(getPic()->getPicSym()->getCtuTsToRsAddrMap(getPic()->getPicSym()->getCtuRsToTsAddrMap(getCtuRsAddr())-1))) )
      {
        // If this isn't the first Ctu (how can it be due to the first 'if'?), and the previous Ctu is from the same tile, examine the previous Ctu.
        return getPic()->getCtu( getPic()->getPicSym()->getCtuTsToRsAddrMap(getPic()->getPicSym()->getCtuRsToTsAddrMap(getCtuRsAddr())-1) )->getLastCodedQP( getPic()->getNumPartitionsInCtu() );  // TODO - remove this recursion
      }
      else
      {
        // No other options available - use the slice-level QP.
        return getSlice()->getSliceQp();
      }
    }
  }
  
  
  /** Check whether the CU is coded in lossless coding mode.
   * \param   absPartIdx
   * \returns true if the CU is coded in lossless coding mode; false if otherwise
   */
  Bool TComDataCU::isLosslessCoded(UInt absPartIdx)
  {
    return (getSlice()->getPPS()->getTransquantBypassEnableFlag() && getCUTransquantBypass (absPartIdx));
  }
  
  
  /** Get allowed chroma intra modes
  *   - fills uiModeList with chroma intra modes
  *
  *\param   [in]  uiAbsPartIdx
  *\param   [out] uiModeList pointer to chroma intra modes array
  */
  Void TComDataCU::getAllowedChromaDir( UInt uiAbsPartIdx, UInt uiModeList[NUM_CHROMA_MODE] )
  {
    uiModeList[0] = PLANAR_IDX;
    uiModeList[1] = VER_IDX;
    uiModeList[2] = HOR_IDX;
    uiModeList[3] = DC_IDX;
    uiModeList[4] = DM_CHROMA_IDX;
    assert(4<NUM_CHROMA_MODE);
  
    UInt uiLumaMode = getIntraDir( CHANNEL_TYPE_LUMA, uiAbsPartIdx );
  
    for( Int i = 0; i < NUM_CHROMA_MODE - 1; i++ )
    {
      if( uiLumaMode == uiModeList[i] )
      {
        uiModeList[i] = 34; // VER+8 mode
        break;
      }
    }
  }
  
  /** Get most probable intra modes
  *\param   uiAbsPartIdx    partition index
  *\param   uiIntraDirPred  pointer to the array for MPM storage
  *\param   compID          colour component ID
  *\param   piMode          it is set with MPM mode in case both MPM are equal. It is used to restrict RD search at encode side.
  *\returns Number of MPM
  */
  Void TComDataCU::getIntraDirPredictor( UInt uiAbsPartIdx, Int uiIntraDirPred[NUM_MOST_PROBABLE_MODES], const ComponentID compID, Int* piMode  )
  {
    TComDataCU* pcCULeft, *pcCUAbove;
    UInt        LeftPartIdx  = MAX_UINT;
    UInt        AbovePartIdx = MAX_UINT;
    Int         iLeftIntraDir, iAboveIntraDir;
    const TComSPS *sps=getSlice()->getSPS();
    const UInt partsPerMinCU = 1<<(2*(sps->getMaxTotalCUDepth() - sps->getLog2DiffMaxMinCodingBlockSize()));
  
    const ChannelType chType = toChannelType(compID);
    const ChromaFormat chForm = getPic()->getChromaFormat();
    // Get intra direction of left PU
    pcCULeft = getPULeft( LeftPartIdx, m_absZIdxInCtu + uiAbsPartIdx );
  
    if (isChroma(compID))
    {
      LeftPartIdx = getChromasCorrespondingPULumaIdx(LeftPartIdx, chForm, partsPerMinCU);
    }
    iLeftIntraDir  = pcCULeft ? ( pcCULeft->isIntra( LeftPartIdx ) ? pcCULeft->getIntraDir( chType, LeftPartIdx ) : DC_IDX ) : DC_IDX;
  
    // Get intra direction of above PU
    pcCUAbove = getPUAbove( AbovePartIdx, m_absZIdxInCtu + uiAbsPartIdx, true, true );
  
    if (isChroma(compID))
    {
      AbovePartIdx = getChromasCorrespondingPULumaIdx(AbovePartIdx, chForm, partsPerMinCU);
    }
    iAboveIntraDir = pcCUAbove ? ( pcCUAbove->isIntra( AbovePartIdx ) ? pcCUAbove->getIntraDir( chType, AbovePartIdx ) : DC_IDX ) : DC_IDX;
  
    if (isChroma(chType))
    {
      if (iLeftIntraDir  == DM_CHROMA_IDX)
      {
        iLeftIntraDir  = pcCULeft-> getIntraDir( CHANNEL_TYPE_LUMA, LeftPartIdx  );
      }
      if (iAboveIntraDir == DM_CHROMA_IDX)
      {
        iAboveIntraDir = pcCUAbove->getIntraDir( CHANNEL_TYPE_LUMA, AbovePartIdx );
      }
    }
  
    assert (2<NUM_MOST_PROBABLE_MODES);
    if(iLeftIntraDir == iAboveIntraDir)
    {
      if( piMode )
      {
        *piMode = 1;
      }
  
      if (iLeftIntraDir > 1) // angular modes
      {
        uiIntraDirPred[0] = iLeftIntraDir;
        uiIntraDirPred[1] = ((iLeftIntraDir + 29) % 32) + 2;
        uiIntraDirPred[2] = ((iLeftIntraDir - 1 ) % 32) + 2;
      }
      else //non-angular
      {
        uiIntraDirPred[0] = PLANAR_IDX;
        uiIntraDirPred[1] = DC_IDX;
        uiIntraDirPred[2] = VER_IDX;
      }
    }
    else
    {
      if( piMode )
      {
        *piMode = 2;
      }
      uiIntraDirPred[0] = iLeftIntraDir;
      uiIntraDirPred[1] = iAboveIntraDir;
  
      if (iLeftIntraDir && iAboveIntraDir ) //both modes are non-planar
      {
        uiIntraDirPred[2] = PLANAR_IDX;
      }
      else
      {
        uiIntraDirPred[2] =  (iLeftIntraDir+iAboveIntraDir)<2? VER_IDX : DC_IDX;
      }
    }
    for (UInt i=0; i<NUM_MOST_PROBABLE_MODES; i++)
    {
      assert(uiIntraDirPred[i] < 35);
    }
  }
  
  UInt TComDataCU::getCtxSplitFlag( UInt uiAbsPartIdx, UInt uiDepth )
  {
    TComDataCU* pcTempCU;
    UInt        uiTempPartIdx;
    UInt        uiCtx;
    // Get left split flag
    pcTempCU = getPULeft( uiTempPartIdx, m_absZIdxInCtu + uiAbsPartIdx );
    uiCtx  = ( pcTempCU ) ? ( ( pcTempCU->getDepth( uiTempPartIdx ) > uiDepth ) ? 1 : 0 ) : 0;
  
    // Get above split flag
    pcTempCU = getPUAbove( uiTempPartIdx, m_absZIdxInCtu + uiAbsPartIdx );
    uiCtx += ( pcTempCU ) ? ( ( pcTempCU->getDepth( uiTempPartIdx ) > uiDepth ) ? 1 : 0 ) : 0;
  
    return uiCtx;
  }
  
  UInt TComDataCU::getCtxQtCbf( TComTU &rTu, const ChannelType chType )
  {
    const UInt transformDepth = rTu.GetTransformDepthRel();
  
    if (isChroma(chType))
    {
      return transformDepth;
    }
    else
    {
      const UInt uiCtx = ( transformDepth == 0 ? 1 : 0 );
      return uiCtx;
    }
  }
  
  UInt TComDataCU::getQuadtreeTULog2MinSizeInCU( UInt absPartIdx )
  {
    UInt log2CbSize = g_aucConvertToBit[getWidth( absPartIdx )] + 2;
    PartSize  partSize  = getPartitionSize( absPartIdx );
    UInt quadtreeTUMaxDepth = isIntra( absPartIdx ) ? m_pcSlice->getSPS()->getQuadtreeTUMaxDepthIntra() : m_pcSlice->getSPS()->getQuadtreeTUMaxDepthInter();
    Int intraSplitFlag = ( isIntra( absPartIdx ) && partSize == SIZE_NxN ) ? 1 : 0;
    Int interSplitFlag = ((quadtreeTUMaxDepth == 1) && isInter( absPartIdx ) && (partSize != SIZE_2Nx2N) );
  
    UInt log2MinTUSizeInCU = 0;
    if (log2CbSize < (m_pcSlice->getSPS()->getQuadtreeTULog2MinSize() + quadtreeTUMaxDepth - 1 + interSplitFlag + intraSplitFlag) )
    {
      // when fully making use of signaled TUMaxDepth + inter/intraSplitFlag, resulting luma TB size is < QuadtreeTULog2MinSize
      log2MinTUSizeInCU = m_pcSlice->getSPS()->getQuadtreeTULog2MinSize();
    }
    else
    {
      // when fully making use of signaled TUMaxDepth + inter/intraSplitFlag, resulting luma TB size is still >= QuadtreeTULog2MinSize
      log2MinTUSizeInCU = log2CbSize - ( quadtreeTUMaxDepth - 1 + interSplitFlag + intraSplitFlag); // stop when trafoDepth == hierarchy_depth = splitFlag
      if ( log2MinTUSizeInCU > m_pcSlice->getSPS()->getQuadtreeTULog2MaxSize())
      {
        // when fully making use of signaled TUMaxDepth + inter/intraSplitFlag, resulting luma TB size is still > QuadtreeTULog2MaxSize
        log2MinTUSizeInCU = m_pcSlice->getSPS()->getQuadtreeTULog2MaxSize();
      }
    }
    return log2MinTUSizeInCU;
  }
  
  UInt TComDataCU::getCtxSkipFlag( UInt uiAbsPartIdx )
  {
    TComDataCU* pcTempCU;
    UInt        uiTempPartIdx;
    UInt        uiCtx = 0;
  
    // Get BCBP of left PU
    pcTempCU = getPULeft( uiTempPartIdx, m_absZIdxInCtu + uiAbsPartIdx );
    uiCtx    = ( pcTempCU ) ? pcTempCU->isSkipped( uiTempPartIdx ) : 0;
  
    // Get BCBP of above PU
    pcTempCU = getPUAbove( uiTempPartIdx, m_absZIdxInCtu + uiAbsPartIdx );
    uiCtx   += ( pcTempCU ) ? pcTempCU->isSkipped( uiTempPartIdx ) : 0;
  
    return uiCtx;
  }
  
  UInt TComDataCU::getCtxInterDir( UInt uiAbsPartIdx )
  {
    return getDepth( uiAbsPartIdx );
  }
  
  
  UChar TComDataCU::getQtRootCbf( UInt uiIdx )
  {
    const UInt numberValidComponents = getPic()->getNumberValidComponents();
    return getCbf( uiIdx, COMPONENT_Y, 0 )
            || ((numberValidComponents > COMPONENT_Cb) && getCbf( uiIdx, COMPONENT_Cb, 0 ))
            || ((numberValidComponents > COMPONENT_Cr) && getCbf( uiIdx, COMPONENT_Cr, 0 ));
  }
  
  Void TComDataCU::setCbfSubParts( const UInt uiCbf[MAX_NUM_COMPONENT], UInt uiAbsPartIdx, UInt uiDepth )
  {
    UInt uiCurrPartNumb = m_pcPic->getNumPartitionsInCtu() >> (uiDepth << 1);
    for(UInt comp=0; comp<MAX_NUM_COMPONENT; comp++)
    {
      memset( m_puhCbf[comp] + uiAbsPartIdx, uiCbf[comp], sizeof( UChar ) * uiCurrPartNumb );
    }
  }
  
  Void TComDataCU::setCbfSubParts( UInt uiCbf, ComponentID compID, UInt uiAbsPartIdx, UInt uiDepth )
  {
    UInt uiCurrPartNumb = m_pcPic->getNumPartitionsInCtu() >> (uiDepth << 1);
    memset( m_puhCbf[compID] + uiAbsPartIdx, uiCbf, sizeof( UChar ) * uiCurrPartNumb );
  }
  
  /** Sets a coded block flag for all sub-partitions of a partition
   * \param uiCbf          The value of the coded block flag to be set
   * \param compID
   * \param uiAbsPartIdx
   * \param uiPartIdx
   * \param uiDepth
   */
  Void TComDataCU::setCbfSubParts ( UInt uiCbf, ComponentID compID, UInt uiAbsPartIdx, UInt uiPartIdx, UInt uiDepth )
  {
    setSubPart<UChar>( uiCbf, m_puhCbf[compID], uiAbsPartIdx, uiDepth, uiPartIdx );
  }
  
  Void TComDataCU::setCbfPartRange ( UInt uiCbf, ComponentID compID, UInt uiAbsPartIdx, UInt uiCoveredPartIdxes )
  {
    memset((m_puhCbf[compID] + uiAbsPartIdx), uiCbf, (sizeof(UChar) * uiCoveredPartIdxes));
  }
  
  Void TComDataCU::bitwiseOrCbfPartRange( UInt uiCbf, ComponentID compID, UInt uiAbsPartIdx, UInt uiCoveredPartIdxes )
  {
    const UInt stopAbsPartIdx = uiAbsPartIdx + uiCoveredPartIdxes;
  
    for (UInt subPartIdx = uiAbsPartIdx; subPartIdx < stopAbsPartIdx; subPartIdx++)
    {
      m_puhCbf[compID][subPartIdx] |= uiCbf;
    }
  }
  
  Void TComDataCU::setDepthSubParts( UInt uiDepth, UInt uiAbsPartIdx )
  {
    UInt uiCurrPartNumb = m_pcPic->getNumPartitionsInCtu() >> (uiDepth << 1);
    memset( m_puhDepth + uiAbsPartIdx, uiDepth, sizeof(UChar)*uiCurrPartNumb );
  }
  
  Bool TComDataCU::isFirstAbsZorderIdxInDepth (UInt uiAbsPartIdx, UInt uiDepth)
  {
    UInt uiPartNumb = m_pcPic->getNumPartitionsInCtu() >> (uiDepth << 1);
    return (((m_absZIdxInCtu + uiAbsPartIdx)% uiPartNumb) == 0);
  }
  
  Void TComDataCU::setPartSizeSubParts( PartSize eMode, UInt uiAbsPartIdx, UInt uiDepth )
  {
    assert( sizeof( *m_pePartSize) == 1 );
    memset( m_pePartSize + uiAbsPartIdx, eMode, m_pcPic->getNumPartitionsInCtu() >> ( 2 * uiDepth ) );
  }
  
  Void TComDataCU::setCUTransquantBypassSubParts( Bool flag, UInt uiAbsPartIdx, UInt uiDepth )
  {
    memset( m_CUTransquantBypass + uiAbsPartIdx, flag, m_pcPic->getNumPartitionsInCtu() >> ( 2 * uiDepth ) );
  }
  
  Void TComDataCU::setSkipFlagSubParts( Bool skip, UInt absPartIdx, UInt depth )
  {
    assert( sizeof( *m_skipFlag) == 1 );
    memset( m_skipFlag + absPartIdx, skip, m_pcPic->getNumPartitionsInCtu() >> ( 2 * depth ) );
  }
  
  Void TComDataCU::setPredModeSubParts( PredMode eMode, UInt uiAbsPartIdx, UInt uiDepth )
  {
    assert( sizeof( *m_pePredMode) == 1 );
    memset( m_pePredMode + uiAbsPartIdx, eMode, m_pcPic->getNumPartitionsInCtu() >> ( 2 * uiDepth ) );
  }
  
  Void TComDataCU::setChromaQpAdjSubParts( UChar val, Int absPartIdx, Int depth )
  {
    assert( sizeof(*m_ChromaQpAdj) == 1 );
    memset( m_ChromaQpAdj + absPartIdx, val, m_pcPic->getNumPartitionsInCtu() >> ( 2 * depth ) );
  }
  
  Void TComDataCU::setQPSubCUs( Int qp, UInt absPartIdx, UInt depth, Bool &foundNonZeroCbf )
  {
    UInt currPartNumb = m_pcPic->getNumPartitionsInCtu() >> (depth << 1);
    UInt currPartNumQ = currPartNumb >> 2;
    const UInt numValidComp = m_pcPic->getNumberValidComponents();
  
    if(!foundNonZeroCbf)
    {
      if(getDepth(absPartIdx) > depth)
      {
        for ( UInt partUnitIdx = 0; partUnitIdx < 4; partUnitIdx++ )
        {
          setQPSubCUs( qp, absPartIdx+partUnitIdx*currPartNumQ, depth+1, foundNonZeroCbf );
        }
      }
      else
      {
        if(getCbf( absPartIdx, COMPONENT_Y ) || (numValidComp>COMPONENT_Cb && getCbf( absPartIdx, COMPONENT_Cb )) || (numValidComp>COMPONENT_Cr && getCbf( absPartIdx, COMPONENT_Cr) ) )
        {
          foundNonZeroCbf = true;
        }
        else
        {
          setQPSubParts(qp, absPartIdx, depth);
        }
      }
    }
  }
  
  Void TComDataCU::setQPSubParts( Int qp, UInt uiAbsPartIdx, UInt uiDepth )
  {
    const UInt numPart = m_pcPic->getNumPartitionsInCtu() >> (uiDepth << 1);
    memset(m_phQP+uiAbsPartIdx, qp, numPart);
  }
  
  Void TComDataCU::setIntraDirSubParts( const ChannelType channelType, const UInt dir, const UInt absPartIdx, const UInt depth )
  {
    UInt numPart = m_pcPic->getNumPartitionsInCtu() >> (depth << 1);
    memset( m_puhIntraDir[channelType] + absPartIdx, dir,sizeof(UChar)*numPart );
  }
  
  template<typename T>
  Void TComDataCU::setSubPart( T uiParameter, T* puhBaseCtu, UInt uiCUAddr, UInt uiCUDepth, UInt uiPUIdx )
  {
    assert( sizeof(T) == 1 ); // Using memset() works only for types of size 1
  
    UInt uiCurrPartNumQ = (m_pcPic->getNumPartitionsInCtu() >> (2 * uiCUDepth)) >> 2;
    switch ( m_pePartSize[ uiCUAddr ] )
    {
      case SIZE_2Nx2N:
        memset( puhBaseCtu + uiCUAddr, uiParameter, 4 * uiCurrPartNumQ );
        break;
      case SIZE_2NxN:
        memset( puhBaseCtu + uiCUAddr, uiParameter, 2 * uiCurrPartNumQ );
        break;
      case SIZE_Nx2N:
        memset( puhBaseCtu + uiCUAddr, uiParameter, uiCurrPartNumQ );
        memset( puhBaseCtu + uiCUAddr + 2 * uiCurrPartNumQ, uiParameter, uiCurrPartNumQ );
        break;
      case SIZE_NxN:
        memset( puhBaseCtu + uiCUAddr, uiParameter, uiCurrPartNumQ );
        break;
      case SIZE_2NxnU:
        if ( uiPUIdx == 0 )
        {
          memset( puhBaseCtu + uiCUAddr, uiParameter, (uiCurrPartNumQ >> 1) );
          memset( puhBaseCtu + uiCUAddr + uiCurrPartNumQ, uiParameter, (uiCurrPartNumQ >> 1) );
        }
        else if ( uiPUIdx == 1 )
        {
          memset( puhBaseCtu + uiCUAddr, uiParameter, (uiCurrPartNumQ >> 1) );
          memset( puhBaseCtu + uiCUAddr + uiCurrPartNumQ, uiParameter, ((uiCurrPartNumQ >> 1) + (uiCurrPartNumQ << 1)) );
        }
        else
        {
          assert(0);
        }
        break;
      case SIZE_2NxnD:
        if ( uiPUIdx == 0 )
        {
          memset( puhBaseCtu + uiCUAddr, uiParameter, ((uiCurrPartNumQ << 1) + (uiCurrPartNumQ >> 1)) );
          memset( puhBaseCtu + uiCUAddr + (uiCurrPartNumQ << 1) + uiCurrPartNumQ, uiParameter, (uiCurrPartNumQ >> 1) );
        }
        else if ( uiPUIdx == 1 )
        {
          memset( puhBaseCtu + uiCUAddr, uiParameter, (uiCurrPartNumQ >> 1) );
          memset( puhBaseCtu + uiCUAddr + uiCurrPartNumQ, uiParameter, (uiCurrPartNumQ >> 1) );
        }
        else
        {
          assert(0);
        }
        break;
      case SIZE_nLx2N:
        if ( uiPUIdx == 0 )
        {
          memset( puhBaseCtu + uiCUAddr, uiParameter, (uiCurrPartNumQ >> 2) );
          memset( puhBaseCtu + uiCUAddr + (uiCurrPartNumQ >> 1), uiParameter, (uiCurrPartNumQ >> 2) );
          memset( puhBaseCtu + uiCUAddr + (uiCurrPartNumQ << 1), uiParameter, (uiCurrPartNumQ >> 2) );
          memset( puhBaseCtu + uiCUAddr + (uiCurrPartNumQ << 1) + (uiCurrPartNumQ >> 1), uiParameter, (uiCurrPartNumQ >> 2) );
        }
        else if ( uiPUIdx == 1 )
        {
          memset( puhBaseCtu + uiCUAddr, uiParameter, (uiCurrPartNumQ >> 2) );
          memset( puhBaseCtu + uiCUAddr + (uiCurrPartNumQ >> 1), uiParameter, (uiCurrPartNumQ + (uiCurrPartNumQ >> 2)) );
          memset( puhBaseCtu + uiCUAddr + (uiCurrPartNumQ << 1), uiParameter, (uiCurrPartNumQ >> 2) );
          memset( puhBaseCtu + uiCUAddr + (uiCurrPartNumQ << 1) + (uiCurrPartNumQ >> 1), uiParameter, (uiCurrPartNumQ + (uiCurrPartNumQ >> 2)) );
        }
        else
        {
          assert(0);
        }
        break;
      case SIZE_nRx2N:
        if ( uiPUIdx == 0 )
        {
          memset( puhBaseCtu + uiCUAddr, uiParameter, (uiCurrPartNumQ + (uiCurrPartNumQ >> 2)) );
          memset( puhBaseCtu + uiCUAddr + uiCurrPartNumQ + (uiCurrPartNumQ >> 1), uiParameter, (uiCurrPartNumQ >> 2) );
          memset( puhBaseCtu + uiCUAddr + (uiCurrPartNumQ << 1), uiParameter, (uiCurrPartNumQ + (uiCurrPartNumQ >> 2)) );
          memset( puhBaseCtu + uiCUAddr + (uiCurrPartNumQ << 1) + uiCurrPartNumQ + (uiCurrPartNumQ >> 1), uiParameter, (uiCurrPartNumQ >> 2) );
        }
        else if ( uiPUIdx == 1 )
        {
          memset( puhBaseCtu + uiCUAddr, uiParameter, (uiCurrPartNumQ >> 2) );
          memset( puhBaseCtu + uiCUAddr + (uiCurrPartNumQ >> 1), uiParameter, (uiCurrPartNumQ >> 2) );
          memset( puhBaseCtu + uiCUAddr + (uiCurrPartNumQ << 1), uiParameter, (uiCurrPartNumQ >> 2) );
          memset( puhBaseCtu + uiCUAddr + (uiCurrPartNumQ << 1) + (uiCurrPartNumQ >> 1), uiParameter, (uiCurrPartNumQ >> 2) );
        }
        else
        {
          assert(0);
        }
        break;
      default:
        assert( 0 );
        break;
    }
  }
  
  Void TComDataCU::setMergeFlagSubParts ( Bool bMergeFlag, UInt uiAbsPartIdx, UInt uiPartIdx, UInt uiDepth )
  {
    setSubPart( bMergeFlag, m_pbMergeFlag, uiAbsPartIdx, uiDepth, uiPartIdx );
  }
  
  Void TComDataCU::setMergeIndexSubParts ( UInt uiMergeIndex, UInt uiAbsPartIdx, UInt uiPartIdx, UInt uiDepth )
  {
    setSubPart<UChar>( uiMergeIndex, m_puhMergeIndex, uiAbsPartIdx, uiDepth, uiPartIdx );
  }
  
  Void TComDataCU::setInterDirSubParts( UInt uiDir, UInt uiAbsPartIdx, UInt uiPartIdx, UInt uiDepth )
  {
    setSubPart<UChar>( uiDir, m_puhInterDir, uiAbsPartIdx, uiDepth, uiPartIdx );
  }
  
  Void TComDataCU::setMVPIdxSubParts( Int iMVPIdx, RefPicList eRefPicList, UInt uiAbsPartIdx, UInt uiPartIdx, UInt uiDepth )
  {
    setSubPart<Char>( iMVPIdx, m_apiMVPIdx[eRefPicList], uiAbsPartIdx, uiDepth, uiPartIdx );
  }
  
  Void TComDataCU::setMVPNumSubParts( Int iMVPNum, RefPicList eRefPicList, UInt uiAbsPartIdx, UInt uiPartIdx, UInt uiDepth )
  {
    setSubPart<Char>( iMVPNum, m_apiMVPNum[eRefPicList], uiAbsPartIdx, uiDepth, uiPartIdx );
  }
  
  
  Void TComDataCU::setTrIdxSubParts( UInt uiTrIdx, UInt uiAbsPartIdx, UInt uiDepth )
  {
    UInt uiCurrPartNumb = m_pcPic->getNumPartitionsInCtu() >> (uiDepth << 1);
  
    memset( m_puhTrIdx + uiAbsPartIdx, uiTrIdx, sizeof(UChar)*uiCurrPartNumb );
  }
  
  Void TComDataCU::setTransformSkipSubParts( const UInt useTransformSkip[MAX_NUM_COMPONENT], UInt uiAbsPartIdx, UInt uiDepth )
  {
    UInt uiCurrPartNumb = m_pcPic->getNumPartitionsInCtu() >> (uiDepth << 1);
  
    for(UInt i=0; i<MAX_NUM_COMPONENT; i++)
    {
      memset( m_puhTransformSkip[i] + uiAbsPartIdx, useTransformSkip[i], sizeof( UChar ) * uiCurrPartNumb );
    }
  }
  
  Void TComDataCU::setTransformSkipSubParts( UInt useTransformSkip, ComponentID compID, UInt uiAbsPartIdx, UInt uiDepth)
  {
    UInt uiCurrPartNumb = m_pcPic->getNumPartitionsInCtu() >> (uiDepth << 1);
  
    memset( m_puhTransformSkip[compID] + uiAbsPartIdx, useTransformSkip, sizeof( UChar ) * uiCurrPartNumb );
  }
  
  Void TComDataCU::setTransformSkipPartRange ( UInt useTransformSkip, ComponentID compID, UInt uiAbsPartIdx, UInt uiCoveredPartIdxes )
  {
    memset((m_puhTransformSkip[compID] + uiAbsPartIdx), useTransformSkip, (sizeof(UChar) * uiCoveredPartIdxes));
  }
  
  Void TComDataCU::setCrossComponentPredictionAlphaPartRange( Char alphaValue, ComponentID compID, UInt uiAbsPartIdx, UInt uiCoveredPartIdxes )
  {
    memset((m_crossComponentPredictionAlpha[compID] + uiAbsPartIdx), alphaValue, (sizeof(Char) * uiCoveredPartIdxes));
  }
  
  Void TComDataCU::setExplicitRdpcmModePartRange ( UInt rdpcmMode, ComponentID compID, UInt uiAbsPartIdx, UInt uiCoveredPartIdxes )
  {
    memset((m_explicitRdpcmMode[compID] + uiAbsPartIdx), rdpcmMode, (sizeof(UChar) * uiCoveredPartIdxes));
  }
  
  Void TComDataCU::setSizeSubParts( UInt uiWidth, UInt uiHeight, UInt uiAbsPartIdx, UInt uiDepth )
  {
    UInt uiCurrPartNumb = m_pcPic->getNumPartitionsInCtu() >> (uiDepth << 1);
  
    memset( m_puhWidth  + uiAbsPartIdx, uiWidth,  sizeof(UChar)*uiCurrPartNumb );
    memset( m_puhHeight + uiAbsPartIdx, uiHeight, sizeof(UChar)*uiCurrPartNumb );
  }
  
  UChar TComDataCU::getNumPartitions(const UInt uiAbsPartIdx)
  {
    UChar iNumPart = 0;
  
    switch ( m_pePartSize[uiAbsPartIdx] )
    {
      case SIZE_2Nx2N:    iNumPart = 1; break;
      case SIZE_2NxN:     iNumPart = 2; break;
      case SIZE_Nx2N:     iNumPart = 2; break;
      case SIZE_NxN:      iNumPart = 4; break;
      case SIZE_2NxnU:    iNumPart = 2; break;
      case SIZE_2NxnD:    iNumPart = 2; break;
      case SIZE_nLx2N:    iNumPart = 2; break;
      case SIZE_nRx2N:    iNumPart = 2; break;
      default:            assert (0);   break;
    }
  
    return  iNumPart;
  }
  
  // This is for use by a leaf/sub CU object only, with no additional AbsPartIdx
  Void TComDataCU::getPartIndexAndSize( UInt uiPartIdx, UInt& ruiPartAddr, Int& riWidth, Int& riHeight )
  {
    switch ( m_pePartSize[0] )
    {
      case SIZE_2NxN:
        riWidth = getWidth(0);      riHeight = getHeight(0) >> 1; ruiPartAddr = ( uiPartIdx == 0 )? 0 : m_uiNumPartition >> 1;
        break;
      case SIZE_Nx2N:
        riWidth = getWidth(0) >> 1; riHeight = getHeight(0);      ruiPartAddr = ( uiPartIdx == 0 )? 0 : m_uiNumPartition >> 2;
        break;
      case SIZE_NxN:
        riWidth = getWidth(0) >> 1; riHeight = getHeight(0) >> 1; ruiPartAddr = ( m_uiNumPartition >> 2 ) * uiPartIdx;
        break;
      case SIZE_2NxnU:
        riWidth     = getWidth(0);
        riHeight    = ( uiPartIdx == 0 ) ?  getHeight(0) >> 2 : ( getHeight(0) >> 2 ) + ( getHeight(0) >> 1 );
        ruiPartAddr = ( uiPartIdx == 0 ) ? 0 : m_uiNumPartition >> 3;
        break;
      case SIZE_2NxnD:
        riWidth     = getWidth(0);
        riHeight    = ( uiPartIdx == 0 ) ?  ( getHeight(0) >> 2 ) + ( getHeight(0) >> 1 ) : getHeight(0) >> 2;
        ruiPartAddr = ( uiPartIdx == 0 ) ? 0 : (m_uiNumPartition >> 1) + (m_uiNumPartition >> 3);
        break;
      case SIZE_nLx2N:
        riWidth     = ( uiPartIdx == 0 ) ? getWidth(0) >> 2 : ( getWidth(0) >> 2 ) + ( getWidth(0) >> 1 );
        riHeight    = getHeight(0);
        ruiPartAddr = ( uiPartIdx == 0 ) ? 0 : m_uiNumPartition >> 4;
        break;
      case SIZE_nRx2N:
        riWidth     = ( uiPartIdx == 0 ) ? ( getWidth(0) >> 2 ) + ( getWidth(0) >> 1 ) : getWidth(0) >> 2;
        riHeight    = getHeight(0);
        ruiPartAddr = ( uiPartIdx == 0 ) ? 0 : (m_uiNumPartition >> 2) + (m_uiNumPartition >> 4);
        break;
      default:
        assert ( m_pePartSize[0] == SIZE_2Nx2N );
        riWidth = getWidth(0);      riHeight = getHeight(0);      ruiPartAddr = 0;
        break;
    }
  }
  
  
  Void TComDataCU::getMvField ( TComDataCU* pcCU, UInt uiAbsPartIdx, RefPicList eRefPicList, TComMvField& rcMvField )
  {
    if ( pcCU == NULL )  // OUT OF BOUNDARY
    {
      TComMv  cZeroMv;
      rcMvField.setMvField( cZeroMv, NOT_VALID );
      return;
    }
  
    TComCUMvField*  pcCUMvField = pcCU->getCUMvField( eRefPicList );
    rcMvField.setMvField( pcCUMvField->getMv( uiAbsPartIdx ), pcCUMvField->getRefIdx( uiAbsPartIdx ) );
  }
  
  Void TComDataCU::deriveLeftRightTopIdxGeneral ( UInt uiAbsPartIdx, UInt uiPartIdx, UInt& ruiPartIdxLT, UInt& ruiPartIdxRT )
  {
    ruiPartIdxLT = m_absZIdxInCtu + uiAbsPartIdx;
    UInt uiPUWidth = 0;
  
    switch ( m_pePartSize[uiAbsPartIdx] )
    {
      case SIZE_2Nx2N: uiPUWidth = m_puhWidth[uiAbsPartIdx];  break;
      case SIZE_2NxN:  uiPUWidth = m_puhWidth[uiAbsPartIdx];   break;
      case SIZE_Nx2N:  uiPUWidth = m_puhWidth[uiAbsPartIdx]  >> 1;  break;
      case SIZE_NxN:   uiPUWidth = m_puhWidth[uiAbsPartIdx]  >> 1; break;
      case SIZE_2NxnU:   uiPUWidth = m_puhWidth[uiAbsPartIdx]; break;
      case SIZE_2NxnD:   uiPUWidth = m_puhWidth[uiAbsPartIdx]; break;
      case SIZE_nLx2N:
        if ( uiPartIdx == 0 )
        {
          uiPUWidth = m_puhWidth[uiAbsPartIdx]  >> 2;
        }
        else if ( uiPartIdx == 1 )
        {
          uiPUWidth = (m_puhWidth[uiAbsPartIdx]  >> 1) + (m_puhWidth[uiAbsPartIdx]  >> 2);
        }
        else
        {
          assert(0);
        }
        break;
      case SIZE_nRx2N:
        if ( uiPartIdx == 0 )
        {
          uiPUWidth = (m_puhWidth[uiAbsPartIdx]  >> 1) + (m_puhWidth[uiAbsPartIdx]  >> 2);
        }
        else if ( uiPartIdx == 1 )
        {
          uiPUWidth = m_puhWidth[uiAbsPartIdx]  >> 2;
        }
        else
        {
          assert(0);
        }
        break;
      default:
        assert (0);
        break;
    }
  
    ruiPartIdxRT = g_auiRasterToZscan [g_auiZscanToRaster[ ruiPartIdxLT ] + uiPUWidth / m_pcPic->getMinCUWidth() - 1 ];
  }
  
  Void TComDataCU::deriveLeftBottomIdxGeneral( UInt uiAbsPartIdx, UInt uiPartIdx, UInt& ruiPartIdxLB )
  {
    UInt uiPUHeight = 0;
    switch ( m_pePartSize[uiAbsPartIdx] )
    {
      case SIZE_2Nx2N: uiPUHeight = m_puhHeight[uiAbsPartIdx];    break;
      case SIZE_2NxN:  uiPUHeight = m_puhHeight[uiAbsPartIdx] >> 1;    break;
      case SIZE_Nx2N:  uiPUHeight = m_puhHeight[uiAbsPartIdx];  break;
      case SIZE_NxN:   uiPUHeight = m_puhHeight[uiAbsPartIdx] >> 1;    break;
      case SIZE_2NxnU:
        if ( uiPartIdx == 0 )
        {
          uiPUHeight = m_puhHeight[uiAbsPartIdx] >> 2;
        }
        else if ( uiPartIdx == 1 )
        {
          uiPUHeight = (m_puhHeight[uiAbsPartIdx] >> 1) + (m_puhHeight[uiAbsPartIdx] >> 2);
        }
        else
        {
          assert(0);
        }
        break;
      case SIZE_2NxnD:
        if ( uiPartIdx == 0 )
        {
          uiPUHeight = (m_puhHeight[uiAbsPartIdx] >> 1) + (m_puhHeight[uiAbsPartIdx] >> 2);
        }
        else if ( uiPartIdx == 1 )
        {
          uiPUHeight = m_puhHeight[uiAbsPartIdx] >> 2;
        }
        else
        {
          assert(0);
        }
        break;
      case SIZE_nLx2N: uiPUHeight = m_puhHeight[uiAbsPartIdx];  break;
      case SIZE_nRx2N: uiPUHeight = m_puhHeight[uiAbsPartIdx];  break;
      default:
        assert (0);
        break;
    }
  
    ruiPartIdxLB      = g_auiRasterToZscan [g_auiZscanToRaster[ m_absZIdxInCtu + uiAbsPartIdx ] + ((uiPUHeight / m_pcPic->getMinCUHeight()) - 1)*m_pcPic->getNumPartInCtuWidth()];
  }
  
  Void TComDataCU::deriveLeftRightTopIdx ( UInt uiPartIdx, UInt& ruiPartIdxLT, UInt& ruiPartIdxRT )
  {
    ruiPartIdxLT = m_absZIdxInCtu;
    ruiPartIdxRT = g_auiRasterToZscan [g_auiZscanToRaster[ ruiPartIdxLT ] + m_puhWidth[0] / m_pcPic->getMinCUWidth() - 1 ];
  
    switch ( m_pePartSize[0] )
    {
      case SIZE_2Nx2N:                                                                                                                                break;
      case SIZE_2NxN:
        ruiPartIdxLT += ( uiPartIdx == 0 )? 0 : m_uiNumPartition >> 1; ruiPartIdxRT += ( uiPartIdx == 0 )? 0 : m_uiNumPartition >> 1;
        break;
      case SIZE_Nx2N:
        ruiPartIdxLT += ( uiPartIdx == 0 )? 0 : m_uiNumPartition >> 2; ruiPartIdxRT -= ( uiPartIdx == 1 )? 0 : m_uiNumPartition >> 2;
        break;
      case SIZE_NxN:
        ruiPartIdxLT += ( m_uiNumPartition >> 2 ) * uiPartIdx;         ruiPartIdxRT +=  ( m_uiNumPartition >> 2 ) * ( uiPartIdx - 1 );
        break;
      case SIZE_2NxnU:
        ruiPartIdxLT += ( uiPartIdx == 0 )? 0 : m_uiNumPartition >> 3;
        ruiPartIdxRT += ( uiPartIdx == 0 )? 0 : m_uiNumPartition >> 3;
        break;
      case SIZE_2NxnD:
        ruiPartIdxLT += ( uiPartIdx == 0 )? 0 : ( m_uiNumPartition >> 1 ) + ( m_uiNumPartition >> 3 );
        ruiPartIdxRT += ( uiPartIdx == 0 )? 0 : ( m_uiNumPartition >> 1 ) + ( m_uiNumPartition >> 3 );
        break;
      case SIZE_nLx2N:
        ruiPartIdxLT += ( uiPartIdx == 0 )? 0 : m_uiNumPartition >> 4;
        ruiPartIdxRT -= ( uiPartIdx == 1 )? 0 : ( m_uiNumPartition >> 2 ) + ( m_uiNumPartition >> 4 );
        break;
      case SIZE_nRx2N:
        ruiPartIdxLT += ( uiPartIdx == 0 )? 0 : ( m_uiNumPartition >> 2 ) + ( m_uiNumPartition >> 4 );
        ruiPartIdxRT -= ( uiPartIdx == 1 )? 0 : m_uiNumPartition >> 4;
        break;
      default:
        assert (0);
        break;
    }
  
  }
  
  Void TComDataCU::deriveLeftBottomIdx( UInt  uiPartIdx,      UInt&      ruiPartIdxLB )
  {
    ruiPartIdxLB      = g_auiRasterToZscan [g_auiZscanToRaster[ m_absZIdxInCtu ] + ( ((m_puhHeight[0] / m_pcPic->getMinCUHeight())>>1) - 1)*m_pcPic->getNumPartInCtuWidth()];
  
    switch ( m_pePartSize[0] )
    {
      case SIZE_2Nx2N:
        ruiPartIdxLB += m_uiNumPartition >> 1;
        break;
      case SIZE_2NxN:
        ruiPartIdxLB += ( uiPartIdx == 0 )? 0 : m_uiNumPartition >> 1;
        break;
      case SIZE_Nx2N:
        ruiPartIdxLB += ( uiPartIdx == 0 )? m_uiNumPartition >> 1 : (m_uiNumPartition >> 2)*3;
        break;
      case SIZE_NxN:
        ruiPartIdxLB += ( m_uiNumPartition >> 2 ) * uiPartIdx;
        break;
      case SIZE_2NxnU:
        ruiPartIdxLB += ( uiPartIdx == 0 ) ? -((Int)m_uiNumPartition >> 3) : m_uiNumPartition >> 1;
        break;
      case SIZE_2NxnD:
        ruiPartIdxLB += ( uiPartIdx == 0 ) ? (m_uiNumPartition >> 2) + (m_uiNumPartition >> 3): m_uiNumPartition >> 1;
        break;
      case SIZE_nLx2N:
        ruiPartIdxLB += ( uiPartIdx == 0 ) ? m_uiNumPartition >> 1 : (m_uiNumPartition >> 1) + (m_uiNumPartition >> 4);
        break;
      case SIZE_nRx2N:
        ruiPartIdxLB += ( uiPartIdx == 0 ) ? m_uiNumPartition >> 1 : (m_uiNumPartition >> 1) + (m_uiNumPartition >> 2) + (m_uiNumPartition >> 4);
        break;
      default:
        assert (0);
        break;
    }
  }
  
  /** Derive the partition index of neighbouring bottom right block
   * \param [in]  uiPartIdx     current partition index
   * \param [out] ruiPartIdxRB  partition index of neighbouring bottom right block
   */
  Void TComDataCU::deriveRightBottomIdx( UInt uiPartIdx, UInt &ruiPartIdxRB )
  {
    ruiPartIdxRB      = g_auiRasterToZscan [g_auiZscanToRaster[ m_absZIdxInCtu ] + ( ((m_puhHeight[0] / m_pcPic->getMinCUHeight())>>1) - 1)*m_pcPic->getNumPartInCtuWidth() +  m_puhWidth[0] / m_pcPic->getMinCUWidth() - 1];
  
    switch ( m_pePartSize[0] )
    {
      case SIZE_2Nx2N:
        ruiPartIdxRB += m_uiNumPartition >> 1;
        break;
      case SIZE_2NxN:
        ruiPartIdxRB += ( uiPartIdx == 0 )? 0 : m_uiNumPartition >> 1;
        break;
      case SIZE_Nx2N:
        ruiPartIdxRB += ( uiPartIdx == 0 )? m_uiNumPartition >> 2 : (m_uiNumPartition >> 1);
        break;
      case SIZE_NxN:
        ruiPartIdxRB += ( m_uiNumPartition >> 2 ) * ( uiPartIdx - 1 );
        break;
      case SIZE_2NxnU:
        ruiPartIdxRB += ( uiPartIdx == 0 ) ? -((Int)m_uiNumPartition >> 3) : m_uiNumPartition >> 1;
        break;
      case SIZE_2NxnD:
        ruiPartIdxRB += ( uiPartIdx == 0 ) ? (m_uiNumPartition >> 2) + (m_uiNumPartition >> 3): m_uiNumPartition >> 1;
        break;
      case SIZE_nLx2N:
        ruiPartIdxRB += ( uiPartIdx == 0 ) ? (m_uiNumPartition >> 3) + (m_uiNumPartition >> 4): m_uiNumPartition >> 1;
        break;
      case SIZE_nRx2N:
        ruiPartIdxRB += ( uiPartIdx == 0 ) ? (m_uiNumPartition >> 2) + (m_uiNumPartition >> 3) + (m_uiNumPartition >> 4) : m_uiNumPartition >> 1;
        break;
      default:
        assert (0);
        break;
    }
  }
  
  Void TComDataCU::deriveLeftRightTopIdxAdi ( UInt& ruiPartIdxLT, UInt& ruiPartIdxRT, UInt uiPartOffset, UInt uiPartDepth )
  {
    UInt uiNumPartInWidth = (m_puhWidth[0]/m_pcPic->getMinCUWidth())>>uiPartDepth;
    ruiPartIdxLT = m_absZIdxInCtu + uiPartOffset;
    ruiPartIdxRT = g_auiRasterToZscan[ g_auiZscanToRaster[ ruiPartIdxLT ] + uiNumPartInWidth - 1 ];
  }
  
  Void TComDataCU::deriveLeftBottomIdxAdi( UInt& ruiPartIdxLB, UInt uiPartOffset, UInt uiPartDepth )
  {
    UInt uiAbsIdx;
    UInt uiMinCuWidth, uiWidthInMinCus;
  
    uiMinCuWidth    = getPic()->getMinCUWidth();
    uiWidthInMinCus = (getWidth(0)/uiMinCuWidth)>>uiPartDepth;
    uiAbsIdx        = getZorderIdxInCtu()+uiPartOffset+(m_uiNumPartition>>(uiPartDepth<<1))-1;
    uiAbsIdx        = g_auiZscanToRaster[uiAbsIdx]-(uiWidthInMinCus-1);
    ruiPartIdxLB    = g_auiRasterToZscan[uiAbsIdx];
  }
  
  Bool TComDataCU::hasEqualMotion( UInt uiAbsPartIdx, TComDataCU* pcCandCU, UInt uiCandAbsPartIdx )
  {
    if ( getInterDir( uiAbsPartIdx ) != pcCandCU->getInterDir( uiCandAbsPartIdx ) )
    {
      return false;
    }
  
    for ( UInt uiRefListIdx = 0; uiRefListIdx < 2; uiRefListIdx++ )
    {
      if ( getInterDir( uiAbsPartIdx ) & ( 1 << uiRefListIdx ) )
      {
        if ( getCUMvField( RefPicList( uiRefListIdx ) )->getMv( uiAbsPartIdx )     != pcCandCU->getCUMvField( RefPicList( uiRefListIdx ) )->getMv( uiCandAbsPartIdx ) ||
          getCUMvField( RefPicList( uiRefListIdx ) )->getRefIdx( uiAbsPartIdx ) != pcCandCU->getCUMvField( RefPicList( uiRefListIdx ) )->getRefIdx( uiCandAbsPartIdx ) )
        {
          return false;
        }
      }
    }
  
    return true;
  }
  
  //! Construct a list of merging candidates
  Void TComDataCU::getInterMergeCandidates( UInt uiAbsPartIdx, UInt uiPUIdx, TComMvField* pcMvFieldNeighbours, UChar* puhInterDirNeighbours, Int& numValidMergeCand, Int mrgCandIdx )
  {
    UInt uiAbsPartAddr = m_absZIdxInCtu + uiAbsPartIdx;
    Bool abCandIsInter[ MRG_MAX_NUM_CANDS ];
    for( UInt ui = 0; ui < getSlice()->getMaxNumMergeCand(); ++ui )
    {
      abCandIsInter[ui] = false;
      pcMvFieldNeighbours[ ( ui << 1 )     ].setRefIdx(NOT_VALID);
      pcMvFieldNeighbours[ ( ui << 1 ) + 1 ].setRefIdx(NOT_VALID);
    }
    numValidMergeCand = getSlice()->getMaxNumMergeCand();
    // compute the location of the current PU
    Int xP, yP, nPSW, nPSH;
    this->getPartPosition(uiPUIdx, xP, yP, nPSW, nPSH);
  
    Int iCount = 0;
  
    UInt uiPartIdxLT, uiPartIdxRT, uiPartIdxLB;
    PartSize cCurPS = getPartitionSize( uiAbsPartIdx );
    deriveLeftRightTopIdxGeneral( uiAbsPartIdx, uiPUIdx, uiPartIdxLT, uiPartIdxRT );
    deriveLeftBottomIdxGeneral( uiAbsPartIdx, uiPUIdx, uiPartIdxLB );
  
    //left
    UInt uiLeftPartIdx = 0;
    TComDataCU* pcCULeft = 0;
    pcCULeft = getPULeft( uiLeftPartIdx, uiPartIdxLB );
  
    Bool isAvailableA1 = pcCULeft &&
                         pcCULeft->isDiffMER(xP -1, yP+nPSH-1, xP, yP) &&
                         !( uiPUIdx == 1 && (cCurPS == SIZE_Nx2N || cCurPS == SIZE_nLx2N || cCurPS == SIZE_nRx2N) ) &&
                         pcCULeft->isInter( uiLeftPartIdx ) ;
  
    if ( isAvailableA1 )
    {
      abCandIsInter[iCount] = true;
      // get Inter Dir
      puhInterDirNeighbours[iCount] = pcCULeft->getInterDir( uiLeftPartIdx );
      // get Mv from Left
      pcCULeft->getMvField( pcCULeft, uiLeftPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );
      if ( getSlice()->isInterB() )
      {
        pcCULeft->getMvField( pcCULeft, uiLeftPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );
      }
      if ( mrgCandIdx == iCount )
      {
        return;
      }
      iCount ++;
    }
  
    // early termination
    if (iCount == getSlice()->getMaxNumMergeCand())
    {
      return;
    }
    // above
    UInt uiAbovePartIdx = 0;
    TComDataCU* pcCUAbove = 0;
    pcCUAbove = getPUAbove( uiAbovePartIdx, uiPartIdxRT );
  
    Bool isAvailableB1 = pcCUAbove &&
                         pcCUAbove->isDiffMER(xP+nPSW-1, yP-1, xP, yP) &&
                         !( uiPUIdx == 1 && (cCurPS == SIZE_2NxN || cCurPS == SIZE_2NxnU || cCurPS == SIZE_2NxnD) ) &&
                         pcCUAbove->isInter( uiAbovePartIdx );
  
    if ( isAvailableB1 && (!isAvailableA1 || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCUAbove, uiAbovePartIdx ) ) )
    {
      abCandIsInter[iCount] = true;
      // get Inter Dir
      puhInterDirNeighbours[iCount] = pcCUAbove->getInterDir( uiAbovePartIdx );
      // get Mv from Left
      pcCUAbove->getMvField( pcCUAbove, uiAbovePartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );
      if ( getSlice()->isInterB() )
      {
        pcCUAbove->getMvField( pcCUAbove, uiAbovePartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );
      }
      if ( mrgCandIdx == iCount )
      {
        return;
      }
      iCount ++;
    }
    // early termination
    if (iCount == getSlice()->getMaxNumMergeCand())
    {
      return;
    }
  
    // above right
    UInt uiAboveRightPartIdx = 0;
    TComDataCU* pcCUAboveRight = 0;
    pcCUAboveRight = getPUAboveRight( uiAboveRightPartIdx, uiPartIdxRT );
  
    Bool isAvailableB0 = pcCUAboveRight &&
                         pcCUAboveRight->isDiffMER(xP+nPSW, yP-1, xP, yP) &&
                         pcCUAboveRight->isInter( uiAboveRightPartIdx );
  
    if ( isAvailableB0 && ( !isAvailableB1 || !pcCUAbove->hasEqualMotion( uiAbovePartIdx, pcCUAboveRight, uiAboveRightPartIdx ) ) )
    {
      abCandIsInter[iCount] = true;
      // get Inter Dir
      puhInterDirNeighbours[iCount] = pcCUAboveRight->getInterDir( uiAboveRightPartIdx );
      // get Mv from Left
      pcCUAboveRight->getMvField( pcCUAboveRight, uiAboveRightPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );
      if ( getSlice()->isInterB() )
      {
        pcCUAboveRight->getMvField( pcCUAboveRight, uiAboveRightPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );
      }
      if ( mrgCandIdx == iCount )
      {
        return;
      }
      iCount ++;
    }
    // early termination
    if (iCount == getSlice()->getMaxNumMergeCand())
    {
      return;
    }
  
    //left bottom
    UInt uiLeftBottomPartIdx = 0;
    TComDataCU* pcCULeftBottom = 0;
    pcCULeftBottom = this->getPUBelowLeft( uiLeftBottomPartIdx, uiPartIdxLB );
  
    Bool isAvailableA0 = pcCULeftBottom &&
                         pcCULeftBottom->isDiffMER(xP-1, yP+nPSH, xP, yP) &&
                         pcCULeftBottom->isInter( uiLeftBottomPartIdx ) ;
  
    if ( isAvailableA0 && ( !isAvailableA1 || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCULeftBottom, uiLeftBottomPartIdx ) ) )
    {
      abCandIsInter[iCount] = true;
      // get Inter Dir
      puhInterDirNeighbours[iCount] = pcCULeftBottom->getInterDir( uiLeftBottomPartIdx );
      // get Mv from Left
      pcCULeftBottom->getMvField( pcCULeftBottom, uiLeftBottomPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );
      if ( getSlice()->isInterB() )
      {
        pcCULeftBottom->getMvField( pcCULeftBottom, uiLeftBottomPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );
      }
      if ( mrgCandIdx == iCount )
      {
        return;
      }
      iCount ++;
    }
    // early termination
    if (iCount == getSlice()->getMaxNumMergeCand())
    {
      return;
    }
  
    // above left
    if( iCount < 4 )
    {
      UInt uiAboveLeftPartIdx = 0;
      TComDataCU* pcCUAboveLeft = 0;
      pcCUAboveLeft = getPUAboveLeft( uiAboveLeftPartIdx, uiAbsPartAddr );
  
      Bool isAvailableB2 = pcCUAboveLeft &&
                           pcCUAboveLeft->isDiffMER(xP-1, yP-1, xP, yP) &&
                           pcCUAboveLeft->isInter( uiAboveLeftPartIdx );
  
      if ( isAvailableB2 && ( !isAvailableA1 || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCUAboveLeft, uiAboveLeftPartIdx ) )
          && ( !isAvailableB1 || !pcCUAbove->hasEqualMotion( uiAbovePartIdx, pcCUAboveLeft, uiAboveLeftPartIdx ) ) )
      {
        abCandIsInter[iCount] = true;
        // get Inter Dir
        puhInterDirNeighbours[iCount] = pcCUAboveLeft->getInterDir( uiAboveLeftPartIdx );
        // get Mv from Left
        pcCUAboveLeft->getMvField( pcCUAboveLeft, uiAboveLeftPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );
        if ( getSlice()->isInterB() )
        {
          pcCUAboveLeft->getMvField( pcCUAboveLeft, uiAboveLeftPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );
        }
        if ( mrgCandIdx == iCount )
        {
          return;
        }
        iCount ++;
      }
    }
    // early termination
    if (iCount == getSlice()->getMaxNumMergeCand())
    {
      return;
    }
  
    if ( getSlice()->getEnableTMVPFlag() )
    {
      //>> MTK colocated-RightBottom
      UInt uiPartIdxRB;
  
      deriveRightBottomIdx( uiPUIdx, uiPartIdxRB );
  
      UInt uiAbsPartIdxTmp = g_auiZscanToRaster[uiPartIdxRB];
      const UInt numPartInCtuWidth  = m_pcPic->getNumPartInCtuWidth();
      const UInt numPartInCtuHeight = m_pcPic->getNumPartInCtuHeight();
  
      TComMv cColMv;
      Int iRefIdx;
      Int ctuRsAddr = -1;
  
      if (   ( ( m_pcPic->getCtu(m_ctuRsAddr)->getCUPelX() + g_auiRasterToPelX[uiAbsPartIdxTmp] + m_pcPic->getMinCUWidth () ) < m_pcSlice->getSPS()->getPicWidthInLumaSamples () )  // image boundary check
          && ( ( m_pcPic->getCtu(m_ctuRsAddr)->getCUPelY() + g_auiRasterToPelY[uiAbsPartIdxTmp] + m_pcPic->getMinCUHeight() ) < m_pcSlice->getSPS()->getPicHeightInLumaSamples() ) )
      {
        if ( ( uiAbsPartIdxTmp % numPartInCtuWidth < numPartInCtuWidth - 1 ) &&           // is not at the last column of CTU
          ( uiAbsPartIdxTmp / numPartInCtuWidth < numPartInCtuHeight - 1 ) )              // is not at the last row    of CTU
        {
          uiAbsPartAddr = g_auiRasterToZscan[ uiAbsPartIdxTmp + numPartInCtuWidth + 1 ];
          ctuRsAddr = getCtuRsAddr();
        }
        else if ( uiAbsPartIdxTmp % numPartInCtuWidth < numPartInCtuWidth - 1 )           // is not at the last column of CTU But is last row of CTU
        {
          uiAbsPartAddr = g_auiRasterToZscan[ (uiAbsPartIdxTmp + numPartInCtuWidth + 1) % m_pcPic->getNumPartitionsInCtu() ];
        }
        else if ( uiAbsPartIdxTmp / numPartInCtuWidth < numPartInCtuHeight - 1 )          // is not at the last row of CTU But is last column of CTU
        {
          uiAbsPartAddr = g_auiRasterToZscan[ uiAbsPartIdxTmp + 1 ];
          ctuRsAddr = getCtuRsAddr() + 1;
        }
        else //is the right bottom corner of CTU
        {
          uiAbsPartAddr = 0;
        }
      }
  
      iRefIdx = 0;
  
      Bool bExistMV = false;
      UInt uiPartIdxCenter;
      Int dir = 0;
      UInt uiArrayAddr = iCount;
      xDeriveCenterIdx( uiPUIdx, uiPartIdxCenter );
      bExistMV = ctuRsAddr >= 0 && xGetColMVP( REF_PIC_LIST_0, ctuRsAddr, uiAbsPartAddr, cColMv, iRefIdx );
      if( bExistMV == false )
      {
        bExistMV = xGetColMVP( REF_PIC_LIST_0, getCtuRsAddr(), uiPartIdxCenter,  cColMv, iRefIdx );
      }
      if( bExistMV )
      {
        dir |= 1;
        pcMvFieldNeighbours[ 2 * uiArrayAddr ].setMvField( cColMv, iRefIdx );
      }
  
      if ( getSlice()->isInterB() )
      {
        bExistMV = ctuRsAddr >= 0 && xGetColMVP( REF_PIC_LIST_1, ctuRsAddr, uiAbsPartAddr, cColMv, iRefIdx);
        if( bExistMV == false )
        {
          bExistMV = xGetColMVP( REF_PIC_LIST_1, getCtuRsAddr(), uiPartIdxCenter, cColMv, iRefIdx );
        }
        if( bExistMV )
        {
          dir |= 2;
          pcMvFieldNeighbours[ 2 * uiArrayAddr + 1 ].setMvField( cColMv, iRefIdx );
        }
      }
  
      if (dir != 0)
      {
        puhInterDirNeighbours[uiArrayAddr] = dir;
        abCandIsInter[uiArrayAddr] = true;
  
        if ( mrgCandIdx == iCount )
        {
          return;
        }
        iCount++;
      }
    }
    // early termination
    if (iCount == getSlice()->getMaxNumMergeCand())
    {
      return;
    }
  
    UInt uiArrayAddr = iCount;
    UInt uiCutoff = uiArrayAddr;
  
    if ( getSlice()->isInterB() )
    {
      static const UInt NUM_PRIORITY_LIST=12;
      static const UInt uiPriorityList0[NUM_PRIORITY_LIST] = {0 , 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3};
      static const UInt uiPriorityList1[NUM_PRIORITY_LIST] = {1 , 0, 2, 0, 2, 1, 3, 0, 3, 1, 3, 2};
  
      for (Int idx=0; idx<uiCutoff*(uiCutoff-1) && uiArrayAddr!= getSlice()->getMaxNumMergeCand(); idx++)
      {
        assert(idx<NUM_PRIORITY_LIST);
        Int i = uiPriorityList0[idx];
        Int j = uiPriorityList1[idx];
        if (abCandIsInter[i] && abCandIsInter[j]&& (puhInterDirNeighbours[i]&0x1)&&(puhInterDirNeighbours[j]&0x2))
        {
          abCandIsInter[uiArrayAddr] = true;
          puhInterDirNeighbours[uiArrayAddr] = 3;
  
          // get Mv from cand[i] and cand[j]
          pcMvFieldNeighbours[uiArrayAddr << 1].setMvField(pcMvFieldNeighbours[i<<1].getMv(), pcMvFieldNeighbours[i<<1].getRefIdx());
          pcMvFieldNeighbours[( uiArrayAddr << 1 ) + 1].setMvField(pcMvFieldNeighbours[(j<<1)+1].getMv(), pcMvFieldNeighbours[(j<<1)+1].getRefIdx());
  
          Int iRefPOCL0 = m_pcSlice->getRefPOC( REF_PIC_LIST_0, pcMvFieldNeighbours[(uiArrayAddr<<1)].getRefIdx() );
          Int iRefPOCL1 = m_pcSlice->getRefPOC( REF_PIC_LIST_1, pcMvFieldNeighbours[(uiArrayAddr<<1)+1].getRefIdx() );
          if (iRefPOCL0 == iRefPOCL1 && pcMvFieldNeighbours[(uiArrayAddr<<1)].getMv() == pcMvFieldNeighbours[(uiArrayAddr<<1)+1].getMv())
          {
            abCandIsInter[uiArrayAddr] = false;
          }
          else
          {
            uiArrayAddr++;
          }
        }
      }
    }
    // early termination
    if (uiArrayAddr == getSlice()->getMaxNumMergeCand())
    {
      return;
    }
  
    Int iNumRefIdx = (getSlice()->isInterB()) ? min(m_pcSlice->getNumRefIdx(REF_PIC_LIST_0), m_pcSlice->getNumRefIdx(REF_PIC_LIST_1)) : m_pcSlice->getNumRefIdx(REF_PIC_LIST_0);
  
    Int r = 0;
    Int refcnt = 0;
    while (uiArrayAddr < getSlice()->getMaxNumMergeCand())
    {
      abCandIsInter[uiArrayAddr] = true;
      puhInterDirNeighbours[uiArrayAddr] = 1;
      pcMvFieldNeighbours[uiArrayAddr << 1].setMvField( TComMv(0, 0), r);
  
      if ( getSlice()->isInterB() )
      {
        puhInterDirNeighbours[uiArrayAddr] = 3;
        pcMvFieldNeighbours[(uiArrayAddr << 1) + 1].setMvField(TComMv(0, 0), r);
      }
      uiArrayAddr++;
  
      if ( refcnt == iNumRefIdx - 1 )
      {
        r = 0;
      }
      else
      {
        ++r;
        ++refcnt;
      }
    }
    numValidMergeCand = uiArrayAddr;
  }
  
  /** Check whether the current PU and a spatial neighboring PU are in a same ME region.
   * \param xN, yN   location of the upper-left corner pixel of a neighboring PU
   * \param xP, yP   location of the upper-left corner pixel of the current PU
   */
  Bool TComDataCU::isDiffMER(Int xN, Int yN, Int xP, Int yP)
  {
  
    UInt plevel = this->getSlice()->getPPS()->getLog2ParallelMergeLevelMinus2() + 2;
    if ((xN>>plevel)!= (xP>>plevel))
    {
      return true;
    }
    if ((yN>>plevel)!= (yP>>plevel))
    {
      return true;
    }
    return false;
  }
  
  /** Calculate the location of upper-left corner pixel and size of the current PU.
   * \param partIdx       PU index within a CU
   * \param xP, yP        location of the upper-left corner pixel of the current PU
   * \param nPSW, nPSH    size of the current PU
   */
  Void TComDataCU::getPartPosition( UInt partIdx, Int& xP, Int& yP, Int& nPSW, Int& nPSH)
  {
    UInt col = m_uiCUPelX;
    UInt row = m_uiCUPelY;
  
    switch ( m_pePartSize[0] )
    {
    case SIZE_2NxN:
      nPSW = getWidth(0);
      nPSH = getHeight(0) >> 1;
      xP   = col;
      yP   = (partIdx ==0)? row: row + nPSH;
      break;
    case SIZE_Nx2N:
      nPSW = getWidth(0) >> 1;
      nPSH = getHeight(0);
      xP   = (partIdx ==0)? col: col + nPSW;
      yP   = row;
      break;
    case SIZE_NxN:
      nPSW = getWidth(0) >> 1;
      nPSH = getHeight(0) >> 1;
      xP   = col + (partIdx&0x1)*nPSW;
      yP   = row + (partIdx>>1)*nPSH;
      break;
    case SIZE_2NxnU:
      nPSW = getWidth(0);
      nPSH = ( partIdx == 0 ) ?  getHeight(0) >> 2 : ( getHeight(0) >> 2 ) + ( getHeight(0) >> 1 );
      xP   = col;
      yP   = (partIdx ==0)? row: row + getHeight(0) - nPSH;
  
      break;
    case SIZE_2NxnD:
      nPSW = getWidth(0);
      nPSH = ( partIdx == 0 ) ?  ( getHeight(0) >> 2 ) + ( getHeight(0) >> 1 ) : getHeight(0) >> 2;
      xP   = col;
      yP   = (partIdx ==0)? row: row + getHeight(0) - nPSH;
      break;
    case SIZE_nLx2N:
      nPSW = ( partIdx == 0 ) ? getWidth(0) >> 2 : ( getWidth(0) >> 2 ) + ( getWidth(0) >> 1 );
      nPSH = getHeight(0);
      xP   = (partIdx ==0)? col: col + getWidth(0) - nPSW;
      yP   = row;
      break;
    case SIZE_nRx2N:
      nPSW = ( partIdx == 0 ) ? ( getWidth(0) >> 2 ) + ( getWidth(0) >> 1 ) : getWidth(0) >> 2;
      nPSH = getHeight(0);
      xP   = (partIdx ==0)? col: col + getWidth(0) - nPSW;
      yP   = row;
      break;
    default:
      assert ( m_pePartSize[0] == SIZE_2Nx2N );
      nPSW = getWidth(0);
      nPSH = getHeight(0);
      xP   = col ;
      yP   = row ;
  
      break;
    }
  }
  
  /** Constructs a list of candidates for AMVP
   * \param uiPartIdx
   * \param uiPartAddr
   * \param eRefPicList
   * \param iRefIdx
   * \param pInfo
   */
  Void TComDataCU::fillMvpCand ( UInt uiPartIdx, UInt uiPartAddr, RefPicList eRefPicList, Int iRefIdx, AMVPInfo* pInfo )
  {
    TComMv cMvPred;
    Bool bAddedSmvp = false;
  
    pInfo->iN = 0;
    if (iRefIdx < 0)
    {
      return;
    }
  
    //-- Get Spatial MV
    UInt uiPartIdxLT, uiPartIdxRT, uiPartIdxLB;
    const UInt numPartInCtuWidth  = m_pcPic->getNumPartInCtuWidth();
    const UInt numPartInCtuHeight = m_pcPic->getNumPartInCtuHeight();
    Bool bAdded = false;
  
    deriveLeftRightTopIdx( uiPartIdx, uiPartIdxLT, uiPartIdxRT );
    deriveLeftBottomIdx( uiPartIdx, uiPartIdxLB );
  
    TComDataCU* tmpCU = NULL;
    UInt idx;
    tmpCU = getPUBelowLeft(idx, uiPartIdxLB);
    bAddedSmvp = (tmpCU != NULL) && (tmpCU->isInter(idx));
  
    if (!bAddedSmvp)
    {
      tmpCU = getPULeft(idx, uiPartIdxLB);
      bAddedSmvp = (tmpCU != NULL) && (tmpCU->isInter(idx));
    }
  
    // Left predictor search
    bAdded = xAddMVPCand( pInfo, eRefPicList, iRefIdx, uiPartIdxLB, MD_BELOW_LEFT);
    if (!bAdded)
    {
      bAdded = xAddMVPCand( pInfo, eRefPicList, iRefIdx, uiPartIdxLB, MD_LEFT );
    }
  
    if(!bAdded)
    {
      bAdded = xAddMVPCandOrder( pInfo, eRefPicList, iRefIdx, uiPartIdxLB, MD_BELOW_LEFT);
      if (!bAdded)
      {
        xAddMVPCandOrder( pInfo, eRefPicList, iRefIdx, uiPartIdxLB, MD_LEFT );
      }
    }
  
    // Above predictor search
    bAdded = xAddMVPCand( pInfo, eRefPicList, iRefIdx, uiPartIdxRT, MD_ABOVE_RIGHT);
  
    if (!bAdded)
    {
      bAdded = xAddMVPCand( pInfo, eRefPicList, iRefIdx, uiPartIdxRT, MD_ABOVE);
    }
  
    if(!bAdded)
    {
      xAddMVPCand( pInfo, eRefPicList, iRefIdx, uiPartIdxLT, MD_ABOVE_LEFT);
    }
  
    if(!bAddedSmvp)
    {
      bAdded = xAddMVPCandOrder( pInfo, eRefPicList, iRefIdx, uiPartIdxRT, MD_ABOVE_RIGHT);
      if (!bAdded)
      {
        bAdded = xAddMVPCandOrder( pInfo, eRefPicList, iRefIdx, uiPartIdxRT, MD_ABOVE);
      }
  
      if(!bAdded)
      {
        xAddMVPCandOrder( pInfo, eRefPicList, iRefIdx, uiPartIdxLT, MD_ABOVE_LEFT);
      }
    }
  
    if ( pInfo->iN == 2 )
    {
      if ( pInfo->m_acMvCand[ 0 ] == pInfo->m_acMvCand[ 1 ] )
      {
        pInfo->iN = 1;
      }
    }
  
    if ( getSlice()->getEnableTMVPFlag() )
    {
      // Get Temporal Motion Predictor
      Int iRefIdx_Col = iRefIdx;
      TComMv cColMv;
      UInt uiPartIdxRB;
      UInt uiAbsPartIdx;
      UInt uiAbsPartAddr;
  
      deriveRightBottomIdx( uiPartIdx, uiPartIdxRB );
      uiAbsPartAddr = m_absZIdxInCtu + uiPartAddr;
  
      //----  co-located RightBottom Temporal Predictor (H) ---//
      uiAbsPartIdx = g_auiZscanToRaster[uiPartIdxRB];
      Int ctuRsAddr = -1;
      if (  ( ( m_pcPic->getCtu(m_ctuRsAddr)->getCUPelX() + g_auiRasterToPelX[uiAbsPartIdx] + m_pcPic->getMinCUWidth () ) < m_pcSlice->getSPS()->getPicWidthInLumaSamples () )  // image boundary check
         && ( ( m_pcPic->getCtu(m_ctuRsAddr)->getCUPelY() + g_auiRasterToPelY[uiAbsPartIdx] + m_pcPic->getMinCUHeight() ) < m_pcSlice->getSPS()->getPicHeightInLumaSamples() ) )
      {
        if ( ( uiAbsPartIdx % numPartInCtuWidth < numPartInCtuWidth - 1 ) &&  // is not at the last column of CTU
             ( uiAbsPartIdx / numPartInCtuWidth < numPartInCtuHeight - 1 ) )  // is not at the last row    of CTU
        {
          uiAbsPartAddr = g_auiRasterToZscan[ uiAbsPartIdx + numPartInCtuWidth + 1 ];
          ctuRsAddr = getCtuRsAddr();
        }
        else if ( uiAbsPartIdx % numPartInCtuWidth < numPartInCtuWidth - 1 )  // is not at the last column of CTU But is last row of CTU
        {
          uiAbsPartAddr = g_auiRasterToZscan[ (uiAbsPartIdx + numPartInCtuWidth + 1) % m_pcPic->getNumPartitionsInCtu() ];
        }
        else if ( uiAbsPartIdx / numPartInCtuWidth < numPartInCtuHeight - 1 ) // is not at the last row of CTU But is last column of CTU
        {
          uiAbsPartAddr = g_auiRasterToZscan[ uiAbsPartIdx + 1 ];
          ctuRsAddr = getCtuRsAddr() + 1;
        }
        else //is the right bottom corner of CTU
        {
          uiAbsPartAddr = 0;
        }
      }
      if ( ctuRsAddr >= 0 && xGetColMVP( eRefPicList, ctuRsAddr, uiAbsPartAddr, cColMv, iRefIdx_Col ) )
      {
        pInfo->m_acMvCand[pInfo->iN++] = cColMv;
      }
      else
      {
        UInt uiPartIdxCenter;
        xDeriveCenterIdx( uiPartIdx, uiPartIdxCenter );
        if (xGetColMVP( eRefPicList, getCtuRsAddr(), uiPartIdxCenter,  cColMv, iRefIdx_Col ))
        {
          pInfo->m_acMvCand[pInfo->iN++] = cColMv;
        }
      }
      //----  co-located RightBottom Temporal Predictor  ---//
    }
  
    if (pInfo->iN > AMVP_MAX_NUM_CANDS)
    {
      pInfo->iN = AMVP_MAX_NUM_CANDS;
    }
  
    while (pInfo->iN < AMVP_MAX_NUM_CANDS)
    {
      pInfo->m_acMvCand[pInfo->iN].set(0,0);
      pInfo->iN++;
    }
    return ;
  }
  
  
  Bool TComDataCU::isBipredRestriction(UInt puIdx)
  {
    Int width = 0;
    Int height = 0;
    UInt partAddr;
  
    getPartIndexAndSize( puIdx, partAddr, width, height );
    if ( getWidth(0) == 8 && (width < 8 || height < 8) )
    {
      return true;
    }
    return false;
  }
  
  
  Void TComDataCU::clipMv    (TComMv&  rcMv)
  {
    const TComSPS &sps=*(m_pcSlice->getSPS());
    Int  iMvShift = 2;
    Int iOffset = 8;
    Int iHorMax = ( sps.getPicWidthInLumaSamples() + iOffset - (Int)m_uiCUPelX - 1 ) << iMvShift;
    Int iHorMin = (      -(Int)sps.getMaxCUWidth() - iOffset - (Int)m_uiCUPelX + 1 ) << iMvShift;
  
    Int iVerMax = ( sps.getPicHeightInLumaSamples() + iOffset - (Int)m_uiCUPelY - 1 ) << iMvShift;
    Int iVerMin = (      -(Int)sps.getMaxCUHeight() - iOffset - (Int)m_uiCUPelY + 1 ) << iMvShift;
  
    rcMv.setHor( min (iHorMax, max (iHorMin, rcMv.getHor())) );
    rcMv.setVer( min (iVerMax, max (iVerMin, rcMv.getVer())) );
  }
  
  
  UInt TComDataCU::getIntraSizeIdx(UInt uiAbsPartIdx)
  {
    UInt uiShift = ( m_pePartSize[uiAbsPartIdx]==SIZE_NxN ? 1 : 0 );
  
    UChar uiWidth = m_puhWidth[uiAbsPartIdx]>>uiShift;
    UInt  uiCnt = 0;
    while( uiWidth )
    {
      uiCnt++;
      uiWidth>>=1;
    }
    uiCnt-=2;
    return uiCnt > 6 ? 6 : uiCnt;
  }
  
  Void TComDataCU::clearCbf( UInt uiIdx, ComponentID compID, UInt uiNumParts )
  {
    memset( &m_puhCbf[compID][uiIdx], 0, sizeof(UChar)*uiNumParts);
  }
  
  /** Set a I_PCM flag for all sub-partitions of a partition.
   * \param bIpcmFlag I_PCM flag
   * \param uiAbsPartIdx patition index
   * \param uiDepth CU depth
   * \returns Void
   */
  Void TComDataCU::setIPCMFlagSubParts  (Bool bIpcmFlag, UInt uiAbsPartIdx, UInt uiDepth)
  {
    UInt uiCurrPartNumb = m_pcPic->getNumPartitionsInCtu() >> (uiDepth << 1);
  
    memset(m_pbIPCMFlag + uiAbsPartIdx, bIpcmFlag, sizeof(Bool)*uiCurrPartNumb );
  }
  
  /** Test whether the block at uiPartIdx is skipped.
   * \param uiPartIdx Partition index
   * \returns true if the current the block is skipped
   */
  Bool TComDataCU::isSkipped( UInt uiPartIdx )
  {
    return ( getSkipFlag( uiPartIdx ) );
  }
  
  // ====================================================================================================================
  // Protected member functions
  // ====================================================================================================================
  
  Bool TComDataCU::xAddMVPCand( AMVPInfo* pInfo, RefPicList eRefPicList, Int iRefIdx, UInt uiPartUnitIdx, MVP_DIR eDir )
  {
    TComDataCU* pcTmpCU = NULL;
    UInt uiIdx;
    switch( eDir )
    {
      case MD_LEFT:
      {
        pcTmpCU = getPULeft(uiIdx, uiPartUnitIdx);
        break;
      }
      case MD_ABOVE:
      {
        pcTmpCU = getPUAbove(uiIdx, uiPartUnitIdx);
        break;
      }
      case MD_ABOVE_RIGHT:
      {
        pcTmpCU = getPUAboveRight(uiIdx, uiPartUnitIdx);
        break;
      }
      case MD_BELOW_LEFT:
      {
        pcTmpCU = getPUBelowLeft(uiIdx, uiPartUnitIdx);
        break;
      }
      case MD_ABOVE_LEFT:
      {
        pcTmpCU = getPUAboveLeft(uiIdx, uiPartUnitIdx);
        break;
      }
      default:
      {
        break;
      }
    }
  
    if ( pcTmpCU == NULL )
    {
      return false;
    }
  
    if ( pcTmpCU->getCUMvField(eRefPicList)->getRefIdx(uiIdx) >= 0 && m_pcSlice->getRefPic( eRefPicList, iRefIdx)->getPOC() == pcTmpCU->getSlice()->getRefPOC( eRefPicList, pcTmpCU->getCUMvField(eRefPicList)->getRefIdx(uiIdx) ))
    {
      TComMv cMvPred = pcTmpCU->getCUMvField(eRefPicList)->getMv(uiIdx);
  
      pInfo->m_acMvCand[ pInfo->iN++] = cMvPred;
      return true;
    }
  
    RefPicList eRefPicList2nd = REF_PIC_LIST_0;
    if(       eRefPicList == REF_PIC_LIST_0 )
    {
      eRefPicList2nd = REF_PIC_LIST_1;
    }
    else if ( eRefPicList == REF_PIC_LIST_1)
    {
      eRefPicList2nd = REF_PIC_LIST_0;
    }
  
  
    Int iCurrRefPOC = m_pcSlice->getRefPic( eRefPicList, iRefIdx)->getPOC();
    Int iNeibRefPOC;
  
  
    if( pcTmpCU->getCUMvField(eRefPicList2nd)->getRefIdx(uiIdx) >= 0 )
    {
      iNeibRefPOC = pcTmpCU->getSlice()->getRefPOC( eRefPicList2nd, pcTmpCU->getCUMvField(eRefPicList2nd)->getRefIdx(uiIdx) );
      if( iNeibRefPOC == iCurrRefPOC ) // Same Reference Frame But Diff List//
      {
        TComMv cMvPred = pcTmpCU->getCUMvField(eRefPicList2nd)->getMv(uiIdx);
        pInfo->m_acMvCand[ pInfo->iN++] = cMvPred;
        return true;
      }
    }
    return false;
  }
  
  /**
   * \param pInfo
   * \param eRefPicList
   * \param iRefIdx
   * \param uiPartUnitIdx
   * \param eDir
   * \returns Bool
   */
  Bool TComDataCU::xAddMVPCandOrder( AMVPInfo* pInfo, RefPicList eRefPicList, Int iRefIdx, UInt uiPartUnitIdx, MVP_DIR eDir )
  {
    TComDataCU* pcTmpCU = NULL;
    UInt uiIdx;
    switch( eDir )
    {
    case MD_LEFT:
      {
        pcTmpCU = getPULeft(uiIdx, uiPartUnitIdx);
        break;
      }
    case MD_ABOVE:
      {
        pcTmpCU = getPUAbove(uiIdx, uiPartUnitIdx);
        break;
      }
    case MD_ABOVE_RIGHT:
      {
        pcTmpCU = getPUAboveRight(uiIdx, uiPartUnitIdx);
        break;
      }
    case MD_BELOW_LEFT:
      {
        pcTmpCU = getPUBelowLeft(uiIdx, uiPartUnitIdx);
        break;
      }
    case MD_ABOVE_LEFT:
      {
        pcTmpCU = getPUAboveLeft(uiIdx, uiPartUnitIdx);
        break;
      }
    default:
      {
        break;
      }
    }
  
    if ( pcTmpCU == NULL )
    {
      return false;
    }
  
    RefPicList eRefPicList2nd = REF_PIC_LIST_0;
    if(       eRefPicList == REF_PIC_LIST_0 )
    {
      eRefPicList2nd = REF_PIC_LIST_1;
    }
    else if ( eRefPicList == REF_PIC_LIST_1)
    {
      eRefPicList2nd = REF_PIC_LIST_0;
    }
  
    Int iCurrPOC = m_pcSlice->getPOC();
    Int iCurrRefPOC = m_pcSlice->getRefPic( eRefPicList, iRefIdx)->getPOC();
    Int iNeibPOC = iCurrPOC;
    Int iNeibRefPOC;
    Bool bIsCurrRefLongTerm = m_pcSlice->getRefPic( eRefPicList, iRefIdx)->getIsLongTerm();
    Bool bIsNeibRefLongTerm = false;
  
    //---------------  V1 (END) ------------------//
    if( pcTmpCU->getCUMvField(eRefPicList)->getRefIdx(uiIdx) >= 0)
    {
      iNeibRefPOC = pcTmpCU->getSlice()->getRefPOC( eRefPicList, pcTmpCU->getCUMvField(eRefPicList)->getRefIdx(uiIdx) );
      TComMv cMvPred = pcTmpCU->getCUMvField(eRefPicList)->getMv(uiIdx);
      TComMv rcMv;
  
      bIsNeibRefLongTerm = pcTmpCU->getSlice()->getRefPic( eRefPicList, pcTmpCU->getCUMvField(eRefPicList)->getRefIdx(uiIdx) )->getIsLongTerm();
      if ( bIsCurrRefLongTerm == bIsNeibRefLongTerm )
      {
        if ( bIsCurrRefLongTerm || bIsNeibRefLongTerm )
        {
          rcMv = cMvPred;
        }
        else
        {
          Int iScale = xGetDistScaleFactor( iCurrPOC, iCurrRefPOC, iNeibPOC, iNeibRefPOC );
          if ( iScale == 4096 )
          {
            rcMv = cMvPred;
          }
          else
          {
            rcMv = cMvPred.scaleMv( iScale );
          }
        }
  
        pInfo->m_acMvCand[ pInfo->iN++] = rcMv;
        return true;
      }
    }
    //---------------------- V2(END) --------------------//
    if( pcTmpCU->getCUMvField(eRefPicList2nd)->getRefIdx(uiIdx) >= 0)
    {
      iNeibRefPOC = pcTmpCU->getSlice()->getRefPOC( eRefPicList2nd, pcTmpCU->getCUMvField(eRefPicList2nd)->getRefIdx(uiIdx) );
      TComMv cMvPred = pcTmpCU->getCUMvField(eRefPicList2nd)->getMv(uiIdx);
      TComMv rcMv;
  
      bIsNeibRefLongTerm = pcTmpCU->getSlice()->getRefPic( eRefPicList2nd, pcTmpCU->getCUMvField(eRefPicList2nd)->getRefIdx(uiIdx) )->getIsLongTerm();
      if ( bIsCurrRefLongTerm == bIsNeibRefLongTerm )
      {
        if ( bIsCurrRefLongTerm || bIsNeibRefLongTerm )
        {
          rcMv = cMvPred;
        }
        else
        {
          Int iScale = xGetDistScaleFactor( iCurrPOC, iCurrRefPOC, iNeibPOC, iNeibRefPOC );
          if ( iScale == 4096 )
          {
            rcMv = cMvPred;
          }
          else
          {
            rcMv = cMvPred.scaleMv( iScale );
          }
        }
  
        pInfo->m_acMvCand[ pInfo->iN++] = rcMv;
        return true;
      }
    }
    //---------------------- V3(END) --------------------//
    return false;
  }
  
  Bool TComDataCU::xGetColMVP( RefPicList eRefPicList, Int ctuRsAddr, Int uiPartUnitIdx, TComMv& rcMv, Int& riRefIdx )
  {
    UInt uiAbsPartAddr = uiPartUnitIdx;
  
    RefPicList  eColRefPicList;
    Int iColPOC, iColRefPOC, iCurrPOC, iCurrRefPOC, iScale;
    TComMv cColMv;
  
    // use coldir.
    TComPic *pColPic = getSlice()->getRefPic( RefPicList(getSlice()->isInterB() ? 1-getSlice()->getColFromL0Flag() : 0), getSlice()->getColRefIdx());
    TComDataCU *pColCtu = pColPic->getCtu( ctuRsAddr );
    if(pColCtu->getPic()==0||pColCtu->getPartitionSize(uiPartUnitIdx)==NUMBER_OF_PART_SIZES)
    {
      return false;
    }
    iCurrPOC = m_pcSlice->getPOC();
    iColPOC = pColCtu->getSlice()->getPOC();
  
    if (!pColCtu->isInter(uiAbsPartAddr))
    {
      return false;
    }
  
    eColRefPicList = getSlice()->getCheckLDC() ? eRefPicList : RefPicList(getSlice()->getColFromL0Flag());
  
    Int iColRefIdx = pColCtu->getCUMvField(RefPicList(eColRefPicList))->getRefIdx(uiAbsPartAddr);
  
    if (iColRefIdx < 0 )
    {
      eColRefPicList = RefPicList(1 - eColRefPicList);
      iColRefIdx = pColCtu->getCUMvField(RefPicList(eColRefPicList))->getRefIdx(uiAbsPartAddr);
  
      if (iColRefIdx < 0 )
      {
        return false;
      }
    }
  
    // Scale the vector.
    iColRefPOC = pColCtu->getSlice()->getRefPOC(eColRefPicList, iColRefIdx);
    cColMv = pColCtu->getCUMvField(eColRefPicList)->getMv(uiAbsPartAddr);
  
    iCurrRefPOC = m_pcSlice->getRefPic(eRefPicList, riRefIdx)->getPOC();
  
    Bool bIsCurrRefLongTerm = m_pcSlice->getRefPic(eRefPicList, riRefIdx)->getIsLongTerm();
    Bool bIsColRefLongTerm = pColCtu->getSlice()->getIsUsedAsLongTerm(eColRefPicList, iColRefIdx);
  
    if ( bIsCurrRefLongTerm != bIsColRefLongTerm )
    {
      return false;
    }
  
    if ( bIsCurrRefLongTerm || bIsColRefLongTerm )
    {
      rcMv = cColMv;
    }
    else
    {
      iScale = xGetDistScaleFactor(iCurrPOC, iCurrRefPOC, iColPOC, iColRefPOC);
      if ( iScale == 4096 )
      {
        rcMv = cColMv;
      }
      else
      {
        rcMv = cColMv.scaleMv( iScale );
      }
    }
  
    return true;
  }
  
  UInt TComDataCU::xGetMvdBits(TComMv cMvd)
  {
    return ( xGetComponentBits(cMvd.getHor()) + xGetComponentBits(cMvd.getVer()) );
  }
  
  UInt TComDataCU::xGetComponentBits(Int iVal)
  {
    UInt uiLength = 1;
    UInt uiTemp   = ( iVal <= 0) ? (-iVal<<1)+1: (iVal<<1);
  
    assert ( uiTemp );
  
    while ( 1 != uiTemp )
    {
      uiTemp >>= 1;
      uiLength += 2;
    }
  
    return uiLength;
  }
  
  
  Int TComDataCU::xGetDistScaleFactor(Int iCurrPOC, Int iCurrRefPOC, Int iColPOC, Int iColRefPOC)
  {
    Int iDiffPocD = iColPOC - iColRefPOC;
    Int iDiffPocB = iCurrPOC - iCurrRefPOC;
  
    if( iDiffPocD == iDiffPocB )
    {
      return 4096;
    }
    else
    {
      Int iTDB      = Clip3( -128, 127, iDiffPocB );
      Int iTDD      = Clip3( -128, 127, iDiffPocD );
      Int iX        = (0x4000 + abs(iTDD/2)) / iTDD;
      Int iScale    = Clip3( -4096, 4095, (iTDB * iX + 32) >> 6 );
      return iScale;
    }
  }
  
  Void TComDataCU::xDeriveCenterIdx( UInt uiPartIdx, UInt& ruiPartIdxCenter )
  {
    UInt uiPartAddr;
    Int  iPartWidth;
    Int  iPartHeight;
    getPartIndexAndSize( uiPartIdx, uiPartAddr, iPartWidth, iPartHeight);
  
    ruiPartIdxCenter = m_absZIdxInCtu+uiPartAddr; // partition origin.
    ruiPartIdxCenter = g_auiRasterToZscan[ g_auiZscanToRaster[ ruiPartIdxCenter ]
                                          + ( iPartHeight/m_pcPic->getMinCUHeight()  )/2*m_pcPic->getNumPartInCtuWidth()
                                          + ( iPartWidth/m_pcPic->getMinCUWidth()  )/2];
  }
  
  Void TComDataCU::compressMV()
  {
    Int scaleFactor = 4 * AMVP_DECIMATION_FACTOR / m_unitSize;
    if (scaleFactor > 0)
    {
      for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
      {
        m_acCUMvField[i].compress(m_pePredMode, scaleFactor);
      }
    }
  }
  
  UInt TComDataCU::getCoefScanIdx(const UInt uiAbsPartIdx, const UInt uiWidth, const UInt uiHeight, const ComponentID compID) const
  {
    //------------------------------------------------
  
    //this mechanism is available for intra only
  
    if (!isIntra(uiAbsPartIdx))
    {
      return SCAN_DIAG;
    }
  
    //------------------------------------------------
  
    //check that MDCS can be used for this TU
  
    const ChromaFormat format = getPic()->getChromaFormat();
  
    const UInt maximumWidth  = MDCS_MAXIMUM_WIDTH  >> getComponentScaleX(compID, format);
    const UInt maximumHeight = MDCS_MAXIMUM_HEIGHT >> getComponentScaleY(compID, format);
  
    if ((uiWidth > maximumWidth) || (uiHeight > maximumHeight))
    {
      return SCAN_DIAG;
    }
  
    //------------------------------------------------
  
    //otherwise, select the appropriate mode
  
    UInt uiDirMode  = getIntraDir(toChannelType(compID), uiAbsPartIdx);
  
    if (uiDirMode==DM_CHROMA_IDX)
    {
      const TComSPS *sps=getSlice()->getSPS();
      const UInt partsPerMinCU = 1<<(2*(sps->getMaxTotalCUDepth() - sps->getLog2DiffMaxMinCodingBlockSize()));
      uiDirMode = getIntraDir(CHANNEL_TYPE_LUMA, getChromasCorrespondingPULumaIdx(uiAbsPartIdx, getPic()->getChromaFormat(), partsPerMinCU));
    }
  
    if (isChroma(compID) && (format == CHROMA_422))
    {
      uiDirMode = g_chroma422IntraAngleMappingTable[uiDirMode];
    }
  
    //------------------
  
    if      (abs((Int)uiDirMode - VER_IDX) <= MDCS_ANGLE_LIMIT)
    {
      return SCAN_HOR;
    }
    else if (abs((Int)uiDirMode - HOR_IDX) <= MDCS_ANGLE_LIMIT)
    {
      return SCAN_VER;
    }
    else
    {
      return SCAN_DIAG;
    }
  }
  
  /* Get Index of Motion Vector and ruiCost in arrays regarding CU info 
    */
  Int TComDataCU::getIndexBlock(Int iPartIdx)
  {
      /* Create Int that concatenates CU info and return respective index 
       PartSize   Depth   PartIdx  zOrder  Height  Width
          9         8        7     6 5 4    3 2     1 0
      */
      
      Int index = 0;
      Int tmpIdx = 0;
      tmpIdx = static_cast<PartSize>( m_pePartSize[0] ) + ((Int)m_puhDepth[0]* 10) + (iPartIdx * 100);
      tmpIdx = (Int)m_absZIdxInCtu + (tmpIdx * 1000);
      tmpIdx = (Int)m_puhHeight[0] + (tmpIdx * 100);
      tmpIdx = (Int)m_puhWidth[0] + (tmpIdx * 100);
   
  #if AMP_ENC_SPEEDUP
  
      switch(tmpIdx){
      case   6464: 
          index =	424;
          break;
      case   1020006464: 
          index =	422;
          break;
      case   20006464: 
          index =	423;
          break;
      case   1010006464: 
          index =	420;
          break;
      case   10006464: 
          index =	421;
          break;
      case   101923232: 
          index =	419;
          break;
      case   101283232: 
          index =	418;
          break;
      case   100643232: 
          index =	417;
          break;
      case   100003232: 
          index =	416;
          break;
      case   1121923232: 
          index =	415;
          break;
      case   121923232: 
          index =	414;
          break;
      case   1121283232: 
          index =	413;
          break;
      case   121283232: 
          index =	412;
          break;
      case   1120643232: 
          index =	411;
          break;
      case   120643232: 
          index =	410;
          break;
      case   1120003232: 
          index =	409;
          break;
      case   120003232: 
          index =	408;
          break;
      case   1111923232: 
          index =	407;
          break;
      case   1111283232: 
          index =	406;
          break;
      case   111923232: 
          index =	405;
          break;
      case   111283232: 
          index =	404;
          break;
      case   1110643232: 
          index =	403;
          break;
      case   1110003232: 
          index =	402;
          break;
      case   110643232: 
          index =	401;
          break;
      case   110003232: 
          index =	400;
          break;
      case   202401616: 
          index =	399;
          break;
      case   202241616: 
          index =	398;
          break;
      case   201761616: 
          index =	397;
          break;
      case   201601616: 
          index =	396;
          break;
      case   202081616: 
          index =	395;
          break;
      case   201921616: 
          index =	394;
          break;
      case   201441616: 
          index =	393;
          break;
      case   201281616: 
          index =	392;
          break;
      case   201121616: 
          index =	391;
          break;
      case   200961616: 
          index =	390;
          break;
      case   200481616: 
          index =	389;
          break;
      case   200321616: 
          index =	388;
          break;
      case   200801616: 
          index =	387;
          break;
      case   200641616: 
          index =	386;
          break;
      case   200161616: 
          index =	385;
          break;
      case   200001616: 
          index =	384;
          break;
      case   1222401616: 
          index =	383;
          break;
      case   222401616: 
          index =	382;
          break;
      case   1222241616: 
          index =	381;
          break;
      case   222241616: 
          index =	380;
          break;
      case   1221761616: 
          index =	379;
          break;
      case   221761616: 
          index =	378;
          break;
      case   1221601616: 
          index =	377;
          break;
      case   221601616: 
          index =	376;
          break;
      case   1222081616: 
          index =	375;
          break;
      case   222081616: 
          index =	374;
          break;
      case   1221921616: 
          index =	373;
          break;
      case   221921616: 
          index =	372;
          break;
      case   1221441616: 
          index =	371;
          break;
      case   221441616: 
          index =	370;
          break;
      case   1221281616: 
          index =	369;
          break;
      case   221281616: 
          index =	368;
          break;
      case   1221121616: 
          index =	367;
          break;
      case   221121616: 
          index =	366;
          break;
      case   1220961616: 
          index =	365;
          break;
      case   220961616: 
          index =	364;
          break;
      case   1220481616: 
          index =	363;
          break;
      case   220481616: 
          index =	362;
          break;
      case   1220321616: 
          index =	361;
          break;
      case   220321616: 
          index =	360;
          break;
      case   1220801616: 
          index =	359;
          break;
      case   220801616: 
          index =	358;
          break;
      case   1220641616: 
          index =	357;
          break;
      case   220641616: 
          index =	356;
          break;
      case   1220161616: 
          index =	355;
          break;
      case   220161616: 
          index =	354;
          break;
      case   1220001616: 
          index =	353;
          break;
      case   220001616: 
          index =	352;
          break;
      case   1212401616: 
          index =	351;
          break;
      case   1212241616: 
          index =	350;
          break;
      case   1211761616: 
          index =	349;
          break;
      case   1211601616: 
          index =	348;
          break;
      case   212401616: 
          index =	347;
          break;
      case   212241616: 
          index =	346;
          break;
      case   211761616: 
          index =	345;
          break;
      case   211601616: 
          index =	344;
          break;
      case   1212081616: 
          index =	343;
          break;
      case   1211921616: 
          index =	342;
          break;
      case   1211441616: 
          index =	341;
          break;
      case   1211281616: 
          index =	340;
          break;
      case   212081616: 
          index =	339;
          break;
      case   211921616: 
          index =	338;
          break;
      case   211441616: 
          index =	337;
          break;
      case   211281616: 
          index =	336;
          break;
      case   1211121616: 
          index =	335;
          break;
      case   1210961616: 
          index =	334;
          break;
      case   1210481616: 
          index =	333;
          break;
      case   1210321616: 
          index =	332;
          break;
      case   211121616: 
          index =	331;
          break;
      case   210961616: 
          index =	330;
          break;
      case   210481616: 
          index =	329;
          break;
      case   210321616: 
          index =	328;
          break;
      case   1210801616: 
          index =	327;
          break;
      case   1210641616: 
          index =	326;
          break;
      case   1210161616: 
          index =	325;
          break;
      case   1210001616: 
          index =	324;
          break;
      case   210801616: 
          index =	323;
          break;
      case   210641616: 
          index =	322;
          break;
      case   210161616: 
          index =	321;
          break;
      case   210001616: 
          index =	320;
          break;
      case   302520808: 
          index =	319;
          break;
      case   302480808: 
          index =	318;
          break;
      case   302360808: 
          index =	317;
          break;
      case   302320808: 
          index =	316;
          break;
      case   301880808: 
          index =	315;
          break;
      case   301840808: 
          index =	314;
          break;
      case   301720808: 
          index =	313;
          break;
      case   301680808: 
          index =	312;
          break;
      case   302440808: 
          index =	311;
          break;
      case   302400808: 
          index =	310;
          break;
      case   302280808: 
          index =	309;
          break;
      case   302240808: 
          index =	308;
          break;
      case   301800808: 
          index =	307;
          break;
      case   301760808: 
          index =	306;
          break;
      case   301640808: 
          index =	305;
          break;
      case   301600808: 
          index =	304;
          break;
      case   302200808: 
          index =	303;
          break;
      case   302160808: 
          index =	302;
          break;
      case   302040808: 
          index =	301;
          break;
      case   302000808: 
          index =	300;
          break;
      case   301560808: 
          index =	299;
          break;
      case   301520808: 
          index =	298;
          break;
      case   301400808: 
          index =	297;
          break;
      case   301360808: 
          index =	296;
          break;
      case   302120808: 
          index =	295;
          break;
      case   302080808: 
          index =	294;
          break;
      case   301960808: 
          index =	293;
          break;
      case   301920808: 
          index =	292;
          break;
      case   301480808: 
          index =	291;
          break;
      case   301440808: 
          index =	290;
          break;
      case   301320808: 
          index =	289;
          break;
      case   301280808: 
          index =	288;
          break;
      case   301240808: 
          index =	287;
          break;
      case   301200808: 
          index =	286;
          break;
      case   301080808: 
          index =	285;
          break;
      case   301040808: 
          index =	284;
          break;
      case   300600808: 
          index =	283;
          break;
      case   300560808: 
          index =	282;
          break;
      case   300440808: 
          index =	281;
          break;
      case   300400808: 
          index =	280;
          break;
      case   301160808: 
          index =	279;
          break;
      case   301120808: 
          index =	278;
          break;
      case   301000808: 
          index =	277;
          break;
      case   300960808: 
          index =	276;
          break;
      case   300520808: 
          index =	275;
          break;
      case   300480808: 
          index =	274;
          break;
      case   300360808: 
          index =	273;
          break;
      case   300320808: 
          index =	272;
          break;
      case   300920808: 
          index =	271;
          break;
      case   300880808: 
          index =	270;
          break;
      case   300760808: 
          index =	269;
          break;
      case   300720808: 
          index =	268;
          break;
      case   300280808: 
          index =	267;
          break;
      case   300240808: 
          index =	266;
          break;
      case   300120808: 
          index =	265;
          break;
      case   300080808: 
          index =	264;
          break;
      case   300840808: 
          index =	263;
          break;
      case   300800808: 
          index =	262;
          break;
      case   300680808: 
          index =	261;
          break;
      case   300640808: 
          index =	260;
          break;
      case   300200808: 
          index =	259;
          break;
      case   300160808: 
          index =	258;
          break;
      case   300040808: 
          index =	257;
          break;
      case   300000808: 
          index =	256;
          break;
      case   1322520808: 
          index =	255;
          break;
      case   322520808: 
          index =	254;
          break;
      case   1322480808: 
          index =	253;
          break;
      case   322480808: 
          index =	252;
          break;
      case   1322360808: 
          index =	251;
          break;
      case   322360808: 
          index =	250;
          break;
      case   1322320808: 
          index =	249;
          break;
      case   322320808: 
          index =	248;
          break;
      case   1321880808: 
          index =	247;
          break;
      case   321880808: 
          index =	246;
          break;
      case   1321840808: 
          index =	245;
          break;
      case   321840808: 
          index =	244;
          break;
      case   1321720808: 
          index =	243;
          break;
      case   321720808: 
          index =	242;
          break;
      case   1321680808: 
          index =	241;
          break;
      case   321680808: 
          index =	240;
          break;
      case   1322440808: 
          index =	239;
          break;
      case   322440808: 
          index =	238;
          break;
      case   1322400808: 
          index =	237;
          break;
      case   322400808: 
          index =	236;
          break;
      case   1322280808: 
          index =	235;
          break;
      case   322280808: 
          index =	234;
          break;
      case   1322240808: 
          index =	233;
          break;
      case   322240808: 
          index =	232;
          break;
      case   1321800808: 
          index =	231;
          break;
      case   321800808: 
          index =	230;
          break;
      case   1321760808: 
          index =	229;
          break;
      case   321760808: 
          index =	228;
          break;
      case   1321640808: 
          index =	227;
          break;
      case   321640808: 
          index =	226;
          break;
      case   1321600808: 
          index =	225;
          break;
      case   321600808: 
          index =	224;
          break;
      case   1322200808: 
          index =	223;
          break;
      case   322200808: 
          index =	222;
          break;
      case   1322160808: 
          index =	221;
          break;
      case   322160808: 
          index =	220;
          break;
      case   1322040808: 
          index =	219;
          break;
      case   322040808: 
          index =	218;
          break;
      case   1322000808: 
          index =	217;
          break;
      case   322000808: 
          index =	216;
          break;
      case   1321560808: 
          index =	215;
          break;
      case   321560808: 
          index =	214;
          break;
      case   1321520808: 
          index =	213;
          break;
      case   321520808: 
          index =	212;
          break;
      case   1321400808: 
          index =	211;
          break;
      case   321400808: 
          index =	210;
          break;
      case   1321360808: 
          index =	209;
          break;
      case   321360808: 
          index =	208;
          break;
      case   1322120808: 
          index =	207;
          break;
      case   322120808: 
          index =	206;
          break;
      case   1322080808: 
          index =	205;
          break;
      case   322080808: 
          index =	204;
          break;
      case   1321960808: 
          index =	203;
          break;
      case   321960808: 
          index =	202;
          break;
      case   1321920808: 
          index =	201;
          break;
      case   321920808: 
          index =	200;
          break;
      case   1321480808: 
          index =	199;
          break;
      case   321480808: 
          index =	198;
          break;
      case   1321440808: 
          index =	197;
          break;
      case   321440808: 
          index =	196;
          break;
      case   1321320808: 
          index =	195;
          break;
      case   321320808: 
          index =	194;
          break;
      case   1321280808: 
          index =	193;
          break;
      case   321280808: 
          index =	192;
          break;
      case   1321240808: 
          index =	191;
          break;
      case   321240808: 
          index =	190;
          break;
      case   1321200808: 
          index =	189;
          break;
      case   321200808: 
          index =	188;
          break;
      case   1321080808: 
          index =	187;
          break;
      case   321080808: 
          index =	186;
          break;
      case   1321040808: 
          index =	185;
          break;
      case   321040808: 
          index =	184;
          break;
      case   1320600808: 
          index =	183;
          break;
      case   320600808: 
          index =	182;
          break;
      case   1320560808: 
          index =	181;
          break;
      case   320560808: 
          index =	180;
          break;
      case   1320440808: 
          index =	179;
          break;
      case   320440808: 
          index =	178;
          break;
      case   1320400808: 
          index =	177;
          break;
      case   320400808: 
          index =	176;
          break;
      case   1321160808: 
          index =	175;
          break;
      case   321160808: 
          index =	174;
          break;
      case   1321120808: 
          index =	173;
          break;
      case   321120808: 
          index =	172;
          break;
      case   1321000808: 
          index =	171;
          break;
      case   321000808: 
          index =	170;
          break;
      case   1320960808: 
          index =	169;
          break;
      case   320960808: 
          index =	168;
          break;
      case   1320520808: 
          index =	167;
          break;
      case   320520808: 
          index =	166;
          break;
      case   1320480808: 
          index =	165;
          break;
      case   320480808: 
          index =	164;
          break;
      case   1320360808: 
          index =	163;
          break;
      case   320360808: 
          index =	162;
          break;
      case   1320320808: 
          index =	161;
          break;
      case   320320808: 
          index =	160;
          break;
      case   1320920808: 
          index =	159;
          break;
      case   320920808: 
          index =	158;
          break;
      case   1320880808: 
          index =	157;
          break;
      case   320880808: 
          index =	156;
          break;
      case   1320760808: 
          index =	155;
          break;
      case   320760808: 
          index =	154;
          break;
      case   1320720808: 
          index =	153;
          break;
      case   320720808: 
          index =	152;
          break;
      case   1320280808: 
          index =	151;
          break;
      case   320280808: 
          index =	150;
          break;
      case   1320240808: 
          index =	149;
          break;
      case   320240808: 
          index =	148;
          break;
      case   1320120808: 
          index =	147;
          break;
      case   320120808: 
          index =	146;
          break;
      case   1320080808: 
          index =	145;
          break;
      case   320080808: 
          index =	144;
          break;
      case   1320840808: 
          index =	143;
          break;
      case   320840808: 
          index =	142;
          break;
      case   1320800808: 
          index =	141;
          break;
      case   320800808: 
          index =	140;
          break;
      case   1320680808: 
          index =	139;
          break;
      case   320680808: 
          index =	138;
          break;
      case   1320640808: 
          index =	137;
          break;
      case   320640808: 
          index =	136;
          break;
      case   1320200808: 
          index =	135;
          break;
      case   320200808: 
          index =	134;
          break;
      case   1320160808: 
          index =	133;
          break;
      case   320160808: 
          index =	132;
          break;
      case   1320040808: 
          index =	131;
          break;
      case   320040808: 
          index =	130;
          break;
      case   1320000808: 
          index =	129;
          break;
      case   320000808: 
          index =	128;
          break;
      case   1312520808: 
          index =	127;
          break;
      case   1312480808: 
          index =	126;
          break;
      case   1312360808: 
          index =	125;
          break;
      case   1312320808: 
          index =	124;
          break;
      case   1311880808: 
          index =	123;
          break;
      case   1311840808: 
          index =	122;
          break;
      case   1311720808: 
          index =	121;
          break;
      case   1311680808: 
          index =	120;
          break;
      case   1312440808: 
          index =	111;
          break;
      case   312520808: 
          index =	119;
          break;
      case   312480808: 
          index =	118;
          break;
      case   312360808: 
          index =	117;
          break;
      case   312320808: 
          index =	116;
          break;
      case   311880808: 
          index =	115;
          break;
      case   311840808: 
          index =	114;
          break;
      case   311720808: 
          index =	113;
          break;
      case   311680808: 
          index =	112;
          break;
      case   1312400808: 
          index =	110;
          break;
      case   1312280808: 
          index =	109;
          break;
      case   1312240808: 
          index =	108;
          break;
      case   1311800808: 
          index =	107;
          break;
      case   1311760808: 
          index =	106;
          break;
      case   1311640808: 
          index =	105;
          break;
      case   1311600808: 
          index =	104;
          break;
      case   312440808: 
          index =	103;
          break;
      case   312400808: 
          index =	102;
          break;
      case   312280808: 
          index =	101;
          break;
      case   312240808: 
          index =	100;
          break;
      case   311800808: 
          index =	99;
          break;
      case   311760808: 
          index =	98;
          break;
      case   311640808: 
          index =	97;
          break;
      case   311600808: 
          index =	96;
          break;
      case   1312200808: 
          index =	95;
          break;
      case   1312160808: 
          index =	94;
          break;
      case   1312040808: 
          index =	93;
          break;
      case   1312000808: 
          index =	92;
          break;
      case   1311560808: 
          index =	91;
          break;
      case   1311520808: 
          index =	90;
          break;
      case   1311400808: 
          index =	89;
          break;
      case   1311360808: 
          index =	88;
          break;
      case   312200808: 
          index =	87;
          break;
      case   312160808: 
          index =	86;
          break;
      case   312040808: 
          index =	85;
          break;
      case   312000808: 
          index =	84;
          break;
      case   311560808: 
          index =	83;
          break;
      case   311520808: 
          index =	82;
          break;
      case   311400808: 
          index =	81;
          break;
      case   311360808: 
          index =	80;
          break;
      case   1312120808: 
          index =	79;
          break;
      case   1312080808: 
          index =	78;
          break;
      case   1311960808: 
          index =	77;
          break;
      case   1311920808: 
          index =	76;
          break;
      case   1311480808: 
          index =	75;
          break;
      case   1311440808: 
          index =	74;
          break;
      case   1311320808: 
          index =	73;
          break;
      case   1311280808: 
          index =	72;
          break;
      case   312120808: 
          index =	71;
          break;
      case   312080808: 
          index =	70;
          break;
      case   311960808: 
          index =	69;
          break;
      case   311920808: 
          index =	68;
          break;
      case   311480808: 
          index =	67;
          break;
      case   311440808: 
          index =	66;
          break;
      case   311320808: 
          index =	65;
          break;
      case   311280808: 
          index =	64;
          break;
      case   1311240808: 
          index =	63;
          break;
      case   1311200808: 
          index =	62;
          break;
      case   1311080808: 
          index =	61;
          break;
      case   1311040808: 
          index =	60;
          break;
      case   1310600808: 
          index =	59;
          break;
      case   1310560808: 
          index =	58;
          break;
      case   1310440808: 
          index =	57;
          break;
      case   1310400808: 
          index =	56;
          break;
      case   311240808: 
          index =	55;
          break;
      case   311200808: 
          index =	54;
          break;
      case   311080808: 
          index =	53;
          break;
      case   311040808: 
          index =	52;
          break;
      case   310600808: 
          index =	51;
          break;
      case   310560808: 
          index =	50;
          break;
      case   310440808: 
          index =	49;
          break;
      case   310400808: 
          index =	48;
          break;
      case   1311160808: 
          index =	47;
          break;
      case   1311120808: 
          index =	46;
          break;
      case   1311000808: 
          index =	45;
          break;
      case   1310960808: 
          index =	44;
          break;
      case   1310520808: 
          index =	43;
          break;
      case   1310480808: 
          index =	42;
          break;
      case   1310360808: 
          index =	41;
          break;
      case   1310320808: 
          index =	40;
          break;
      case   311160808: 
          index =	39;
          break;
      case   311120808: 
          index =	38;
          break;
      case   311000808: 
          index =	37;
          break;
      case   310960808: 
          index =	36;
          break;
      case   310520808: 
          index =	35;
          break;
      case   310480808: 
          index =	34;
          break;
      case   310360808: 
          index =	33;
          break;
      case   310320808: 
          index =	32;
          break;
      case   1310920808: 
          index =	31;
          break;
      case   1310880808: 
          index =	30;
          break;
      case   1310760808: 
          index =	29;
          break;
      case   1310720808: 
          index =	28;
          break;
      case   1310280808: 
          index =	27;
          break;
      case   1310240808: 
          index =	26;
          break;
      case   1310120808: 
          index =	25;
          break;
      case   1310080808: 
          index =	24;
          break;
      case   310920808: 
          index =	23;
          break;
      case   310880808: 
          index =	22;
          break;
      case   310760808: 
          index =	21;
          break;
      case   310720808: 
          index =	20;
          break;
      case   310280808: 
          index =	19;
          break;
      case   310240808: 
          index =	18;
          break;
      case   310120808: 
          index =	17;
          break;
      case   310080808: 
          index =	16;
          break;
      case   1310840808: 
          index =	15;
          break;
      case   1310800808: 
          index =	14;
          break;
      case   1310680808: 
          index =	13;
          break;
      case   1310640808: 
          index =	12;
          break;
      case   1310200808: 
          index =	11;
          break;
      case   1310160808: 
          index =	10;
          break;
      case   1310040808: 
          index =	9;
          break;
      case   1310000808: 
          index =	8;
          break;
      case   310840808: 
          index =	7;
          break;
      case   310800808: 
          index =	6;
          break;
      case   310680808: 
          index =	5;
          break;
      case   310640808: 
          index =	4;
          break;
      case   310200808: 
          index =	3;
          break;
      case   310160808: 
          index =	2;
          break;
      case   310040808: 
          index =	1;
          break;
      case   310000808: 
          index =	0;
          break;
      default:
          index = -1;
  
      }
  
  #else   
  
      switch(tmpIdx){
      case  6464: 
          index = 592;
          break;
      case  20006464: 
          index = 590;
          break;
      case  1020006464: 
          index = 591;
          break;
      case  10006464: 
          index = 588;
          break;
      case  1010006464: 
          index = 589;
          break;
      case  40006464: 
          index = 576;
          break;
      case  1040006464: 
          index = 579;
          break;
      case  50006464: 
          index = 578;
          break;
      case  1050006464: 
          index = 577;
          break;
      case  60006464: 
          index = 580;
          break;
      case  1060006464: 
          index = 583;
          break;
      case  70006464: 
          index = 582;
          break;
      case  1070006464: 
          index = 581;
          break;
      case  100003232: 
          index = 584;
          break;
      case  120003232: 
          index = 568;
          break;
      case  1120003232: 
          index = 569;
          break;
      case  110003232: 
          index = 560;
          break;
      case  1110003232: 
          index = 562;
          break;
      case  140003232: 
          index = 512;
          break;
      case  1140003232: 
          index = 524;
          break;
      case  150003232: 
          index = 520;
          break;
      case  1150003232: 
          index = 516;
          break;
      case  160003232: 
          index = 528;
          break;
      case  1160003232: 
          index = 540;
          break;
      case  170003232: 
          index = 536;
          break;
      case  1170003232: 
          index = 532;
          break;
      case  200001616: 
          index = 544;
          break;
      case  220001616: 
          index = 480;
          break;
      case  1220001616: 
          index = 481;
          break;
      case  210001616: 
          index = 448;
          break;
      case  1210001616: 
          index = 452;
          break;
      case  240001616: 
          index = 256;
          break;
      case  1240001616: 
          index = 304;
          break;
      case  250001616: 
          index = 288;
          break;
      case  1250001616: 
          index = 272;
          break;
      case  260001616: 
          index = 320;
          break;
      case  1260001616: 
          index = 368;
          break;
      case  270001616: 
          index = 352;
          break;
      case  1270001616: 
          index = 336;
          break;
      case  300000808: 
          index = 384;
          break;
      case  320000808: 
          index = 128;
          break;
      case  1320000808: 
          index = 129;
          break;
      case  310000808: 
          index = 0;
          break;
      case  1310000808: 
          index = 8;
          break;
      case  300040808: 
          index = 385;
          break;
      case  320040808: 
          index = 130;
          break;
      case  1320040808: 
          index = 131;
          break;
      case  310040808: 
          index = 1;
          break;
      case  1310040808: 
          index = 9;
          break;
      case  300080808: 
          index = 392;
          break;
      case  320080808: 
          index = 144;
          break;
      case  1320080808: 
          index = 145;
          break;
      case  310080808: 
          index = 16;
          break;
      case  1310080808: 
          index = 24;
          break;
      case  300120808: 
          index = 393;
          break;
      case  320120808: 
          index = 146;
          break;
      case  1320120808: 
          index = 147;
          break;
      case  310120808: 
          index = 17;
          break;
      case  1310120808: 
          index = 25;
          break;
      case  200161616: 
          index = 545;
          break;
      case  220161616: 
          index = 482;
          break;
      case  1220161616: 
          index = 483;
          break;
      case  210161616: 
          index = 449;
          break;
      case  1210161616: 
          index = 453;
          break;
      case  240161616: 
          index = 257;
          break;
      case  1240161616: 
          index = 305;
          break;
      case  250161616: 
          index = 289;
          break;
      case  1250161616: 
          index = 273;
          break;
      case  260161616: 
          index = 321;
          break;
      case  1260161616: 
          index = 369;
          break;
      case  270161616: 
          index = 353;
          break;
      case  1270161616: 
          index = 337;
          break;
      case  300160808: 
          index = 386;
          break;
      case  320160808: 
          index = 132;
          break;
      case  1320160808: 
          index = 133;
          break;
      case  310160808: 
          index = 2;
          break;
      case  1310160808: 
          index = 10;
          break;
      case  300200808: 
          index = 387;
          break;
      case  320200808: 
          index = 134;
          break;
      case  1320200808: 
          index = 135;
          break;
      case  310200808: 
          index = 3;
          break;
      case  1310200808: 
          index = 11;
          break;
      case  300240808: 
          index = 394;
          break;
      case  320240808: 
          index = 148;
          break;
      case  1320240808: 
          index = 149;
          break;
      case  310240808: 
          index = 18;
          break;
      case  1310240808: 
          index = 26;
          break;
      case  300280808: 
          index = 395;
          break;
      case  320280808: 
          index = 150;
          break;
      case  1320280808: 
          index = 151;
          break;
      case  310280808: 
          index = 19;
          break;
      case  1310280808: 
          index = 27;
          break;
      case  200321616: 
          index = 548;
          break;
      case  220321616: 
          index = 488;
          break;
      case  1220321616: 
          index = 489;
          break;
      case  210321616: 
          index = 456;
          break;
      case  1210321616: 
          index = 460;
          break;
      case  240321616: 
          index = 260;
          break;
      case  1240321616: 
          index = 308;
          break;
      case  250321616: 
          index = 292;
          break;
      case  1250321616: 
          index = 276;
          break;
      case  260321616: 
          index = 324;
          break;
      case  1260321616: 
          index = 372;
          break;
      case  270321616: 
          index = 356;
          break;
      case  1270321616: 
          index = 340;
          break;
      case  300320808: 
          index = 400;
          break;
      case  320320808: 
          index = 160;
          break;
      case  1320320808: 
          index = 161;
          break;
      case  310320808: 
          index = 32;
          break;
      case  1310320808: 
          index = 40;
          break;
      case  300360808: 
          index = 401;
          break;
      case  320360808: 
          index = 162;
          break;
      case  1320360808: 
          index = 163;
          break;
      case  310360808: 
          index = 33;
          break;
      case  1310360808: 
          index = 41;
          break;
      case  300400808: 
          index = 408;
          break;
      case  320400808: 
          index = 176;
          break;
      case  1320400808: 
          index = 177;
          break;
      case  310400808: 
          index = 48;
          break;
      case  1310400808: 
          index = 56;
          break;
      case  300440808: 
          index = 409;
          break;
      case  320440808: 
          index = 178;
          break;
      case  1320440808: 
          index = 179;
          break;
      case  310440808: 
          index = 49;
          break;
      case  1310440808: 
          index = 57;
          break;
      case  200481616: 
          index = 549;
          break;
      case  220481616: 
          index = 490;
          break;
      case  1220481616: 
          index = 491;
          break;
      case  210481616: 
          index = 457;
          break;
      case  1210481616: 
          index = 461;
          break;
      case  240481616: 
          index = 261;
          break;
      case  1240481616: 
          index = 309;
          break;
      case  250481616: 
          index = 293;
          break;
      case  1250481616: 
          index = 277;
          break;
      case  260481616: 
          index = 325;
          break;
      case  1260481616: 
          index = 373;
          break;
      case  270481616: 
          index = 357;
          break;
      case  1270481616: 
          index = 341;
          break;
      case  300480808: 
          index = 402;
          break;
      case  320480808: 
          index = 164;
          break;
      case  1320480808: 
          index = 165;
          break;
      case  310480808: 
          index = 34;
          break;
      case  1310480808: 
          index = 42;
          break;
      case  300520808: 
          index = 403;
          break;
      case  320520808: 
          index = 166;
          break;
      case  1320520808: 
          index = 167;
          break;
      case  310520808: 
          index = 35;
          break;
      case  1310520808: 
          index = 43;
          break;
      case  300560808: 
          index = 410;
          break;
      case  320560808: 
          index = 180;
          break;
      case  1320560808: 
          index = 181;
          break;
      case  310560808: 
          index = 50;
          break;
      case  1310560808: 
          index = 58;
          break;
      case  300600808: 
          index = 411;
          break;
      case  320600808: 
          index = 182;
          break;
      case  1320600808: 
          index = 183;
          break;
      case  310600808: 
          index = 51;
          break;
      case  1310600808: 
          index = 59;
          break;
      case  100643232: 
          index = 585;
          break;
      case  120643232: 
          index = 570;
          break;
      case  1120643232: 
          index = 571;
          break;
      case  110643232: 
          index = 561;
          break;
      case  1110643232: 
          index = 563;
          break;
      case  140643232: 
          index = 513;
          break;
      case  1140643232: 
          index = 525;
          break;
      case  150643232: 
          index = 521;
          break;
      case  1150643232: 
          index = 517;
          break;
      case  160643232: 
          index = 529;
          break;
      case  1160643232: 
          index = 541;
          break;
      case  170643232: 
          index = 537;
          break;
      case  1170643232: 
          index = 533;
          break;
      case  200641616: 
          index = 546;
          break;
      case  220641616: 
          index = 484;
          break;
      case  1220641616: 
          index = 485;
          break;
      case  210641616: 
          index = 450;
          break;
      case  1210641616: 
          index = 454;
          break;
      case  240641616: 
          index = 258;
          break;
      case  1240641616: 
          index = 306;
          break;
      case  250641616: 
          index = 290;
          break;
      case  1250641616: 
          index = 274;
          break;
      case  260641616: 
          index = 322;
          break;
      case  1260641616: 
          index = 370;
          break;
      case  270641616: 
          index = 354;
          break;
      case  1270641616: 
          index = 338;
          break;
      case  300640808: 
          index = 388;
          break;
      case  320640808: 
          index = 136;
          break;
      case  1320640808: 
          index = 137;
          break;
      case  310640808: 
          index = 4;
          break;
      case  1310640808: 
          index = 12;
          break;
      case  300680808: 
          index = 389;
          break;
      case  320680808: 
          index = 138;
          break;
      case  1320680808: 
          index = 139;
          break;
      case  310680808: 
          index = 5;
          break;
      case  1310680808: 
          index = 13;
          break;
      case  300720808: 
          index = 396;
          break;
      case  320720808: 
          index = 152;
          break;
      case  1320720808: 
          index = 153;
          break;
      case  310720808: 
          index = 20;
          break;
      case  1310720808: 
          index = 28;
          break;
      case  300760808: 
          index = 397;
          break;
      case  320760808: 
          index = 154;
          break;
      case  1320760808: 
          index = 155;
          break;
      case  310760808: 
          index = 21;
          break;
      case  1310760808: 
          index = 29;
          break;
      case  200801616: 
          index = 547;
          break;
      case  220801616: 
          index = 486;
          break;
      case  1220801616: 
          index = 487;
          break;
      case  210801616: 
          index = 451;
          break;
      case  1210801616: 
          index = 455;
          break;
      case  240801616: 
          index = 259;
          break;
      case  1240801616: 
          index = 307;
          break;
      case  250801616: 
          index = 291;
          break;
      case  1250801616: 
          index = 275;
          break;
      case  260801616: 
          index = 323;
          break;
      case  1260801616: 
          index = 371;
          break;
      case  270801616: 
          index = 355;
          break;
      case  1270801616: 
          index = 339;
          break;
      case  300800808: 
          index = 390;
          break;
      case  320800808: 
          index = 140;
          break;
      case  1320800808: 
          index = 141;
          break;
      case  310800808: 
          index = 6;
          break;
      case  1310800808: 
          index = 14;
          break;
      case  300840808: 
          index = 391;
          break;
      case  320840808: 
          index = 142;
          break;
      case  1320840808: 
          index = 143;
          break;
      case  310840808: 
          index = 7;
          break;
      case  1310840808: 
          index = 15;
          break;
      case  300880808: 
          index = 398;
          break;
      case  320880808: 
          index = 156;
          break;
      case  1320880808: 
          index = 157;
          break;
      case  310880808: 
          index = 22;
          break;
      case  1310880808: 
          index = 30;
          break;
      case  300920808: 
          index = 399;
          break;
      case  320920808: 
          index = 158;
          break;
      case  1320920808: 
          index = 159;
          break;
      case  310920808: 
          index = 23;
          break;
      case  1310920808: 
          index = 31;
          break;
      case  200961616: 
          index = 550;
          break;
      case  220961616: 
          index = 492;
          break;
      case  1220961616: 
          index = 493;
          break;
      case  210961616: 
          index = 458;
          break;
      case  1210961616: 
          index = 462;
          break;
      case  240961616: 
          index = 262;
          break;
      case  1240961616: 
          index = 310;
          break;
      case  250961616: 
          index = 294;
          break;
      case  1250961616: 
          index = 278;
          break;
      case  260961616: 
          index = 326;
          break;
      case  1260961616: 
          index = 374;
          break;
      case  270961616: 
          index = 358;
          break;
      case  1270961616: 
          index = 342;
          break;
      case  300960808: 
          index = 404;
          break;
      case  320960808: 
          index = 168;
          break;
      case  1320960808: 
          index = 169;
          break;
      case  310960808: 
          index = 36;
          break;
      case  1310960808: 
          index = 44;
          break;
      case  301000808: 
          index = 405;
          break;
      case  321000808: 
          index = 170;
          break;
      case  1321000808: 
          index = 171;
          break;
      case  311000808: 
          index = 37;
          break;
      case  1311000808: 
          index = 45;
          break;
      case  301040808: 
          index = 412;
          break;
      case  321040808: 
          index = 184;
          break;
      case  1321040808: 
          index = 185;
          break;
      case  311040808: 
          index = 52;
          break;
      case  1311040808: 
          index = 60;
          break;
      case  301080808: 
          index = 413;
          break;
      case  321080808: 
          index = 186;
          break;
      case  1321080808: 
          index = 187;
          break;
      case  311080808: 
          index = 53;
          break;
      case  1311080808: 
          index = 61;
          break;
      case  201121616: 
          index = 551;
          break;
      case  221121616: 
          index = 494;
          break;
      case  1221121616: 
          index = 495;
          break;
      case  211121616: 
          index = 459;
          break;
      case  1211121616: 
          index = 463;
          break;
      case  241121616: 
          index = 263;
          break;
      case  1241121616: 
          index = 311;
          break;
      case  251121616: 
          index = 295;
          break;
      case  1251121616: 
          index = 279;
          break;
      case  261121616: 
          index = 327;
          break;
      case  1261121616: 
          index = 375;
          break;
      case  271121616: 
          index = 359;
          break;
      case  1271121616: 
          index = 343;
          break;
      case  301120808: 
          index = 406;
          break;
      case  321120808: 
          index = 172;
          break;
      case  1321120808: 
          index = 173;
          break;
      case  311120808: 
          index = 38;
          break;
      case  1311120808: 
          index = 46;
          break;
      case  301160808: 
          index = 407;
          break;
      case  321160808: 
          index = 174;
          break;
      case  1321160808: 
          index = 175;
          break;
      case  311160808: 
          index = 39;
          break;
      case  1311160808: 
          index = 47;
          break;
      case  301200808: 
          index = 414;
          break;
      case  321200808: 
          index = 188;
          break;
      case  1321200808: 
          index = 189;
          break;
      case  311200808: 
          index = 54;
          break;
      case  1311200808: 
          index = 62;
          break;
      case  301240808: 
          index = 415;
          break;
      case  321240808: 
          index = 190;
          break;
      case  1321240808: 
          index = 191;
          break;
      case  311240808: 
          index = 55;
          break;
      case  1311240808: 
          index = 63;
          break;
      case  101283232: 
          index = 586;
          break;
      case  121283232: 
          index = 572;
          break;
      case  1121283232: 
          index = 573;
          break;
      case  111283232: 
          index = 564;
          break;
      case  1111283232: 
          index = 566;
          break;
      case  141283232: 
          index = 514;
          break;
      case  1141283232: 
          index = 526;
          break;
      case  151283232: 
          index = 522;
          break;
      case  1151283232: 
          index = 518;
          break;
      case  161283232: 
          index = 530;
          break;
      case  1161283232: 
          index = 542;
          break;
      case  171283232: 
          index = 538;
          break;
      case  1171283232: 
          index = 534;
          break;
      case  201281616: 
          index = 552;
          break;
      case  221281616: 
          index = 496;
          break;
      case  1221281616: 
          index = 497;
          break;
      case  211281616: 
          index = 464;
          break;
      case  1211281616: 
          index = 468;
          break;
      case  241281616: 
          index = 264;
          break;
      case  1241281616: 
          index = 312;
          break;
      case  251281616: 
          index = 296;
          break;
      case  1251281616: 
          index = 280;
          break;
      case  261281616: 
          index = 328;
          break;
      case  1261281616: 
          index = 376;
          break;
      case  271281616: 
          index = 360;
          break;
      case  1271281616: 
          index = 344;
          break;
      case  301280808: 
          index = 416;
          break;
      case  321280808: 
          index = 192;
          break;
      case  1321280808: 
          index = 193;
          break;
      case  311280808: 
          index = 64;
          break;
      case  1311280808: 
          index = 72;
          break;
      case  301320808: 
          index = 417;
          break;
      case  321320808: 
          index = 194;
          break;
      case  1321320808: 
          index = 195;
          break;
      case  311320808: 
          index = 65;
          break;
      case  1311320808: 
          index = 73;
          break;
      case  301360808: 
          index = 424;
          break;
      case  321360808: 
          index = 208;
          break;
      case  1321360808: 
          index = 209;
          break;
      case  311360808: 
          index = 80;
          break;
      case  1311360808: 
          index = 88;
          break;
      case  301400808: 
          index = 425;
          break;
      case  321400808: 
          index = 210;
          break;
      case  1321400808: 
          index = 211;
          break;
      case  311400808: 
          index = 81;
          break;
      case  1311400808: 
          index = 89;
          break;
      case  201441616: 
          index = 553;
          break;
      case  221441616: 
          index = 498;
          break;
      case  1221441616: 
          index = 499;
          break;
      case  211441616: 
          index = 465;
          break;
      case  1211441616: 
          index = 469;
          break;
      case  241441616: 
          index = 265;
          break;
      case  1241441616: 
          index = 313;
          break;
      case  251441616: 
          index = 297;
          break;
      case  1251441616: 
          index = 281;
          break;
      case  261441616: 
          index = 329;
          break;
      case  1261441616: 
          index = 377;
          break;
      case  271441616: 
          index = 361;
          break;
      case  1271441616: 
          index = 345;
          break;
      case  301440808: 
          index = 418;
          break;
      case  321440808: 
          index = 196;
          break;
      case  1321440808: 
          index = 197;
          break;
      case  311440808: 
          index = 66;
          break;
      case  1311440808: 
          index = 74;
          break;
      case  301480808: 
          index = 419;
          break;
      case  321480808: 
          index = 198;
          break;
      case  1321480808: 
          index = 199;
          break;
      case  311480808: 
          index = 67;
          break;
      case  1311480808: 
          index = 75;
          break;
      case  301520808: 
          index = 426;
          break;
      case  321520808: 
          index = 212;
          break;
      case  1321520808: 
          index = 213;
          break;
      case  311520808: 
          index = 82;
          break;
      case  1311520808: 
          index = 90;
          break;
      case  301560808: 
          index = 427;
          break;
      case  321560808: 
          index = 214;
          break;
      case  1321560808: 
          index = 215;
          break;
      case  311560808: 
          index = 83;
          break;
      case  1311560808: 
          index = 91;
          break;
      case  201601616: 
          index = 556;
          break;
      case  221601616: 
          index = 504;
          break;
      case  1221601616: 
          index = 505;
          break;
      case  211601616: 
          index = 472;
          break;
      case  1211601616: 
          index = 476;
          break;
      case  241601616: 
          index = 268;
          break;
      case  1241601616: 
          index = 316;
          break;
      case  251601616: 
          index = 300;
          break;
      case  1251601616: 
          index = 284;
          break;
      case  261601616: 
          index = 332;
          break;
      case  1261601616: 
          index = 380;
          break;
      case  271601616: 
          index = 364;
          break;
      case  1271601616: 
          index = 348;
          break;
      case  301600808: 
          index = 432;
          break;
      case  321600808: 
          index = 224;
          break;
      case  1321600808: 
          index = 225;
          break;
      case  311600808: 
          index = 96;
          break;
      case  1311600808: 
          index = 104;
          break;
      case  301640808: 
          index = 433;
          break;
      case  321640808: 
          index = 226;
          break;
      case  1321640808: 
          index = 227;
          break;
      case  311640808: 
          index = 97;
          break;
      case  1311640808: 
          index = 105;
          break;
      case  301680808: 
          index = 440;
          break;
      case  321680808: 
          index = 240;
          break;
      case  1321680808: 
          index = 241;
          break;
      case  311680808: 
          index = 112;
          break;
      case  1311680808: 
          index = 120;
          break;
      case  301720808: 
          index = 441;
          break;
      case  321720808: 
          index = 242;
          break;
      case  1321720808: 
          index = 243;
          break;
      case  311720808: 
          index = 113;
          break;
      case  1311720808: 
          index = 121;
          break;
      case  201761616: 
          index = 557;
          break;
      case  221761616: 
          index = 506;
          break;
      case  1221761616: 
          index = 507;
          break;
      case  211761616: 
          index = 473;
          break;
      case  1211761616: 
          index = 477;
          break;
      case  241761616: 
          index = 269;
          break;
      case  1241761616: 
          index = 317;
          break;
      case  251761616: 
          index = 301;
          break;
      case  1251761616: 
          index = 285;
          break;
      case  261761616: 
          index = 333;
          break;
      case  1261761616: 
          index = 381;
          break;
      case  271761616: 
          index = 365;
          break;
      case  1271761616: 
          index = 349;
          break;
      case  301760808: 
          index = 434;
          break;
      case  321760808: 
          index = 228;
          break;
      case  1321760808: 
          index = 229;
          break;
      case  311760808: 
          index = 98;
          break;
      case  1311760808: 
          index = 106;
          break;
      case  301800808: 
          index = 435;
          break;
      case  321800808: 
          index = 230;
          break;
      case  1321800808: 
          index = 231;
          break;
      case  311800808: 
          index = 99;
          break;
      case  1311800808: 
          index = 107;
          break;
      case  301840808: 
          index = 442;
          break;
      case  321840808: 
          index = 244;
          break;
      case  1321840808: 
          index = 245;
          break;
      case  311840808: 
          index = 114;
          break;
      case  1311840808: 
          index = 122;
          break;
      case  301880808: 
          index = 443;
          break;
      case  321880808: 
          index = 246;
          break;
      case  1321880808: 
          index = 247;
          break;
      case  311880808: 
          index = 115;
          break;
      case  1311880808: 
          index = 123;
          break;
      case  101923232: 
          index = 587;
          break;
      case  121923232: 
          index = 574;
          break;
      case  1121923232: 
          index = 575;
          break;
      case  111923232: 
          index = 565;
          break;
      case  1111923232: 
          index = 567;
          break;
      case  141923232: 
          index = 515;
          break;
      case  1141923232: 
          index = 527;
          break;
      case  151923232: 
          index = 523;
          break;
      case  1151923232: 
          index = 519;
          break;
      case  161923232: 
          index = 531;
          break;
      case  1161923232: 
          index = 543;
          break;
      case  171923232: 
          index = 539;
          break;
      case  1171923232: 
          index = 535;
          break;
      case  201921616: 
          index = 554;
          break;
      case  221921616: 
          index = 500;
          break;
      case  1221921616: 
          index = 501;
          break;
      case  211921616: 
          index = 466;
          break;
      case  1211921616: 
          index = 470;
          break;
      case  241921616: 
          index = 266;
          break;
      case  1241921616: 
          index = 314;
          break;
      case  251921616: 
          index = 298;
          break;
      case  1251921616: 
          index = 282;
          break;
      case  261921616: 
          index = 330;
          break;
      case  1261921616: 
          index = 378;
          break;
      case  271921616: 
          index = 362;
          break;
      case  1271921616: 
          index = 346;
          break;
      case  301920808: 
          index = 420;
          break;
      case  321920808: 
          index = 200;
          break;
      case  1321920808: 
          index = 201;
          break;
      case  311920808: 
          index = 68;
          break;
      case  1311920808: 
          index = 76;
          break;
      case  301960808: 
          index = 421;
          break;
      case  321960808: 
          index = 202;
          break;
      case  1321960808: 
          index = 203;
          break;
      case  311960808: 
          index = 69;
          break;
      case  1311960808: 
          index = 77;
          break;
      case  302000808: 
          index = 428;
          break;
      case  322000808: 
          index = 216;
          break;
      case  1322000808: 
          index = 217;
          break;
      case  312000808: 
          index = 84;
          break;
      case  1312000808: 
          index = 92;
          break;
      case  302040808: 
          index = 429;
          break;
      case  322040808: 
          index = 218;
          break;
      case  1322040808: 
          index = 219;
          break;
      case  312040808: 
          index = 85;
          break;
      case  1312040808: 
          index = 93;
          break;
      case  202081616: 
          index = 555;
          break;
      case  222081616: 
          index = 502;
          break;
      case  1222081616: 
          index = 503;
          break;
      case  212081616: 
          index = 467;
          break;
      case  1212081616: 
          index = 471;
          break;
      case  242081616: 
          index = 267;
          break;
      case  1242081616: 
          index = 315;
          break;
      case  252081616: 
          index = 299;
          break;
      case  1252081616: 
          index = 283;
          break;
      case  262081616: 
          index = 331;
          break;
      case  1262081616: 
          index = 379;
          break;
      case  272081616: 
          index = 363;
          break;
      case  1272081616: 
          index = 347;
          break;
      case  302080808: 
          index = 422;
          break;
      case  322080808: 
          index = 204;
          break;
      case  1322080808: 
          index = 205;
          break;
      case  312080808: 
          index = 70;
          break;
      case  1312080808: 
          index = 78;
          break;
      case  302120808: 
          index = 423;
          break;
      case  322120808: 
          index = 206;
          break;
      case  1322120808: 
          index = 207;
          break;
      case  312120808: 
          index = 71;
          break;
      case  1312120808: 
          index = 79;
          break;
      case  302160808: 
          index = 430;
          break;
      case  322160808: 
          index = 220;
          break;
      case  1322160808: 
          index = 221;
          break;
      case  312160808: 
          index = 86;
          break;
      case  1312160808: 
          index = 94;
          break;
      case  302200808: 
          index = 431;
          break;
      case  322200808: 
          index = 222;
          break;
      case  1322200808: 
          index = 223;
          break;
      case  312200808: 
          index = 87;
          break;
      case  1312200808: 
          index = 95;
          break;
      case  202241616: 
          index = 558;
          break;
      case  222241616: 
          index = 508;
          break;
      case  1222241616: 
          index = 509;
          break;
      case  212241616: 
          index = 474;
          break;
      case  1212241616: 
          index = 478;
          break;
      case  242241616: 
          index = 270;
          break;
      case  1242241616: 
          index = 318;
          break;
      case  252241616: 
          index = 302;
          break;
      case  1252241616: 
          index = 286;
          break;
      case  262241616: 
          index = 334;
          break;
      case  1262241616: 
          index = 382;
          break;
      case  272241616: 
          index = 366;
          break;
      case  1272241616: 
          index = 350;
          break;
      case  302240808: 
          index = 436;
          break;
      case  322240808: 
          index = 232;
          break;
      case  1322240808: 
          index = 233;
          break;
      case  312240808: 
          index = 100;
          break;
      case  1312240808: 
          index = 108;
          break;
      case  302280808: 
          index = 437;
          break;
      case  322280808: 
          index = 234;
          break;
      case  1322280808: 
          index = 235;
          break;
      case  312280808: 
          index = 101;
          break;
      case  1312280808: 
          index = 109;
          break;
      case  302320808: 
          index = 444;
          break;
      case  322320808: 
          index = 248;
          break;
      case  1322320808: 
          index = 249;
          break;
      case  312320808: 
          index = 116;
          break;
      case  1312320808: 
          index = 124;
          break;
      case  302360808: 
          index = 445;
          break;
      case  322360808: 
          index = 250;
          break;
      case  1322360808: 
          index = 251;
          break;
      case  312360808: 
          index = 117;
          break;
      case  1312360808: 
          index = 125;
          break;
      case  202401616: 
          index = 559;
          break;
      case  222401616: 
          index = 510;
          break;
      case  1222401616: 
          index = 511;
          break;
      case  212401616: 
          index = 475;
          break;
      case  1212401616: 
          index = 479;
          break;
      case  242401616: 
          index = 271;
          break;
      case  1242401616: 
          index = 319;
          break;
      case  252401616: 
          index = 303;
          break;
      case  1252401616: 
          index = 287;
          break;
      case  262401616: 
          index = 335;
          break;
      case  1262401616: 
          index = 383;
          break;
      case  272401616: 
          index = 367;
          break;
      case  1272401616: 
          index = 351;
          break;
      case  302400808: 
          index = 438;
          break;
      case  322400808: 
          index = 236;
          break;
      case  1322400808: 
          index = 237;
          break;
      case  312400808: 
          index = 102;
          break;
      case  1312400808: 
          index = 110;
          break;
      case  302440808: 
          index = 439;
          break;
      case  322440808: 
          index = 238;
          break;
      case  1322440808: 
          index = 239;
          break;
      case  312440808: 
          index = 103;
          break;
      case  1312440808: 
          index = 111;
          break;
      case  302480808: 
          index = 446;
          break;
      case  322480808: 
          index = 252;
          break;
      case  1322480808: 
          index = 253;
          break;
      case  312480808: 
          index = 118;
          break;
      case  1312480808: 
          index = 126;
          break;
      case  302520808: 
          index = 447;
          break;
      case  322520808: 
          index = 254;
          break;
      case  1322520808: 
          index = 255;
          break;
      case  312520808: 
          index = 119;
          break;
      case  1312520808: 
          index = 127;
          break;
      default:
        index = -1;
          }
  #endif
  
    return index;
  }
  
  //! \}
  