diff --git a/graf2d/graf/inc/TCrown.h b/graf2d/graf/inc/TCrown.h index 94a2eccf90818..c746349cbd879 100644 --- a/graf2d/graf/inc/TCrown.h +++ b/graf2d/graf/inc/TCrown.h @@ -25,11 +25,12 @@ class TCrown : public TEllipse { TCrown(const TCrown &crown); ~TCrown() override; - void Copy(TObject &crown) const override; + void Copy(TObject &crown) const override; Int_t DistancetoPrimitive(Int_t px, Int_t py) override; virtual TCrown *DrawCrown(Double_t x1, Double_t y1, Double_t radin, Double_t radout, Double_t phimin=0, Double_t phimax=360, Option_t *option=""); void ExecuteEvent(Int_t event, Int_t px, Int_t py) override; + Int_t IsInside(Double_t x, Double_t y) const; void Paint(Option_t *option="") override; void SavePrimitive(std::ostream &out, Option_t *option = "") override; diff --git a/graf2d/graf/inc/TDiamond.h b/graf2d/graf/inc/TDiamond.h index 7290e51d5bf60..d7a8e0bba83ae 100644 --- a/graf2d/graf/inc/TDiamond.h +++ b/graf2d/graf/inc/TDiamond.h @@ -23,6 +23,7 @@ class TDiamond : public TPaveText { ~TDiamond() override; Int_t DistancetoPrimitive(Int_t px, Int_t py) override; void Draw(Option_t *option="") override; + Int_t IsInside(Double_t x, Double_t y) const override; void ExecuteEvent(Int_t event, Int_t px, Int_t py) override; void Paint(Option_t *option="") override; void SavePrimitive(std::ostream &out, Option_t *option = "") override; @@ -31,4 +32,3 @@ class TDiamond : public TPaveText { }; #endif - diff --git a/graf2d/graf/inc/TEllipse.h b/graf2d/graf/inc/TEllipse.h index b0912d408d2f5..f54f54336b3cf 100644 --- a/graf2d/graf/inc/TEllipse.h +++ b/graf2d/graf/inc/TEllipse.h @@ -45,6 +45,7 @@ class TEllipse : public TObject, public TAttLine, public TAttFill, public TAttBB void Draw(Option_t *option="") override; virtual TEllipse *DrawEllipse(Double_t x1, Double_t y1, Double_t r1,Double_t r2,Double_t phimin, Double_t phimax,Double_t theta,Option_t *option=""); void ExecuteEvent(Int_t event, Int_t px, Int_t py) override; + Int_t IsInside(Double_t x, Double_t y) const; Double_t GetX1() const {return fX1;} Double_t GetY1() const {return fY1;} Double_t GetR1() const {return fR1;} diff --git a/graf2d/graf/src/TCrown.cxx b/graf2d/graf/src/TCrown.cxx index 56c72dccfafef..077a0bb9c250a 100644 --- a/graf2d/graf/src/TCrown.cxx +++ b/graf2d/graf/src/TCrown.cxx @@ -173,6 +173,45 @@ void TCrown::ExecuteEvent(Int_t event, Int_t px, Int_t py) TEllipse::ExecuteEvent(event,px,py); } +//////////////////////////////////////////////////////////////////////////////// +/// Return 1 if the point (x,y) is inside the polygon defined by +/// the crown 0 otherwise. + +Int_t TCrown::IsInside(Double_t x, Double_t y) const +{ + + const Double_t kPI = TMath::Pi(); + const Int_t np = 40; + static Double_t xc[2 * np + 3], yc[2 * np +3]; + + Double_t angle, dx, dy; + Double_t dphi = (fPhimax - fPhimin) * kPI / (180 * np); + Double_t ct = TMath::Cos(kPI * fTheta / 180); + Double_t st = TMath::Sin(kPI * fTheta / 180); + Int_t i; + + // compute outer points + for (i = 0; i <= np; i++) { + angle = fPhimin * kPI / 180 + Double_t(i) * dphi; + dx = fR2 * TMath::Cos(angle); + dy = fR2 * TMath::Sin(angle); + xc[i] = fX1 + dx * ct - dy * st; + yc[i] = fY1 + dx * st + dy * ct; + } + // compute inner points + for (i = 0; i <= np; i++) { + angle = fPhimin * kPI / 180 + Double_t(i) * dphi; + dx = fR1 * TMath::Cos(angle); + dy = fR1 * TMath::Sin(angle); + xc[2 * np - i + 1] = fX1 + dx * ct - dy * st; + yc[2 * np - i + 1] = fY1 + dx * st + dy * ct; + } + xc[2 * np + 2] = xc[0]; + yc[2 * np + 2] = yc[0]; + + return (Int_t)TMath::IsInside(x, y, 2 * np + 3, xc, yc); +} + //////////////////////////////////////////////////////////////////////////////// /// Paint this crown with its current attributes. @@ -182,47 +221,47 @@ void TCrown::Paint(Option_t *) const Double_t kPI = TMath::Pi(); const Int_t np = 40; - static Double_t x[2*np+3], y[2*np+3]; + static Double_t x[2 * np + 3], y[2 * np + 3]; TAttLine::Modify(); TAttFill::Modify(); Double_t angle,dx,dy; - Double_t dphi = (fPhimax-fPhimin)*kPI/(180*np); - Double_t ct = TMath::Cos(kPI*fTheta/180); - Double_t st = TMath::Sin(kPI*fTheta/180); + Double_t dphi = (fPhimax - fPhimin) * kPI / (180 * np); + Double_t ct = TMath::Cos(kPI * fTheta / 180); + Double_t st = TMath::Sin(kPI * fTheta / 180); Int_t i; - //compute outer points - for (i=0;i<=np;i++) { - angle = fPhimin*kPI/180 + Double_t(i)*dphi; - dx = fR2*TMath::Cos(angle); - dy = fR2*TMath::Sin(angle); - x[i] = fX1 + dx*ct - dy*st; - y[i] = fY1 + dx*st + dy*ct; + // compute outer points + for (i = 0; i <= np; i++) { + angle = fPhimin * kPI / 180 + Double_t(i) * dphi; + dx = fR2 * TMath::Cos(angle); + dy = fR2 * TMath::Sin(angle); + x[i] = fX1 + dx * ct - dy * st; + y[i] = fY1 + dx * st + dy * ct; } - //compute inner points - for (i=0;i<=np;i++) { - angle = fPhimin*kPI/180 + Double_t(i)*dphi; - dx = fR1*TMath::Cos(angle); - dy = fR1*TMath::Sin(angle); - x[2*np-i+1] = fX1 + dx*ct - dy*st; - y[2*np-i+1] = fY1 + dx*st + dy*ct; + // compute inner points + for (i = 0; i <= np; i++) { + angle = fPhimin * kPI / 180 + Double_t(i) * dphi; + dx = fR1 * TMath::Cos(angle); + dy = fR1 * TMath::Sin(angle); + x[2 * np - i + 1] = fX1 + dx * ct - dy * st; + y[2 * np - i + 1] = fY1 + dx * st + dy * ct; } - x[2*np+2] = x[0]; - y[2*np+2] = y[0]; - if (fPhimax-fPhimin >= 360 ) { + x[2 * np + 2] = x[0]; + y[2 * np + 2] = y[0]; + if (fPhimax - fPhimin >= 360 ) { // a complete filled crown if (GetFillColor() && GetFillStyle()) { - gPad->PaintFillArea(2*np+2,x,y); + gPad->PaintFillArea(2 * np + 2,x,y); } // a complete empty crown if (GetLineStyle()) { - gPad->PaintPolyLine(np+1,x,y); - gPad->PaintPolyLine(np+1,&x[np+1],&y[np+1]); + gPad->PaintPolyLine(np + 1,x,y); + gPad->PaintPolyLine(np + 1,&x[np + 1],&y[np + 1]); } } else { //crown segment - if (GetFillColor() && GetFillStyle()) gPad->PaintFillArea(2*np+2,x,y); - if (GetLineStyle()) gPad->PaintPolyLine(2*np+3,x,y); + if (GetFillColor() && GetFillStyle()) gPad->PaintFillArea(2 * np + 2,x,y); + if (GetLineStyle()) gPad->PaintPolyLine(2 * np + 3,x,y); } } diff --git a/graf2d/graf/src/TDiamond.cxx b/graf2d/graf/src/TDiamond.cxx index 821b795cd6f90..f7ec00c893612 100644 --- a/graf2d/graf/src/TDiamond.cxx +++ b/graf2d/graf/src/TDiamond.cxx @@ -374,6 +374,27 @@ void TDiamond::ExecuteEvent(Int_t event, Int_t px, Int_t py) } } +//////////////////////////////////////////////////////////////////////////////// +/// Return 1 if the point (x,y) is inside the polygon defined by +/// the diamond 0 otherwise. + +Int_t TDiamond::IsInside(Double_t x, Double_t y) const +{ + + Double_t xd[4], yd[4]; + + xd[0] = fX1; + yd[0] = (fY2 + fY1) / 2.; + xd[1] = (fX2 + fX1) / 2.; + yd[1] = fY1; + xd[2] = fX2; + yd[2] = yd[0]; + xd[3] = xd[1]; + yd[3] = fY2; + + return (Int_t)TMath::IsInside(x, y, 4, xd, yd); +} + //////////////////////////////////////////////////////////////////////////////// /// Paint this diamond with its current attributes. diff --git a/graf2d/graf/src/TEllipse.cxx b/graf2d/graf/src/TEllipse.cxx index dd3f43ec8fe50..726b6749a7bc0 100644 --- a/graf2d/graf/src/TEllipse.cxx +++ b/graf2d/graf/src/TEllipse.cxx @@ -21,7 +21,7 @@ #include "TVirtualX.h" -const Double_t kPI = 3.14159265358979323846; +constexpr Double_t kPI = TMath::Pi(); ClassImp(TEllipse); @@ -507,6 +507,38 @@ void TEllipse::ExecuteEvent(Int_t event, Int_t px, Int_t py) } } +//////////////////////////////////////////////////////////////////////////////// +/// Return 1 if the point (x,y) is inside the polygon defined by +/// the ellipse 0 otherwise. +/// Author: Ole Hansen (ole@jlab.org) +Int_t TEllipse::IsInside(Double_t x, Double_t y) const +{ + x -= fX1; + y -= fY1; + Double_t th = fTheta * TMath::DegToRad(); + Double_t st = TMath::Sin(th); + Double_t ct = TMath::Cos(th); + Double_t xx = ct * x + st * y; + Double_t yy = -st * x + ct * y; + + if (TMath::Abs(xx) > fR1 || TMath::Abs(yy) > fR2) + return 0; + Double_t xn = xx / fR1; + Double_t yn = yy / fR2; + if (xn * xn + yn * yn > 1.) + return 0; + if (fPhimax - fPhimin >= 360.) + return 1; + Double_t phimin = std::fmod(fPhimin, 360.); + Double_t phimax = std::fmod(fPhimax, 360.); + Double_t phi = TMath::RadToDeg()*(TMath::Pi() + TMath::ATan2(-yy * fR1 / fR2, -xx)); + if (phi < phimin || phi > phimax) + return 0; + + return 1; +} + + //////////////////////////////////////////////////////////////////////////////// /// List this ellipse with its attributes. diff --git a/tutorials/graphics/inside.C b/tutorials/graphics/inside.C new file mode 100644 index 0000000000000..b51e1784e0fff --- /dev/null +++ b/tutorials/graphics/inside.C @@ -0,0 +1,46 @@ +/// \file +/// \ingroup tutorial_graphics +/// \notebook -js +/// Test the IsInside methods of various graphics primitives. +/// +/// \macro_image +/// \macro_code +/// +/// \author Olivier Couet + +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); + } + } +}