// @(#)root/geom:$Name:  $:$Id: TGeoChecker.cxx,v 1.3 2002/07/17 14:22:54 brun Exp $
// Author: Andrei Gheata   01/11/01

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

////////////////////////////////////////////////////////////////////////////////
// A simple geometry checker. Points can be randomly generated inside the 
// bounding  box of a node. For each point the distance to the nearest surface
// and the corresponting point on that surface are computed. These points are 
// stored in a tree and can be directly visualized within ROOT
// A second algoritm is shooting multiple rays from a given point to a geometry
// branch and storing the intersection points with surfaces in same tree. 
// Rays can be traced backwords in order to find overlaps by comparing direct 
// and inverse points.
//
/*

*/
//

#include "TVirtualPad.h"
#include "TNtuple.h"
#include "TRandom3.h"
#include "TPolyMarker3D.h"
#include "TPolyLine3D.h"
#include "TStopwatch.h"

#include "TGeoBBox.h"
#include "TGeoManager.h"
#include "TGeoChecker.h"


// statics and globals

ClassImp(TGeoChecker)

//-----------------------------------------------------------------------------
 TGeoChecker::TGeoChecker()
{
// Default constructor
   fGeom = 0;
   fTreePts      = 0; 
}
//-----------------------------------------------------------------------------
 TGeoChecker::TGeoChecker(TGeoManager *geom)
{
// Constructor for a given geometry
   fGeom = geom;
   fTreePts = 0;
}
//-----------------------------------------------------------------------------
 TGeoChecker::TGeoChecker(const char *treename, const char *filename)
{
// constructor
   fGeom = gGeoManager;
   fTreePts = 0;
}
//-----------------------------------------------------------------------------
 TGeoChecker::~TGeoChecker()
{
// Destructor
}
//-----------------------------------------------------------------------------
 void TGeoChecker::CheckPoint(Double_t x, Double_t y, Double_t z, Option_t *)
{
//--- Draw point (x,y,z) over the picture of the daughers of the volume containing this point.
//   Generates a report regarding the path to the node containing this point and the distance to
//   the closest boundary.

   Double_t point[3];
   Double_t local[3];
   Double_t dir[3];
   point[0] = x;
   point[1] = y;
   point[2] = z;
   memset(&dir[0], 0, 3*sizeof(Double_t));
   dir[2] = 1.;
   // init dummy track from current point
   fGeom->InitTrack(&point[0], &dir[0]);
   // get current node
   TGeoNode *node = fGeom->GetCurrentNode();
   printf("===  Check current point ===n");
   printf("Current point : x=%f y=%f z=%fn", point[0], point[1], point[2]);
   printf("  - path : %sn", fGeom->GetPath());
   // get corresponding volume
   TGeoVolume *vol = node->GetVolume();
   // compute safety distance (distance to boundary ignored)
   fGeom->FindNextBoundary();
   Double_t close = fGeom->GetSafeDistance();
   if (close>1E10) {
      printf("Safety not implemented for shape %sn",
             vol->GetShape()->ClassName());
   } else {
      printf("Safety radius : %fn", close);
   }   
   fGeom->MasterToLocal(&point[0], &local[0]);
   TPolyMarker3D *pm = new TPolyMarker3D();
   pm->SetMarkerColor(2);
   pm->SetMarkerStyle(8);
   pm->SetMarkerSize(0.5);
   pm->SetNextPoint(local[0], local[1], local[2]);
   if (vol->GetNdaughters()) {
      fGeom->SetVisLevel(1);
      vol->Draw();
   } else {
      vol->DrawOnly();
   }   
   pm->Draw("SAME");
   gPad->Modified();
   gPad->Update();
}  
//______________________________________________________________________________
 void TGeoChecker::RandomPoints(TGeoVolume *vol, Int_t npoints, Option_t *option)
{
// Draw random points in the bounding box of a volume.
   if (!vol) return;
   gRandom = new TRandom3();
   vol->VisibleDaughters(kTRUE);
   vol->Draw();
   TString opt = option;
   opt.ToLower();
   TObjArray *pm = new TObjArray(128);
   TPolyMarker3D *marker = 0;
   const TGeoShape *shape = vol->GetShape();
   TGeoBBox *box = (TGeoBBox *)shape;
   Double_t dx = box->GetDX();
   Double_t dy = box->GetDY();
   Double_t dz = box->GetDZ();
   Double_t ox = (box->GetOrigin())[0];
   Double_t oy = (box->GetOrigin())[1];
   Double_t oz = (box->GetOrigin())[2];
   Double_t *xyz = new Double_t[3];
   printf("Random box : %f, %f, %fn", dx, dy, dz);
   TGeoNode *node = 0;
   printf("Start... %i pointsn", npoints);
   Int_t i=0;
   Int_t igen=0;
   Int_t ic = 0;
   Int_t n10 = npoints/10;
   Double_t ratio=0;
   while (igen<npoints) {
      xyz[0] = ox-dx+2*dx*gRandom->Rndm();
      xyz[1] = oy-dy+2*dy*gRandom->Rndm();
      xyz[2] = oz-dz+2*dz*gRandom->Rndm();
      fGeom->SetCurrentPoint(xyz);
      igen++;
      if (n10) {
         if ((igen%n10) == 0) printf("%i percentn", Int_t(100*igen/npoints));
      }  
      node = fGeom->FindNode();
      if (!node) continue;
      if (!node->IsOnScreen()) continue;
      // draw only points in overlapping/non-overlapping volumes
      if (opt.Contains("many") && !node->IsOverlapping()) continue;
      if (opt.Contains("only") && node->IsOverlapping()) continue;
      ic = node->GetColour();
      if (ic >= 128) ic = 0;
      marker = (TPolyMarker3D*)pm->At(ic);
      if (!marker) {
         marker = new TPolyMarker3D();
         marker->SetMarkerColor(ic);
         marker->SetMarkerStyle(8);
         marker->SetMarkerSize(0.4);
         pm->AddAt(marker, ic);
      }
      marker->SetNextPoint(xyz[0], xyz[1], xyz[2]);
      i++;
   }
   printf("Number of visible points : %in", i);
   ratio = (Double_t)i/(Double_t)igen;
   printf("efficiency : %gn", ratio);
   for (Int_t m=0; m<128; m++) {
      marker = (TPolyMarker3D*)pm->At(m);
      if (marker) marker->Draw("SAME");
   }
   fGeom->GetTopVolume()->VisibleDaughters(kFALSE);
   printf("---Daughters of %s made invisible.n", fGeom->GetTopVolume()->GetName());
   printf("---Make them visible with : gGeoManager->GetTopVolume()->VisibleDaughters();n");
   delete pm;
   delete xyz;
}   
//-----------------------------------------------------------------------------
 void TGeoChecker::RandomRays(Int_t nrays, Double_t startx, Double_t starty, Double_t startz)
{
// Randomly shoot nrays from point (startx,starty,startz) and plot intersections 
// with surfaces for current top node.
   TObjArray *pm = new TObjArray(128);
   TPolyLine3D *line = 0;
   gRandom = new TRandom3();
   TGeoVolume *vol=fGeom->GetTopVolume();
   vol->VisibleDaughters(kTRUE);

   Double_t start[3];
   Double_t dir[3];
   Double_t *point = fGeom->GetCurrentPoint();
   vol->Draw();
   printf("Start... %i raysn", nrays);
   //TGeoNode *node;
   //Bool_t is_sentering;
   TGeoNode *startnode, *endnode;
   Bool_t vis1,vis2, is_entering, is_null;
   Int_t i=0;
   Int_t ipoint;
   Int_t itot=0;
   Int_t n10=nrays/10;
   Double_t theta,phi, step;
   while (itot<nrays) {
      itot++;
      ipoint = 0;
      if (n10) {
         if ((itot%n10) == 0) printf("%i percentn", Int_t(100*itot/nrays));
      }
      start[0] = startx;
      start[1] = starty;
      start[2] = startz;
      phi = 2*TMath::Pi()*gRandom->Rndm();
      theta= TMath::ACos(1.-2.*gRandom->Rndm());
      dir[0]=TMath::Sin(theta)*TMath::Cos(phi);
      dir[1]=TMath::Sin(theta)*TMath::Sin(phi);
      dir[2]=TMath::Cos(theta);
      fGeom->InitTrack(&start[0], &dir[0]);
      line = 0;
      startnode = fGeom->GetCurrentNode();
      if (fGeom->IsOutside()) startnode=0;
      vis1 = (startnode)?(startnode->IsOnScreen()):kFALSE;
      if (vis1) {
         line = new TPolyLine3D(2);
         line->SetLineColor(startnode->GetVolume()->GetLineColor());
         line->SetPoint(ipoint++, startx, starty, startz);
         i++;
         pm->Add(line);
      }
      // find the node that will be crossed first      
      fGeom->FindNextBoundary();
      fGeom->IsStepEntering();
      // find where we end-up
      endnode = fGeom->Step();
      if (fGeom->IsOutside()) endnode=0;
      step = fGeom->GetStep();
      vis2 = (endnode)?(endnode->IsOnScreen()):kFALSE;
      is_entering = fGeom->IsEntering();
      is_null = fGeom->IsNullStep();
      while (step<1E10) {
         if (ipoint>0) {
         // old visible node had an entry point -> finish segment
            line->SetPoint(ipoint, point[0], point[1], point[2]);
            ipoint = 0;
            line   = 0;
         }
         if (is_entering && vis2 && (startnode!=endnode)) {
            // create new segment
            line = new TPolyLine3D(2);   
            line->SetLineColor(endnode->GetVolume()->GetLineColor());
            line->SetPoint(ipoint++, point[0], point[1], point[2]);
            i++;
            pm->Add(line);
         }
         // now see if we can make an other step
         if (endnode==0) break;
         if (is_null) break;
         startnode = endnode;    
         fGeom->FindNextBoundary();
         fGeom->IsStepEntering();
         endnode = fGeom->Step();
         if (fGeom->IsOutside()) endnode=0;
         step = fGeom->GetStep();
         vis2 = (endnode)?(endnode->IsOnScreen()):kFALSE;
         is_entering = fGeom->IsEntering();
         is_null = fGeom->IsNullStep();
      }      
   }   
   // draw all segments
   for (Int_t m=0; m<pm->GetEntriesFast(); m++) {
      line = (TPolyLine3D*)pm->At(m);
      if (line) line->Draw("SAME");
   }
   printf("number of segments : %in", i);
   fGeom->GetTopVolume()->VisibleDaughters(kFALSE);
   printf("---Daughters of %s made invisible.n", fGeom->GetTopVolume()->GetName());
   printf("---Make them visible with : gGeoManager->GetTopVolume()->VisibleDaughters();n");
   delete pm;
}
//-----------------------------------------------------------------------------
 TGeoNode *TGeoChecker::SamplePoints(Int_t npoints, Double_t &dist, Double_t epsil,
                                    const char* g3path)
{
// shoot npoints randomly in a box of 1E-5 arround current point.
// return minimum distance to points outside
   // make sure that path to current node is updated
   // get the response of tgeo
   TGeoNode *node = fGeom->FindNode();
   TGeoNode *nodegeo = 0;
   TGeoNode *nodeg3 = 0;
   TGeoNode *solg3 = 0;
   if (!node) {dist=-1; return 0;}
   gRandom = new TRandom3();
   Bool_t hasg3 = kFALSE;
   if (strlen(g3path)) hasg3 = kTRUE;
   char geopath[200];
   sprintf(geopath, "%sn", fGeom->GetPath());
   dist = 1E10;
   TString common = "";
   // cd to common path
   Double_t point[3];
   Double_t closest[3];
   TGeoNode *node1 = 0;
   TGeoNode *node_close = 0;
   dist = 1E10;
   Double_t dist1 = 0;
   // initialize size of random box to epsil
   Double_t eps[3];
   eps[0] = epsil; eps[1]=epsil; eps[2]=epsil;
   Double_t *pointg = fGeom->GetCurrentPoint();
   if (hasg3) {
      TString spath = geopath;
      TString name = "";
      Int_t index=0;
      while (index>=0) {
         index = spath.Index("/", index+1);
         if (index>0) {
            name = spath(0, index);
            if (strstr(g3path, name.Data())) {
               common = name;
               continue;
            } else break;
         }
      }
      // if g3 response was given, cd to common path
      if (strlen(common.Data())) {
         while (strcmp(fGeom->GetPath(), common.Data()) && fGeom->GetLevel()) {
            nodegeo = fGeom->GetCurrentNode();
            fGeom->CdUp();
         }
         fGeom->cd(g3path);
         solg3 = fGeom->GetCurrentNode();
         while (strcmp(fGeom->GetPath(), common.Data()) && fGeom->GetLevel()) {
            nodeg3 = fGeom->GetCurrentNode();
            fGeom->CdUp();
         }
         if (!nodegeo) return 0;
         if (!nodeg3) return 0;
         fGeom->cd(common.Data());
         fGeom->MasterToLocal(fGeom->GetCurrentPoint(), &point[0]);
         Double_t xyz[3], local[3];
         for (Int_t i=0; i<npoints; i++) {
            xyz[0] = point[0] - eps[0] + 2*eps[0]*gRandom->Rndm();
            xyz[1] = point[1] - eps[1] + 2*eps[1]*gRandom->Rndm();
            xyz[2] = point[2] - eps[2] + 2*eps[2]*gRandom->Rndm();
            nodeg3->MasterToLocal(&xyz[0], &local[0]);
            if (!nodeg3->GetVolume()->Contains(&local[0])) continue;
            dist1 = TMath::Sqrt((xyz[0]-point[0])*(xyz[0]-point[0])+
                   (xyz[1]-point[1])*(xyz[1]-point[1])+(xyz[2]-point[2])*(xyz[2]-point[2]));
            if (dist1<dist) {
            // save node and closest point
               dist = dist1;
               node_close = solg3;
               // make the random box smaller
               eps[0] = TMath::Abs(point[0]-pointg[0]);
               eps[1] = TMath::Abs(point[1]-pointg[1]);
               eps[2] = TMath::Abs(point[2]-pointg[2]);
            }
         }
      }
      if (!node_close) dist = -1;
      return node_close;
   }

//   gRandom = new TRandom3();
   // save current point
   memcpy(&point[0], pointg, 3*sizeof(Double_t));
   for (Int_t i=0; i<npoints; i++) {
      // generate a random point in MARS
      pointg[0] = point[0] - eps[0] + 2*eps[0]*gRandom->Rndm();
      pointg[1] = point[1] - eps[1] + 2*eps[1]*gRandom->Rndm();
      pointg[2] = point[2] - eps[2] + 2*eps[2]*gRandom->Rndm();
      // check if new node is different from the old one
      if (node1!=node) {
         dist1 = TMath::Sqrt((point[0]-pointg[0])*(point[0]-pointg[0])+
                 (point[1]-pointg[1])*(point[1]-pointg[1])+(point[2]-pointg[2])*(point[2]-pointg[2]));
         if (dist1<dist) {
            dist = dist1;
            node_close = node1;
            memcpy(&closest[0], pointg, 3*sizeof(Double_t));
            // make the random box smaller
            eps[0] = TMath::Abs(point[0]-pointg[0]);
            eps[1] = TMath::Abs(point[1]-pointg[1]);
            eps[2] = TMath::Abs(point[2]-pointg[2]);
         }
      }
   }
   // restore the original point and path
   memcpy(pointg, &point[0], 3*sizeof(Double_t));
   fGeom->FindNode();  // really needed ?
   if (!node_close) dist=-1;
   return node_close;
}
//-----------------------------------------------------------------------------
 void TGeoChecker::Test(Int_t npoints, Option_t *option)
{
   // Check time of finding "Where am I" for n points.
   gRandom= new TRandom3();
   Bool_t recheck = !strcmp(option, "RECHECK");
   if (recheck) printf("RECHECKn");
   const TGeoShape *shape = fGeom->GetTopVolume()->GetShape();
   Double_t dx = ((TGeoBBox*)shape)->GetDX();
   Double_t dy = ((TGeoBBox*)shape)->GetDY();
   Double_t dz = ((TGeoBBox*)shape)->GetDZ();
   Double_t *xyz = new Double_t[3*npoints];
   TStopwatch *timer = new TStopwatch();
   printf("Random box : %f, %f, %fn", dx, dy, dz);
   timer->Start(kFALSE);
   Int_t i;
   for (i=0; i<npoints; i++) {
      xyz[3*i] = -dx+2*dx*gRandom->Rndm();
      xyz[3*i+1] = -dy+2*dy*gRandom->Rndm();
      xyz[3*i+2] = -dz+2*dz*gRandom->Rndm();
   }
   timer->Stop();
   printf("Generation time :n");
   timer->Print();
   timer->Reset();
   TGeoNode *node, *node1;
   printf("Start... %i pointsn", npoints);
   timer->Start(kFALSE);
   for (i=0; i<npoints; i++) {
      fGeom->SetCurrentPoint(xyz+3*i);
      if (recheck) fGeom->CdTop();
      node = fGeom->FindNode();
      if (recheck) {
         node1 = fGeom->FindNode();
         if (node1 != node) {
            printf("Difference for x=%g y=%g z=%gn", xyz[3*i], xyz[3*i+1], xyz[3*i+2]);
            printf(" from top : %sn", node->GetName());
            printf(" redo     : %sn", fGeom->GetPath());
         }
      }
   }
   timer->Stop();
   timer->Print();
   delete xyz;
   delete timer;
}
//-----------------------------------------------------------------------------
 void TGeoChecker::TestOverlaps(const char* path)
{
//--- Geometry overlap checker based on sampling. 
   if (fGeom->GetTopVolume()!=fGeom->GetMasterVolume()) fGeom->RestoreMasterVolume();
   printf("Checking overlaps for path :n");
   if (!fGeom->cd(path)) return;
   TGeoNode *checked = fGeom->GetCurrentNode();
   checked->InspectNode();
   // shoot 1E4 points in the shape of the current volume
   gRandom= new TRandom3();
   Int_t npoints = 1000000;
   Double_t big = 1E6;
   Double_t xmin = big;
   Double_t xmax = -big;
   Double_t ymin = big;
   Double_t ymax = -big;
   Double_t zmin = big;
   Double_t zmax = -big;
   TObjArray *pm = new TObjArray(128);
   TPolyMarker3D *marker = 0;
   TPolyMarker3D *markthis = new TPolyMarker3D();
   markthis->SetMarkerColor(5);
   TNtuple *ntpl = new TNtuple("ntpl","random points","x:y:z");
   TGeoShape *shape = fGeom->GetCurrentNode()->GetVolume()->GetShape();
   Double_t *point = new Double_t[3];
   Double_t dx = ((TGeoBBox*)shape)->GetDX();
   Double_t dy = ((TGeoBBox*)shape)->GetDY();
   Double_t dz = ((TGeoBBox*)shape)->GetDZ();
   Double_t ox = (((TGeoBBox*)shape)->GetOrigin())[0];
   Double_t oy = (((TGeoBBox*)shape)->GetOrigin())[1];
   Double_t oz = (((TGeoBBox*)shape)->GetOrigin())[2];
   Double_t *xyz = new Double_t[3*npoints];
   Int_t i=0;
   printf("Generating %i points inside %sn", npoints, fGeom->GetPath());
   while (i<npoints) {
      point[0] = ox-dx+2*dx*gRandom->Rndm();
      point[1] = oy-dy+2*dy*gRandom->Rndm();
      point[2] = oz-dz+2*dz*gRandom->Rndm();
      if (!shape->Contains(point)) continue;
      // convert each point to MARS
//      printf("local  %9.3f %9.3f %9.3fn", point[0], point[1], point[2]);
      fGeom->LocalToMaster(point, &xyz[3*i]);
//      printf("master %9.3f %9.3f %9.3fn", xyz[3*i], xyz[3*i+1], xyz[3*i+2]);
      xmin = TMath::Min(xmin, xyz[3*i]);
      xmax = TMath::Max(xmax, xyz[3*i]);
      ymin = TMath::Min(ymin, xyz[3*i+1]);
      ymax = TMath::Max(ymax, xyz[3*i+1]);
      zmin = TMath::Min(zmin, xyz[3*i+2]);
      zmax = TMath::Max(zmax, xyz[3*i+2]);
      i++;
   }
   delete point;
   ntpl->Fill(xmin,ymin,zmin);
   ntpl->Fill(xmax,ymin,zmin);
   ntpl->Fill(xmin,ymax,zmin);
   ntpl->Fill(xmax,ymax,zmin);
   ntpl->Fill(xmin,ymin,zmax);
   ntpl->Fill(xmax,ymin,zmax);
   ntpl->Fill(xmin,ymax,zmax);
   ntpl->Fill(xmax,ymax,zmax);
   ntpl->Draw("z:y:x");

   // shoot the poins in the geometry
   TGeoNode *node;
   TString cpath;
   Int_t ic=0;
   TObjArray *overlaps = new TObjArray();
   printf("using FindNode...n");
   for (Int_t j=0; j<npoints; j++) {
      // always start from top level (testing only)
      fGeom->CdTop();
      fGeom->SetCurrentPoint(&xyz[3*j]);
      node = fGeom->FindNode();
      cpath = fGeom->GetPath();
      if (cpath.Contains(path)) {
         markthis->SetNextPoint(xyz[3*j], xyz[3*j+1], xyz[3*j+2]);
         continue;
      }
      // current point is found in an overlapping node
      if (!node) ic=128;
      else ic = node->GetVolume()->GetLineColor();
      if (ic >= 128) ic = 0;
      marker = (TPolyMarker3D*)pm->At(ic);
      if (!marker) {
         marker = new TPolyMarker3D();
         marker->SetMarkerColor(ic);
         pm->AddAt(marker, ic);
      }
      // draw the overlapping point
      marker->SetNextPoint(xyz[3*j], xyz[3*j+1], xyz[3*j+2]);
      if (node) {
         if (overlaps->IndexOf(node) < 0) overlaps->Add(node);
      }
   }
   // draw all overlapping points
   for (Int_t m=0; m<128; m++) {
      marker = (TPolyMarker3D*)pm->At(m);
//      if (marker) marker->Draw("SAME");
   }
   markthis->Draw("SAME");
   if (gPad) gPad->Update();
   // display overlaps
   if (overlaps->GetEntriesFast()) {
      printf("list of overlapping nodes :n");
      for (i=0; i<overlaps->GetEntriesFast(); i++) {
         node = (TGeoNode*)overlaps->At(i);
         if (node->IsOverlapping()) printf("%s  MANYn", node->GetName());
         else printf("%s  ONLYn", node->GetName());
      }
   } else printf("No overlapsn");
   delete ntpl;
   delete pm;
   delete xyz;
   delete overlaps;
}
//-----------------------------------------------------------------------------
 void TGeoChecker::CreateTree(const char *treename, const char *filename)
{
// These points are stored in a tree and can be directly visualized within ROOT.
//
/*

*/
//
}
//-----------------------------------------------------------------------------
 void TGeoChecker::Generate(UInt_t npoint)
{
// Points are randomly generated inside the 
// bounding  box of a node. For each point the distance to the nearest surface
// and the corresponding point on that surface are computed.
//
/*

*/
//
}
//-----------------------------------------------------------------------------
 void TGeoChecker::Raytrace(Double_t *startpoint, UInt_t npoints)
{
// A second algoritm is shooting multiple rays from a given point to a geometry
// branch and storing the intersection points with surfaces in same tree. 
// Rays can be traced backwords in order to find overlaps by comparing direct 
// and inverse points.   
//
/*

*/
//
}
//-----------------------------------------------------------------------------
 void TGeoChecker::ShowPoints(Option_t *option)
{
// 
//
/*

*/
//
}


ROOT page - Class index - Top of the page

This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.