I went ahead and coded a mostly-naive implementation of this. It’s mostly long because of my coding/indentation style, but it’s still the kind of thing I would like to see in a method. TLine doesn’t have too many methods on it yet, so maybe something like this could be added?
void RestrictLine(TLine & l, Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax)
{ // Basic line equations.
Double_t m = (l.GetY2()-l.GetY1())/(l.GetX2()-l.GetX1());
Double_t b = l.GetY1()-m*l.GetX1();
// When does the line cross the limits requested?
Double_t y_at_xmin = m*xmin+b;
Double_t y_at_xmax = m*xmax+b;
Double_t x_at_ymin = (ymin-b)/m;
Double_t x_at_ymax = (ymax-b)/m;
// This will hold the new start/end coordinates of the line.
vector<pair<Double_t, Double_t> > xy;
if( y_at_xmin <= ymax && y_at_xmin >= ymin )
{ // Crosses the left vertical edge inside the bounds.
xy.push_back(pair<Double_t,Double_t>(xmin,y_at_xmin));
}
if( y_at_xmax <= ymax && y_at_xmax >= ymin )
{ // Crosses the right vertical edge inside the bounds.
xy.push_back(pair<Double_t,Double_t>(xmax,y_at_xmax));
}
if( x_at_ymin <= xmax && x_at_ymin >= xmin )
{ // Crosses the bottom horizontal edge inside the bounds.
xy.push_back(pair<Double_t,Double_t>(x_at_ymin,ymin));
}
if( x_at_ymax <= xmax && x_at_ymax >= xmin )
{ // Crosses the upper horizontal edge inside the bounds.
xy.push_back(pair<Double_t,Double_t>(x_at_ymax,ymax));
}
if(xy.size() != 2)
{ // The line is only clipped if it enters and exits the box.
// Note that this has a problem if the line lies along one
// of the bounding edges, but I don't want to deal with that.
cout << "Line crosses " << xy.size() << " edges of bounding box." << endl;
return;
}
// Set the new coordinates of the line.
l.SetX1(xy[0].first);
l.SetY1(xy[0].second);
l.SetX2(xy[1].first);
l.SetY2(xy[1].second);
return;
}
You can test it by giving these commands in CINT (after .L RestrictLine.C+, it needs to be compiled because of the vector<pair<…> >).
TH1F h("h","h",10,0,10);
h.Fill(5);
TLine L(-5,-.2,20,1.0);
L.Draw(); // See how the line flows out past the axes boundaries.
RestrictLine(L,0,0,10,1);
L.Draw(); // The bounds are properly applied without changing the slope/y-intercept.
Of course this still needs one to get the proper bounds, but that’s easy with whatever object holds the Axes with ->GetXmin() and ->GetXmax();.
Jean-François