I use the class TEllipse as 95% contour, generated from a set of points in two dimensions. How can I find out whether a new point is inside the ellipse. I want to use physical coordinates, not pixels on my screen.
Are you sure you are using TEllipse ? I am asking because TEllipse is not defined by a set of points but by the box enclosing it. Maybe you are using TGraph ?
TGraph has the IsInside method which does what you are looking for.
Given that you defined an TEllipse like
TEllipse *el = new TEllipse(x_c, y_c, r_x, r_y);
You can verify with just an if statement a new point with coordinates x,y is inside the ellipse.
if( ( (x - x_c)*(x - x_c)/r_x/r_x + (y - y_c)*(y - y_c)/r_y/r_y)<=1 )
cout<<"is inside" <<endl;
else
cout<< "is outside" << endl;
Dear Dilicus,
thanks for the formula for the ellipse. I actually hoped that there is a
method in the TEllipse class to return “Inside” or “Outside”. In
addition in my case the ellipse is tilted by an angle theta, so that I
have to use a rotation in addition to the formula you showed. This is
actually the argument number 7 when calling TEllipse: TEllipse(x_c,
y_c, r_x, r_y, phimin, phimax, theta).
So in my case: x → x cos(theta) -y sin(theta) and y-> x sin(theta) - y
cos(theta). It would be great if a method (“Inside”) would be integrated
in the TEllipse class. For the moment I have to do it “the hard way”, as
you suggest, with my rotations added.
Best
Christian
Agreed!
Note it is a bit more tricky than just taking into account the tilting, as TEllipse allows to produce this kind of polygon:
Dear Olivier,
indeed, cutting out a sector from the ellipse (arguments 5 = phimin and 6 = phimax) is an additional challenge for the “Inside” method . Nevertheless, I am happy to read that the ROOT team will consider this additional feature for TEllipse.
Best
Christian
I have implemented it:
Macro inside.C
TEllipse *el;
void EPoint(double x, double y) {
auto p = new TMarker(x,y,20);
p->Draw();
if (el->IsInside(x,y)) {
p->SetMarkerColor(kGreen);
printf("The point (%g, %g) is inside the ellipse\n",x,y);
} else {
p->SetMarkerColor(kRed);
printf("The point (%g, %g) is outside the ellipse\n",x,y);
}
}
void inside(){
el = new TEllipse(0.75, 0.25, .2,.15,45,315,62);
el->SetLineColor(4);
el->Draw();
EPoint(.5,.5);
EPoint(.7,.3);
EPoint(.8,.2);
EPoint(.8,.3);
}
But for completeness, I will also implement it for other primitives like TBox etc … I’ll make a PR once I have them.
I made an issue: Implement IsInside for TEllipse · Issue #14453 · root-project/root · GitHub
Dear Olivier,
great, thanks!
I am looking forward to the PR and the new version of ROOT to download via snap!
Cheers
Christian
The PR is here: Implement some missing "IsInside" by couet · Pull Request #14456 · root-project/root · GitHub
I added a new tutorial testing IsInside for various classes.
void inside(){
auto el = new TEllipse(0.75, 0.25, .2,.15,45,315,62);
el->Draw();
auto gr = new TGraph();
double gr_x1[5] = { 0.1, 0.3388252, 0.03796561, 0.4176218, 0.1 };
double gr_y1[5] = { 0.5, 0.9644737, 0.7776316, 0.6960526, 0.5 };
gr = new TGraph(5,gr_x1,gr_y1);
gr->Draw("L");
auto bx = new TBox(.7,.8,.9,.95);
bx->Draw();
auto pv = new TPave(.05,.1,.3,.2);
pv->Draw();
auto di = new TDiamond(.05,.25,.3,.4);
di->Draw();
auto cr = new TCrown(.5,.5,.1,.15);
cr->SetFillColor(19);
cr->Draw();
for (int i=0; i<10000; i++) {
double x = gRandom->Rndm();
double y = gRandom->Rndm();
auto p = new TMarker(x,y,7);
p->Draw();
if (el->IsInside(x,y) || bx->IsInside(x,y) ||
pv->IsInside(x,y) || di->IsInside(x,y) ||
cr->IsInside(x,y) || gr->IsInside(x,y)) {
p->SetMarkerColor(kGreen);
} else {
p->SetMarkerColor(kRed);
}
}
}