    // @(#)root/star:$Name:  $:$Id: TVolumeViewIter.cxx,v 1.3 2003/08/14 12:02:20 brun Exp $
    // Author: Valery Fine(fine@bnl.gov)   25/01/99

    #include "TVolumeViewIter.h"
    #include "TObjArray.h"
    #include "TVolumeView.h"
    #include "TDataSetIter.h"
    #include "TGeometry.h"

    /////////////////////////////////////////////////////////////////////////////////
    //
    //   TVolumeViewIter is a special class-iterator to
    //   iterate over GEANT geometry dataset TVolumeView.
    //   Class should provide a "standard" well-known
    //   "TDataSetIter" interface to navigate and access
    //   the geometry information supplied by Tgeant_Maker
    //   as the TVolume object. Apart of the the base
    //   TDataSetIter this special class may supply
    //   not only pointer to the selected dataset but some
    //   "position" information (like translate vectors and
    //   rotation matrice).
    //
    /////////////////////////////////////////////////////////////////////////////////

    ClassImp(TVolumeViewIter)
    //______________________________________________________________________________
     TVolumeViewIter::TVolumeViewIter(TVolumeView *view, Int_t depth, Bool_t dir):
               TDataSetIter(view,depth,dir),fPositions(0)
    {
    }

    //______________________________________________________________________________
     TVolumeViewIter::~TVolumeViewIter()
    {
      if (fPositions) { fPositions->Delete(); delete fPositions; }
    }
    //______________________________________________________________________________
     const TVolumePosition *TVolumeViewIter::GetPosition(Int_t level) const
    {
      const TVolumePosition *pos = 0;
      if (fPositions) {
        Int_t thisLevel = level;
        if (!thisLevel) thisLevel = fDepth;
        pos=(TVolumePosition *)fPositions->At(thisLevel);
      }
      return pos;
    }

    //______________________________________________________________________________
    TVolumePosition *TVolumeViewIter::operator[](Int_t level)
    {
      const TVolumePosition *pos = GetPosition(level);
      if (pos) return new TVolumePosition(*pos);
      else {
         Error("operator[]"," GetPosition: %d %d %x", level,fDepth, fPositions);
         return 0;
      }
    }

    //______________________________________________________________________________
     void TVolumeViewIter::Notify(TDataSet *set)
    {
      if (!set) return;
      TVolumeView     *view         = (TVolumeView *) set;
      TVolumePosition *position     = 0;
      position = view->GetPosition();
      UpdateTempMatrix(position);
    }

    //______________________________________________________________________________
     TVolumePosition *TVolumeViewIter::UpdateTempMatrix(TVolumePosition *curPosition)
    {
      // Pick the "old" position by pieces
      TVolumePosition *newPosition = 0;
      TVolume *curNode = 0;
      UInt_t curPositionId    = 0;
      if (curPosition) {
          curNode       = curPosition->GetNode();
          curPositionId = curPosition->GetId();
      }
      if (fDepth-1) {
        TVolumePosition *oldPosition = 0;
        const TRotMatrix *oldMatrix = 0;
        oldPosition = fPositions ? (TVolumePosition *)fPositions->At(fDepth-1):0;
        Double_t oldTranslation[] = { 0, 0, 0 };
        if (oldPosition)
        {
          oldMatrix         = oldPosition->GetMatrix();
          oldTranslation[0] = oldPosition->GetX();
          oldTranslation[1] = oldPosition->GetY();
          oldTranslation[2] = oldPosition->GetZ();
        }

        // Pick the "current" position by pieces
        const TRotMatrix *curMatrix        = curPosition->GetMatrix();

        // Create a new position
        Double_t newTranslation[3];
        Double_t newMatrix[9];

        if(oldMatrix)
        {
          TGeometry::UpdateTempMatrix(oldTranslation,((TRotMatrix *)oldMatrix)->GetMatrix()
                           ,curPosition->GetX(),curPosition->GetY(),curPosition->GetZ()
                           ,((TRotMatrix *)curMatrix)->GetMatrix()
                           ,newTranslation,newMatrix);
          Int_t num = gGeometry->GetListOfMatrices()->GetSize();
          Char_t anum[100];
          sprintf(anum,"%d",num+1);
          newPosition = SetPositionAt(curNode
                                    ,newTranslation[0],newTranslation[1],newTranslation[2]
                                    ,new TRotMatrix(anum,"NodeView",newMatrix));
          newPosition->SetMatrixOwner();
        }
        else {
           newTranslation[0] = oldTranslation[0] + curPosition->GetX();
           newTranslation[1] = oldTranslation[1] + curPosition->GetY();
           newTranslation[2] = oldTranslation[2] + curPosition->GetZ();
           newPosition = SetPositionAt(curNode,newTranslation[0],newTranslation[1],newTranslation[2]);
        }
      }
      else if (curPosition)  {
             newPosition =  SetPositionAt(*curPosition);
    //         printf(" new level %d %s\n",fDepth, curNode->GetName());
           }
           else
             Error("UpdateTempMatrix","No position has been defined");
      if (newPosition) newPosition->SetId(curPositionId);
      return newPosition;
    }

    //______________________________________________________________________________
     void TVolumeViewIter::ResetPosition(Int_t level, TVolumePosition *newPosition)
    {
      Int_t thisLevel = level;
      if (!thisLevel) thisLevel = fDepth;
      TVolumePosition *thisPosition  =  (TVolumePosition *) GetPosition(level);
      if (newPosition)
         *thisPosition =  *newPosition;
    }

    //______________________________________________________________________________
     void TVolumeViewIter::Reset(TDataSet *l,Int_t depth)
    {
      TDataSetIter::Reset(l,depth);
    }

    //______________________________________________________________________________
     TVolumePosition *TVolumeViewIter::SetPositionAt(TVolume *node,Double_t x, Double_t y, Double_t z, TRotMatrix *matrix)
    {
       if (!fPositions)  fPositions = new TObjArray(100);
       TVolumePosition *position =  (TVolumePosition *) fPositions->At(fDepth);
       if (position) position->Reset(node,x,y,z,matrix);
       else {
          position = new TVolumePosition(node,x,y,z,matrix);
          fPositions->AddAtAndExpand(position,fDepth);
        }
       return position;
    }

    //______________________________________________________________________________
     TVolumePosition *TVolumeViewIter::SetPositionAt(TVolumePosition &curPosition)
    {
       if (!fPositions)  fPositions = new TObjArray(100);
       TVolumePosition *position =  (TVolumePosition *) fPositions->At(fDepth);
       if (position) *position = curPosition;
       else {
          position = new TVolumePosition(curPosition);
          fPositions->AddAtAndExpand(position,fDepth);
        }
       return position;
    }