Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGLClip.cxx
Go to the documentation of this file.
1 // @(#)root/gl:$Id$
2 // Author: Richard Maunder 16/09/2005
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2005, 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 "TGLClip.h"
13 #include "TGLIncludes.h"
14 #include "TGLRnrCtx.h"
15 #include "TGLManipSet.h"
16 
17 #include "TGLFaceSet.h"
18 #include "TBuffer3D.h"
19 #include "TBuffer3DTypes.h"
20 
21 namespace
22 {
23 
24 class TGLClipPlaneLogical : public TGLLogicalShape
25 {
26 protected:
27  virtual void DirectDraw(TGLRnrCtx & rnrCtx) const
28  {
29  glBegin(rnrCtx.IsDrawPassFilled() ? GL_QUADS : GL_LINE_LOOP);
30  glNormal3d (0.0, 0.0, 1.0);
31  glVertex3dv(fBoundingBox[4].CArr());
32  glVertex3dv(fBoundingBox[7].CArr());
33  glVertex3dv(fBoundingBox[6].CArr());
34  glVertex3dv(fBoundingBox[5].CArr());
35  glEnd();
36  }
37 
38 public:
39  TGLClipPlaneLogical() : TGLLogicalShape() { fDLCache = kFALSE; }
40  virtual ~TGLClipPlaneLogical() {}
41 
42  void Resize(Double_t ext)
43  {
44  fBoundingBox.SetAligned(TGLVertex3(-ext, -ext, 0),
45  TGLVertex3( ext, ext, 0));
46  UpdateBoundingBoxesOfPhysicals();
47  }
48 
49 };
50 
51 
52 class TGLClipBoxLogical : public TGLLogicalShape
53 {
54 protected:
55  virtual void DirectDraw(TGLRnrCtx & rnrCtx) const
56  {
57  glEnable(GL_NORMALIZE);
58  fBoundingBox.Draw(rnrCtx.IsDrawPassFilled());
59  glDisable(GL_NORMALIZE);
60  }
61 
62 public:
63  TGLClipBoxLogical() : TGLLogicalShape() { fDLCache = kFALSE; }
64  virtual ~TGLClipBoxLogical() {}
65 
66  void Resize(const TGLVertex3 & lowVertex, const TGLVertex3 & highVertex)
67  {
68  fBoundingBox.SetAligned(lowVertex, highVertex);
69  UpdateBoundingBoxesOfPhysicals();
70  }
71 };
72 
73 }
74 
75 
76 /** \class TGLClip
77 \ingroup opengl
78 Abstract clipping shape - derives from TGLPhysicalShape
79 Adds clip mode (inside/outside) and pure virtual method to
80 approximate shape as set of planes. This plane set is used to perform
81 interactive clipping using OpenGL clip planes.
82 */
83 
84 ClassImp(TGLClip);
85 
86 ////////////////////////////////////////////////////////////////////////////////
87 /// Construct a stand-alone physical clipping object.
88 
89 TGLClip::TGLClip(const TGLLogicalShape & logical, const TGLMatrix & transform, const float color[4]) :
90  TGLPhysicalShape(0, logical, transform, kTRUE, color),
91  fMode (kInside),
92  fTimeStamp (1),
93  fValid (kFALSE)
94 {
95  logical.StrongRef(kTRUE);
96 }
97 
98 ////////////////////////////////////////////////////////////////////////////////
99 /// Destroy clip object.
100 
101 TGLClip::~TGLClip()
102 {
103 }
104 
105 ////////////////////////////////////////////////////////////////////////////////
106 /// Setup the clipping object with two vectors.
107 /// The interpretation of the two is different for plane and box
108 /// clipping objects.
109 
110 void TGLClip::Setup(const TGLVector3&, const TGLVector3&)
111 {
112  Warning("TGLClip::Setup", "Called on base-class -- should be re-implemented in derived class.");
113 
114 }
115 
116 ////////////////////////////////////////////////////////////////////////////////
117 /// Draw out clipping object with blending and back + front filling.
118 /// Some clip objects are single face which we want to see both sides of.
119 
120 void TGLClip::Draw(TGLRnrCtx & rnrCtx) const
121 {
122  glDepthMask(GL_FALSE);
123  glEnable(GL_BLEND);
124  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
125  glDisable(GL_CULL_FACE);
126  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
127 
128  TGLPhysicalShape::Draw(rnrCtx);
129 
130  glPolygonMode(GL_FRONT, GL_FILL);
131  glEnable(GL_CULL_FACE);
132  glDisable(GL_BLEND);
133  glDepthMask(GL_TRUE);
134 }
135 
136 /** \class TGLClipPlane
137 \ingroup opengl
138 Concrete clip plane object. This can be translated in all directions
139 rotated about the Y/Z local axes (the in-plane axes). It cannot be
140 scaled.
141 */
142 
143 ClassImp(TGLClipPlane);
144 
145 const float TGLClipPlane::fgColor[4] = { 1.0, 0.6, 0.2, 0.5 };
146 
147 ////////////////////////////////////////////////////////////////////////////////
148 /// Construct a clip plane object, based on supplied 'plane', with
149 /// initial manipulation pivot at 'center', with drawn extents (in
150 /// local x/y axes) of 'extents'
151 ///
152 /// Plane can have center pivot translated in all directions, and
153 /// rotated round center in X/Y axes , the in-plane axes. It cannot
154 /// be scaled
155 ///
156 /// Note theoretically a plane is of course infinite - however we
157 /// want to draw the object in viewer - so we fake it with a single
158 /// GL face (polygon) - extents defines the width/depth of this -
159 /// should be several times scene extents - see Setup().
160 
161 TGLClipPlane::TGLClipPlane() :
162  TGLClip(* new TGLClipPlaneLogical, TGLMatrix(), fgColor)
163 {
164  SetManip(EManip(kTranslateAll | kRotateX | kRotateY));
165 
166  TGLPlane plane(0.0, -1.0, 0.0, 0.0);
167  Set(plane);
168  fValid = kFALSE;
169 }
170 
171 ////////////////////////////////////////////////////////////////////////////////
172 /// Destroy clip plane object
173 
174 TGLClipPlane::~TGLClipPlane()
175 {
176 }
177 
178 ////////////////////////////////////////////////////////////////////////////////
179 /// Setup the clip object for scene encompassed by bbox.
180 
181 void TGLClipPlane::Setup(const TGLBoundingBox & bbox)
182 {
183  Double_t extents = bbox.Extents().Mag();
184  TGLClipPlaneLogical* cpl = (TGLClipPlaneLogical*) GetLogical();
185  cpl->Resize(extents);
186  if (!fValid) {
187  SetTransform(TGLMatrix(bbox.Center(), BoundingBox().GetNearPlane().Norm()));
188  }
189  IncTimeStamp();
190  fValid = kTRUE;
191 }
192 
193 ////////////////////////////////////////////////////////////////////////////////
194 /// Setup the clipping plane by point and normal.
195 /// Length of the normal determines the size of the plane drawn in
196 /// GL viewer. The normal points into the direction of visible half-plane.
197 ///
198 /// This only makes sense if you disable auto-update of the
199 /// clip-object:
200 ///
201 /// gl_viewer->SetClipAutoUpdate(kFALSE).
202 ///
203 /// After calling this also call gl_viewer->RefreshPadEditor(gl_viewer)
204 /// and gl_viewer->RequestDraw().
205 
206 void TGLClipPlane::Setup(const TGLVector3& point, const TGLVector3& normal)
207 {
208  TGLVector3 n(normal);
209  Double_t extents = n.Mag();
210  if (extents > 0)
211  {
212  n /= extents;
213  TGLClipPlaneLogical* cpl = (TGLClipPlaneLogical*) GetLogical();
214  cpl->Resize(extents);
215  SetTransform(TGLMatrix(point, n));
216 
217  IncTimeStamp();
218  fValid = kTRUE;
219  }
220  else
221  {
222  Warning("TGLClipPlane::Setup", "Normal with zero length passed.");
223  }
224 }
225 
226 ////////////////////////////////////////////////////////////////////////////////
227 /// Update clip plane object to follow passed 'plane' equation. Center pivot
228 /// is shifted to nearest point on new plane.
229 
230 void TGLClipPlane::Set(const TGLPlane& plane)
231 {
232  TGLVertex3 oldCenter = BoundingBox().Center();
233  TGLVertex3 newCenter = plane.NearestOn(oldCenter);
234  SetTransform(TGLMatrix(newCenter, plane.Norm()));
235  IncTimeStamp();
236  fValid = kTRUE;
237 }
238 
239 ////////////////////////////////////////////////////////////////////////////////
240 /// Return set of planes (actually a single one) describing this clip plane.
241 
242 void TGLClipPlane::PlaneSet(TGLPlaneSet_t& set) const
243 {
244  set.resize(1);
245  set[0] = BoundingBox().GetNearPlane();
246  set[0].Negate();
247 }
248 
249 /** \class TGLClipBox
250 \ingroup opengl
251 Concrete clip box object. Can be translated, rotated and scaled in
252 all (xyz) axes. By default inside of the box is clipped away.
253 */
254 
255 ClassImp(TGLClipBox);
256 
257 const float TGLClipBox::fgColor[4] = { 1.0, 0.6, 0.2, 0.3 };
258 
259 ////////////////////////////////////////////////////////////////////////////////
260 /// Construct an (initially) axis aligned clip pbox object, extents
261 /// 'halfLengths', centered on 'center' vertex.
262 /// Box can be translated, rotated and scaled in all (xyz) local axes.
263 
264 TGLClipBox::TGLClipBox() :
265  TGLClip(* new TGLClipBoxLogical, TGLMatrix(), fgColor)
266 {
267 }
268 
269 ////////////////////////////////////////////////////////////////////////////////
270 /// Destroy clip box object.
271 
272 TGLClipBox::~TGLClipBox()
273 {
274 }
275 
276 ////////////////////////////////////////////////////////////////////////////////
277 /// Setup the clip object for scene encompassed by bbox.
278 
279 void TGLClipBox::Setup(const TGLBoundingBox& bbox)
280 {
281  TGLVector3 halfLengths = bbox.Extents() * 0.2501;
282  TGLVertex3 center = bbox.Center() + halfLengths;
283 
284  TGLClipBoxLogical* cbl = (TGLClipBoxLogical*) GetLogical();
285  cbl->Resize(center - halfLengths, center + halfLengths);
286 
287  IncTimeStamp();
288  fValid = kTRUE;
289 }
290 
291 ////////////////////////////////////////////////////////////////////////////////
292 /// Setup the clip box with min/max points directly.
293 ///
294 /// This only makes sense if you disable auto-update of the
295 /// clip-object:
296 ///
297 /// gl_viewer->SetClipAutoUpdate(kFALSE).
298 ///
299 /// After calling this also call gl_viewer->RefreshPadEditor(gl_viewer)
300 /// and gl_viewer->RequestDraw().
301 
302 void TGLClipBox::Setup(const TGLVector3& min_point, const TGLVector3& max_point)
303 {
304  TGLClipBoxLogical* cbl = (TGLClipBoxLogical*) GetLogical();
305  cbl->Resize(min_point, max_point);
306 
307  IncTimeStamp();
308  fValid = kTRUE;
309 }
310 
311 ////////////////////////////////////////////////////////////////////////////////
312 /// Return set of 6 planes describing faces of the box but invert them
313 /// so that they point inside of box.
314 
315 void TGLClipBox::PlaneSet(TGLPlaneSet_t& set) const
316 {
317  BoundingBox().PlaneSet(set);
318  TGLPlaneSet_i i = set.begin();
319  while (i != set.end()) {
320  i->Negate();
321  ++i;
322  }
323 }
324 
325 
326 /** \class TGLClipSet
327 \ingroup opengl
328 A collection of concrete TGLClip objects to be selected from.
329 */
330 
331 ClassImp(TGLClipSet);
332 
333 ////////////////////////////////////////////////////////////////////////////////
334 /// Constructor.
335 
336 TGLClipSet::TGLClipSet() :
337  TGLOverlayElement(kViewer),
338  fClipPlane (new TGLClipPlane),
339  fClipBox (new TGLClipBox),
340  fCurrentClip (0),
341  fAutoUpdate (kTRUE),
342  fShowClip (kFALSE),
343  fShowManip (kFALSE),
344  fManip (new TGLManipSet)
345 {
346 }
347 
348 ////////////////////////////////////////////////////////////////////////////////
349 /// Destructor.
350 
351 TGLClipSet::~TGLClipSet()
352 {
353  delete fClipPlane;
354  delete fClipBox;
355  delete fManip;
356 }
357 
358 ////////////////////////////////////////////////////////////////////////////////
359 /// Mouse has entered this element.
360 /// Forward to ManipSet.
361 
362 Bool_t TGLClipSet::MouseEnter(TGLOvlSelectRecord& selRec)
363 {
364  return fManip->MouseEnter(selRec);
365 }
366 
367 Bool_t TGLClipSet::MouseStillInside(TGLOvlSelectRecord& selRec)
368 {
369  // A new overlay hit is about to be processed.
370  // Forward to ManipSet.
371 
372  return fManip->MouseStillInside(selRec);
373 }
374 
375 ////////////////////////////////////////////////////////////////////////////////
376 /// Handle overlay event.
377 /// Forward to ManipSet.
378 
379 Bool_t TGLClipSet::Handle(TGLRnrCtx& rnrCtx, TGLOvlSelectRecord& selRec,
380  Event_t* event)
381 {
382  return fManip->Handle(rnrCtx, selRec, event);
383 }
384 
385 ////////////////////////////////////////////////////////////////////////////////
386 /// Mouse has left the element.
387 /// Forward to ManipSet.
388 
389 void TGLClipSet::MouseLeave()
390 {
391  return fManip->MouseLeave();
392 }
393 
394 ////////////////////////////////////////////////////////////////////////////////
395 /// Render clip-shape and manipulator.
396 
397 void TGLClipSet::Render(TGLRnrCtx& rnrCtx)
398 {
399  if (!fCurrentClip) return;
400 
401  rnrCtx.SetShapeLOD(TGLRnrCtx::kLODHigh);
402  rnrCtx.SetDrawPass(TGLRnrCtx::kPassFill);
403  if (fShowClip && ! rnrCtx.Selection())
404  {
405  fCurrentClip->Draw(rnrCtx);
406  }
407  if (fShowManip)
408  {
409  fManip->Render(rnrCtx);
410  }
411 }
412 
413 ////////////////////////////////////////////////////////////////////////////////
414 /// Forward request to fill the plane-set to the current clip.
415 
416 void TGLClipSet::FillPlaneSet(TGLPlaneSet_t& set) const
417 {
418  if (fCurrentClip)
419  fCurrentClip->PlaneSet(set);
420 }
421 
422 ////////////////////////////////////////////////////////////////////////////////
423 /// Setup clipping objects for given scene bounding box.
424 
425 void TGLClipSet::SetupClips(const TGLBoundingBox& sceneBBox)
426 {
427  fLastBBox = sceneBBox;
428  fClipPlane->Setup(sceneBBox);
429  fClipBox ->Setup(sceneBBox);
430 }
431 
432 ////////////////////////////////////////////////////////////////////////////////
433 /// Setup current clipping object for given scene bounding box.
434 
435 void TGLClipSet::SetupCurrentClip(const TGLBoundingBox& sceneBBox)
436 {
437  fLastBBox = sceneBBox;
438  if (fCurrentClip)
439  fCurrentClip->Setup(sceneBBox);
440 }
441 
442 ////////////////////////////////////////////////////////////////////////////////
443 /// Setup current clipping object for given scene bounding box.
444 
445 void TGLClipSet::SetupCurrentClipIfInvalid(const TGLBoundingBox& sceneBBox)
446 {
447  fLastBBox = sceneBBox;
448  if (fCurrentClip && ! fCurrentClip->IsValid())
449  fCurrentClip->Setup(sceneBBox);
450 }
451 
452 ////////////////////////////////////////////////////////////////////////////////
453 /// Invalidate clip objects.
454 
455 void TGLClipSet::InvalidateClips()
456 {
457  fClipPlane->Invalidate();
458  fClipBox ->Invalidate();
459 }
460 
461 ////////////////////////////////////////////////////////////////////////////////
462 /// Invalidate current clip object.
463 
464 void TGLClipSet::InvalidateCurrentClip()
465 {
466  if (fCurrentClip)
467  fCurrentClip->Invalidate();
468 }
469 
470 ////////////////////////////////////////////////////////////////////////////////
471 /// Get state of clip object 'type' into data vector:
472 ///
473 /// 'type' requested - 'data' contents returned
474 /// kClipPlane 4 components - A,B,C,D - of plane eq : Ax+By+CZ+D = 0
475 /// kBoxPlane 6 components - Box Center X/Y/Z - Box Extents X/Y/Z
476 
477 void TGLClipSet::GetClipState(TGLClip::EType type, Double_t data[6]) const
478 {
479  switch (type)
480  {
481  case TGLClip::kClipNone:
482  break;
483 
484  case TGLClip::kClipPlane:
485  {
486  if (!fClipPlane->IsValid())
487  fClipPlane->Setup(fLastBBox);
488  TGLPlaneSet_t planes;
489  fClipPlane->PlaneSet(planes);
490  data[0] = planes[0].A();
491  data[1] = planes[0].B();
492  data[2] = planes[0].C();
493  data[3] = planes[0].D();
494  break;
495  }
496  case TGLClip::kClipBox:
497  {
498  if (!fClipBox->IsValid())
499  fClipBox->Setup(fLastBBox);
500  const TGLBoundingBox & box = fClipBox->BoundingBox();
501  TGLVector3 ext = box.Extents();
502  data[0] = box.Center().X();
503  data[1] = box.Center().Y();
504  data[2] = box.Center().Z();
505  data[3] = box.Extents().X();
506  data[4] = box.Extents().Y();
507  data[5] = box.Extents().Z();
508  break;
509  }
510  default:
511  Error("TGLClipSet::GetClipState", "invalid clip type '%d'.", type);
512  break;
513  }
514 }
515 
516 ////////////////////////////////////////////////////////////////////////////////
517 /// Set state of clip object 'type' into data vector:
518 ///
519 /// 'type' specified 'data' contents interpretation
520 /// kClipNone ignored
521 /// kClipPlane 4 components - A,B,C,D - of plane eq : Ax+By+CZ+D = 0
522 /// kBoxPlane 6 components - Box Center X/Y/Z - Box Extents X/Y/Z
523 
524 void TGLClipSet::SetClipState(TGLClip::EType type, const Double_t data[6])
525 {
526  switch (type) {
527  case TGLClip::kClipNone: {
528  break;
529  }
530  case TGLClip::kClipPlane: {
531  TGLPlane newPlane(-data[0], -data[1], -data[2], -data[3]);
532  fClipPlane->Set(newPlane);
533  break;
534  }
535  case TGLClip::kClipBox: {
536  //TODO: Pull these inside TGLPhysicalShape
537  // Update clip box center
538  const TGLBoundingBox & currentBox = fClipBox->BoundingBox();
539  TGLVector3 shift(data[0] - currentBox.Center().X(),
540  data[1] - currentBox.Center().Y(),
541  data[2] - currentBox.Center().Z());
542  fClipBox->Translate(shift);
543  // Update clip box extents
544 
545  TGLVector3 currentScale = fClipBox->GetScale();
546  TGLVector3 newScale(data[3] / currentBox.Extents().X() * currentScale.X(),
547  data[4] / currentBox.Extents().Y() * currentScale.Y(),
548  data[5] / currentBox.Extents().Z() * currentScale.Z());
549 
550  fClipBox->Scale(newScale);
551  break;
552  }
553  }
554 }
555 
556 ////////////////////////////////////////////////////////////////////////////////
557 /// Get current type active in viewer - returns one of kClipNone
558 /// kClipPlane or kClipBox.
559 
560 TGLClip::EType TGLClipSet::GetClipType() const
561 {
562  TGLClip::EType type;
563  if (fCurrentClip == 0) {
564  type = TGLClip::kClipNone;
565  } else if (fCurrentClip == fClipPlane) {
566  type = TGLClip::kClipPlane;
567  } else if (fCurrentClip == fClipBox) {
568  type = TGLClip::kClipBox;
569  } else {
570  Error("TGLClipSet::GetClipType" , "Unknown clip type");
571  type = TGLClip::kClipNone;
572  }
573  return type;
574 }
575 
576 ////////////////////////////////////////////////////////////////////////////////
577 /// Set current clip active in viewer - 'type' is one of kClipNone
578 /// kClipPlane or kClipBox.
579 
580 void TGLClipSet::SetClipType(TGLClip::EType type)
581 {
582  switch (type) {
583  case TGLClip::kClipNone: {
584  fCurrentClip = 0;
585  break;
586  }
587  case TGLClip::kClipPlane: {
588  fCurrentClip = fClipPlane;
589  break;
590  }
591  case TGLClip::kClipBox: {
592  fCurrentClip = fClipBox;
593  break;
594  }
595  default: {
596  Error("TGLClipSet::SetClipType" , "Unknown clip type");
597  break;
598  }
599  }
600  fManip->SetPShape(fCurrentClip);
601 }