ROOT logo
//*-- Author :    Ole Hansen, Jefferson Lab   16-Aug-2007

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// TreeSearch::Projection                                                    //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#include "Projection.h"
#include "Hitpattern.h"
#include "WirePlane.h"
#include "THaDetectorBase.h"
#include "PatternTree.h"
#include "PatternGenerator.h"
#include "TreeWalk.h"
#include "Road.h"
#include "Helper.h"
#include "Hit.h"
#include "MWDC.h"   // for MWDC bits

#include "TMath.h"
#include "TString.h"
#include "TBits.h"
#include "TError.h"

#include <iostream>
#include <algorithm>
#include <utility>
#ifdef TESTCODE
#include "TStopwatch.h"
#include <cstring>
#endif

using namespace std;

namespace TreeSearch {

typedef vector<WirePlane*>::size_type vwsiz_t;
typedef vector<WirePlane*>::iterator  vwiter_t;

#define ALL(c) (c).begin(), (c).end()

//_____________________________________________________________________________
Projection::Projection( EProjType type, const char* name, Double_t angle,
			THaDetectorBase* parent )
  : THaAnalysisObject( name, name ), fType(type), fNlevels(0),
    fMaxSlope(0.0), fWidth(0.0), fDetector(parent), fPatternTree(0),
    fMinFitPlanes(3), fMaxMiss(0), fRequire1of2(true),
    fPlaneCombos(0), fMaxPat(kMaxUInt), fFrontMaxBinDist(kMaxUInt),
    fBackMaxBinDist(kMaxUInt), fHitMaxDist(0), fConfLevel(1e-3),
    fHitpattern(0), fRoads(0), fNgoodRoads(0), fRoadCorners(0)
{
  // Constructor

  assert( name && parent );

  // angle is the default value. It can be overridden via a database entry.
  SetAngle( angle );

  fTitle.Append(" projection");
  fRoads = new TClonesArray("TreeSearch::Road", 3);
  R__ASSERT(fRoads);
}

//_____________________________________________________________________________
Projection::~Projection()
{
  // Destructor

  if( fIsSetup )
    RemoveVariables();
  delete fRoads;
  delete fRoadCorners;
  delete fPatternTree;
  delete fHitpattern;
  delete fPlaneCombos;
}

//_____________________________________________________________________________
void Projection::AddPlane( WirePlane* wp, WirePlane* partner )
{
  // Add wire plane wp (and optional partner plane) to this projection. 
  // Sets plane numbers.

  assert(wp);

  wp->SetPlaneNum( fPlanes.size() );
  fPlanes.push_back( wp );
  wp->SetProjection( this );
  if( partner ) {
    assert( partner->GetZ() > wp->GetZ() ); // Planes must be ordered
    partner->SetPlaneNum( fPlanes.size() );
    fPlanes.push_back( partner );
    partner->SetProjection( this );
  }
}

//_____________________________________________________________________________
void Projection::Clear( Option_t* )
{    
  // Clear event-by-event data

  if( fHitpattern )
    fHitpattern->Clear();

  fRoads->Delete();
  DeleteContainer( fPatternsFound );
  fNgoodRoads = 0;

  if( TestBit(kEventDisplay) )
    fRoadCorners->Clear();

#ifdef TESTCODE
  size_t nbytes = (char*)&t_track - (char*)&n_hits + sizeof(t_track);
  memset( &n_hits, 0, nbytes );
#endif
}

//_____________________________________________________________________________
Int_t Projection::Decode( const THaEvData& evdata )
{
  // Decode all planes belonging to this projection

  Int_t sum = 0;
  bool err = false;
  for( vwsiz_t i = 0; i < GetNplanes(); ++i ) {
    WirePlane* wp = fPlanes[i];
    Int_t nhits = wp->Decode( evdata );
    if( nhits < 0 ) {
      err = true;
      sum -= nhits;
    } else
      sum += nhits;
  }
  if( err )
    return -sum;

  return sum;
}

//_____________________________________________________________________________
Double_t Projection::GetPlaneZ( UInt_t i ) const
{
  // Return the z-position of the i-th wire plane.

  assert( i<fPlanes.size() );
  return fPlanes[i]->GetZ();
}

//_____________________________________________________________________________
void Projection::Reset()
{
  // Reset parameters, clear list of planes, delete Hitpattern
  
  fIsInit = kFALSE;
  fPlanes.clear();
  fMaxSlope = fWidth = 0.0;
  delete fHitpattern; fHitpattern = 0;
  delete fPatternTree; fPatternTree = 0;
  delete fPlaneCombos; fPlaneCombos = 0;
  delete fRoadCorners; fRoadCorners = 0;
}

//_____________________________________________________________________________
THaAnalysisObject::EStatus Projection::Init( const TDatime& date )
{
  // Initialize the Projection object. Called after MWDC basic initialization.
  // Sets up event display support, then continues with standard 
  // initialization.

  Reset();

  // Set up the event display support if corresponding bit is set in the MWDC
  if( fDetector->TestBit(MWDC::kEventDisplay) ) {
    assert( fRoadCorners == 0 );
    fRoadCorners = new TClonesArray("TreeSearch::Road::Corners", 3);
    R__ASSERT(fRoadCorners);
    // Set local bit to indicate that initialization is done
    SetBit(kEventDisplay);
  }

  // Standard initialization. This calls ReadDatabase() and DefineVariables()
  return THaAnalysisObject::Init(date);
}

//_____________________________________________________________________________
THaAnalysisObject::EStatus Projection::InitLevel2( const TDatime& )
{
  // Level-2 initialization - load pattern database and initialize hitpattern.
  // Requires the wire planes to be fully initialized.

  static const char* const here = "InitLevel2";

  vector<Double_t> zpos;
  for( UInt_t i = 0; i < GetNplanes(); ++i )
    zpos.push_back( GetPlaneZ(i) );
  TreeParam_t tp( fNlevels-1, fWidth, fMaxSlope, zpos );
		  
  if( tp.Normalize() != 0 )
    return fStatus = kInitError;

  // Attempt to read the pattern database from file
  assert( fPatternTree == 0 );
  //TODO: Make the file name
  const char* filename = "test.tree";
  fPatternTree = PatternTree::Read( filename, tp );
  
  // If the tree cannot not be read (or the parameters mismatch), then
  // create it from scratch (takes a few seconds)
  if( !fPatternTree ) {
    PatternGenerator pg;
    fPatternTree = pg.Generate( tp );
    if( fPatternTree ) {
      // Write the freshly-generated tree to file
      // FIXME: hmmm... we don't necesarily have write permission to DB_DIR
//       fPatternTree->Write( filename );
    } else 
      return fStatus = kInitError;
  } 

  // Set up a hitpattern object with the parameters of this projection
  assert( fHitpattern == 0 );
  fHitpattern = new Hitpattern( *fPatternTree );
  if( !fHitpattern || fHitpattern->IsError() )
    return fStatus = kInitError;
  assert( GetNplanes() == fHitpattern->GetNplanes() );

  // Determine maximum search distance (in bins) for combining patterns,
  // separately for front and back planes since they can have different
  // parameters.
  // This is the max distance of bins that can belong to the same hit 
  // plus an allowance for extra slope of a pattern if a front/back hit
  // is missing
  WirePlane *front_plane = fPlanes.front(), *back_plane = fPlanes.back();
  Double_t dxf= front_plane->GetMaxLRdist() + 2.0*front_plane->GetResolution();
  Double_t dxb= back_plane->GetMaxLRdist()  + 2.0*back_plane->GetResolution();
  fFrontMaxBinDist = TMath::CeilNint( dxf * fHitpattern->GetBinScale() ) + 2;
  fBackMaxBinDist  = TMath::CeilNint( dxb * fHitpattern->GetBinScale() ) + 2;

  // Special handling of calibration mode: Allow missing hits in calibration
  // planes, and require hits in all other planes 
  UInt_t ncalib = 0;
  for( UInt_t k = 0; k < GetNplanes(); ++k ) {
    if( fPlanes[k]->IsCalibrating() )
      ++ncalib;
  }
  if( ncalib > 0 ) {
    Info( Here(here), "Calibrating %d planes in %s-projection.",
	  ncalib, GetName() );
    fMaxMiss = ncalib;
    for( UInt_t k = 0; k < GetNplanes(); ++k ) {
      if( fPlanes[k]->IsCalibrating() ) {
	if( fRequire1of2 and fPlanes[k]->GetPartner() and
	    fPlanes[k]->GetPartner()->IsCalibrating() ) {
	  Error( Here(here), "Cannot require 1 of 2 partner planes and "
		 "calibrate both partners (%s and %s) simultaneously. "
		 "Fix database.", fPlanes[k]->GetName(),
		 fPlanes[k]->GetPartner()->GetName() );
	  return kInitError;
	}
      } else
	fPlanes[k]->SetRequired();
    }
  }

  // Check range of fMinFitPlanes (minimum number of planes require for fit)
  // and fMaxMiss (maximum number of missing planes allowed in a hitpattern).
  // This is done here instead of in ReadDatabase because we need GetNplanes().
  if( fMinFitPlanes < 3 or fMinFitPlanes > GetNplanes() ) {
    Error( Here(here), "Illegal number of required planes for projection "
	   "track fitting = %u. Must be >= 3 and <= %u. Fix database.",
	   fMinFitPlanes, GetNplanes() );
    return kInitError;
  }
  if( fMaxMiss > GetNplanes()-2 ) {
    Error( Here(here), "Illegal number of allowed missing planes = %u. "
	   "Must be <= %u. Fix database.", fMaxMiss, GetNplanes()-2 );
    return kInitError;
  }
  // There cannot be so many planes missing that we don't have at least
  // fMinFitPlanes left
  UInt_t allowed_maxmiss = GetNplanes()-fMinFitPlanes;
  if( fMaxMiss > allowed_maxmiss ) {
    if( ncalib == 0 ) {
      Warning( Here(here), "Allowed number of missing planes = %u reduced "
	       "to %u to satisfy min_fit_planes = %u.  Fix database.", 
	       fMaxMiss, allowed_maxmiss, fMinFitPlanes );
      fMaxMiss = allowed_maxmiss;
    } else {
      Error( Here(here), "Too many planes in calibration mode, found %d, "
	     "max allowed = %d. Fix database.", ncalib, allowed_maxmiss );
      return kInitError;
    }
  }

  // Set up the lookup bitpattern indicating which planes are allowed to have 
  // missing hits. The value of the bit pattern of plane hits is used as an
  // index into this table; if the corresponding bit is set, the plane 
  // combination is allowed.
  assert( fPlaneCombos == 0 );
  UInt_t np = 1U<<GetNplanes();
  fPlaneCombos = new TBits( np );
  fPlaneCombos->SetBitNumber( np-1 );  // Always allow full occupancy
  for( UInt_t i = 1; i <= fMaxMiss; ++i ) {
    UniqueCombo c( GetNplanes(), i );
    while( c ) {
      // Clear the bit numbers from this combination
      UInt_t bitval = np-1;
      for( vector<int>::size_type j = 0; j < c().size(); ++j )
	bitval &= ~( 1U << c()[j] );
      // Test if this pattern satisfies other constraints
      UInt_t k = 0;
      for( ; k < GetNplanes(); ++k ) {
	// Disallow bit pattern if a required plane is missing
	if( 0 == (bitval & (1U<<k)) and fPlanes[k]->IsRequired() )
	  break;
	// If requested, ensure that at least one plane of a plane pair is set
	if( fRequire1of2 and fPlanes[k]->GetPartner() and
	    0 == (bitval & (1U<<k)) and
	    0 == (bitval & (1U<<fPlanes[k]->GetPartner()->GetPlaneNum())) )
	  break;
      }
      assert( bitval < np );
      if( k == GetNplanes() )
	fPlaneCombos->SetBitNumber( bitval );
      ++c;
    }
  }
  
  // Determine Chi2 confidence interval limits for the selected CL and the
  // possible degrees of freedom (minfit-2...nplanes-2) of the projection fit
  fChisqLimits.clear();
  fChisqLimits.resize( GetNplanes()-1, make_pair<Double_t,Double_t>(0,0) );
  for( vec_pdbl_t::size_type dof = fMinFitPlanes-2;
       dof < fChisqLimits.size(); ++dof ) {
    fChisqLimits[dof].first = TMath::ChisquareQuantile( fConfLevel, dof );
    fChisqLimits[dof].second = TMath::ChisquareQuantile( 1.0-fConfLevel, dof );
  }
  
  fPatternsFound.reserve( 200 );

  return fStatus = kOK;
}

//_____________________________________________________________________________
Int_t Projection::ReadDatabase( const TDatime& date )
{
  // Read parameters from database

  static const char* const here = "ReadDatabase";

  FILE* file = OpenFile( date );
  if( !file ) return kFileError;

  Double_t angle = kBig;
  fHitMaxDist = 0;
  fMinFitPlanes = 3;
  fMaxMiss = 0;
  fMaxPat  = kMaxUInt;
  fConfLevel = 1e-3;
  Int_t req1of2 = 1;
  const DBRequest request[] = {
    { "angle",           &angle,         kDouble, 0, 1 },
    { "maxslope",        &fMaxSlope,     kDouble, 0, 1, -1 },
    { "search_depth",    &fNlevels,      kUInt,   0, 0, -1 },
    { "cluster_maxdist", &fHitMaxDist,   kUInt,   0, 1, -1 },
    { "min_fit_planes",  &fMinFitPlanes, kUInt,   0, 1, -1 },
    { "chi2_conflevel",  &fConfLevel,    kDouble, 0, 1, -1 },
    { "maxmiss",         &fMaxMiss,      kUInt,   0, 1, -1 },
    { "req1of2",         &req1of2,       kInt,    0, 1, -1 },
    { "maxpat",          &fMaxPat,       kUInt,   0, 1, -1 },
    { 0 }
  };

  Int_t err = LoadDB( file, date, request, fPrefix );
  fclose(file);
  if( err )
    return kInitError;

  if( fNlevels >= 16 ) {
    Error( Here(here), "Illegal search_depth = %u. Must be < 16. "
	   "Fix database.", fNlevels );
    return kInitError;
  }
  ++fNlevels; // The number of levels is maxdepth+1

  // If angle read, set it, otherwise keep default from call to constructor
  if( angle < kBig )
    SetAngle( angle*TMath::DegToRad() );

  if( fMaxSlope < 0.0 ) {
    Warning( Here(here), "Negative maxslope = %lf makes no sense. "
	     "Using |maxslope|.", fMaxSlope );
    fMaxSlope = -fMaxSlope;
  }

  if( fConfLevel < 0.0 || fConfLevel > 1.0 ) {
    Error( Here(here), "Illegal fit confidence level = %lf. "
	   "Must be 0-1. Fix database.", fConfLevel );
    return kInitError;
  }

  fRequire1of2 = (req1of2 != 0);

  fIsInit = kTRUE;
  return kOK;
}

//_____________________________________________________________________________
Int_t Projection::DefineVariables( EMode mode )
{
  // Initialize global variables and lookup table for decoder

  if( mode == kDefine && fIsSetup ) return kOK;
  fIsSetup = ( mode == kDefine );

  // Global variables
  RVarDef vars[] = {
#ifdef TESTCODE
    { "n_hits", "Number of hits used for filling hitpattern", "n_hits" },
    { "n_bins", "Number of bins set in hitpattern", "n_bins" },
    { "n_binhits", "Number of references from bins to hits","n_binhits" },
    { "n_maxhits_bin", "Max number of hits per bin", "maxhits_bin" },
    { "n_test", "Number of pattern comparisons", "n_test"  },
    { "n_pat", "Number of patterns found",   "n_pat"    },
    { "n_roads", "Number of roads before filter",   "n_roads"    },
    { "n_dupl",  "Number of duplicate roads removed",   "n_dupl"    },
    { "n_badfits", "Number of roads found",   "n_badfits"    },
    { "t_treesearch", "Time in TreeSearch (us)", "t_treesearch" },
    { "t_roads", "Time in MakeRoads (us)", "t_roads" },
    { "t_fit", "Time for fitting Roads (us)", "t_fit" },
    { "t_track", "Total time in Track (us)", "t_track" },
    { "rd.nfits", "Number of acceptable fits in road",
                                         "fRoads.TreeSearch::Road.fNfits" },
#endif
    { "nroads","Number of roads (good or bad)",        "GetNroads()"      },
    { "ngood", "Number of good roads",                 "fNgoodRoads"      },
    { "rd.pos",   "Origin of best track (m)",
                                           "fRoads.TreeSearch::Road.fPos" },
    { "rd.slope", "Slope (dx/dz) of best track",
                                         "fRoads.TreeSearch::Road.fSlope" },
    { "rd.chi2",  "Chi2 of best fit", 
                                          "fRoads.TreeSearch::Road.fChi2" },
    { "rd.dof",   "Degrees of freedom of best fit",
                                           "fRoads.TreeSearch::Road.fDof" },
    { "rd.good",  "Road has valid data",
                                          "fRoads.TreeSearch::Road.fGood" },
    { 0 }
  };
  DefineVarsFromList( vars, mode );
 
  // Additional information about the roads found, for event display
  if( TestBit(kEventDisplay) ) {
    RVarDef vars_evtdisp[] = {
      { "rd.xLL","Lower left corner x coordinate (m)",
	              "fRoadCorners.TreeSearch::Road::Corners.fXLL" },
      { "rd.xLR","Lower right corner x coordinate (m)",
	              "fRoadCorners.TreeSearch::Road::Corners.fXLR" },
      { "rd.zL", "Lower edge z coordinate (m)",
                       "fRoadCorners.TreeSearch::Road::Corners.fZL" },
      { "rd.xUL","Upper left corner x coordinate (m)",
	              "fRoadCorners.TreeSearch::Road::Corners.fXUL" },
      { "rd.xUR","Upper right corner x coordinate (m)",
	              "fRoadCorners.TreeSearch::Road::Corners.fXUR" },
      { "rd.zU", "Upper edge z coordinate (m)",
                       "fRoadCorners.TreeSearch::Road::Corners.fZU" },
      { 0 }
    };
    DefineVarsFromList( vars_evtdisp, mode );
  }
 
  return 0;
}

//_____________________________________________________________________________
Int_t Projection::FillHitpattern()
{
  // Fill this projection's hitpattern with hits from the wire planes.
  // Returns the total number of hits processed (where hit pairs on plane
  // and partner plane count as one).

  Int_t ntot = 0;
  for( vwiter_t it = fPlanes.begin(); it != fPlanes.end(); ++it ) {
    WirePlane *plane = *it, *partner = plane->GetPartner();
    // If a plane has a partner (usually with staggered wires), scan them
    // together to resolve some of the L/R ambiguity of the hit positions
    ntot += fHitpattern->ScanHits( plane, partner );
    // If the partner plane was just scanned, don't scan it again
    if( partner ) {
      ++it;
      assert( it != fPlanes.end() );
      assert( *it == partner );
    }
  }
#ifdef TESTCODE
  n_hits = ntot;
  n_bins = fHitpattern->GetBinsSet();
  n_binhits = fHitpattern->GetNhits();
  maxhits_bin = fHitpattern->GetMaxhitBin();
#endif
  return ntot;
}

//_____________________________________________________________________________
Int_t Projection::Track()
{
  // Perform tracking in this projection:
  //
  // - match hits to straight-line patterns
  // - combine patterns referring to common sets of hits into one ("Roads")
  // - fit hits in each road
  // - filter roads according to chi^2 and similarity
  //
  // Results in fRoads

  Int_t ret = 0;

  // TreeSearch:
  // Match the hitpattern of the current event against the pattern template
  // database. Results in fPatternsFound.

  assert( fPatternsFound.empty() );

#ifdef TESTCODE
  TStopwatch timer, timer_tot;
#endif

  ComparePattern compare( fHitpattern, fPlaneCombos, &fPatternsFound );
  TreeWalk walk( fNlevels );
  walk( fPatternTree->GetRoot(), compare );

#ifdef VERBOSE
  if( fDebug > 0 ) {
    UInt_t npat = fPatternsFound.size();
    cout << npat << " pattern";
    if( npat!=1 ) cout << "s";
    if( npat > fMaxPat )
      cout << " >>> exceeding limit of " << fMaxPat << ", terminating";
    cout << endl;
  }
#endif
#ifdef TESTCODE
  t_treesearch = 1e6*timer.RealTime();

  n_test = compare.GetNtest();
  n_pat  = fPatternsFound.size();

  timer.Start();
#endif

  if( fPatternsFound.empty() )
    goto quit;
  // Die if too many patterns - noisy event
  if( (UInt_t)fPatternsFound.size() > fMaxPat ) {
    // TODO: keep statistics
    ret = -1;
    goto quit;
  }

  // Combine patterns with common sets of hits into Roads
  MakeRoads();

#ifdef VERBOSE
  if( fDebug > 0 ) {
    if( !fRoads->IsEmpty() ) {
      Int_t nroads = GetNroads();
      cout << nroads << " road";
      if( nroads>1 ) cout << "s";
      cout << endl;
    }
  }
#endif
#ifdef TESTCODE
  n_roads = GetNroads();
#endif

  // This seems to cost much more than it gains
//   // Check for indentical roads or roads that include each other.
//   // Any roads that are eliminated are marked as void.
//   if( GetNroads() > 1 ) {
//     if( RemoveDuplicateRoads() )
//       // Remove empty slots caused by removed duplicate roads
//       fRoads->Compress();
//   }

// #ifdef VERBOSE
//   if( fDebug > 0 ) {
//     if( !fRoads->IsEmpty() ) {
//       Int_t nroads = GetNroads();
//       cout << nroads << " road";
//       if( nroads>1 ) cout << "s";
//       cout << " after filter" << endl;
//     }
//   }
// #endif
#ifdef TESTCODE
  t_roads = 1e6*timer.RealTime();
  timer.Start();
#endif

  // Fit hit positions in the roads to straight lines
  FitRoads();

#ifdef TESTCODE
  t_fit   = 1e6*timer.RealTime();
  t_track = 1e6*timer_tot.RealTime();
#endif

#ifdef VERBOSE
  if( fDebug > 0 ) {
    if( !fRoads->IsEmpty() ) {
      Int_t nroads = GetNgoodRoads();
      cout << nroads << " road";
      if( nroads>1 ) cout << "s";
      cout << " successfully fit" << endl;
    }
  }
#endif

  ret = GetNgoodRoads();

 quit:
#ifdef VERBOSE
  if( fDebug > 0 ) {
    cout << "------------ end of projection  " << GetName()
	 << "------------" << endl;
  }
#endif
  return ret;
}


//_____________________________________________________________________________
#ifdef VERBOSE
static void PrintNode( const Node_t& node )
{
  const HitSet& hs = node.second;
  cout << " npl/nhits= " << hs.nplanes << "/" << hs.hits.size()
       << "  wnums= ";
  UInt_t ipl = 0;
  for( Hset_t::iterator ihit = hs.hits.begin(); ihit != hs.hits.end(); ) {
    while( ipl < (*ihit)->GetPlaneNum() ) { cout << "--/"; ++ipl; }
    bool seq = false;
    do {
      if( seq )  cout << " ";
      cout << (*ihit)->GetWireNum();
      seq = true;
      ++ihit;
    } while( ihit != hs.hits.end() and (*ihit)->GetPlaneNum() == ipl );
    if( ipl != node.first.link->GetPattern()->GetNbits()-1 ) {
      cout << "/";
      if( ihit == hs.hits.end() )
	cout << "--";
    }
    ++ipl;
  }
  cout << "  pat= ";
  node.first.Print();
}

inline
static void PrintNodeP( const Node_t* node )
{
  PrintNode( *node );
}

#endif

//_____________________________________________________________________________
// Comparison functors used for sorting patterns in MakeRoads()

struct MostPlanes : public binary_function< Node_t*, Node_t*, bool >
{
  bool operator() ( const Node_t* a, const Node_t* b ) const
  {
    // Order patterns by decreasing number of active planes, then
    // decreasing number of hits, then ascending bin numbers
    if( a->second.nplanes > b->second.nplanes ) return true;
    if( a->second.nplanes < b->second.nplanes ) return false;
    if( a->second.hits.size() > b->second.hits.size() ) return true;
    if( a->second.hits.size() < b->second.hits.size() ) return false;
    return ( a->first < b->first );
  }
};

struct BinIsLess : public binary_function< Node_t*, Node_t*, bool >
{
  bool operator() ( const Node_t* a, const Node_t* b ) const
  {
    // Order by bin number only
    return ( a->first < b->first );
  }
};

//_____________________________________________________________________________
Int_t Projection::MakeRoads()
{
  // Combine patterns with common sets of hits into Roads.
  //
  // This is the primary de-cloning algorithm. It finds clusters of patterns
  // that share active wires (hits).

  // Sort patterns according to MostPlanes (see above)
  sort( ALL(fPatternsFound), MostPlanes() );

  // Copy patterns to secondary key sorted by bin number only. This key 
  // greatly improves lookup speed of potential similar patterns
  typedef set<const Node_t*,BinIsLess> BinOrdNodes_t;
  BinOrdNodes_t nodelookup;

  // Inserting one-by-one with hint is faster than range insert without hint
  // since fPatternsFound is already sorted in a similar order, so the hint
  // is often good
  copy( ALL(fPatternsFound), inserter( nodelookup, nodelookup.end() ));

  assert( fPatternsFound.size() == nodelookup.size() );

#ifdef VERBOSE
  if( fDebug > 2 ) {
    cout << fPatternsFound.size() << " patterns found:" << endl;
    for_each( ALL(fPatternsFound), PrintNodeP );

    cout << "--------------------------------------------" << endl;
    cout << nodelookup.size() << " patterns sorted by bin:" << endl;
    for_each( ALL(nodelookup), PrintNodeP );
  }
#endif

  // Build roads starting with patterns that have the most active planes.
  // These tend to yield the best track candidates.
  for( NodeVec_t::iterator it = fPatternsFound.begin(); it !=
	 fPatternsFound.end(); ++it ) {
    const Node_t& nd1 = **it;

    if( nd1.second.used )
      continue;

    // Start a new road with next unused pattern
    Road* rd = new( (*fRoads)[GetNroads()] ) Road(nd1,this);

    // Try to add similar patterns to this road (cf. HitSet::IsSimilarTo)
    // Since only patterns with front bin numbers near the start pattern
    // are candidates, search along the start bin index built above.
    BinOrdNodes_t::iterator jt = nodelookup.find( &nd1 );
    assert( jt != nodelookup.end() );
    assert( (*jt)->first == nd1.first );

    // Test patterns in direction of decreasing front bin number index, 
    // beginning with the road start pattern, until they are too far away.

    // need to rescan if fHitMaxDist > 0 because IsInFrontRange may catch
    // more patterns after patterns with new hits have been added
    while( rd->HasGrown() ) { 
      rd->ClearGrow();
      // The following runs much slower with a reverse_iterator
      BinOrdNodes_t::iterator jr(jt);
      if( jt != nodelookup.begin() ) {
	--jr;
	while( rd->IsInFrontRange((*jr)->first) ) {
	  if( rd->Add(**jr) ) {
	    // Pattern successfully added
	    // Erase used patterns from the lookup index
	    if( jr == nodelookup.begin() ) {
	      nodelookup.erase( jr );
	      break;
	    } else {
	      nodelookup.erase( jr-- );
	    }
	  } else if( jr != nodelookup.begin() ) {
	    --jr;
	  } else
	    break;
	}
      }
    }
    // Repeat in the forward direction along the index
    rd->SetGrow();
    while( rd->HasGrown() ) {
      rd->ClearGrow();
      BinOrdNodes_t::iterator jf(jt);
      ++jf;
      while( jf != nodelookup.end() and rd->IsInFrontRange((*jf)->first) ) {
	if( rd->Add(**jf) )
	  nodelookup.erase( jf++ );
	else
	  ++jf;
      }
    }
    nodelookup.erase( jt );

    // Update the "used" flags of the road's component patterns
    rd->Finish();

    // If event display enabled, export the road's corner coordinates
    if( TestBit(kEventDisplay) ) {
      assert( fRoads->GetLast() == fRoadCorners->GetLast()+1 );
      new( (*fRoadCorners)[fRoads->GetLast()] ) Road::Corners(rd);
    }
  }
  assert( nodelookup.empty() );

#ifdef VERBOSE
  if( fDebug > 2 ) {
    cout << "Generated roads: " << endl;
    for( UInt_t i = 0; i < GetNroads(); ++i ) {
      const Road* rd = GetRoad(i);
      const Road::NodeList_t& ndlst = rd->GetPatterns();
      for_each( ALL(ndlst), PrintNodeP );
      cout << "--------------------------------------------" << endl;
    }
  }
#endif

  return 0;
}

//_____________________________________________________________________________
Bool_t Projection::RemoveDuplicateRoads()
{
  // Check for identical roads or roads that include each other

  // This runs in ~O(N^2) time, but if N>1, it is typically only 2-5.
  bool changed = false, restart = true;
  while( restart ) {
    restart = false;
    for( UInt_t i = 0; i < GetNroads(); ++i ) {
      Road* rd = static_cast<Road*>(fRoads->UncheckedAt(i));
      if( !rd )
	continue;
      for( UInt_t j = i+1; j < GetNroads(); ++j ) {
	Road* rd2 = static_cast<Road*>(fRoads->UncheckedAt(j));
	if( !rd2 )
	  continue;
	if( rd->Include(rd2) ) {
	  fRoads->RemoveAt(j);
	  changed = restart = true;
#ifdef TESTCODE
	  ++n_dupl;
#endif
	} else if( rd2->Include(rd) ) {
	  fRoads->RemoveAt(i);
	  changed = restart = true;
#ifdef TESTCODE
	  ++n_dupl;
#endif
	}
	if( restart )
	  break;
      }
      if( restart )
	break;
    }
  }
  return changed;
}

//_____________________________________________________________________________
Bool_t Projection::FitRoads()
{
  // Fit hits within each road. Store fit parameters with Road. 
  // Also, store the hits & positions used by the best fit with Road.
  bool changed = false;

  for( UInt_t i = 0; i < GetNroads(); ++i ) {
    Road* rd = static_cast<Road*>(fRoads->UncheckedAt(i));
    assert(rd);
    if( rd->IsGood() ) {
      if( rd->Fit() )
	// Count good roads (not void and good fit)
	++fNgoodRoads;
      else {
	// Void roads with bad fits
	rd->Void();
	changed = true;
#ifdef TESTCODE
	++n_badfits;
#endif
      }
    }
  }
  return changed;
}

//_____________________________________________________________________________
void Projection::MakePrefix()
{
  // Set up name prefix for global variables. 

  TString basename;
  if( fDetector ) {
    basename = fDetector->GetPrefix();
    basename.Chop();  // delete trailing dot
  } else
    Warning( Here("MakePrefix"), "No parent detector defined. "
	     "Using \"%s\".", GetName() );

  THaAnalysisObject::MakePrefix( basename.Data() );
}

//_____________________________________________________________________________
const char* Projection::GetDBFileName() const
{
  // Return database file name prefix. We want the same database file
  // as our parent detector.

  return fDetector ? fDetector->GetDBFileName() : GetPrefix();
}

//_____________________________________________________________________________
Double_t Projection::GetZsize() const
{
  // Get z_max - z_min of the planes.
  
  assert( !fPlanes.empty() );

  return fPlanes.back()->GetZ() - fPlanes.front()->GetZ();
}

//_____________________________________________________________________________
void Projection::SetAngle( Double_t angle )
{
  // Set wire angle (rad)
  
  fAxis.Set( TMath::Cos(angle), TMath::Sin(angle) );
}

//_____________________________________________________________________________
void Projection::Print( Option_t* opt ) const
{    
  // Print plane type info

  Int_t verbose = 0;
  if( opt ) {
    TString opt_s(opt);
    opt_s.ToLower();
    verbose = opt_s.CountChar('v');
  }

  cout << "Projection:  " 
       << GetName()
       << " type="  << GetType()
       << " npl="   << fPlanes.size()
       << " nlev="  << GetNlevels()
       << " zsize=" << GetZsize()
       << " maxsl=" << GetMaxSlope()
       << " width=" << GetWidth()
       << " angle=" << GetAngle()*TMath::RadToDeg();
  cout << endl;

  if( verbose > 0 ) {
    for( vwsiz_t i = 0; i < fPlanes.size(); ++i ) {
      WirePlane* wp = fPlanes[i];
      wp->Print(opt);
    }
  }
}

//_____________________________________________________________________________
NodeVisitor::ETreeOp 
Projection::ComparePattern::operator() ( const NodeDescriptor& nd )
{
  // Test if the pattern from the database that is given by NodeDescriptor
  // is present in the current event's hitpattern

#ifdef TESTCODE
  ++fNtest;
#endif
  // Compute the match pattern and see if it is allowed
  pair<UInt_t,UInt_t> match = fHitpattern->ContainsPattern(nd);
  if( fPlaneCombos->TestBitNumber(match.first)  ) {
    if( nd.depth < fHitpattern->GetNlevels()-1 )
      return kRecurse;

    // Found a match at the bottom of the pattern tree
    Node_t* node = new Node_t;
    node->first = nd;

    // Collect all hits associated with the pattern's bins and save them
    // in the node's HitSet.
    for( UInt_t i = 0; i < fHitpattern->GetNplanes(); ++i ) {
      const vector<Hit*>& hits = fHitpattern->GetHits( i, nd[i] );
      node->second.hits.insert( ALL(hits) );
    }
    assert( HitSet::GetMatchValue(node->second.hits) == match.first );
    node->second.plane_pattern = match.first;
    node->second.nplanes = match.second;

    // Add the pointer to the new node to the vector of results
    //TODO: stop if max num of patterns reached
    fMatches->push_back( node );
  }
  return kSkipChildNodes;
}

//_____________________________________________________________________________

}  // end namespace TreeSearch

ClassImp(TreeSearch::Projection)

///////////////////////////////////////////////////////////////////////////////
 Projection.cxx:1
 Projection.cxx:2
 Projection.cxx:3
 Projection.cxx:4
 Projection.cxx:5
 Projection.cxx:6
 Projection.cxx:7
 Projection.cxx:8
 Projection.cxx:9
 Projection.cxx:10
 Projection.cxx:11
 Projection.cxx:12
 Projection.cxx:13
 Projection.cxx:14
 Projection.cxx:15
 Projection.cxx:16
 Projection.cxx:17
 Projection.cxx:18
 Projection.cxx:19
 Projection.cxx:20
 Projection.cxx:21
 Projection.cxx:22
 Projection.cxx:23
 Projection.cxx:24
 Projection.cxx:25
 Projection.cxx:26
 Projection.cxx:27
 Projection.cxx:28
 Projection.cxx:29
 Projection.cxx:30
 Projection.cxx:31
 Projection.cxx:32
 Projection.cxx:33
 Projection.cxx:34
 Projection.cxx:35
 Projection.cxx:36
 Projection.cxx:37
 Projection.cxx:38
 Projection.cxx:39
 Projection.cxx:40
 Projection.cxx:41
 Projection.cxx:42
 Projection.cxx:43
 Projection.cxx:44
 Projection.cxx:45
 Projection.cxx:46
 Projection.cxx:47
 Projection.cxx:48
 Projection.cxx:49
 Projection.cxx:50
 Projection.cxx:51
 Projection.cxx:52
 Projection.cxx:53
 Projection.cxx:54
 Projection.cxx:55
 Projection.cxx:56
 Projection.cxx:57
 Projection.cxx:58
 Projection.cxx:59
 Projection.cxx:60
 Projection.cxx:61
 Projection.cxx:62
 Projection.cxx:63
 Projection.cxx:64
 Projection.cxx:65
 Projection.cxx:66
 Projection.cxx:67
 Projection.cxx:68
 Projection.cxx:69
 Projection.cxx:70
 Projection.cxx:71
 Projection.cxx:72
 Projection.cxx:73
 Projection.cxx:74
 Projection.cxx:75
 Projection.cxx:76
 Projection.cxx:77
 Projection.cxx:78
 Projection.cxx:79
 Projection.cxx:80
 Projection.cxx:81
 Projection.cxx:82
 Projection.cxx:83
 Projection.cxx:84
 Projection.cxx:85
 Projection.cxx:86
 Projection.cxx:87
 Projection.cxx:88
 Projection.cxx:89
 Projection.cxx:90
 Projection.cxx:91
 Projection.cxx:92
 Projection.cxx:93
 Projection.cxx:94
 Projection.cxx:95
 Projection.cxx:96
 Projection.cxx:97
 Projection.cxx:98
 Projection.cxx:99
 Projection.cxx:100
 Projection.cxx:101
 Projection.cxx:102
 Projection.cxx:103
 Projection.cxx:104
 Projection.cxx:105
 Projection.cxx:106
 Projection.cxx:107
 Projection.cxx:108
 Projection.cxx:109
 Projection.cxx:110
 Projection.cxx:111
 Projection.cxx:112
 Projection.cxx:113
 Projection.cxx:114
 Projection.cxx:115
 Projection.cxx:116
 Projection.cxx:117
 Projection.cxx:118
 Projection.cxx:119
 Projection.cxx:120
 Projection.cxx:121
 Projection.cxx:122
 Projection.cxx:123
 Projection.cxx:124
 Projection.cxx:125
 Projection.cxx:126
 Projection.cxx:127
 Projection.cxx:128
 Projection.cxx:129
 Projection.cxx:130
 Projection.cxx:131
 Projection.cxx:132
 Projection.cxx:133
 Projection.cxx:134
 Projection.cxx:135
 Projection.cxx:136
 Projection.cxx:137
 Projection.cxx:138
 Projection.cxx:139
 Projection.cxx:140
 Projection.cxx:141
 Projection.cxx:142
 Projection.cxx:143
 Projection.cxx:144
 Projection.cxx:145
 Projection.cxx:146
 Projection.cxx:147
 Projection.cxx:148
 Projection.cxx:149
 Projection.cxx:150
 Projection.cxx:151
 Projection.cxx:152
 Projection.cxx:153
 Projection.cxx:154
 Projection.cxx:155
 Projection.cxx:156
 Projection.cxx:157
 Projection.cxx:158
 Projection.cxx:159
 Projection.cxx:160
 Projection.cxx:161
 Projection.cxx:162
 Projection.cxx:163
 Projection.cxx:164
 Projection.cxx:165
 Projection.cxx:166
 Projection.cxx:167
 Projection.cxx:168
 Projection.cxx:169
 Projection.cxx:170
 Projection.cxx:171
 Projection.cxx:172
 Projection.cxx:173
 Projection.cxx:174
 Projection.cxx:175
 Projection.cxx:176
 Projection.cxx:177
 Projection.cxx:178
 Projection.cxx:179
 Projection.cxx:180
 Projection.cxx:181
 Projection.cxx:182
 Projection.cxx:183
 Projection.cxx:184
 Projection.cxx:185
 Projection.cxx:186
 Projection.cxx:187
 Projection.cxx:188
 Projection.cxx:189
 Projection.cxx:190
 Projection.cxx:191
 Projection.cxx:192
 Projection.cxx:193
 Projection.cxx:194
 Projection.cxx:195
 Projection.cxx:196
 Projection.cxx:197
 Projection.cxx:198
 Projection.cxx:199
 Projection.cxx:200
 Projection.cxx:201
 Projection.cxx:202
 Projection.cxx:203
 Projection.cxx:204
 Projection.cxx:205
 Projection.cxx:206
 Projection.cxx:207
 Projection.cxx:208
 Projection.cxx:209
 Projection.cxx:210
 Projection.cxx:211
 Projection.cxx:212
 Projection.cxx:213
 Projection.cxx:214
 Projection.cxx:215
 Projection.cxx:216
 Projection.cxx:217
 Projection.cxx:218
 Projection.cxx:219
 Projection.cxx:220
 Projection.cxx:221
 Projection.cxx:222
 Projection.cxx:223
 Projection.cxx:224
 Projection.cxx:225
 Projection.cxx:226
 Projection.cxx:227
 Projection.cxx:228
 Projection.cxx:229
 Projection.cxx:230
 Projection.cxx:231
 Projection.cxx:232
 Projection.cxx:233
 Projection.cxx:234
 Projection.cxx:235
 Projection.cxx:236
 Projection.cxx:237
 Projection.cxx:238
 Projection.cxx:239
 Projection.cxx:240
 Projection.cxx:241
 Projection.cxx:242
 Projection.cxx:243
 Projection.cxx:244
 Projection.cxx:245
 Projection.cxx:246
 Projection.cxx:247
 Projection.cxx:248
 Projection.cxx:249
 Projection.cxx:250
 Projection.cxx:251
 Projection.cxx:252
 Projection.cxx:253
 Projection.cxx:254
 Projection.cxx:255
 Projection.cxx:256
 Projection.cxx:257
 Projection.cxx:258
 Projection.cxx:259
 Projection.cxx:260
 Projection.cxx:261
 Projection.cxx:262
 Projection.cxx:263
 Projection.cxx:264
 Projection.cxx:265
 Projection.cxx:266
 Projection.cxx:267
 Projection.cxx:268
 Projection.cxx:269
 Projection.cxx:270
 Projection.cxx:271
 Projection.cxx:272
 Projection.cxx:273
 Projection.cxx:274
 Projection.cxx:275
 Projection.cxx:276
 Projection.cxx:277
 Projection.cxx:278
 Projection.cxx:279
 Projection.cxx:280
 Projection.cxx:281
 Projection.cxx:282
 Projection.cxx:283
 Projection.cxx:284
 Projection.cxx:285
 Projection.cxx:286
 Projection.cxx:287
 Projection.cxx:288
 Projection.cxx:289
 Projection.cxx:290
 Projection.cxx:291
 Projection.cxx:292
 Projection.cxx:293
 Projection.cxx:294
 Projection.cxx:295
 Projection.cxx:296
 Projection.cxx:297
 Projection.cxx:298
 Projection.cxx:299
 Projection.cxx:300
 Projection.cxx:301
 Projection.cxx:302
 Projection.cxx:303
 Projection.cxx:304
 Projection.cxx:305
 Projection.cxx:306
 Projection.cxx:307
 Projection.cxx:308
 Projection.cxx:309
 Projection.cxx:310
 Projection.cxx:311
 Projection.cxx:312
 Projection.cxx:313
 Projection.cxx:314
 Projection.cxx:315
 Projection.cxx:316
 Projection.cxx:317
 Projection.cxx:318
 Projection.cxx:319
 Projection.cxx:320
 Projection.cxx:321
 Projection.cxx:322
 Projection.cxx:323
 Projection.cxx:324
 Projection.cxx:325
 Projection.cxx:326
 Projection.cxx:327
 Projection.cxx:328
 Projection.cxx:329
 Projection.cxx:330
 Projection.cxx:331
 Projection.cxx:332
 Projection.cxx:333
 Projection.cxx:334
 Projection.cxx:335
 Projection.cxx:336
 Projection.cxx:337
 Projection.cxx:338
 Projection.cxx:339
 Projection.cxx:340
 Projection.cxx:341
 Projection.cxx:342
 Projection.cxx:343
 Projection.cxx:344
 Projection.cxx:345
 Projection.cxx:346
 Projection.cxx:347
 Projection.cxx:348
 Projection.cxx:349
 Projection.cxx:350
 Projection.cxx:351
 Projection.cxx:352
 Projection.cxx:353
 Projection.cxx:354
 Projection.cxx:355
 Projection.cxx:356
 Projection.cxx:357
 Projection.cxx:358
 Projection.cxx:359
 Projection.cxx:360
 Projection.cxx:361
 Projection.cxx:362
 Projection.cxx:363
 Projection.cxx:364
 Projection.cxx:365
 Projection.cxx:366
 Projection.cxx:367
 Projection.cxx:368
 Projection.cxx:369
 Projection.cxx:370
 Projection.cxx:371
 Projection.cxx:372
 Projection.cxx:373
 Projection.cxx:374
 Projection.cxx:375
 Projection.cxx:376
 Projection.cxx:377
 Projection.cxx:378
 Projection.cxx:379
 Projection.cxx:380
 Projection.cxx:381
 Projection.cxx:382
 Projection.cxx:383
 Projection.cxx:384
 Projection.cxx:385
 Projection.cxx:386
 Projection.cxx:387
 Projection.cxx:388
 Projection.cxx:389
 Projection.cxx:390
 Projection.cxx:391
 Projection.cxx:392
 Projection.cxx:393
 Projection.cxx:394
 Projection.cxx:395
 Projection.cxx:396
 Projection.cxx:397
 Projection.cxx:398
 Projection.cxx:399
 Projection.cxx:400
 Projection.cxx:401
 Projection.cxx:402
 Projection.cxx:403
 Projection.cxx:404
 Projection.cxx:405
 Projection.cxx:406
 Projection.cxx:407
 Projection.cxx:408
 Projection.cxx:409
 Projection.cxx:410
 Projection.cxx:411
 Projection.cxx:412
 Projection.cxx:413
 Projection.cxx:414
 Projection.cxx:415
 Projection.cxx:416
 Projection.cxx:417
 Projection.cxx:418
 Projection.cxx:419
 Projection.cxx:420
 Projection.cxx:421
 Projection.cxx:422
 Projection.cxx:423
 Projection.cxx:424
 Projection.cxx:425
 Projection.cxx:426
 Projection.cxx:427
 Projection.cxx:428
 Projection.cxx:429
 Projection.cxx:430
 Projection.cxx:431
 Projection.cxx:432
 Projection.cxx:433
 Projection.cxx:434
 Projection.cxx:435
 Projection.cxx:436
 Projection.cxx:437
 Projection.cxx:438
 Projection.cxx:439
 Projection.cxx:440
 Projection.cxx:441
 Projection.cxx:442
 Projection.cxx:443
 Projection.cxx:444
 Projection.cxx:445
 Projection.cxx:446
 Projection.cxx:447
 Projection.cxx:448
 Projection.cxx:449
 Projection.cxx:450
 Projection.cxx:451
 Projection.cxx:452
 Projection.cxx:453
 Projection.cxx:454
 Projection.cxx:455
 Projection.cxx:456
 Projection.cxx:457
 Projection.cxx:458
 Projection.cxx:459
 Projection.cxx:460
 Projection.cxx:461
 Projection.cxx:462
 Projection.cxx:463
 Projection.cxx:464
 Projection.cxx:465
 Projection.cxx:466
 Projection.cxx:467
 Projection.cxx:468
 Projection.cxx:469
 Projection.cxx:470
 Projection.cxx:471
 Projection.cxx:472
 Projection.cxx:473
 Projection.cxx:474
 Projection.cxx:475
 Projection.cxx:476
 Projection.cxx:477
 Projection.cxx:478
 Projection.cxx:479
 Projection.cxx:480
 Projection.cxx:481
 Projection.cxx:482
 Projection.cxx:483
 Projection.cxx:484
 Projection.cxx:485
 Projection.cxx:486
 Projection.cxx:487
 Projection.cxx:488
 Projection.cxx:489
 Projection.cxx:490
 Projection.cxx:491
 Projection.cxx:492
 Projection.cxx:493
 Projection.cxx:494
 Projection.cxx:495
 Projection.cxx:496
 Projection.cxx:497
 Projection.cxx:498
 Projection.cxx:499
 Projection.cxx:500
 Projection.cxx:501
 Projection.cxx:502
 Projection.cxx:503
 Projection.cxx:504
 Projection.cxx:505
 Projection.cxx:506
 Projection.cxx:507
 Projection.cxx:508
 Projection.cxx:509
 Projection.cxx:510
 Projection.cxx:511
 Projection.cxx:512
 Projection.cxx:513
 Projection.cxx:514
 Projection.cxx:515
 Projection.cxx:516
 Projection.cxx:517
 Projection.cxx:518
 Projection.cxx:519
 Projection.cxx:520
 Projection.cxx:521
 Projection.cxx:522
 Projection.cxx:523
 Projection.cxx:524
 Projection.cxx:525
 Projection.cxx:526
 Projection.cxx:527
 Projection.cxx:528
 Projection.cxx:529
 Projection.cxx:530
 Projection.cxx:531
 Projection.cxx:532
 Projection.cxx:533
 Projection.cxx:534
 Projection.cxx:535
 Projection.cxx:536
 Projection.cxx:537
 Projection.cxx:538
 Projection.cxx:539
 Projection.cxx:540
 Projection.cxx:541
 Projection.cxx:542
 Projection.cxx:543
 Projection.cxx:544
 Projection.cxx:545
 Projection.cxx:546
 Projection.cxx:547
 Projection.cxx:548
 Projection.cxx:549
 Projection.cxx:550
 Projection.cxx:551
 Projection.cxx:552
 Projection.cxx:553
 Projection.cxx:554
 Projection.cxx:555
 Projection.cxx:556
 Projection.cxx:557
 Projection.cxx:558
 Projection.cxx:559
 Projection.cxx:560
 Projection.cxx:561
 Projection.cxx:562
 Projection.cxx:563
 Projection.cxx:564
 Projection.cxx:565
 Projection.cxx:566
 Projection.cxx:567
 Projection.cxx:568
 Projection.cxx:569
 Projection.cxx:570
 Projection.cxx:571
 Projection.cxx:572
 Projection.cxx:573
 Projection.cxx:574
 Projection.cxx:575
 Projection.cxx:576
 Projection.cxx:577
 Projection.cxx:578
 Projection.cxx:579
 Projection.cxx:580
 Projection.cxx:581
 Projection.cxx:582
 Projection.cxx:583
 Projection.cxx:584
 Projection.cxx:585
 Projection.cxx:586
 Projection.cxx:587
 Projection.cxx:588
 Projection.cxx:589
 Projection.cxx:590
 Projection.cxx:591
 Projection.cxx:592
 Projection.cxx:593
 Projection.cxx:594
 Projection.cxx:595
 Projection.cxx:596
 Projection.cxx:597
 Projection.cxx:598
 Projection.cxx:599
 Projection.cxx:600
 Projection.cxx:601
 Projection.cxx:602
 Projection.cxx:603
 Projection.cxx:604
 Projection.cxx:605
 Projection.cxx:606
 Projection.cxx:607
 Projection.cxx:608
 Projection.cxx:609
 Projection.cxx:610
 Projection.cxx:611
 Projection.cxx:612
 Projection.cxx:613
 Projection.cxx:614
 Projection.cxx:615
 Projection.cxx:616
 Projection.cxx:617
 Projection.cxx:618
 Projection.cxx:619
 Projection.cxx:620
 Projection.cxx:621
 Projection.cxx:622
 Projection.cxx:623
 Projection.cxx:624
 Projection.cxx:625
 Projection.cxx:626
 Projection.cxx:627
 Projection.cxx:628
 Projection.cxx:629
 Projection.cxx:630
 Projection.cxx:631
 Projection.cxx:632
 Projection.cxx:633
 Projection.cxx:634
 Projection.cxx:635
 Projection.cxx:636
 Projection.cxx:637
 Projection.cxx:638
 Projection.cxx:639
 Projection.cxx:640
 Projection.cxx:641
 Projection.cxx:642
 Projection.cxx:643
 Projection.cxx:644
 Projection.cxx:645
 Projection.cxx:646
 Projection.cxx:647
 Projection.cxx:648
 Projection.cxx:649
 Projection.cxx:650
 Projection.cxx:651
 Projection.cxx:652
 Projection.cxx:653
 Projection.cxx:654
 Projection.cxx:655
 Projection.cxx:656
 Projection.cxx:657
 Projection.cxx:658
 Projection.cxx:659
 Projection.cxx:660
 Projection.cxx:661
 Projection.cxx:662
 Projection.cxx:663
 Projection.cxx:664
 Projection.cxx:665
 Projection.cxx:666
 Projection.cxx:667
 Projection.cxx:668
 Projection.cxx:669
 Projection.cxx:670
 Projection.cxx:671
 Projection.cxx:672
 Projection.cxx:673
 Projection.cxx:674
 Projection.cxx:675
 Projection.cxx:676
 Projection.cxx:677
 Projection.cxx:678
 Projection.cxx:679
 Projection.cxx:680
 Projection.cxx:681
 Projection.cxx:682
 Projection.cxx:683
 Projection.cxx:684
 Projection.cxx:685
 Projection.cxx:686
 Projection.cxx:687
 Projection.cxx:688
 Projection.cxx:689
 Projection.cxx:690
 Projection.cxx:691
 Projection.cxx:692
 Projection.cxx:693
 Projection.cxx:694
 Projection.cxx:695
 Projection.cxx:696
 Projection.cxx:697
 Projection.cxx:698
 Projection.cxx:699
 Projection.cxx:700
 Projection.cxx:701
 Projection.cxx:702
 Projection.cxx:703
 Projection.cxx:704
 Projection.cxx:705
 Projection.cxx:706
 Projection.cxx:707
 Projection.cxx:708
 Projection.cxx:709
 Projection.cxx:710
 Projection.cxx:711
 Projection.cxx:712
 Projection.cxx:713
 Projection.cxx:714
 Projection.cxx:715
 Projection.cxx:716
 Projection.cxx:717
 Projection.cxx:718
 Projection.cxx:719
 Projection.cxx:720
 Projection.cxx:721
 Projection.cxx:722
 Projection.cxx:723
 Projection.cxx:724
 Projection.cxx:725
 Projection.cxx:726
 Projection.cxx:727
 Projection.cxx:728
 Projection.cxx:729
 Projection.cxx:730
 Projection.cxx:731
 Projection.cxx:732
 Projection.cxx:733
 Projection.cxx:734
 Projection.cxx:735
 Projection.cxx:736
 Projection.cxx:737
 Projection.cxx:738
 Projection.cxx:739
 Projection.cxx:740
 Projection.cxx:741
 Projection.cxx:742
 Projection.cxx:743
 Projection.cxx:744
 Projection.cxx:745
 Projection.cxx:746
 Projection.cxx:747
 Projection.cxx:748
 Projection.cxx:749
 Projection.cxx:750
 Projection.cxx:751
 Projection.cxx:752
 Projection.cxx:753
 Projection.cxx:754
 Projection.cxx:755
 Projection.cxx:756
 Projection.cxx:757
 Projection.cxx:758
 Projection.cxx:759
 Projection.cxx:760
 Projection.cxx:761
 Projection.cxx:762
 Projection.cxx:763
 Projection.cxx:764
 Projection.cxx:765
 Projection.cxx:766
 Projection.cxx:767
 Projection.cxx:768
 Projection.cxx:769
 Projection.cxx:770
 Projection.cxx:771
 Projection.cxx:772
 Projection.cxx:773
 Projection.cxx:774
 Projection.cxx:775
 Projection.cxx:776
 Projection.cxx:777
 Projection.cxx:778
 Projection.cxx:779
 Projection.cxx:780
 Projection.cxx:781
 Projection.cxx:782
 Projection.cxx:783
 Projection.cxx:784
 Projection.cxx:785
 Projection.cxx:786
 Projection.cxx:787
 Projection.cxx:788
 Projection.cxx:789
 Projection.cxx:790
 Projection.cxx:791
 Projection.cxx:792
 Projection.cxx:793
 Projection.cxx:794
 Projection.cxx:795
 Projection.cxx:796
 Projection.cxx:797
 Projection.cxx:798
 Projection.cxx:799
 Projection.cxx:800
 Projection.cxx:801
 Projection.cxx:802
 Projection.cxx:803
 Projection.cxx:804
 Projection.cxx:805
 Projection.cxx:806
 Projection.cxx:807
 Projection.cxx:808
 Projection.cxx:809
 Projection.cxx:810
 Projection.cxx:811
 Projection.cxx:812
 Projection.cxx:813
 Projection.cxx:814
 Projection.cxx:815
 Projection.cxx:816
 Projection.cxx:817
 Projection.cxx:818
 Projection.cxx:819
 Projection.cxx:820
 Projection.cxx:821
 Projection.cxx:822
 Projection.cxx:823
 Projection.cxx:824
 Projection.cxx:825
 Projection.cxx:826
 Projection.cxx:827
 Projection.cxx:828
 Projection.cxx:829
 Projection.cxx:830
 Projection.cxx:831
 Projection.cxx:832
 Projection.cxx:833
 Projection.cxx:834
 Projection.cxx:835
 Projection.cxx:836
 Projection.cxx:837
 Projection.cxx:838
 Projection.cxx:839
 Projection.cxx:840
 Projection.cxx:841
 Projection.cxx:842
 Projection.cxx:843
 Projection.cxx:844
 Projection.cxx:845
 Projection.cxx:846
 Projection.cxx:847
 Projection.cxx:848
 Projection.cxx:849
 Projection.cxx:850
 Projection.cxx:851
 Projection.cxx:852
 Projection.cxx:853
 Projection.cxx:854
 Projection.cxx:855
 Projection.cxx:856
 Projection.cxx:857
 Projection.cxx:858
 Projection.cxx:859
 Projection.cxx:860
 Projection.cxx:861
 Projection.cxx:862
 Projection.cxx:863
 Projection.cxx:864
 Projection.cxx:865
 Projection.cxx:866
 Projection.cxx:867
 Projection.cxx:868
 Projection.cxx:869
 Projection.cxx:870
 Projection.cxx:871
 Projection.cxx:872
 Projection.cxx:873
 Projection.cxx:874
 Projection.cxx:875
 Projection.cxx:876
 Projection.cxx:877
 Projection.cxx:878
 Projection.cxx:879
 Projection.cxx:880
 Projection.cxx:881
 Projection.cxx:882
 Projection.cxx:883
 Projection.cxx:884
 Projection.cxx:885
 Projection.cxx:886
 Projection.cxx:887
 Projection.cxx:888
 Projection.cxx:889
 Projection.cxx:890
 Projection.cxx:891
 Projection.cxx:892
 Projection.cxx:893
 Projection.cxx:894
 Projection.cxx:895
 Projection.cxx:896
 Projection.cxx:897
 Projection.cxx:898
 Projection.cxx:899
 Projection.cxx:900
 Projection.cxx:901
 Projection.cxx:902
 Projection.cxx:903
 Projection.cxx:904
 Projection.cxx:905
 Projection.cxx:906
 Projection.cxx:907
 Projection.cxx:908
 Projection.cxx:909
 Projection.cxx:910
 Projection.cxx:911
 Projection.cxx:912
 Projection.cxx:913
 Projection.cxx:914
 Projection.cxx:915
 Projection.cxx:916
 Projection.cxx:917
 Projection.cxx:918
 Projection.cxx:919
 Projection.cxx:920
 Projection.cxx:921
 Projection.cxx:922
 Projection.cxx:923
 Projection.cxx:924
 Projection.cxx:925
 Projection.cxx:926
 Projection.cxx:927
 Projection.cxx:928
 Projection.cxx:929
 Projection.cxx:930
 Projection.cxx:931
 Projection.cxx:932
 Projection.cxx:933
 Projection.cxx:934
 Projection.cxx:935
 Projection.cxx:936
 Projection.cxx:937
 Projection.cxx:938
 Projection.cxx:939
 Projection.cxx:940
 Projection.cxx:941
 Projection.cxx:942
 Projection.cxx:943
 Projection.cxx:944
 Projection.cxx:945
 Projection.cxx:946
 Projection.cxx:947
 Projection.cxx:948
 Projection.cxx:949
 Projection.cxx:950
 Projection.cxx:951
 Projection.cxx:952
 Projection.cxx:953
 Projection.cxx:954
 Projection.cxx:955
 Projection.cxx:956
 Projection.cxx:957
 Projection.cxx:958
 Projection.cxx:959
 Projection.cxx:960
 Projection.cxx:961
 Projection.cxx:962
 Projection.cxx:963
 Projection.cxx:964
 Projection.cxx:965
 Projection.cxx:966
 Projection.cxx:967
 Projection.cxx:968
 Projection.cxx:969
 Projection.cxx:970
 Projection.cxx:971
 Projection.cxx:972
 Projection.cxx:973
 Projection.cxx:974
 Projection.cxx:975
 Projection.cxx:976
 Projection.cxx:977
 Projection.cxx:978
 Projection.cxx:979
 Projection.cxx:980
 Projection.cxx:981
 Projection.cxx:982
 Projection.cxx:983
 Projection.cxx:984
 Projection.cxx:985
 Projection.cxx:986
 Projection.cxx:987
 Projection.cxx:988
 Projection.cxx:989
 Projection.cxx:990
 Projection.cxx:991
 Projection.cxx:992
 Projection.cxx:993
 Projection.cxx:994
 Projection.cxx:995
 Projection.cxx:996
 Projection.cxx:997
 Projection.cxx:998
 Projection.cxx:999
 Projection.cxx:1000
 Projection.cxx:1001