#include "TBrowser.h"
#include "TPolyLine3D.h"
#include "TPoint.h"
#include "TVirtualPad.h"
#include "TView.h"
#include "TGeoManager.h"
#include "TVirtualGeoPainter.h"
#include "TGeoTrack.h"
ClassImp(TGeoTrack)
TGeoTrack::TGeoTrack()
{
fPointsSize = 0;
fNpoints = 0;
fPoints = 0;
}
TGeoTrack::TGeoTrack(Int_t id, Int_t pdgcode, TVirtualGeoTrack *parent, TObject *particle)
:TVirtualGeoTrack(id,pdgcode,parent,particle)
{
fPointsSize = 0;
fNpoints = 0;
fPoints = 0;
if (fParent==0) {
SetMarkerColor(2);
SetMarkerStyle(8);
SetMarkerSize(0.6);
SetLineColor(2);
SetLineWidth(2);
} else {
SetMarkerColor(4);
SetMarkerStyle(8);
SetMarkerSize(0.6);
SetLineColor(4);
SetLineWidth(2);
}
}
TGeoTrack::TGeoTrack(const TGeoTrack& other)
:TVirtualGeoTrack(other),
fPointsSize(other.fPointsSize),
fNpoints(other.fNpoints),
fPoints(other.fPoints)
{
}
TGeoTrack& TGeoTrack::operator=(const TGeoTrack& gv)
{
if(this!=&gv) {
TVirtualGeoTrack::operator=(gv);
fPointsSize=gv.fPointsSize;
fNpoints=gv.fNpoints;
fPoints=gv.fPoints;
}
return *this;
}
TGeoTrack::~TGeoTrack()
{
if (fPoints) delete [] fPoints;
}
TVirtualGeoTrack *TGeoTrack::AddDaughter(Int_t id, Int_t pdgcode, TObject *particle)
{
if (!fTracks) fTracks = new TObjArray(1);
Int_t index = fTracks->GetEntriesFast();
TGeoTrack *daughter = new TGeoTrack(id,pdgcode,this,particle);
fTracks->AddAtAndExpand(daughter,index);
return daughter;
}
Int_t TGeoTrack::AddDaughter(TVirtualGeoTrack *other)
{
if (!fTracks) fTracks = new TObjArray(1);
Int_t index = fTracks->GetEntriesFast();
fTracks->AddAtAndExpand(other,index);
other->SetParent(this);
return index;
}
void TGeoTrack::AnimateTrack(Double_t tmin, Double_t tmax, Double_t nframes, Option_t *option)
{
if (tmin<0 || tmin>=tmax || nframes<1) return;
gGeoManager->SetAnimateTracks();
gGeoManager->SetVisLevel(1);
if (!gPad) {
gGeoManager->GetMasterVolume()->Draw();
}
TList *list = gPad->GetListOfPrimitives();
TIter next(list);
TObject *obj;
while ((obj = next())) {
if (!strcmp(obj->ClassName(), "TGeoTrack")) list->Remove(obj);
}
Double_t dt = (tmax-tmin)/Double_t(nframes);
Double_t delt = 2E-9;
Double_t t = tmin;
Bool_t geomanim = kFALSE;
Bool_t issave = kFALSE;
TString fname;
TString opt(option);
if (opt.Contains("/G")) geomanim = kTRUE;
if (opt.Contains("/S")) issave = kTRUE;
TVirtualGeoPainter *p = gGeoManager->GetGeomPainter();
Double_t *box = p->GetViewBox();
box[0] = box[1] = box[2] = 0;
box[3] = box[4] = box[5] = 100;
gGeoManager->SetTminTmax(0,0);
Draw(opt.Data());
Double_t start[6], end[6];
Int_t i, j;
Double_t dlat=0, dlong=0, dpsi=0;
Double_t dd[6] = {0,0,0,0,0,0};
if (geomanim) {
p->EstimateCameraMove(tmin+5*dt, tmin+15*dt, start, end);
for (i=0; i<3; i++) {
start[i+3] = 20 + 1.3*start[i+3];
end[i+3] = 20 + 0.9*end[i+3];
}
for (i=0; i<6; i++) {
dd[i] = (end[i]-start[i])/10.;
}
memcpy(box, start, 6*sizeof(Double_t));
p->GetViewAngles(dlong,dlat,dpsi);
dlong = (-206-dlong)/Double_t(nframes);
dlat = (126-dlat)/Double_t(nframes);
dpsi = (75-dpsi)/Double_t(nframes);
p->GrabFocus();
}
for (i=0; i<nframes; i++) {
if (t-delt<0) gGeoManager->SetTminTmax(0,t);
else gGeoManager->SetTminTmax(t-delt,t);
if (geomanim) {
for (j=0; j<6; j++) box[j]+=dd[j];
p->GrabFocus(1,dlong,dlat,dpsi);
} else {
gPad->Modified();
gPad->Update();
}
if (issave) {
fname = TString::Format("anim%04d.gif", i);
gPad->Print(fname);
}
t += dt;
}
gGeoManager->SetAnimateTracks(kFALSE);
}
void TGeoTrack::AddPoint(Double_t x, Double_t y, Double_t z, Double_t t)
{
if (!fPoints) {
fPointsSize = 16;
fPoints = new Double_t[fPointsSize];
} else {
if (fNpoints>=fPointsSize) {
Double_t *temp = new Double_t[2*fPointsSize];
memcpy(temp, fPoints, fNpoints*sizeof(Double_t));
fPointsSize *= 2;
delete [] fPoints;
fPoints = temp;
}
}
fPoints[fNpoints++] = x;
fPoints[fNpoints++] = y;
fPoints[fNpoints++] = z;
fPoints[fNpoints++] = t;
}
void TGeoTrack::Browse(TBrowser *b)
{
if (!b) return;
Int_t nd = GetNdaughters();
if (!nd) {
b->Add(this);
return;
}
for (Int_t i=0; i<nd; i++)
b->Add(GetDaughter(i));
}
Int_t TGeoTrack::DistancetoPrimitive(Int_t px, Int_t py)
{
const Int_t inaxis = 7;
const Int_t maxdist = 5;
Int_t dist = 9999;
Int_t puxmin = gPad->XtoAbsPixel(gPad->GetUxmin());
Int_t puymin = gPad->YtoAbsPixel(gPad->GetUymin());
Int_t puxmax = gPad->XtoAbsPixel(gPad->GetUxmax());
Int_t puymax = gPad->YtoAbsPixel(gPad->GetUymax());
if (px < puxmin - inaxis) return dist;
if (py > puymin + inaxis) return dist;
if (px > puxmax + inaxis) return dist;
if (py < puymax - inaxis) return dist;
TView *view = gPad->GetView();
if (!view) return dist;
Int_t imin, imax;
if (TObject::TestBit(kGeoPDrawn) && Size(imin,imax)>=2) {
Int_t i, dsegment;
Double_t x1,y1,x2,y2;
Double_t xndc[3];
Int_t np = fNpoints>>2;
if (imin<0) imin=0;
if (imax>np-1) imax=np-1;
for (i=imin;i<imax;i++) {
view->WCtoNDC(&fPoints[i<<2], xndc);
x1 = xndc[0];
y1 = xndc[1];
view->WCtoNDC(&fPoints[(i+1)<<2], xndc);
x2 = xndc[0];
y2 = xndc[1];
dsegment = DistancetoLine(px,py,x1,y1,x2,y2);
if (dsegment < dist) {
dist = dsegment;
if (dist<maxdist) {
gPad->SetSelected(this);
return 0;
}
}
}
if (dist<maxdist) {
gPad->SetSelected(this);
return 0;
}
}
Int_t nd = GetNdaughters();
if (!nd) return dist;
TGeoTrack *track;
for (Int_t id=0; id<nd; id++) {
track = (TGeoTrack*)GetDaughter(id);
dist = track->DistancetoPrimitive(px,py);
if (dist<maxdist) return 0;
}
return dist;
}
void TGeoTrack::Draw(Option_t *option)
{
if (!gPad) gGeoManager->GetMasterVolume()->Draw();
char *opt1 = Compress(option);
TString opt(opt1);
Bool_t is_default = kTRUE;
Bool_t is_onelevel = kFALSE;
Bool_t is_all = kFALSE;
Bool_t is_type = kFALSE;
if (opt.Contains("/D")) {
is_onelevel = kTRUE;
is_default = kFALSE;
}
if (opt.Contains("/*")) {
is_all = kTRUE;
is_default = kFALSE;
}
if (opt.Contains("/N")) {
is_type = kTRUE;
Int_t ist = opt.Index("/N")+2;
Int_t ilast = opt.Index("/",ist);
if (ilast<0) ilast=opt.Length();
TString type = opt(ist, ilast-ist);
gGeoManager->SetParticleName(type.Data());
}
SetBits(is_default, is_onelevel, is_all, is_type);
AppendPad("SAME");
if (!gGeoManager->IsAnimatingTracks()) {
gPad->Modified();
gPad->Update();
}
delete [] opt1;
return;
}
void TGeoTrack::ExecuteEvent(Int_t , Int_t , Int_t )
{
if (!gPad) return;
gPad->SetCursor(kHand);
}
char *TGeoTrack::GetObjectInfo(Int_t , Int_t ) const
{
static TString info;
Double_t x=0,y=0,z=0,t=0;
GetPoint(0,x,y,z,t);
info = TString::Format("%s (%g, %g, %g) tof=%g", GetName(),x,y,z,t);
return (char*)info.Data();
}
Int_t TGeoTrack::GetPoint(Int_t i, Double_t &x, Double_t &y, Double_t &z, Double_t &t) const
{
Int_t np = fNpoints>>2;
if (i<0 || i>=np) {
Error("GetPoint", "no point %i, indmax=%d", i, np-1);
return -1;
}
Int_t icrt = 4*i;
x = fPoints[icrt];
y = fPoints[icrt+1];
z = fPoints[icrt+2];
t = fPoints[icrt+3];
return i;
}
const Double_t *TGeoTrack::GetPoint(Int_t i) const
{
if (!fNpoints) return 0;
return (&fPoints[i<<2]);
}
Int_t TGeoTrack::GetPoint(Double_t tof, Double_t *point, Int_t istart) const
{
Int_t np = fNpoints>>2;
if (istart>(np-2)) return (np-1);
Int_t ip = SearchPoint(tof, istart);
if (ip<0 || ip>(np-2)) return ip;
Int_t i;
Int_t j = ip<<2;
Int_t k = (ip+1)<<2;
Double_t dt = tof-fPoints[j+3];
Double_t ddt = fPoints[k+3]-fPoints[j+3];
for (i=0; i<3; i++) point[i] = fPoints[j+i] +(fPoints[k+i]-fPoints[j+i])*dt/ddt;
return ip;
}
void TGeoTrack::Paint(Option_t *option)
{
Bool_t is_default = TObject::TestBit(kGeoPDefault);
Bool_t is_onelevel = TObject::TestBit(kGeoPOnelevel);
Bool_t is_all = TObject::TestBit(kGeoPAllDaughters);
Bool_t is_type = TObject::TestBit(kGeoPType);
Bool_t match_type = kTRUE;
TObject::SetBit(kGeoPDrawn, kFALSE);
if (is_type) {
const char *type = gGeoManager->GetParticleName();
if (strlen(type) && strcmp(type, GetName())) match_type=kFALSE;
}
if (match_type) {
if (is_default || is_onelevel || is_all) PaintTrack(option);
}
Int_t nd = GetNdaughters();
if (!nd || is_default) return;
TGeoTrack *track;
for (Int_t i=0; i<nd; i++) {
track = (TGeoTrack*)GetDaughter(i);
if (track->IsInTimeRange()) {
track->SetBits(is_default,kFALSE,is_all,is_type);
track->Paint(option);
}
}
}
void TGeoTrack::PaintCollect(Double_t time, Double_t *box)
{
Bool_t is_default = TObject::TestBit(kGeoPDefault);
Bool_t is_onelevel = TObject::TestBit(kGeoPOnelevel);
Bool_t is_all = TObject::TestBit(kGeoPAllDaughters);
Bool_t is_type = TObject::TestBit(kGeoPType);
Bool_t match_type = kTRUE;
if (is_type) {
const char *type = gGeoManager->GetParticleName();
if (strlen(type) && strcmp(type, GetName())) match_type=kFALSE;
}
if (match_type) {
if (is_default || is_onelevel || is_all) PaintCollectTrack(time, box);
}
Int_t nd = GetNdaughters();
if (!nd || is_default) return;
TGeoTrack *track;
for (Int_t i=0; i<nd; i++) {
track = (TGeoTrack*)GetDaughter(i);
track->PaintCollect(time, box);
}
}
void TGeoTrack::PaintCollectTrack(Double_t time, Double_t *box)
{
TVirtualGeoPainter *painter = gGeoManager->GetGeomPainter();
if (!painter) return;
Int_t np = fNpoints>>2;
Double_t point[3], local[3];
Bool_t convert = (gGeoManager->GetTopVolume() == gGeoManager->GetMasterVolume())?kFALSE:kTRUE;
Int_t ip = GetPoint(time, point);
if (ip>=0 && ip<np-1) {
if (convert) gGeoManager->MasterToTop(point, local);
else memcpy(local, point, 3*sizeof(Double_t));
painter->AddTrackPoint(local, box);
}
}
void TGeoTrack::PaintMarker(Double_t *point, Option_t *)
{
TPoint p;
Double_t xndc[3];
TView *view = gPad->GetView();
if (!view) return;
view->WCtoNDC(point, xndc);
if (xndc[0] < gPad->GetX1() || xndc[0] > gPad->GetX2()) return;
if (xndc[1] < gPad->GetY1() || xndc[1] > gPad->GetY2()) return;
p.fX = gPad->XtoPixel(xndc[0]);
p.fY = gPad->YtoPixel(xndc[1]);
TAttMarker::Modify();
gVirtualX->DrawPolyMarker(1, &p);
}
void TGeoTrack::PaintTrack(Option_t *option)
{
TString opt(option);
opt.ToLower();
TObject::SetBit(kGeoPDrawn, kFALSE);
if (opt.Contains("x")) return;
Int_t np = fNpoints>>2;
Int_t imin=0;
Int_t imax=np-1;
Int_t ip;
Double_t start[3], end[3], seg[6];
Bool_t convert = (gGeoManager->GetTopVolume() == gGeoManager->GetMasterVolume())?kFALSE:kTRUE;
Double_t tmin,tmax;
Bool_t is_time = gGeoManager->GetTminTmax(tmin,tmax);
if (is_time) {
imin = GetPoint(tmin, start);
if (imin>=0 && imin<np-1) {
imax = GetPoint(tmax, end, imin);
if (imax<np-1) {
if (imax==imin) {
TAttLine::Modify();
if (convert) {
gGeoManager->MasterToTop(start, &seg[0]);
gGeoManager->MasterToTop(end, &seg[3]);
gPad->PaintLine3D(&seg[0], &seg[3]);
} else {
gPad->PaintLine3D(start, end);
}
} else {
TAttLine::Modify();
if (convert) {
gGeoManager->MasterToTop(start, &seg[0]);
gGeoManager->MasterToTop(&fPoints[(imin+1)<<2], &seg[3]);
gPad->PaintLine3D(&seg[0], &seg[3]);
gGeoManager->MasterToTop(&fPoints[imax<<2], &seg[0]);
gGeoManager->MasterToTop(end, &seg[3]);
gPad->PaintLine3D(&seg[0], &seg[3]);
for (ip=imin+1; ip<imax; ip++) {
gGeoManager->MasterToTop(&fPoints[ip<<2], &seg[0]);
gGeoManager->MasterToTop(&fPoints[(ip+1)<<2], &seg[3]);
gPad->PaintLine3D(&seg[0], &seg[3]);
}
} else {
gPad->PaintLine3D(start, &fPoints[(imin+1)<<2]);
gPad->PaintLine3D(&fPoints[imax<<2], end);
for (ip=imin+1; ip<imax; ip++) {
gPad->PaintLine3D(&fPoints[ip<<2], &fPoints[(ip+1)<<2]);
}
}
}
if (convert) {
gGeoManager->MasterToTop(end, &seg[0]);
PaintMarker(&seg[0]);
} else {
PaintMarker(end);
}
} else {
TAttLine::Modify();
if (convert) {
gGeoManager->MasterToTop(start, &seg[0]);
gGeoManager->MasterToTop(&fPoints[(imin+1)<<2], &seg[3]);
gPad->PaintLine3D(&seg[0], &seg[3]);
for (ip=imin+1; ip<np-2; ip++) {
gGeoManager->MasterToTop(&fPoints[ip<<2], &seg[0]);
gGeoManager->MasterToTop(&fPoints[(ip+1)<<2], &seg[3]);
gPad->PaintLine3D(&seg[0], &seg[3]);
}
} else {
gPad->PaintLine3D(start, &fPoints[(imin+1)<<2]);
for (ip=imin+1; ip<np-2; ip++) {
gPad->PaintLine3D(&fPoints[ip<<2], &fPoints[(ip+1)<<2]);
}
}
}
} else {
imax = GetPoint(tmax, end);
if (imax<0 || imax>=(np-1)) return;
TAttLine::Modify();
if (convert) {
for (ip=0; ip<imax-1; ip++) {
gGeoManager->MasterToTop(&fPoints[ip<<2], &seg[0]);
gGeoManager->MasterToTop(&fPoints[(ip+1)<<2], &seg[3]);
gPad->PaintLine3D(&seg[0], &seg[3]);
}
} else {
for (ip=0; ip<imax-1; ip++) {
gPad->PaintLine3D(&fPoints[ip<<2], &fPoints[(ip+1)<<2]);
}
}
if (convert) {
gGeoManager->MasterToTop(&fPoints[imax<<2], &seg[0]);
gGeoManager->MasterToTop(end, &seg[3]);
gPad->PaintLine3D(&seg[0], &seg[3]);
PaintMarker(&seg[3]);
} else {
gPad->PaintLine3D(&fPoints[imax<<2], end);
PaintMarker(end);
}
}
TObject::SetBit(kGeoPDrawn);
return;
}
TObject::SetBit(kGeoPDrawn);
TAttLine::Modify();
for (ip=imin; ip<imax; ip++) {
gPad->PaintLine3D(&fPoints[ip<<2], &fPoints[(ip+1)<<2]);
}
}
void TGeoTrack::Print(Option_t * ) const
{
Int_t np = fNpoints>>2;
printf(" TGeoTrack%6i : %s ===============================\n", fId,GetName());
printf(" parent =%6i nd =%3i\n", (fParent)?fParent->GetId():-1, GetNdaughters());
Double_t x,y,z,t;
GetPoint(0,x,y,z,t);
printf(" production vertex : (%g, %g, %g) at tof=%g\n", x,y,z,t);
GetPoint(np-1,x,y,z,t);
printf(" Npoints =%6i, last : (%g, %g, %g) at tof=%g\n\n", np,x,y,z,t);
}
Int_t TGeoTrack::Size(Int_t &imin, Int_t &imax)
{
Double_t tmin, tmax;
Int_t np = fNpoints>>2;
imin = 0;
imax = np-1;
Int_t size = np;
if (!gGeoManager->GetTminTmax(tmin, tmax)) return size;
imin = SearchPoint(tmin);
imax = SearchPoint(tmax, imin);
return (imax-imin+1);
}
Int_t TGeoTrack::SearchPoint(Double_t time, Int_t istart) const
{
Int_t nabove, nbelow, middle, midloc;
Int_t np = fNpoints>>2;
nabove = np+1;
nbelow = istart;
while (nabove-nbelow > 1) {
middle = (nabove+nbelow)/2;
midloc = ((middle-1)<<2)+3;
if (time == fPoints[midloc]) return middle-1;
if (time < fPoints[midloc]) nabove = middle;
else nbelow = middle;
}
return (nbelow-1);
}
void TGeoTrack::SetBits(Bool_t is_default, Bool_t is_onelevel,
Bool_t is_all, Bool_t is_type)
{
TObject::SetBit(kGeoPDefault, is_default);
TObject::SetBit(kGeoPOnelevel, is_onelevel);
TObject::SetBit(kGeoPAllDaughters, is_all);
TObject::SetBit(kGeoPType, is_type);
}
void TGeoTrack::Sizeof3D() const
{
}
void TGeoTrack::ResetTrack()
{
fNpoints = 0;
fPointsSize = 0;
if (fTracks) {fTracks->Delete(); delete fTracks;}
fTracks = 0;
if (fPoints) delete [] fPoints;
fPoints = 0;
}