ROOT logo
//*-- Author :    Ole Hansen, Jefferson Lab   07-Feb-2008

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// TreeSearch::Hit                                                           //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#include "Road.h"
#include "TreeWalk.h"
#include "Projection.h"
#include "Hitpattern.h"
#include "Hit.h"
#include "WirePlane.h"
#include "Helper.h"

#include "TMath.h"
#include "TBits.h"
#include "TVector2.h"

#include <iostream>
#include <algorithm>
#include <numeric>
#include <map>
#include <utility>

using namespace std;

ClassImp(TreeSearch::Road)
ClassImp(TreeSearch::Road::Point)
ClassImp(TreeSearch::Road::Corners)

namespace TreeSearch {

typedef Hset_t::iterator siter_t;
#define ALL(c) (c).begin(), (c).end()

// Number of points for polygon test
static const size_t kNcorner = 5;
static const UInt_t kMaxNhitCombos = 1000;

//_____________________________________________________________________________
static inline
UInt_t GetOuterBits( UInt_t p )
{
  // Return the first and last set bits that are set in p
  static const char LogTable256[] = {
    0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
  };
  UInt_t ret = 0;
  if( p != 0 ) {
    register UInt_t t, tt;
    if( (tt = p >> 16) )
      ret = 1U << ((t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt]);
    else 
      ret = 1U << ((t = p >> 8) ? 8 + LogTable256[t] : LogTable256[p]);

    t = 1;
    while( (p & t) == 0 )
      t <<= 1;
    ret |= t;
  }
  return ret;
}

//_____________________________________________________________________________
// Private class for building a cluster of patterns
struct BuildInfo_t {
  HitSet            fCluster;      // Copy of start HitSet of the cluster
  vector< pair<UShort_t,UShort_t> > 
                    fLimits; // [nplanes] Min/max bin numbers in each plane
  UInt_t            fOuterBits;

  BuildInfo_t() : fOuterBits(0) {}
  BuildInfo_t( const Node_t& node )
    : fCluster(node.second), 
      fOuterBits(GetOuterBits(node.second.plane_pattern))
  {
    // Construct from given start pattern/hitset
    const NodeDescriptor& nd = node.first;
    assert( fCluster.plane_pattern > 0 and fCluster.nplanes > 0 );
    UInt_t npl = nd.link->GetPattern()->GetNbits();
    fLimits.reserve( npl );
    for( UInt_t i = 0; i < npl; ++i )
      fLimits.push_back( make_pair(nd[i], nd[i]+1) );
  }
  void ExpandWidth( const NodeDescriptor& nd ) {
    // Widen the bin ranges using the bins in the given pattern
    UInt_t npl = nd.link->GetPattern()->GetNbits();
    assert( fLimits.size() == npl or fLimits.empty() );
    if( fLimits.empty() )
      fLimits.assign( npl, make_pair(kMaxUShort, 0) );
    for( UInt_t i = npl; i; ) { --i;
      pair<UShort_t,UShort_t>& lim = fLimits[i];
      UInt_t bin = nd[i];
      if( bin < lim.first )
	lim.first = bin;
      if( bin+1 > lim.second )
	lim.second = bin+1;
    }
  }
};

//_____________________________________________________________________________
// Helper functor for coordinate conversions
class GetBinX 
  : public unary_function< pair<Double_t,Double_t>, pair<UInt_t,UInt_t> >
{
private:
  const Hitpattern* fHpat;
public:
  explicit GetBinX( const Hitpattern* hpat ) : fHpat(hpat) {}
  pair<Double_t,Double_t> operator() ( const pair<UInt_t,UInt_t>& bin ) const
  {
    // Get X coordinate of left edge of given bin
    Double_t lo = static_cast<Double_t>(bin.first) * fHpat->GetBinWidth() 
      - fHpat->GetOffset();
    Double_t hi = static_cast<Double_t>(bin.second) * fHpat->GetBinWidth() 
      - fHpat->GetOffset();
    return make_pair(lo,hi);
  }
};

//_____________________________________________________________________________
Road::Road( const Projection* proj ) 
  : TObject(), fProjection(proj), fZL(kBig), fZU(kBig), 
    fPos(kBig), fSlope(kBig), fChi2(kBig), fDof(kMaxUInt), fGood(true),
    fTrack(0), fBuild(0), fGrown(false)
#ifdef TESTCODE
  , fNfits(0)
#endif
{
  // Construct empty road

  assert(fProjection);  // Invalid Projection* pointer

  memset( fCornerX, 0, kNcorner*sizeof(Double_t) );
  fV[2] = fV[1] = fV[0] = kBig;
  fPoints.reserve( fProjection->GetNplanes() );
  fBuild = new BuildInfo_t;
}

//_____________________________________________________________________________
Road::Road( const Node_t& nd, const Projection* proj )
  : TObject(), fPatterns(1,&nd), fProjection(proj), fZL(kBig), fZU(kBig),
    fPos(kBig), fSlope(kBig), fChi2(kBig), fDof(kMaxUInt), fGood(true),
    fTrack(0), fBuild(0), fGrown(true)
#ifdef TESTCODE
  , fNfits(0)
#endif
{
  // Construct from pattern

  assert( fProjection );   // Invalid Projection* pointer
  assert( CheckMatch(nd.second.hits) ); // Start pattern must be a good match

  memset( fCornerX, 0, kNcorner*sizeof(Double_t) );
  fV[2] = fV[1] = fV[0] = kBig;
  fPoints.reserve( fProjection->GetNplanes() );
  fBuild = new BuildInfo_t(nd);

#ifdef VERBOSE
  if( fProjection->GetDebug() > 3 ) {
    cout << "New Road:" << endl;
    nd.first.Print();
    PrintHits(nd.second.hits);
  }
#endif
}

//_____________________________________________________________________________
Road::Road( const Road& orig ) : 
  TObject(orig), fPatterns(orig.fPatterns), fHits(orig.fHits),
  fGrown(orig.fGrown)
#ifdef TESTCODE
  , fNfits(orig.fNfits)
#endif
{
  // Copy constructor

  size_t nbytes = (char*)&fTrack - (char*)&fProjection + sizeof(fTrack);
  memcpy( &fProjection, &orig.fProjection, nbytes );
  
  CopyPointData( orig );

  if( orig.fBuild )
    fBuild = new BuildInfo_t( *orig.fBuild );
  else
    fBuild = 0;
}

//_____________________________________________________________________________
Road& Road::operator=( const Road& rhs )
{
  // Print hit info

  if( this != &rhs ) {
    TObject::operator=(rhs);

    fPatterns = rhs.fPatterns;
    fHits     = rhs.fHits;

    size_t nbytes = (char*)&fTrack - (char*)&fProjection + sizeof(fTrack);
    memcpy( &fProjection, &rhs.fProjection, nbytes );

    fFitCoord.clear();
    DeleteContainerOfContainers( fPoints );
    CopyPointData( rhs );

    delete fBuild;
    if( rhs.fBuild )
      fBuild = new BuildInfo_t( *rhs.fBuild );
    else
      fBuild = 0;

    fGrown = rhs.fGrown;
#ifdef TESTCODE
    fNfits = rhs.fNfits;
#endif
  }
  return *this;
}

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

  DeleteContainerOfContainers( fPoints );
  delete fBuild;

}

//_____________________________________________________________________________
void Road::CopyPointData( const Road& orig )
{
  // Copy fPoints and fFitCoord. Used by copy c'tor and assignment operator.
  // Creates actual copies of Points because they are managed by the Roads.

  if( orig.fPoints.empty() )
    assert( orig.fFitCoord.empty() ); // Can't have fit coord but no points :-/
  else {
    typedef map<Point*,Point*> Pmap_t;
    Pmap_t xref;
    fPoints.resize( orig.fPoints.size() );
    for( vector<Pvec_t>::size_type i = 0; i < orig.fPoints.size(); ++i ) {
      const Pvec_t& old_planepoints = orig.fPoints[i];
      fPoints[i].reserve( old_planepoints.size() );
      for( Pvec_t::const_iterator it = old_planepoints.begin(); it !=
	     old_planepoints.end(); ++it ) {
	Point* old_point = *it;
	Point* new_point = new Point( *old_point );
	fPoints[i].push_back( new_point );
	// It gets a bit tricky here: To be able to copy the fFitCoord, which
	// contain pointers to some of the Points in fPoints, we need to keep 
	// track of which old point was copied to which new point.
	pair<Pmap_t::iterator,bool> 
	  ins = xref.insert( make_pair(old_point,new_point) );
	assert( ins.second );  // Duplicate points should never occur
      }
    }

    // Copy fit coordinates (hits used in best fit)
    fFitCoord.reserve( orig.fFitCoord.size() );
    // The copied FitCoord must reference the corresponding copied Points
    for( Pvec_t::const_iterator it = orig.fFitCoord.begin(); it !=
	   orig.fFitCoord.end(); ++it ) {
      Point* old_point = *it;
      Pmap_t::iterator found = xref.find( old_point );
      assert( found != xref.end() );
      fFitCoord.push_back( (*found).second );
    }
  }
}
  
//_____________________________________________________________________________
inline
Bool_t Road::CheckMatch( const Hset_t& hits ) const
{
  // Return true if the hits from the given set either cover all planes
  // or, if planes are missing, the pattern of missing planes is allowed
  // (based on what level of matching the user requests via the database)

  return HitSet::CheckMatch( hits, fProjection->GetPlaneCombos() );
}

//_____________________________________________________________________________
inline
Bool_t Road::IsInBackRange( const NodeDescriptor& nd ) const
{
  assert( fBuild && !fBuild->fLimits.empty() );

  UInt_t bdist = fProjection->GetBinMaxDistB();

  return ( nd.End() + bdist >= fBuild->fLimits.back().first and
	   nd.End()         <  fBuild->fLimits.back().second + bdist );
}

//_____________________________________________________________________________
//inline
Bool_t Road::IsInFrontRange( const NodeDescriptor& nd ) const
{
  assert( fBuild && !fBuild->fLimits.empty() );

  UInt_t fdist = fProjection->GetBinMaxDistF();
  
  return ( nd.Start() + fdist >= fBuild->fLimits.front().first and
	   nd.Start()         <  fBuild->fLimits.front().second + fdist );
}
  
//_____________________________________________________________________________
Bool_t Road::Add( const Node_t& nd )
{
  // Check if the hits from the given NodeDescriptor pattern are common
  // with the common hit set already in this road. If so, add the pattern
  // to this road, update the common hits if necessary, and return true.
  // If not, do nothing and return false.
  //
  // Adding can only be done so long as the road is not yet finished

  assert(fBuild);  // Add() after Finish() not allowed
  assert( fPatterns.empty() || IsInFrontRange(nd.first) );

  const HitSet& new_set  = nd.second;
  const Hset_t& new_hits = nd.second.hits;

#ifdef VERBOSE
  if( fProjection->GetDebug() > 3 ) {
    cout << "Adding:" << endl;
    nd.first.Print();
    PrintHits(new_hits);
  }
#endif

  // If hitdist > 0, roads will collect patterns not only identical hits,
  // but also nearby ones (at most hitdist wire numbers apart)
  UInt_t hitdist = fProjection->GetHitMaxDist();

  if( fPatterns.empty() ) {
    // If this is the first pattern, initialize the cluster
    assert( CheckMatch(new_hits) );
    assert( new_set.nplanes > 0 && new_set.plane_pattern > 0 );
    fBuild->fCluster = new_set;
    fBuild->ExpandWidth( nd.first );
    fBuild->fOuterBits = GetOuterBits( fBuild->fCluster.plane_pattern );
    fGrown = true;
#ifdef VERBOSE
    if( fProjection->GetDebug() > 3 ) {
      cout << "New cluster:" << endl;
      PrintHits( new_hits );
    }
#endif
  } 
  else if( IsInBackRange(nd.first) and 
	   fBuild->fCluster.IsSimilarTo(new_set,hitdist) ) {
    // Accept this pattern if and only if it is a subset of the cluster
    // NB: IsSimilarTo() is a looser match than std::includes(). The new
    // pattern may have extra hits

    // If hitdist > 0, grow the cluster with possible new hits found
    if( hitdist > 0 ) {
      UInt_t outer_bits = fBuild->fOuterBits;
      for( siter_t it = new_hits.begin(); it != new_hits.end(); ++it ) {
	pair< siter_t, bool > ins = fBuild->fCluster.hits.insert(*it);
	if( ins.second and TESTBIT(outer_bits,(*it)->GetPlaneNum()) )
	  fGrown = true;
      }
      // Growing clusters are expanded even for lower match levels
      // if they contain hits in the first and last active bins
      if( (outer_bits & new_set.plane_pattern) == outer_bits )
	fBuild->ExpandWidth( nd.first );
    }
    // Expand the road width, but only for patterns of the same match level.
    // Patterns of lower match level can be artificially wide
    else if( new_set.nplanes == fBuild->fCluster.nplanes ) {
      fBuild->ExpandWidth( nd.first );
    }
  }
  else {
    // The pattern does not fit into this cluster
#ifdef VERBOSE
    if( fProjection->GetDebug() > 3 )
      cout << "Not a subset of this road" << endl;
#endif
    return false;
  }

  // Save a pointer to the added pattern so we can update it later
  fPatterns.push_back(&nd);

#ifdef VERBOSE
  if( fProjection->GetDebug() > 3 ) 
    cout << "new npat = " << fPatterns.size() << endl;
#endif

  return true;
}

//_____________________________________________________________________________
void Road::Finish()
{
  // Finish building the road

  assert(fBuild);   // Road must be incomplete to be able to Finish()
  for( list<const Node_t*>::iterator it = fPatterns.begin(); it !=
	 fPatterns.end(); ++it ) {
    (**it).second.used = 1;
#ifdef VERBOSE
    if( fProjection->GetDebug() > 3 ) { 
      cout << "used pat = ";
      (**it).first.Print(); 
    }
#endif
  }

  // Save the cluster hits. These are the hits that will be considered for
  // fitting later
  assert( fHits.empty() );
  fHits.swap( fBuild->fCluster.hits );

  // Calculate the corner coordinates fCornerX of a polygon with points in the
  // order LL (lower left), LR, UR, UL, LL, as needed by TMath::IsInside()

  // Convert the bin numbers of the left/right edges to physical coordinates
  vector< pair<Double_t,Double_t> > edgpos;
  UInt_t npl = fProjection->GetNplanes(), lastpl = npl-1;
  edgpos.reserve( npl );
  GetBinX binx( fProjection->GetHitpattern() ); // bin# -> position
  transform( ALL(fBuild->fLimits), back_inserter(edgpos), binx );
  
  // Define the road boundaries as the lines with the slope between the
  // front and back bins, shifted to the left/right to include fully the
  // left/rightmost bin. This may not be optimal, but it is fast, unambiguous,
  // and removes the bias towards the front/back bins.
  TVector2 LL( edgpos.front().first,  fProjection->GetPlaneZ(0) );
  TVector2 LR( edgpos.front().second, fProjection->GetPlaneZ(0) );
  TVector2 UL( edgpos.back().first,   fProjection->GetPlaneZ(lastpl) );
  TVector2 UR( edgpos.back().second,  fProjection->GetPlaneZ(lastpl) );
  Double_t slopeL = (UL.X() - LL.X()) / (UL.Y() - LL.Y());
  Double_t slopeR = (UR.X() - LR.X()) / (UR.Y() - LR.Y());
  Double_t maxdL = 0, maxdR = 0;
  for( UInt_t i = lastpl; i>1; ) { --i;
    Double_t z = fProjection->GetPlaneZ(i);
    // Crossing points in test plane (i) of the L/R front/back connections
    Double_t XL = UL.X() + slopeL * (z - UL.Y());
    Double_t XR = UR.X() + slopeR * (z - UR.Y());
    // Memorize the bins that stick out the most on left/right. Reuse UL/UR
    Double_t lpt = edgpos[i].first, rpt = edgpos[i].second;
    Double_t dL = lpt - XL, dR = rpt - XR;
    if( dL < maxdL ) {
      UL.Set( lpt, z );
      maxdL = dL;
    } 
    if( dR > maxdR ) {
      UR.Set( rpt, z );
      maxdR = dR;
    } 
  }
  // Now UL and UR are points on the left and right road boundary, 
  // respectively. The boundaries share the common slope calculated above.
  
  // To compute the corners of the polygon, shift the z-positions of the first
  // and last planes down and up, respectively, by eps, so that the points 
  // on the planes are guaranteed to be included
  const Double_t eps = 1e-3;
  fZL = fProjection->GetPlaneZ(0) - eps;
  fZU = fProjection->GetPlaneZ(lastpl) + eps;
  assert( fZL < fZU );

  fCornerX[0] = UL.X() + slopeL * (fZL - UL.Y());
  fCornerX[1] = UR.X() + slopeR * (fZL - UR.Y());
  fCornerX[2] = UR.X() + slopeR * (fZU - UR.Y());
  fCornerX[3] = UL.X() + slopeL * (fZU - UL.Y());
  fCornerX[4] = fCornerX[0];

  assert( fCornerX[0] < fCornerX[1] );
  assert( fCornerX[3] < fCornerX[2] );

  // All done. Put the tools away
  delete fBuild; fBuild = 0;
  fGrown = false;

  return;
}

//_____________________________________________________________________________
Bool_t Road::Include( const Road* other )
{
  // Check if this road includes 'other'. Either other's hits are a
  // subset of this road's hit set or other lies entirely within the
  // boundaries of this road.
  // If a match is found, adopt the other road (either widen boundaries
  // or adopt the other's hits)

  static const double eps = 1e-6;

  assert( other and !fBuild and fProjection == other->fProjection );

  if( includes(ALL(fHits), ALL(other->fHits), fHits.key_comp()) ) {
    // Widen the road bundaries
    fCornerX[0] = min( fCornerX[0], other->fCornerX[0] );
    fCornerX[1] = max( fCornerX[1], other->fCornerX[1] );
    fCornerX[2] = max( fCornerX[2], other->fCornerX[2] );
    fCornerX[3] = min( fCornerX[3], other->fCornerX[3] );
    fCornerX[4] = fCornerX[0];
    return true;
  }

  if( TMath::Abs(fZL-other->fZL) < eps and
      TMath::Abs(fZU-other->fZU) < eps and
      fCornerX[0] < other->fCornerX[0] + eps and
      other->fCornerX[1] < fCornerX[1] + eps and
      fCornerX[3] < other->fCornerX[3] + eps and
      other->fCornerX[2] < fCornerX[2] + eps ) {
    fHits.insert( ALL(other->fHits) );
    return true;
  }

  return false;
}

//_____________________________________________________________________________
Bool_t Road::CollectCoordinates()
{
  // Gather hit positions that lie within the Road area.
  // Return true if the plane occupancy pattern of the selected points 
  // is allowed by Projection::fPlaneCombos, otherwise false.
  // Results are in fPoints.

  DeleteContainerOfContainers( fPoints );

#ifdef VERBOSE
  if( fProjection->GetDebug() > 3 ) {
    cout << "Collecting coordinates from: (" << fPatterns.size() 
	 << " patterns)" << endl;
    PrintHits( fHits );
    cout << "Seed pattern: " << endl;
    fPatterns.front()->first.Print();
  }
#endif
  Double_t zp[kNcorner] = { fZL, fZL, fZU, fZU, fZL };
  Bool_t good = true;

  // Collect the hit coordinates within this Road
  TBits planepattern;
  UInt_t last_np = kMaxUInt;
  for( siter_t it = fHits.begin(); it != fHits.end(); ++it ) {
    Hit* hit = const_cast<Hit*>(*it);
    // Skip all hits from planes in calibration mode - these are not fitted
    if( hit->GetWirePlane()->IsCalibrating() )
      continue;
    Double_t z = hit->GetZ();
    UInt_t np = hit->GetPlaneNum();
    // Prevent duplicate entries for hits with zero drift
    int i = (hit->GetDriftDist() == 0.0) ? 1 : 2;
    do {
      Double_t x = (--i != 0) ? hit->GetPosL() : hit->GetPosR();
      if( TMath::IsInside( x, z, kNcorner, &fCornerX[0], zp )) {
	// The hits are sorted by ascending plane number
	if( np != last_np ) {
	  fPoints.push_back( Pvec_t() );
	  planepattern.SetBitNumber(np);
	  last_np = np;
	}
	fPoints.back().push_back( new Point(x, z, hit) );
      }
    } while( i );
  }
  // Check if this matchpattern is acceptable
  UInt_t patternvalue = 0;
  assert( planepattern.GetNbytes() <= sizeof(patternvalue) );
  planepattern.Get( &patternvalue );
  good = fProjection->GetPlaneCombos()->TestBitNumber(patternvalue)
    // Need at least MinFitPlanes planes for fitting
    and planepattern.CountBits() >= fProjection->GetMinFitPlanes();
  
#ifdef VERBOSE
  if( fProjection->GetDebug() > 3 ) {
    cout << "Collected:" << endl;
    vector<Pvec_t>::reverse_iterator ipl = fPoints.rbegin();
    for( UInt_t i = fProjection->GetNplanes(); i--; ) {
      cout << " pl= " << i;
      assert( ipl == fPoints.rend() or !(*ipl).empty() );
      if( ipl == fPoints.rend() 
	  or i != (*ipl).front()->hit->GetPlaneNum() ) {
	if( fProjection->GetPlane(i)->IsCalibrating() )
	  cout << " calibrating";
	else
	  cout << " missing";
      }
      else {
	Double_t z = (*ipl).front()->z;
	cout << " z=" << z << "\t x=";
	for( Pvec_t::iterator it = (*ipl).begin(); it != (*ipl).end(); ++it ) {
	  cout << " " << (*it)->x;
	  assert( (*it)->z == z );
	}
	++ipl;
      }
      cout << endl;
    }
    if( !good ) {
      cout << "REJECTED" << endl;
    }
  }
#endif

  return good;
}

//_____________________________________________________________________________
Bool_t Road::Fit()
{
  // Collect hit positions within the Road limits and, if enough points
  // found, fit them to a straight line. If several points found in one
  // or more planes, fit all possible combinations of them.
  // Results of the best fit with acceptable chi2 (Projection::fChisqLimits)
  // are stored in the member variables

  if( !fGood )
    return false;

  if( fFitCoord.empty() )
    assert( fChi2 == kBig );
  else {
    fFitCoord.clear();
    fV[2]= fV[1] = fV[0] = fChi2 = fSlope = fPos = kBig;
    fDof = kMaxUInt;
  }
  fGood = false;
#ifdef TESTCODE
  fNfits = 0;
#endif

  // Collect coordinates of hits that are within the width of the road
  if( !CollectCoordinates() )
    return false;

  // Determine number of permutations
  //TODO: protect against overflow
  UInt_t n_combinations = accumulate( ALL(fPoints),
				      (UInt_t)1, SizeMul<Pvec_t>() );
  if( n_combinations > kMaxNhitCombos ) {
    // TODO: keep statistics
    return false;
  }

  // Loop over all combinations of hits in the planes
  vector<Pvec_t>::size_type npts = fPoints.size();
  Pvec_t selected;
  selected.reserve( npts );
  fDof = npts-2;
  pdbl_t chi2_interval = fProjection->GetChisqLimits(fDof);
  vector<Double_t> w(npts);
  for( UInt_t i = 0; i < n_combinations; ++i ) {
    NthCombination( i, fPoints, selected );
    assert( selected.size() == npts );

    // Do linear fit of the points, assuming uncorrelated measurements (x_i)
    // and different resolutions for each point.
    // We fit x = a1 + a2*z (z independent).
    // Notation from: Review of Particle Properties, PRD 50, 1277 (1994)
    Double_t S11 = 0, S12 = 0, S22 = 0, G1 = 0, G2 = 0, chi2 = 0;
    for( Pvec_t::size_type j = 0; j < npts; j++) {
      register Point* p = selected[j];
      register Double_t r = w[j] = 1.0 / ( p->res() * p->res() );
      S11 += r;
      S12 += p->z * r;
      S22 += p->z * p->z * r;
      G1  += p->x * r;
      G2  += p->x * p->z * r;
    }
    Double_t D   = S11*S22 - S12*S12;
    Double_t iD  = 1.0/D;
    Double_t a1  = (G1*S22 - G2*S12)*iD;  // Intercept
    Double_t a2  = (G2*S11 - G1*S12)*iD;  // Slope
    // Covariance matrix of the fitted parameters
    Double_t V[3] = { S22*iD, -S12*iD, S11*iD };
    for( Pvec_t::size_type j = 0; j < npts; j++) {
      register Point* p = selected[j];
      Double_t d = a1 + a2*p->z - p->x;
      chi2 += d*d * w[j];
    }

#ifdef VERBOSE
    if( fProjection->GetDebug() > 3 ) 
      cout << "Fit:"
	   << " a1 = " << a1 << " (" << TMath::Sqrt(V[0]) << ")"
	   << " a2 = " << a2
	   << " chi2 = " << chi2
	   << " ndof = " << fDof
	   << endl;
#endif
    // Throw out Chi2's outside of selected confidence interval
    // NB: Obviously, this requires accurate hit resolutions
    //TODO: keep statistics
    //TODO: allow disabling of low cutoff via database switch
    if( chi2 < chi2_interval.first )
      continue;
    if( chi2 > chi2_interval.second )
      continue;
#ifdef TESTCODE
    ++fNfits;
#endif

    // Save the best fit results
    if( chi2 < fChi2 ) {
      fPos   = a1;
      fSlope = a2;
      fChi2  = chi2;
      memcpy( fV, V, 3*sizeof(Double_t) );
      // Save points used for this fit
      fFitCoord.swap( selected );
      fGood = true;
#ifdef VERBOSE
      if( fProjection->GetDebug() > 3 ) cout << "ACCEPTED" << endl;
#endif
    }

  }// for n_combinations

  return fGood;
}

//_____________________________________________________________________________
TVector2 Road::Intersect( const Road* other, Double_t z ) const
{
  // Find intersection point in x/y coordinates of the best fit of this
  // road with the best fit of the other in the given z-plane.
  // Both roads must have a good fit and must be from different projections.
  // This function commutes, i.e. a->Intersect(b) == b->Intersect(a)

  assert(other);
  assert(fGood && other->fGood);
  assert(fProjection->GetType() != other->fProjection->GetType());

  Double_t su = fProjection->GetSinAngle();
  Double_t cu = fProjection->GetCosAngle();
  Double_t sv = other->fProjection->GetSinAngle();
  Double_t cv = other->fProjection->GetCosAngle();
  // FIXME: this should be calculated only once
  Double_t inv_denom = 1.0/(sv*cu-su*cv);

  // Standard formulae for the intersection of non-orthogonal coordinates
  // (cf. THaVDCUVTrack.C)
  Double_t x = (GetPos(z) * sv - other->GetPos(z) * su) * inv_denom;
  Double_t y = (other->GetPos(z) * cu - GetPos(z) * cv) * inv_denom;
  return TVector2(x, y);
}

//_____________________________________________________________________________
void Road::Print( Option_t* ) const
{
  // Print road info

  cout << "Road: " << fProjection->GetName() << " type, "
       << fHits.size() << " hits" << endl;
  cout << " TL = (" << fCornerX[3] << "," << fZU << ") "
       << " TR = (" << fCornerX[2] << "," << fZU << ")"
       << endl
       << " BL = (" << fCornerX[0] << "," << fZL << ") "
       << " BR = (" << fCornerX[1] << "," << fZL << ")"
       << endl;

  for( Hset_t::reverse_iterator it = fHits.rbegin(); it != fHits.rend();
       ++it ) {
    cout << " ";
    (*it)->Print();
  }
  if( fGood ) {
    cout << " fitpos = " << fPos << " (" << TMath::Sqrt(fV[0]) << ")"
	 << " slope = " << fSlope
	 << " chi2 = " << fChi2
	 << " ndof = " << fDof
	 << endl;
  }
}

///////////////////////////////////////////////////////////////////////////////

} // end namespace TreeSearch
 Road.cxx:1
 Road.cxx:2
 Road.cxx:3
 Road.cxx:4
 Road.cxx:5
 Road.cxx:6
 Road.cxx:7
 Road.cxx:8
 Road.cxx:9
 Road.cxx:10
 Road.cxx:11
 Road.cxx:12
 Road.cxx:13
 Road.cxx:14
 Road.cxx:15
 Road.cxx:16
 Road.cxx:17
 Road.cxx:18
 Road.cxx:19
 Road.cxx:20
 Road.cxx:21
 Road.cxx:22
 Road.cxx:23
 Road.cxx:24
 Road.cxx:25
 Road.cxx:26
 Road.cxx:27
 Road.cxx:28
 Road.cxx:29
 Road.cxx:30
 Road.cxx:31
 Road.cxx:32
 Road.cxx:33
 Road.cxx:34
 Road.cxx:35
 Road.cxx:36
 Road.cxx:37
 Road.cxx:38
 Road.cxx:39
 Road.cxx:40
 Road.cxx:41
 Road.cxx:42
 Road.cxx:43
 Road.cxx:44
 Road.cxx:45
 Road.cxx:46
 Road.cxx:47
 Road.cxx:48
 Road.cxx:49
 Road.cxx:50
 Road.cxx:51
 Road.cxx:52
 Road.cxx:53
 Road.cxx:54
 Road.cxx:55
 Road.cxx:56
 Road.cxx:57
 Road.cxx:58
 Road.cxx:59
 Road.cxx:60
 Road.cxx:61
 Road.cxx:62
 Road.cxx:63
 Road.cxx:64
 Road.cxx:65
 Road.cxx:66
 Road.cxx:67
 Road.cxx:68
 Road.cxx:69
 Road.cxx:70
 Road.cxx:71
 Road.cxx:72
 Road.cxx:73
 Road.cxx:74
 Road.cxx:75
 Road.cxx:76
 Road.cxx:77
 Road.cxx:78
 Road.cxx:79
 Road.cxx:80
 Road.cxx:81
 Road.cxx:82
 Road.cxx:83
 Road.cxx:84
 Road.cxx:85
 Road.cxx:86
 Road.cxx:87
 Road.cxx:88
 Road.cxx:89
 Road.cxx:90
 Road.cxx:91
 Road.cxx:92
 Road.cxx:93
 Road.cxx:94
 Road.cxx:95
 Road.cxx:96
 Road.cxx:97
 Road.cxx:98
 Road.cxx:99
 Road.cxx:100
 Road.cxx:101
 Road.cxx:102
 Road.cxx:103
 Road.cxx:104
 Road.cxx:105
 Road.cxx:106
 Road.cxx:107
 Road.cxx:108
 Road.cxx:109
 Road.cxx:110
 Road.cxx:111
 Road.cxx:112
 Road.cxx:113
 Road.cxx:114
 Road.cxx:115
 Road.cxx:116
 Road.cxx:117
 Road.cxx:118
 Road.cxx:119
 Road.cxx:120
 Road.cxx:121
 Road.cxx:122
 Road.cxx:123
 Road.cxx:124
 Road.cxx:125
 Road.cxx:126
 Road.cxx:127
 Road.cxx:128
 Road.cxx:129
 Road.cxx:130
 Road.cxx:131
 Road.cxx:132
 Road.cxx:133
 Road.cxx:134
 Road.cxx:135
 Road.cxx:136
 Road.cxx:137
 Road.cxx:138
 Road.cxx:139
 Road.cxx:140
 Road.cxx:141
 Road.cxx:142
 Road.cxx:143
 Road.cxx:144
 Road.cxx:145
 Road.cxx:146
 Road.cxx:147
 Road.cxx:148
 Road.cxx:149
 Road.cxx:150
 Road.cxx:151
 Road.cxx:152
 Road.cxx:153
 Road.cxx:154
 Road.cxx:155
 Road.cxx:156
 Road.cxx:157
 Road.cxx:158
 Road.cxx:159
 Road.cxx:160
 Road.cxx:161
 Road.cxx:162
 Road.cxx:163
 Road.cxx:164
 Road.cxx:165
 Road.cxx:166
 Road.cxx:167
 Road.cxx:168
 Road.cxx:169
 Road.cxx:170
 Road.cxx:171
 Road.cxx:172
 Road.cxx:173
 Road.cxx:174
 Road.cxx:175
 Road.cxx:176
 Road.cxx:177
 Road.cxx:178
 Road.cxx:179
 Road.cxx:180
 Road.cxx:181
 Road.cxx:182
 Road.cxx:183
 Road.cxx:184
 Road.cxx:185
 Road.cxx:186
 Road.cxx:187
 Road.cxx:188
 Road.cxx:189
 Road.cxx:190
 Road.cxx:191
 Road.cxx:192
 Road.cxx:193
 Road.cxx:194
 Road.cxx:195
 Road.cxx:196
 Road.cxx:197
 Road.cxx:198
 Road.cxx:199
 Road.cxx:200
 Road.cxx:201
 Road.cxx:202
 Road.cxx:203
 Road.cxx:204
 Road.cxx:205
 Road.cxx:206
 Road.cxx:207
 Road.cxx:208
 Road.cxx:209
 Road.cxx:210
 Road.cxx:211
 Road.cxx:212
 Road.cxx:213
 Road.cxx:214
 Road.cxx:215
 Road.cxx:216
 Road.cxx:217
 Road.cxx:218
 Road.cxx:219
 Road.cxx:220
 Road.cxx:221
 Road.cxx:222
 Road.cxx:223
 Road.cxx:224
 Road.cxx:225
 Road.cxx:226
 Road.cxx:227
 Road.cxx:228
 Road.cxx:229
 Road.cxx:230
 Road.cxx:231
 Road.cxx:232
 Road.cxx:233
 Road.cxx:234
 Road.cxx:235
 Road.cxx:236
 Road.cxx:237
 Road.cxx:238
 Road.cxx:239
 Road.cxx:240
 Road.cxx:241
 Road.cxx:242
 Road.cxx:243
 Road.cxx:244
 Road.cxx:245
 Road.cxx:246
 Road.cxx:247
 Road.cxx:248
 Road.cxx:249
 Road.cxx:250
 Road.cxx:251
 Road.cxx:252
 Road.cxx:253
 Road.cxx:254
 Road.cxx:255
 Road.cxx:256
 Road.cxx:257
 Road.cxx:258
 Road.cxx:259
 Road.cxx:260
 Road.cxx:261
 Road.cxx:262
 Road.cxx:263
 Road.cxx:264
 Road.cxx:265
 Road.cxx:266
 Road.cxx:267
 Road.cxx:268
 Road.cxx:269
 Road.cxx:270
 Road.cxx:271
 Road.cxx:272
 Road.cxx:273
 Road.cxx:274
 Road.cxx:275
 Road.cxx:276
 Road.cxx:277
 Road.cxx:278
 Road.cxx:279
 Road.cxx:280
 Road.cxx:281
 Road.cxx:282
 Road.cxx:283
 Road.cxx:284
 Road.cxx:285
 Road.cxx:286
 Road.cxx:287
 Road.cxx:288
 Road.cxx:289
 Road.cxx:290
 Road.cxx:291
 Road.cxx:292
 Road.cxx:293
 Road.cxx:294
 Road.cxx:295
 Road.cxx:296
 Road.cxx:297
 Road.cxx:298
 Road.cxx:299
 Road.cxx:300
 Road.cxx:301
 Road.cxx:302
 Road.cxx:303
 Road.cxx:304
 Road.cxx:305
 Road.cxx:306
 Road.cxx:307
 Road.cxx:308
 Road.cxx:309
 Road.cxx:310
 Road.cxx:311
 Road.cxx:312
 Road.cxx:313
 Road.cxx:314
 Road.cxx:315
 Road.cxx:316
 Road.cxx:317
 Road.cxx:318
 Road.cxx:319
 Road.cxx:320
 Road.cxx:321
 Road.cxx:322
 Road.cxx:323
 Road.cxx:324
 Road.cxx:325
 Road.cxx:326
 Road.cxx:327
 Road.cxx:328
 Road.cxx:329
 Road.cxx:330
 Road.cxx:331
 Road.cxx:332
 Road.cxx:333
 Road.cxx:334
 Road.cxx:335
 Road.cxx:336
 Road.cxx:337
 Road.cxx:338
 Road.cxx:339
 Road.cxx:340
 Road.cxx:341
 Road.cxx:342
 Road.cxx:343
 Road.cxx:344
 Road.cxx:345
 Road.cxx:346
 Road.cxx:347
 Road.cxx:348
 Road.cxx:349
 Road.cxx:350
 Road.cxx:351
 Road.cxx:352
 Road.cxx:353
 Road.cxx:354
 Road.cxx:355
 Road.cxx:356
 Road.cxx:357
 Road.cxx:358
 Road.cxx:359
 Road.cxx:360
 Road.cxx:361
 Road.cxx:362
 Road.cxx:363
 Road.cxx:364
 Road.cxx:365
 Road.cxx:366
 Road.cxx:367
 Road.cxx:368
 Road.cxx:369
 Road.cxx:370
 Road.cxx:371
 Road.cxx:372
 Road.cxx:373
 Road.cxx:374
 Road.cxx:375
 Road.cxx:376
 Road.cxx:377
 Road.cxx:378
 Road.cxx:379
 Road.cxx:380
 Road.cxx:381
 Road.cxx:382
 Road.cxx:383
 Road.cxx:384
 Road.cxx:385
 Road.cxx:386
 Road.cxx:387
 Road.cxx:388
 Road.cxx:389
 Road.cxx:390
 Road.cxx:391
 Road.cxx:392
 Road.cxx:393
 Road.cxx:394
 Road.cxx:395
 Road.cxx:396
 Road.cxx:397
 Road.cxx:398
 Road.cxx:399
 Road.cxx:400
 Road.cxx:401
 Road.cxx:402
 Road.cxx:403
 Road.cxx:404
 Road.cxx:405
 Road.cxx:406
 Road.cxx:407
 Road.cxx:408
 Road.cxx:409
 Road.cxx:410
 Road.cxx:411
 Road.cxx:412
 Road.cxx:413
 Road.cxx:414
 Road.cxx:415
 Road.cxx:416
 Road.cxx:417
 Road.cxx:418
 Road.cxx:419
 Road.cxx:420
 Road.cxx:421
 Road.cxx:422
 Road.cxx:423
 Road.cxx:424
 Road.cxx:425
 Road.cxx:426
 Road.cxx:427
 Road.cxx:428
 Road.cxx:429
 Road.cxx:430
 Road.cxx:431
 Road.cxx:432
 Road.cxx:433
 Road.cxx:434
 Road.cxx:435
 Road.cxx:436
 Road.cxx:437
 Road.cxx:438
 Road.cxx:439
 Road.cxx:440
 Road.cxx:441
 Road.cxx:442
 Road.cxx:443
 Road.cxx:444
 Road.cxx:445
 Road.cxx:446
 Road.cxx:447
 Road.cxx:448
 Road.cxx:449
 Road.cxx:450
 Road.cxx:451
 Road.cxx:452
 Road.cxx:453
 Road.cxx:454
 Road.cxx:455
 Road.cxx:456
 Road.cxx:457
 Road.cxx:458
 Road.cxx:459
 Road.cxx:460
 Road.cxx:461
 Road.cxx:462
 Road.cxx:463
 Road.cxx:464
 Road.cxx:465
 Road.cxx:466
 Road.cxx:467
 Road.cxx:468
 Road.cxx:469
 Road.cxx:470
 Road.cxx:471
 Road.cxx:472
 Road.cxx:473
 Road.cxx:474
 Road.cxx:475
 Road.cxx:476
 Road.cxx:477
 Road.cxx:478
 Road.cxx:479
 Road.cxx:480
 Road.cxx:481
 Road.cxx:482
 Road.cxx:483
 Road.cxx:484
 Road.cxx:485
 Road.cxx:486
 Road.cxx:487
 Road.cxx:488
 Road.cxx:489
 Road.cxx:490
 Road.cxx:491
 Road.cxx:492
 Road.cxx:493
 Road.cxx:494
 Road.cxx:495
 Road.cxx:496
 Road.cxx:497
 Road.cxx:498
 Road.cxx:499
 Road.cxx:500
 Road.cxx:501
 Road.cxx:502
 Road.cxx:503
 Road.cxx:504
 Road.cxx:505
 Road.cxx:506
 Road.cxx:507
 Road.cxx:508
 Road.cxx:509
 Road.cxx:510
 Road.cxx:511
 Road.cxx:512
 Road.cxx:513
 Road.cxx:514
 Road.cxx:515
 Road.cxx:516
 Road.cxx:517
 Road.cxx:518
 Road.cxx:519
 Road.cxx:520
 Road.cxx:521
 Road.cxx:522
 Road.cxx:523
 Road.cxx:524
 Road.cxx:525
 Road.cxx:526
 Road.cxx:527
 Road.cxx:528
 Road.cxx:529
 Road.cxx:530
 Road.cxx:531
 Road.cxx:532
 Road.cxx:533
 Road.cxx:534
 Road.cxx:535
 Road.cxx:536
 Road.cxx:537
 Road.cxx:538
 Road.cxx:539
 Road.cxx:540
 Road.cxx:541
 Road.cxx:542
 Road.cxx:543
 Road.cxx:544
 Road.cxx:545
 Road.cxx:546
 Road.cxx:547
 Road.cxx:548
 Road.cxx:549
 Road.cxx:550
 Road.cxx:551
 Road.cxx:552
 Road.cxx:553
 Road.cxx:554
 Road.cxx:555
 Road.cxx:556
 Road.cxx:557
 Road.cxx:558
 Road.cxx:559
 Road.cxx:560
 Road.cxx:561
 Road.cxx:562
 Road.cxx:563
 Road.cxx:564
 Road.cxx:565
 Road.cxx:566
 Road.cxx:567
 Road.cxx:568
 Road.cxx:569
 Road.cxx:570
 Road.cxx:571
 Road.cxx:572
 Road.cxx:573
 Road.cxx:574
 Road.cxx:575
 Road.cxx:576
 Road.cxx:577
 Road.cxx:578
 Road.cxx:579
 Road.cxx:580
 Road.cxx:581
 Road.cxx:582
 Road.cxx:583
 Road.cxx:584
 Road.cxx:585
 Road.cxx:586
 Road.cxx:587
 Road.cxx:588
 Road.cxx:589
 Road.cxx:590
 Road.cxx:591
 Road.cxx:592
 Road.cxx:593
 Road.cxx:594
 Road.cxx:595
 Road.cxx:596
 Road.cxx:597
 Road.cxx:598
 Road.cxx:599
 Road.cxx:600
 Road.cxx:601
 Road.cxx:602
 Road.cxx:603
 Road.cxx:604
 Road.cxx:605
 Road.cxx:606
 Road.cxx:607
 Road.cxx:608
 Road.cxx:609
 Road.cxx:610
 Road.cxx:611
 Road.cxx:612
 Road.cxx:613
 Road.cxx:614
 Road.cxx:615
 Road.cxx:616
 Road.cxx:617
 Road.cxx:618
 Road.cxx:619
 Road.cxx:620
 Road.cxx:621
 Road.cxx:622
 Road.cxx:623
 Road.cxx:624
 Road.cxx:625
 Road.cxx:626
 Road.cxx:627
 Road.cxx:628
 Road.cxx:629
 Road.cxx:630
 Road.cxx:631
 Road.cxx:632
 Road.cxx:633
 Road.cxx:634
 Road.cxx:635
 Road.cxx:636
 Road.cxx:637
 Road.cxx:638
 Road.cxx:639
 Road.cxx:640
 Road.cxx:641
 Road.cxx:642
 Road.cxx:643
 Road.cxx:644
 Road.cxx:645
 Road.cxx:646
 Road.cxx:647
 Road.cxx:648
 Road.cxx:649
 Road.cxx:650
 Road.cxx:651
 Road.cxx:652
 Road.cxx:653
 Road.cxx:654
 Road.cxx:655
 Road.cxx:656
 Road.cxx:657
 Road.cxx:658
 Road.cxx:659
 Road.cxx:660
 Road.cxx:661
 Road.cxx:662
 Road.cxx:663
 Road.cxx:664
 Road.cxx:665
 Road.cxx:666
 Road.cxx:667
 Road.cxx:668
 Road.cxx:669
 Road.cxx:670
 Road.cxx:671
 Road.cxx:672
 Road.cxx:673
 Road.cxx:674
 Road.cxx:675
 Road.cxx:676
 Road.cxx:677
 Road.cxx:678
 Road.cxx:679
 Road.cxx:680
 Road.cxx:681
 Road.cxx:682
 Road.cxx:683
 Road.cxx:684
 Road.cxx:685
 Road.cxx:686
 Road.cxx:687
 Road.cxx:688
 Road.cxx:689
 Road.cxx:690
 Road.cxx:691
 Road.cxx:692
 Road.cxx:693
 Road.cxx:694
 Road.cxx:695
 Road.cxx:696
 Road.cxx:697
 Road.cxx:698
 Road.cxx:699
 Road.cxx:700
 Road.cxx:701
 Road.cxx:702
 Road.cxx:703
 Road.cxx:704
 Road.cxx:705
 Road.cxx:706
 Road.cxx:707
 Road.cxx:708
 Road.cxx:709
 Road.cxx:710
 Road.cxx:711
 Road.cxx:712
 Road.cxx:713
 Road.cxx:714
 Road.cxx:715
 Road.cxx:716
 Road.cxx:717
 Road.cxx:718
 Road.cxx:719
 Road.cxx:720
 Road.cxx:721
 Road.cxx:722
 Road.cxx:723
 Road.cxx:724
 Road.cxx:725
 Road.cxx:726
 Road.cxx:727
 Road.cxx:728
 Road.cxx:729
 Road.cxx:730
 Road.cxx:731
 Road.cxx:732
 Road.cxx:733
 Road.cxx:734
 Road.cxx:735
 Road.cxx:736
 Road.cxx:737
 Road.cxx:738
 Road.cxx:739
 Road.cxx:740
 Road.cxx:741
 Road.cxx:742
 Road.cxx:743
 Road.cxx:744
 Road.cxx:745
 Road.cxx:746
 Road.cxx:747
 Road.cxx:748
 Road.cxx:749
 Road.cxx:750
 Road.cxx:751
 Road.cxx:752
 Road.cxx:753
 Road.cxx:754
 Road.cxx:755
 Road.cxx:756
 Road.cxx:757
 Road.cxx:758
 Road.cxx:759
 Road.cxx:760
 Road.cxx:761
 Road.cxx:762
 Road.cxx:763
 Road.cxx:764
 Road.cxx:765
 Road.cxx:766
 Road.cxx:767
 Road.cxx:768
 Road.cxx:769
 Road.cxx:770
 Road.cxx:771
 Road.cxx:772
 Road.cxx:773
 Road.cxx:774
 Road.cxx:775
 Road.cxx:776
 Road.cxx:777
 Road.cxx:778
 Road.cxx:779
 Road.cxx:780
 Road.cxx:781
 Road.cxx:782
 Road.cxx:783
 Road.cxx:784
 Road.cxx:785
 Road.cxx:786
 Road.cxx:787
 Road.cxx:788
 Road.cxx:789
 Road.cxx:790
 Road.cxx:791
 Road.cxx:792
 Road.cxx:793
 Road.cxx:794
 Road.cxx:795
 Road.cxx:796