Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGLCameraOverlay.cxx
Go to the documentation of this file.
1 // @(#)root/gl:$Id$
2 // Author: Alja Mrak-Tadel 2007
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include "TGLIncludes.h"
13 #include "TGLCameraOverlay.h"
14 #include "TGLViewer.h"
15 #include "TGLCamera.h"
16 #include "TGLSelectRecord.h"
17 #include "TGLUtil.h"
18 #include "TGLRnrCtx.h"
19 #include "TGLAxisPainter.h"
20 
21 #include "TMath.h"
22 #include "TAxis.h"
23 #include "THLimitsFinder.h"
24 
25 /** \class TGLCameraOverlay
26 \ingroup opengl
27 A GL overlay element which displays camera furstum.
28 */
29 
30 ClassImp(TGLCameraOverlay);
31 
32 ////////////////////////////////////////////////////////////////////////////////
33 
34 TGLCameraOverlay::TGLCameraOverlay(Bool_t showOrtho, Bool_t showPersp) :
35  TGLOverlayElement(),
36 
37  fShowOrthographic(showOrtho),
38  fShowPerspective(showPersp),
39 
40  fOrthographicMode(kAxis),
41  fPerspectiveMode(kPlaneIntersect),
42 
43  fAxisPainter(0),
44  fAxis(0),
45  fAxisExtend(0.9),
46  fUseAxisColors(kFALSE),
47 
48  fExternalRefPlane(),
49  fUseExternalRefPlane(kFALSE)
50 {
51  // Constructor.
52 
53  fFrustum[0] = fFrustum[1] = fFrustum[2] = fFrustum[3] = 0;
54 
55  fAxis = new TAxis();
56  fAxis->SetNdivisions(710);
57  fAxis->SetLabelSize(0.018);
58  fAxis->SetLabelOffset(0.01);
59  fAxis->SetAxisColor(kGray+1);
60  fAxis->SetLabelColor(kGray+1);
61 
62  fAxisPainter = new TGLAxisPainter();
63  fAxisPainter->SetFontMode(TGLFont::kBitmap);
64  fAxisPainter->SetUseAxisColors(kFALSE);
65 }
66 
67 ////////////////////////////////////////////////////////////////////////////////
68 /// Destructor.
69 
70 TGLCameraOverlay::~TGLCameraOverlay()
71 {
72  delete fAxisPainter;
73  delete fAxis;
74 }
75 
76 ////////////////////////////////////////////////////////////////////////////////
77 /// Get axis attributes.
78 
79 TAttAxis* TGLCameraOverlay::GetAttAxis()
80 {
81  return dynamic_cast<TAttAxis*>(fAxis);
82 }
83 
84 ////////////////////////////////////////////////////////////////////////////////
85 /// Set frustum values from given camera.
86 
87 void TGLCameraOverlay::SetFrustum(TGLCamera& cam)
88 {
89  TGLVector3 absRef(1., 1., 1.); // needed in case if orthographic camera is negative
90  Float_t l = -cam.FrustumPlane(TGLCamera::kLeft).D() * Dot(cam.GetCamBase().GetBaseVec(2), absRef);
91  Float_t r = cam.FrustumPlane(TGLCamera::kRight).D() * Dot(cam.GetCamBase().GetBaseVec(2), absRef);
92  Float_t t = cam.FrustumPlane(TGLCamera::kTop).D();
93  Float_t b = -cam.FrustumPlane(TGLCamera::kBottom).D();
94 
95  fFrustum[0] = l;
96  fFrustum[1] = b;
97  fFrustum[2] = r;
98  fFrustum[3] = t;
99 }
100 
101 ////////////////////////////////////////////////////////////////////////////////
102 /// Draw cross section coordinates in top right corner of screen.
103 
104 void TGLCameraOverlay::RenderPlaneIntersect(TGLRnrCtx& rnrCtx)
105 {
106  TGLCamera &cam = rnrCtx.RefCamera();
107  // get eye line
108  const TGLMatrix& mx = cam.GetCamBase() * cam.GetCamTrans();
109  TGLVertex3 d = mx.GetTranslation();
110  TGLVertex3 p = d + mx.GetBaseVec(1);
111  TGLLine3 line(d, p);
112  // get ref plane
113  const TGLPlane rp = (fUseExternalRefPlane) ? fExternalRefPlane :
114  TGLPlane(cam.GetCamBase().GetBaseVec(3), TGLVertex3());
115  // get intersection
116  std::pair<Bool_t, TGLVertex3> intersection;
117  intersection = Intersection(rp, line, kTRUE);
118 
119  if (intersection.first)
120  {
121  TGLVertex3 v = intersection.second;
122 
123  glMatrixMode(GL_PROJECTION);
124  glPushMatrix();
125  glLoadIdentity();
126 
127  glMatrixMode(GL_MODELVIEW);
128  glPushMatrix();
129  glLoadIdentity();
130 
131  TGLRect &vp = rnrCtx.GetCamera()->RefViewport();
132  TGLFont font;
133  Int_t fs = TMath::Nint(TMath::Sqrt(vp.Width()*vp.Width() + vp.Height()*vp.Height())*0.02);
134  rnrCtx.RegisterFontNoScale(fs, "arial", TGLFont::kPixmap, font);
135  const char* txt = Form("(%f, %f, %f)", v[0], v[1], v[2]);
136  TGLUtil::Color(rnrCtx.ColorSet().Markup());
137  font.Render(txt, 0.98, 0.98, 0, TGLFont::kRight, TGLFont::kBottom);
138 
139  // render cross
140  TGLUtil::Color(kRed);
141  Float_t w = 0.02; // cross size
142  Float_t ce = 0.15; // empty space
143  glBegin(GL_LINES);
144  glVertex2f(0 +w*ce, 0);
145  glVertex2f(0 +w, 0);
146 
147  glVertex2f(0 -w*ce, 0);
148  glVertex2f(0 -w, 0);
149 
150  Float_t h = w*vp.Width()/vp.Height();
151  glVertex2f(0, 0 +h*ce);
152  glVertex2f(0, 0 +h);
153 
154  glVertex2f(0, 0 -h*ce);
155  glVertex2f(0, 0 -h);
156  glEnd();
157 
158  glPopMatrix();
159  glMatrixMode(GL_PROJECTION);
160  glPopMatrix();
161  glMatrixMode(GL_MODELVIEW);
162  }
163 }
164 
165 ////////////////////////////////////////////////////////////////////////////////
166 /// Draw axis on four edges and a transparent grid.
167 
168 void TGLCameraOverlay::RenderAxis(TGLRnrCtx& rnrCtx, Bool_t grid)
169 {
170  fAxisPainter->SetAttAxis(fAxis);
171  fAxisPainter->SetUseAxisColors(fUseAxisColors);
172 
173  Color_t lineColor = fUseAxisColors ? fAxis->GetAxisColor() : rnrCtx.ColorSet().Markup().GetColorIndex();
174 
175  // font size calculated relative to viewport diagonal
176  GLint vp[4]; glGetIntegerv(GL_VIEWPORT, vp);
177  Float_t rl = 0.5 *((vp[2]-vp[0]) + (vp[3]-vp[1]));
178  Int_t fsizePx = (Int_t)(fAxis->GetLabelSize()*rl);
179  // tick length
180  Float_t tlY = 0.015*rl/(vp[2]-vp[0]);
181  Float_t tlX = 0.015*rl/(vp[3]-vp[1]);
182  // corner vectors
183  Float_t minX, maxX;
184  TGLVector3 xdir = rnrCtx.RefCamera().GetCamBase().GetBaseVec(2); xdir.Normalise(); // left
185  if (fFrustum[2] > fFrustum[0] )
186  {
187  minX = fFrustum[0];
188  maxX = fFrustum[2];
189  }
190  else {
191  xdir = -xdir;
192  minX = fFrustum[2];
193  maxX = fFrustum[0];
194  }
195 
196  TGLVector3 ydir = rnrCtx.RefCamera().GetCamBase().GetBaseVec(3); ydir.Normalise(); // up
197  TGLVector3 vy1 = ydir * fFrustum[1];
198  TGLVector3 vy2 = ydir * fFrustum[3];
199 
200  TGLVector3 vx1 = xdir * minX;
201  TGLVector3 vx2 = xdir * maxX;
202  // range
203  Double_t rngY = fFrustum[3] - fFrustum[1];
204  Double_t rngX = maxX - minX;
205  Double_t off = TMath::Sqrt((rngX*rngX)+(rngY*rngY)) * 0.03;
206  Double_t minY = fFrustum[1] + off;
207  Double_t maxY = fFrustum[3] - off;
208  minX += off;
209  maxX -= off;
210 
211  // grid lines
212  Char_t alpha = 80; //primary
213  Char_t alpha2 = 90; //secondary
214  Int_t secSteps = fAxis->GetNdivisions() % 100;
215  GLushort stipple = 0x5555; // 33333 more rare
216 
217  // horizontal X
218  //
219  fAxisPainter->SetLabelPixelFontSize(fsizePx);
220  fAxis->SetTickLength(tlX);
221  fAxisPainter->RefDir() = xdir;
222  fAxis->SetLimits(minX, maxX);
223  fAxisPainter->RefTMOff(0) = ydir*rngY;
224 
225  // bottom
226  glPushMatrix();
227  glTranslated(vy1.X(), vy1.Y(), vy1.Z());
228  fAxisPainter->SetLabelAlign(TGLFont::kCenterH, TGLFont::kTop);
229  fAxisPainter->PaintAxis(rnrCtx, fAxis);
230  glPopMatrix();
231 
232  // top
233  glPushMatrix();
234  glTranslated(vy2.X(), vy2.Y(), vy2.Z());
235  fAxisPainter->SetLabelAlign(TGLFont::kCenterH, TGLFont::kBottom);
236  fAxisPainter->RefTMOff(0).Negate();
237  fAxisPainter->RnrLabels();
238  fAxisPainter->RnrLines();
239  glPopMatrix();
240 
241  TGLUtil::LineWidth(1);
242  if (grid)
243  {
244  TGLAxisPainter::LabVec_t& labs = fAxisPainter->RefLabVec();
245  TGLVector3 tmp;
246  // draw label vertical lines
247  TGLUtil::ColorTransparency(lineColor, alpha);
248  glBegin(GL_LINES);
249  for (TGLAxisPainter::LabVec_t::iterator i = labs.begin(); i != labs.end(); ++i) {
250  tmp = vy1 + xdir * (i->first);
251  glVertex3dv(tmp.Arr());
252  tmp = vy2 + xdir * (i->first);
253  glVertex3dv(tmp.Arr());
254  }
255  glEnd();
256 
257  // secondary tick mark lines
258  if (labs.size() > 1)
259  {
260  TGLUtil::ColorTransparency(lineColor, alpha2);
261  glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT);
262  glEnable(GL_LINE_STIPPLE);
263  glLineStipple(1, stipple);
264 
265  glBegin(GL_LINES);
266  Int_t ondiv = 0;
267  Double_t omin = 0, omax = 0, bw1 = 0;
268  THLimitsFinder::Optimize(labs[0].second, labs[1].second, secSteps, omin, omax, ondiv, bw1);
269  Double_t val = labs[0].second;
270  while (val < fFrustum[2])
271  {
272  for (Int_t k=0; k<ondiv; k++)
273  {
274  val += bw1;
275  tmp = vy1 + xdir * val;
276  glVertex3dv(tmp.Arr());
277  tmp = vy2 + xdir * val;
278  glVertex3dv(tmp.Arr());
279  }
280  }
281  val = labs[0].second - bw1;
282  while(val > fFrustum[0])
283  {
284  tmp = vy1 + xdir * val;
285  glVertex3dv(tmp.Arr());
286  tmp = vy2 + xdir * val;
287  glVertex3dv(tmp.Arr());
288  val -= bw1;
289  }
290  glEnd();
291  glPopAttrib();
292  }
293  } // draw grid
294 
295  //
296  // vertical Y axis
297  //
298 
299  fAxis->SetTickLength(tlY);
300  fAxisPainter->RefDir() = ydir;
301  fAxis->SetLimits(minY, maxY);
302  fAxisPainter->RefTMOff(0) = xdir*rngX;
303  // left
304  glPushMatrix();
305  glTranslated(vx1.X(), vx1.Y(), vx1.Z());
306  fAxisPainter->SetLabelAlign(TGLFont::kLeft, TGLFont::kCenterV);
307  fAxisPainter->PaintAxis(rnrCtx, fAxis);
308  glPopMatrix();
309  // right
310  glPushMatrix();
311  glTranslated(vx2.X(), vx2.Y(), vx2.Z());
312  fAxisPainter->SetLabelAlign(TGLFont::kRight, TGLFont::kCenterV);
313  fAxisPainter->RefTMOff(0).Negate();
314  fAxisPainter->RnrLabels();
315  fAxisPainter->RnrLines();
316  glPopMatrix();
317 
318  if (grid)
319  {
320  TGLAxisPainter::LabVec_t& labs = fAxisPainter->RefLabVec();
321  TGLVector3 tmp;
322  // draw label horizontal lines
323  TGLUtil::ColorTransparency(lineColor, alpha);
324  glBegin(GL_LINES);
325  for (TGLAxisPainter::LabVec_t::iterator i = labs.begin(); i != labs.end(); ++i) {
326  tmp = vx1 + ydir *(i->first);
327  glVertex3dv(tmp.Arr());
328  tmp = vx2 + ydir *(i->first);
329  glVertex3dv(tmp.Arr());
330  }
331  glEnd();
332 
333  // secondary tick mark lines
334  if (labs.size() > 1)
335  {
336  TGLUtil::ColorTransparency(lineColor, alpha2);
337  glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT);
338  glEnable(GL_LINE_STIPPLE);
339  glLineStipple(1, stipple);
340 
341  glBegin(GL_LINES);
342  Int_t ondiv;
343  Double_t omin = 0, omax = 0, bw1 = 0;
344  Double_t val = 0;
345  THLimitsFinder::Optimize(labs[0].second, labs[1].second, secSteps, omin, omax, ondiv, bw1);
346  val = labs[0].second;
347  while(val < fFrustum[3])
348  {
349  for(Int_t k=0; k<ondiv; k++)
350  {
351  val += bw1;
352  tmp = vx1 + ydir *val;
353  glVertex3dv(tmp.Arr());
354  tmp = vx2 + ydir * val;
355  glVertex3dv(tmp.Arr());
356  }
357  }
358 
359  val = labs[0].second - bw1;
360  while(val > fFrustum[1])
361  {
362  tmp = vx1 + ydir *val;
363  glVertex3dv(tmp.Arr());
364  tmp = vx2 + ydir * val;
365  glVertex3dv(tmp.Arr());
366  val -= bw1;
367  }
368  glEnd();
369  glPopAttrib();
370  }
371  } // draw grid
372 }
373 
374 ////////////////////////////////////////////////////////////////////////////////
375 /// Show frustum size with fixed screen line length and printed value.
376 
377 void TGLCameraOverlay::RenderBar(TGLRnrCtx& rnrCtx)
378 {
379  // factors 10, 5 and 2 are allowed
380  Double_t wfrust = TMath::Abs(fFrustum[2]-fFrustum[0]);
381  Float_t barsize= 0.14* wfrust;
382  Int_t exp = (Int_t) TMath::Floor(TMath::Log10(barsize));
383  Double_t fact = barsize/TMath::Power(10, exp);
384  Double_t red;
385  if (fact > 5)
386  {
387  red = 5*TMath::Power(10, exp);
388  }
389  else if (fact > 2)
390  {
391  red = 2*TMath::Power(10, exp);
392  } else
393  {
394  red = TMath::Power(10, exp);
395  }
396 
397  TGLVector3 v;
398  TGLVector3 xdir = rnrCtx.RefCamera().GetCamBase().GetBaseVec(2); // left
399  TGLVector3 ydir = rnrCtx.RefCamera().GetCamBase().GetBaseVec(3); // up
400  xdir.Normalise();
401  ydir.Normalise();
402 
403  TGLUtil::Color(rnrCtx.ColorSet().Foreground());
404 
405  const char* txt = Form("%.*f", (exp < 0) ? -exp : 0, red);
406  Float_t bb[6];
407  TGLFont font;
408  rnrCtx.RegisterFont(12, "arial", TGLFont::kPixmap, font);
409  font.BBox(txt, bb[0], bb[1], bb[2], bb[3], bb[4], bb[5]);
410  TGLRect &vp = rnrCtx.GetCamera()->RefViewport();
411  Double_t mH = (fFrustum[3]-fFrustum[1])*bb[4]/vp.Height();
412  glPushMatrix();
413  v = xdir*(fFrustum[2]-barsize) + ydir*(fFrustum[3] - mH*1.5);
414  glTranslated(v.X(), v.Y(), v.Z());
415  glRasterPos2i(0,0);
416  font.Render(txt);
417  glPopMatrix();
418 
419  glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT);
420  TGLUtil::LineWidth(2.);
421  glPushMatrix();
422  Float_t xt = fFrustum[2] - 1.1*barsize;
423  Float_t yt = fFrustum[3] - 2.1*mH;
424  v = xdir*xt + ydir*yt;
425  glTranslated(v.X(), v.Y(), v.Z());
426 
427  glBegin(GL_LINES);
428  // horizontal static
429  v = red*xdir;
430  glVertex3dv(v.Arr());
431  v = barsize*xdir;
432  glVertex3dv(v.Arr());
433  // corner bars end
434  v = xdir*barsize + ydir*mH;
435  glVertex3dv(v.Arr());
436  v = xdir*barsize - ydir*mH;
437  glVertex3dv(v.Arr());
438  // corner bar start
439  TGLUtil::Color(kRed);
440  v = ydir*mH;
441  glVertex3dv(v.Arr());
442  v.Negate();
443  glVertex3dv(v.Arr());
444  // marker pointer
445  v = red*ydir;
446  glVertex3dv(v.Arr());
447  v += ydir*mH;
448  glVertex3dv(v.Arr());
449  //marker line
450  glVertex3d(0, 0., 0.);
451  v = red*xdir;
452  glVertex3dv(v.Arr());
453  glEnd();
454  glPopAttrib();
455  glPopMatrix();
456 }
457 
458 ////////////////////////////////////////////////////////////////////////////////
459 /// Display coordinates info of current frustum.
460 
461 void TGLCameraOverlay::Render(TGLRnrCtx& rnrCtx)
462 {
463  TGLCamera &cam = rnrCtx.RefCamera();
464 
465  if (rnrCtx.Selection() ||
466  (cam.IsPerspective() && ! fShowPerspective) ||
467  (cam.IsOrthographic() && ! fShowOrthographic))
468  {
469  return;
470  }
471 
472  glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT);
473  glEnable(GL_BLEND);
474  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
475 
476  TGLUtil::Color(rnrCtx.ColorSet().Markup());
477  TGLCapabilitySwitch lights_off(GL_LIGHTING, kFALSE);
478  Float_t old_depth_range[2];
479  glGetFloatv(GL_DEPTH_RANGE, old_depth_range);
480 
481  SetFrustum(cam);
482 
483  if (cam.IsOrthographic())
484  {
485  switch (fOrthographicMode)
486  {
487  case kBar:
488  glDepthRange(0, 0.1);
489  RenderBar(rnrCtx);
490  break;
491  case kAxis:
492  glDepthRange(0, 0.1);
493  RenderAxis(rnrCtx, kFALSE);
494  break;
495  case kGridFront:
496  glDepthRange(0, 0.1);
497  RenderAxis(rnrCtx, kTRUE);
498  break;
499  case kGridBack:
500  glDepthRange(1, 0.9);
501  RenderAxis(rnrCtx, kTRUE);
502  break;
503  default:
504  break;
505  };
506  }
507  else
508  {
509  RenderPlaneIntersect(rnrCtx);
510  }
511 
512  glDepthRange(old_depth_range[0], old_depth_range[1]);
513  glPopAttrib();
514 }