All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Ortho3DPad.cxx
Go to the documentation of this file.
1 ///
2 /// \file Ortho3DPad.cxx
3 /// \brief Drawing pad showing an orthographic rendering of 3D objects
4 /// in the detector
5 /// \author greenlee@fnal.gov
6 ///
7 
8 #include "TBox.h"
9 #include "TGNumberEntry.h"
10 #include "TH1F.h"
11 #include "TLatex.h"
12 #include "TPad.h"
13 #include "TPolyMarker.h"
14 #include "TVirtualX.h"
15 #include "TVirtualPadPainter.h"
16 
17 #include "art/Framework/Services/Registry/ServiceHandle.h"
18 #include "cetlib_except/exception.h"
19 
27 #include "nuevdb/EventDisplayBase/EventHolder.h"
28 #include "nuevdb/EventDisplayBase/View2D.h"
29 
30 /// Define static data members.
31 
33 
34 ///
35 /// Create a pad to show an orthographic rendering of 3D objcts.
36 /// @param name : Name of the pad
37 /// @param title : Title of the pad
38 /// @param proj : Choose orthographic projection
39 /// @param x1 : Location of left edge of pad (0-1)
40 /// @param x2 : Location of right edge of pad (0-1)
41 /// @param y1 : Location of bottom edge of pad (0-1)
42 /// @param y2 : Location of top edge of pad (0-1)
43 ///
45  const char* title,
46  evd::OrthoProj_t proj,
47  double x1,
48  double y1,
49  double x2,
50  double y2)
51  : DrawingPad(name, title, x1, y1, x2, y2)
52  , fHisto(0)
53  , fProj(proj)
54  , fXLo(0.)
55  , fXHi(0.)
56  , fYLo(0.)
57  , fYHi(0.)
58  , fMSize(0.25)
59  , fMSizeEntry(0)
60  , fPress(false)
61  , fBoxDrawn(false)
62  , fPressPx(0)
63  , fPressPy(0)
64  , fCurrentPx(0)
65  , fCurrentPy(0)
66  , fPressX(0.)
67  , fPressY(0.)
68  , fReleaseX(0.)
69  , fReleaseY(0.)
70 {
71  // Get services.
72 
73  art::ServiceHandle<geo::Geometry const> geo;
74 
75  // Set up pad.
76 
77  // Pad()->SetBit(kCannotPick); // workaround for issue #16169
78  Pad()->SetBit(TPad::kCannotMove);
79  Pad()->Draw();
80  Pad()->cd();
81  Pad()->SetLeftMargin(0.080);
82  Pad()->SetRightMargin(0.010);
83  Pad()->SetTopMargin(0.010);
84  Pad()->SetBottomMargin(0.10);
85 
86  // Define histogram boundaries (cm).
87  // For now only draw cryostat=0.
88  double minx = 1e9;
89  double maxx = -1e9;
90  double miny = 1e9;
91  double maxy = -1e9;
92  double minz = 1e9;
93  double maxz = -1e9;
94  for (size_t i = 0; i < geo->NTPC(); ++i) {
95  double local[3] = {0., 0., 0.};
96  double world[3] = {0., 0., 0.};
97  const geo::TPCGeo& tpc = geo->TPC(i);
98  tpc.LocalToWorld(local, world);
99  if (minx > world[0] - geo->DetHalfWidth(i)) minx = world[0] - geo->DetHalfWidth(i);
100  if (maxx < world[0] + geo->DetHalfWidth(i)) maxx = world[0] + geo->DetHalfWidth(i);
101  if (miny > world[1] - geo->DetHalfHeight(i)) miny = world[1] - geo->DetHalfHeight(i);
102  if (maxy < world[1] + geo->DetHalfHeight(i)) maxy = world[1] + geo->DetHalfHeight(i);
103  if (minz > world[2] - geo->DetLength(i) / 2.) minz = world[2] - geo->DetLength(i) / 2.;
104  if (maxz < world[2] + geo->DetLength(i) / 2.) maxz = world[2] + geo->DetLength(i) / 2.;
105 
106  switch (proj) {
107  case evd::kXY:
108  TPCBox.push_back(TBox(world[0] - geo->DetHalfWidth(i),
109  world[1] - geo->DetHalfHeight(i),
110  world[0] + geo->DetHalfWidth(i),
111  world[1] + geo->DetHalfHeight(i)));
112  break;
113  case evd::kXZ:
114  TPCBox.push_back(TBox(world[2] - geo->DetLength(i) / 2.,
115  world[0] - geo->DetHalfWidth(i),
116  world[2] + geo->DetLength(i) / 2.,
117  world[0] + geo->DetHalfWidth(i)));
118  break;
119  case evd::kYZ:
120  TPCBox.push_back(TBox(world[2] - geo->DetLength(i) / 2.,
121  world[1] - geo->DetHalfHeight(i),
122  world[2] + geo->DetLength(i) / 2.,
123  world[1] + geo->DetHalfHeight(i)));
124  break;
125  default:
126  throw cet::exception("Ortho3DPad")
127  << __func__ << ": unwknow projection " << ((int)proj) << "\n";
128  } // switch
129  TPCBox.back().SetFillStyle(0);
130  TPCBox.back().SetLineStyle(2);
131  TPCBox.back().SetLineWidth(2);
132  TPCBox.back().SetLineColor(16);
133  }
134 
135  switch (proj) {
136  case evd::kXY:
137  fXLo = minx;
138  fXHi = maxx;
139  fYLo = miny;
140  fYHi = maxy;
141  break;
142  case evd::kXZ:
143  fXLo = minz;
144  fXHi = maxz;
145  fYLo = minx;
146  fYHi = maxx;
147  break;
148  case evd::kYZ:
149  fXLo = minz;
150  fXHi = maxz;
151  fYLo = miny;
152  fYHi = maxy;
153  break;
154  default:
155  throw cet::exception("Ortho3DPad")
156  << __func__ << ": unwknow projection " << ((int)proj) << "\n";
157  } // switch
158 
159  // Make enclosing histogram.
160 
161  fHisto = new TH1F(*(Pad()->DrawFrame(fXLo, fYLo, fXHi, fYHi)));
162  fHisto->SetBit(kCannotPick);
163  fHisto->SetBit(TPad::kCannotMove);
164  fHisto->SetTitleOffset(1., "Y");
165  fHisto->SetTitleOffset(1., "X");
166  fHisto->GetXaxis()->SetLabelSize(0.04);
167  fHisto->GetXaxis()->SetTitleSize(0.04);
168  switch (proj) {
169  case evd::kXY:
170  fHisto->GetXaxis()->SetTitle("x (cm)");
171  fHisto->GetYaxis()->SetTitle("y (cm)");
172  break;
173  case evd::kXZ:
174  fHisto->GetXaxis()->SetTitle("z (cm)");
175  fHisto->GetYaxis()->SetTitle("x (cm)");
176  break;
177  case evd::kYZ:
178  fHisto->GetXaxis()->SetTitle("z (cm)");
179  fHisto->GetYaxis()->SetTitle("y (cm)");
180  break;
181  default:
182  throw cet::exception("Ortho3DPad")
183  << __func__ << ": unexpected flow (projection: " << ((int)proj) << ")\n";
184  } // switch
185 
186  fHisto->GetXaxis()->CenterTitle();
187  fHisto->GetYaxis()->SetLabelSize(0.04);
188  fHisto->GetYaxis()->SetTitleSize(0.04);
189  fHisto->GetYaxis()->CenterTitle();
190  fHisto->SetFillColor(18);
191  fHisto->Draw("AB");
192 
193  fView = new evdb::View2D();
194 
195  // Set pad fill color
196  Pad()->SetFillColor(18);
197  Pad()->SetFrameFillColor(18);
198  Pad()->GetPainter()->SetFillColor(18);
199  Pad()->Modified();
200  Pad()->Update();
201 
202  // Install mouse event handler.
203 
204  std::ostringstream ostr;
205  ostr << "evd::Ortho3DPad::MouseEvent((evd::Ortho3DPad*)" << this << ")";
206  fPad->AddExec("getmousezoom", ostr.str().c_str());
207 }
208 
209 //......................................................................
210 // Destructor.
211 
213 {
214  if (fHisto) {
215  delete fHisto;
216  fHisto = nullptr;
217  }
218  if (fView) {
219  delete fView;
220  fView = nullptr;
221  }
222 }
223 
224 //......................................................................
225 // Draw selected objects.
226 
227 void
228 evd::Ortho3DPad::Draw(const char* /*opt*/)
229 {
230  fPad->Clear();
231  fView->Clear();
232 
233  // Remove zoom.
234 
235  UnZoom(false);
236 
237  // grab the event from the singleton
238 
239  // Insert graphic objects into fView collection.
240 
241  if (art::Event const* evtPtr = evdb::EventHolder::Instance()->GetEvent()) {
242  auto const& evt = *evtPtr;
243  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
244  auto const detProp =
245  art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataFor(evt, clockData);
246 
247  SimulationDraw()->MCTruthOrtho(evt, fProj, fMSize, fView);
248  RecoBaseDraw()->SpacePointOrtho(evt, fProj, fMSize, fView);
249  RecoBaseDraw()->PFParticleOrtho(evt, fProj, fMSize, fView);
250  RecoBaseDraw()->ProngOrtho(evt, fProj, fMSize, fView);
251  RecoBaseDraw()->SeedOrtho(evt, fProj, fView);
252  RecoBaseDraw()->OpFlashOrtho(evt, clockData, detProp, fProj, fView);
253  RecoBaseDraw()->VertexOrtho(evt, fProj, fView);
254  }
255  // Draw objects on pad.
256 
257  fPad->cd();
258  fPad->GetPainter()->SetFillColor(18);
259  fHisto->Draw("X-");
260  fView->Draw();
261  TLatex latex;
262  latex.SetTextColor(16);
263  latex.SetTextSize(0.05);
264  for (size_t i = 0; i < TPCBox.size(); ++i) {
265  TPCBox[i].Draw();
266  double x1 = TPCBox[i].GetX2() - 0.02 * (fXHi - fXLo);
267  double y1 = TPCBox[i].GetY2() - 0.05 * (fYHi - fYLo);
268  for (size_t j = 0; j < i; ++j) {
269  if (std::abs(x1 - (TPCBox[j].GetX2() - 0.02 * (fXHi - fXLo))) < 1e-6 &&
270  std::abs(y1 - (TPCBox[j].GetY2() - 0.05 * (fYHi - fYLo))) < 1e-6) {
271  y1 -= 0.05 * (fYHi - fYLo);
272  }
273  }
274  latex.DrawLatex(x1, y1, Form("%lu", i));
275  }
276  fPad->Modified();
277  fPad->Update();
278  fBoxDrawn = false;
279 }
280 
281 //......................................................................
282 // Set zoom region. Limits are specified in user coordinates.
283 
284 void
285 evd::Ortho3DPad::SetZoom(double xlo, double ylo, double xhi, double yhi, bool update)
286 {
287  fHisto->GetXaxis()->SetRangeUser(xlo, xhi);
288  fHisto->GetYaxis()->SetRangeUser(ylo, yhi);
289  fPad->Modified();
290  if (update) {
291  fPad->Update();
292  fBoxDrawn = false;
293  }
294 }
295 
296 //......................................................................
297 // Set zoom region to full range.
298 
299 void
301 {
302  fHisto->GetXaxis()->SetRangeUser(fXLo, fXHi);
303  fHisto->GetYaxis()->SetRangeUser(fYLo, fYHi);
304  fPad->Modified();
305 
306  // Also set marker size to default one pixel.
307 
308  SetMarkerSize(1., false);
309 
310  if (update) {
311  fPad->Update();
312  fBoxDrawn = false;
313  }
314 }
315 
316 //......................................................................
317 // Set the marker size (measured in pixels).
318 
319 void
321 {
322  // Update marker size.
323 
324  if (fMSize != size / 4.) {
325 
326  // Update marker size attribute.
327 
328  fMSize = size / 4.; // Scale to pixels.
329 
330  // Update widget.
331 
332  if (fMSizeEntry) fMSizeEntry->SetNumber(size);
333 
334  // Loop over graphic objects that are currently drawn on
335  // pad, and update any that are polymarkers.
336 
337  TIter next(fPad->GetListOfPrimitives());
338  while (TObject* obj = next()) {
339  if (obj->InheritsFrom(TPolyMarker::Class())) {
340  TPolyMarker* pm = (TPolyMarker*)obj;
341  pm->SetMarkerSize(fMSize);
342  }
343  }
344 
345  fPad->Modified();
346  if (update) {
347  fPad->Update();
348  fBoxDrawn = false;
349  }
350  }
351 }
352 
353 //......................................................................
354 // Save a reference to the marker size number entry widget.
355 // This class gets the marker size from the widget if it is changed
356 // via the gui. It also sets the number in the widget if it is changed
357 // not from the gui.
358 
359 void
361 {
362  fMSizeEntry = p;
363  if (fMSizeEntry) fMSizeEntry->SetNumber(4. * fMSize);
364 }
365 
366 //......................................................................
367 // Slot method for marker size number entry widget.
368 // This method is called when the user changes the marker size via the gui.
369 
370 void
372 {
373 
374  // Get marker size from number entry widget.
375 
376  if (!fMSizeEntry) throw cet::exception("Ortho3DPad") << __func__ << ": no MSize entry\n";
377  double val = fMSizeEntry->GetNumber();
378 
379  // Scale the marker size such that the displayed marker size
380  // is measured in pixels.
381 
382  SetMarkerSize(val, true);
383 }
384 
385 //......................................................................
386 // Static mouse event handler.
387 // This method is called by the gui for mouse events in the graphics pad.
388 
389 void
391 {
392  TObject* select = gPad->GetSelected();
393  if (!select) return;
394  if (!select->InheritsFrom("TBox")) return;
395  ((TBox*)select)->SetBit(TBox::kCannotMove);
396 
397  // This line is a workaround for a root bug that sends mouse events
398  // to the wrong pad.
399 
400  if (fMousePad != 0) p = fMousePad;
401 
402  p->MouseEvent();
403 }
404 
405 //......................................................................
406 // Mouse event handler (called from static handler).
407 
408 void
410 {
411  // Get event type and location.
412 
413  int event = gPad->GetEvent();
414  int px = gPad->GetEventX(); // pixels.
415  int py = gPad->GetEventY(); // pixels.
416  double x = gPad->AbsPixeltoX(px); // User coordinates.
417  double y = gPad->AbsPixeltoY(py); // User coordinates.
418 
419  // Handle different events.
420 
421  switch (event) {
422  case kMouseEnter:
423 
424  // Main purpose of this case is to set the cursor shape.
425 
426  gPad->SetCursor(kCross);
427  fCurrentPx = px;
428  fCurrentPy = py;
429  fMousePad = this;
430  break;
431 
432  case kMouseMotion:
433 
434  // Not really needed...
435 
436  gPad->SetCursor(kCross);
437  fCurrentPx = px;
438  fCurrentPy = py;
439  break;
440 
441  case kMouseLeave:
442 
443  // Undraw box.
444 
445  //if(fBoxDrawn) {
446  // double pxlo = std::min(fPressPx, fCurrentPx);
447  // double pxhi = std::max(fPressPx, fCurrentPx);
448  // double pylo = std::min(fPressPy, fCurrentPy);
449  // double pyhi = std::max(fPressPy, fCurrentPy);
450  // gVirtualX->DrawBox(pxlo, pylo, pxhi, pyhi, TVirtualX::kHollow);
451  // fBoxDrawn = false;
452  //}
453 
454  // Set everything to default.
455 
456  fPress = false;
457  fPressPx = 0;
458  fPressPy = 0;
459  fCurrentPx = 0;
460  fCurrentPy = 0;
461  fPressX = 0.;
462  fPressY = 0.;
463  fReleaseX = 0.;
464  fReleaseY = 0.;
465  fMousePad = 0;
466  break;
467 
468  case kButton1Motion:
469 
470  // Undraw old selection box.
471 
472  //if(fBoxDrawn) {
473  // double pxlo = std::min(fPressPx, fCurrentPx);
474  // double pxhi = std::max(fPressPx, fCurrentPx);
475  // double pylo = std::min(fPressPy, fCurrentPy);
476  // double pyhi = std::max(fPressPy, fCurrentPy);
477  // gVirtualX->DrawBox(pxlo, pylo, pxhi, pyhi, TVirtualX::kHollow);
478  // fBoxDrawn = false;
479  //}
480 
481  // Update cursor location.
482 
483  gPad->SetCursor(kCross);
484  fCurrentPx = px;
485  fCurrentPy = py;
486 
487  // Draw new selection box.
488 
489  {
490  double pxlo = std::min(fPressPx, fCurrentPx);
491  double pxhi = std::max(fPressPx, fCurrentPx);
492  double pylo = std::min(fPressPy, fCurrentPy);
493  double pyhi = std::max(fPressPy, fCurrentPy);
494  gVirtualX->DrawBox(pxlo, pylo, pxhi, pyhi, TVirtualX::kHollow);
495  fBoxDrawn = true;
496  }
497  break;
498 
499  case kButton1Down:
500  gVirtualX->SetLineColor(-1);
501  gVirtualX->SetLineStyle(0);
502  gVirtualX->SetLineWidth(1);
503 
504  // Record the location of the button press event, which will be
505  // one corner of zoom region.
506 
507  gPad->SetCursor(kCross);
508  fPress = true;
509  fPressPx = px;
510  fPressPy = py;
511  fCurrentPx = px;
512  fCurrentPy = py;
513  fPressX = x;
514  fPressY = y;
515  fReleaseX = 0.;
516  fReleaseY = 0.;
517  fMousePad = this;
518  break;
519 
520  case kButton1Up:
521 
522  // Get the location of button release event, then zoom.
523 
524  gPad->SetCursor(kCross);
525  fPress = false;
526  fCurrentPx = px;
527  fCurrentPy = py;
528  fReleaseX = x;
529  fReleaseY = y;
530  {
531  double xlo = std::min(fPressX, fReleaseX);
532  double xhi = std::max(fPressX, fReleaseX);
533  double ylo = std::min(fPressY, fReleaseY);
534  double yhi = std::max(fPressY, fReleaseY);
535  SetZoom(xlo, ylo, xhi, yhi, true);
536  }
537  fMousePad = 0;
538  break;
539  }
540 }
541 
542 ////////////////////////////////////////////////////////////////////////
void SetZoom(double xlo, double ylo, double xhi, double yhi, bool update)
Definition: Ortho3DPad.cxx:285
double fXHi
High x value.
Definition: Ortho3DPad.h:75
void UnZoom(bool update)
Definition: Ortho3DPad.cxx:300
process_name opflash particleana ie x
void SetMarkerSize(double size, bool update)
Definition: Ortho3DPad.cxx:320
void SetMSizeEntry(TGNumberEntry *p)
Definition: Ortho3DPad.cxx:360
double fYHi
High y value.
Definition: Ortho3DPad.h:77
pdgs p
Definition: selectors.fcl:22
Geometry information for a single TPC.
Definition: TPCGeo.h:38
A drawing pad showing an orthographic rendering of 3D objects.
Definition: Ortho3DPad.h:26
std::size_t size(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:561
OrthoProj_t
Definition: OrthoProj.h:12
double fXLo
Low x value.
Definition: Ortho3DPad.h:74
then local
T abs(T value)
process_name opflash particleana ie ie y
double fYLo
Low y value.
Definition: Ortho3DPad.h:76
Base class for event display drawing pads.
Definition: DrawingPad.h:29
TPad * Pad()
Definition: DrawingPad.h:37
Drawing pad showing an orthographic projection of 3D objects in the detector.
Ortho3DPad(const char *nm, const char *ti, evd::OrthoProj_t proj, double x1, double y1, double x2, double y2)
Definition: Ortho3DPad.cxx:44
Class to aid in the rendering of RecoBase objects.
BEGIN_PROLOG px
Definition: filemuons.fcl:10
std::vector< TBox > TPCBox
TPC box.
Definition: Ortho3DPad.h:79
process_name physics producers generator physics producers generator physics producers generator py
Render the objects from the Simulation package.
do i e
TH1F * fHisto
Enclosing histogram.
Definition: Ortho3DPad.h:72
then echo fcl name
TPad * fPad
The ROOT graphics pad.
Definition: DrawingPad.h:52
TCEvent evt
Definition: DataStructs.cxx:8
static void MouseEvent(evd::Ortho3DPad *p)
Definition: Ortho3DPad.cxx:390
static Ortho3DPad * fMousePad
Selected pad for mouse action.
Definition: Ortho3DPad.h:68
void LocalToWorld(const double *tpc, double *world) const
Transform point from local TPC frame to world frame.
Definition: TPCGeo.h:563
evdb::View2D * fView
Collection of graphics objects to render.
Definition: Ortho3DPad.h:80
art framework interface to geometry description
auto const detProp
void Draw(const char *opt=0)
Definition: Ortho3DPad.cxx:228
Encapsulate the construction of a single detector plane.