Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGLParametric.cxx
Go to the documentation of this file.
1 // @(#)root/gl:$Id$
2 // Author: Timur Pocheptsov 26/01/2007
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, 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 #include <cctype>
12 
13 #ifdef WIN32
14 #ifndef NOMINMAX
15 #define NOMINMAX
16 #endif
17 #endif
18 
19 #include "TVirtualX.h"
20 #include "TString.h"
21 #include "TROOT.h"
22 #include "TH3.h"
23 
24 #include "TGLPlotCamera.h"
25 #include "TGLParametric.h"
26 #include "TGLIncludes.h"
27 #include "TVirtualPad.h"
28 #include "KeySymbols.h"
29 #include "Buttons.h"
30 #include "TString.h"
31 #include "TColor.h"
32 #include "TMath.h"
33 
34 namespace
35 {
36 
37  /////////////////////////////////////////////////////////////////////////////
38  ///User defines equations using names 'u' and 'v' for
39  ///parameters. But TF2 works with 'x' and 'y'. So,
40  ///find 'u' and 'v' (which are not parts of other names)
41  ///and replace them with 'x' and 'y' correspondingly.
42 
43  void ReplaceUVNames(TString &equation)
44  {
45  using namespace std;
46  const Ssiz_t len = equation.Length();
47  //TF2 requires 'y' in formula.
48  //'v' <=> 'y', so if none 'v' was found, I'll append "+0*y" to the equation.
49  Int_t vFound = 0;
50 
51  for (Ssiz_t i = 0; i < len;) {
52  const char c = equation[i];
53  if (!isalpha(c)) {
54  ++i;
55  continue;
56  } else{
57  ++i;
58  if (c == 'u' || c == 'v') {
59  //1. This 'u' or 'v' is the last symbol in a string or
60  //2. After this 'u' or 'v' symbol, which cannot be part of longer name.
61  if (i == len || (!isalpha(equation[i]) && !isdigit(equation[i]) && equation[i] != '_')) {
62  //Replace 'u' with 'x' or 'v' with 'y'.
63  equation[i - 1] = c == 'u' ? 'x' : (++vFound, 'y');
64  } else {
65  //This 'u' or 'v' is the beginning of some longer name.
66  //Skip the remaining part of this name.
67  while (i < len && (isalpha(equation[i]) || isdigit(equation[i]) || equation[i] == '_'))
68  ++i;
69  }
70  } else {
71  while (i < len && (isalpha(equation[i]) || isdigit(equation[i]) || equation[i] == '_'))
72  ++i;
73  }
74  }
75  }
76 
77  if (!vFound)
78  equation += "+0*y";
79  }
80 
81 }
82 
83 /** \class TGLParametricEquation
84 \ingroup opengl
85 A parametric surface is a surface defined by a parametric equation, involving
86 two parameters (u, v):
87 
88 ~~~ {.cpp}
89 S(u, v) = (x(u, v), y(u, v), z(u, v)).
90 ~~~
91 
92 For example, "limpet torus" surface can be defined as:
93 
94 ~~~ {.cpp}
95  x = cos(u) / (sqrt(2) + sin(v))
96  y = sin(u) / (sqrt(2) + sin(v))
97  z = 1 / (sqrt(2) + cos(v)),
98 ~~~
99 
100 where -pi <= u <= pi, -pi <= v <= pi.
101 
102 ~~~ {.cpp}
103  TGLParametricEquation * eq =
104  new TGLParametricEquation("Limpet_torus", "cos(u) / (sqrt(2.) + sin(v))",
105  "sin(u) / (sqrt(2.) + sin(v))",
106  "1 / (sqrt(2) + cos(v))");
107 ~~~
108 
109  `$ROOTSYS/tutorials/gl/glparametric.C` contains more examples.
110 
111  Parametric equations can be specified:
112  - 1. by string expressions, as with TF2, but with 'u' instead of 'x' and
113  'v' instead of 'y'.
114  - 2. by function - see ParametricEquation_t declaration.
115 
116 */
117 
118 ClassImp(TGLParametricEquation);
119 
120 ////////////////////////////////////////////////////////////////////////////////
121 ///Surface is defined by three strings.
122 ///ROOT does not use exceptions in ctors,
123 ///so, I have to use MakeZombie to let
124 ///external user know about errors.
125 
126 TGLParametricEquation::TGLParametricEquation(const TString &name, const TString &xFun, const TString &yFun,
127  const TString &zFun, Double_t uMin, Double_t uMax,
128  Double_t vMin, Double_t vMax)
129  : TNamed(name, name),
130  fEquation(0),
131  fURange(uMin, uMax),
132  fVRange(vMin, vMax),
133  fConstrained(kFALSE),
134  fModified(kFALSE)
135 {
136  if (!xFun.Length() || !yFun.Length() || !zFun.Length()) {
137  Error("TGLParametricEquation", "One of string expressions is empty");
138  MakeZombie();
139  return;
140  }
141 
142  TString equation(xFun);
143  equation.ToLower();
144  ReplaceUVNames(equation);
145  fXEquation.reset(new TF2(name + "xEquation", equation.Data(), uMin, uMax, vMin, vMax));
146  //Formula was incorrect.
147  if (fXEquation->IsZombie()) {
148  MakeZombie();
149  return;
150  }
151 
152  equation = yFun;
153  equation.ToLower();
154  ReplaceUVNames(equation);
155  fYEquation.reset(new TF2(name + "yEquation", equation.Data(), uMin, uMax, vMin, vMax));
156  //Formula was incorrect.
157  if (fYEquation->IsZombie()) {
158  MakeZombie();
159  return;
160  }
161 
162  equation = zFun;
163  equation.ToLower();
164  ReplaceUVNames(equation);
165  fZEquation.reset(new TF2(name + "zEquation", equation.Data(), uMin, uMax, vMin, vMax));
166  //Formula was incorrect.
167  if (fZEquation->IsZombie())
168  MakeZombie();
169 }
170 
171 ////////////////////////////////////////////////////////////////////////////////
172 ///Surface defined by user's function (see ParametricEquation_t declaration in TGLParametricEquation.h)
173 
174 TGLParametricEquation::TGLParametricEquation(const TString &name, ParametricEquation_t equation,
175  Double_t uMin, Double_t uMax, Double_t vMin, Double_t vMax)
176  : TNamed(name, name),
177  fEquation(equation),
178  fURange(uMin, uMax),
179  fVRange(vMin, vMax),
180  fConstrained(kFALSE),
181  fModified(kFALSE)
182 {
183  if (!fEquation) {
184  Error("TGLParametricEquation", "Function ptr is null");
185  MakeZombie();
186  }
187 }
188 
189 ////////////////////////////////////////////////////////////////////////////////
190 ///[uMin, uMax]
191 
192 Rgl::Range_t TGLParametricEquation::GetURange()const
193 {
194  return fURange;
195 }
196 
197 ////////////////////////////////////////////////////////////////////////////////
198 ///[vMin, vMax]
199 
200 Rgl::Range_t TGLParametricEquation::GetVRange()const
201 {
202  return fVRange;
203 }
204 
205 ////////////////////////////////////////////////////////////////////////////////
206 ///Check is constrained.
207 
208 Bool_t TGLParametricEquation::IsConstrained()const
209 {
210  return fConstrained;
211 }
212 
213 ////////////////////////////////////////////////////////////////////////////////
214 ///Set constrained.
215 
216 void TGLParametricEquation::SetConstrained(Bool_t c)
217 {
218  fConstrained = c;
219 }
220 
221 ////////////////////////////////////////////////////////////////////////////////
222 ///Something was changed in parametric equation (or constrained option was changed).
223 
224 Bool_t TGLParametricEquation::IsModified()const
225 {
226  return fModified;
227 }
228 
229 ////////////////////////////////////////////////////////////////////////////////
230 ///Set modified.
231 
232 void TGLParametricEquation::SetModified(Bool_t m)
233 {
234  fModified = m;
235 }
236 
237 ////////////////////////////////////////////////////////////////////////////////
238 ///Calculate vertex.
239 
240 void TGLParametricEquation::EvalVertex(TGLVertex3 &newVertex, Double_t u, Double_t v)const
241 {
242  if (fEquation)
243  return fEquation(newVertex, u, v);
244 
245  if (IsZombie())
246  return;
247 
248  newVertex.X() = fXEquation->Eval(u, v);
249  newVertex.Y() = fYEquation->Eval(u, v);
250  newVertex.Z() = fZEquation->Eval(u, v);
251 }
252 
253 ////////////////////////////////////////////////////////////////////////////////
254 ///Check, if parametric surface is under cursor.
255 
256 Int_t TGLParametricEquation::DistancetoPrimitive(Int_t px, Int_t py)
257 {
258  if (fPainter.get())
259  return fPainter->DistancetoPrimitive(px, py);
260  return 9999;
261 }
262 
263 ////////////////////////////////////////////////////////////////////////////////
264 ///Pass event to painter.
265 
266 void TGLParametricEquation::ExecuteEvent(Int_t event, Int_t px, Int_t py)
267 {
268  if (fPainter.get())
269  return fPainter->ExecuteEvent(event, px, py);
270 }
271 
272 ////////////////////////////////////////////////////////////////////////////////
273 ///No object info yet.
274 
275 char *TGLParametricEquation::GetObjectInfo(Int_t /*px*/, Int_t /*py*/) const
276 {
277  static char mess[] = { "parametric surface" };
278  return mess;
279 }
280 
281 ////////////////////////////////////////////////////////////////////////////////
282 ///Delegate paint.
283 
284 void TGLParametricEquation::Paint(Option_t * /*option*/)
285 {
286  if (!fPainter.get())
287  fPainter.reset(new TGLHistPainter(this));
288  fPainter->Paint("dummyoption");
289 }
290 
291 /** \class TGLParametricPlot
292 \ingroup opengl
293 */
294 
295 ClassImp(TGLParametricPlot);
296 
297 ////////////////////////////////////////////////////////////////////////////////
298 ///Constructor.
299 
300 TGLParametricPlot::TGLParametricPlot(TGLParametricEquation *eq,
301  TGLPlotCamera *camera)
302  : TGLPlotPainter(camera),
303  fMeshSize(90),
304  fShowMesh(kFALSE),
305  fColorScheme(4),
306  fEquation(eq)
307 {
308  fXAxis = &fCartesianXAxis;
309  fYAxis = &fCartesianYAxis;
310  fZAxis = &fCartesianZAxis;
311 
312  fCoord = &fCartesianCoord;
313 
314  InitGeometry();
315  InitColors();
316 }
317 
318 ////////////////////////////////////////////////////////////////////////////////
319 ///Build mesh. The surface is 'immutable':
320 ///the only reason to rebuild it - the change in size or
321 ///if one of equations contain reference to TF2 function, whose
322 ///parameters were changed.
323 
324 Bool_t TGLParametricPlot::InitGeometry()
325 {
326  // const Bool_t constrained = kTRUE;//fEquation->IsConstrained();
327 
328  if (fMeshSize * fMeshSize != (Int_t)fMesh.size() || fEquation->IsModified()) {
329  if (fEquation->IsZombie())
330  return kFALSE;
331 
332  fEquation->SetModified(kFALSE);
333 
334  fMesh.resize(fMeshSize * fMeshSize);
335  fMesh.SetRowLen(fMeshSize);
336 
337  const Rgl::Range_t uRange(fEquation->GetURange());
338  const Rgl::Range_t vRange(fEquation->GetVRange());
339 
340  const Double_t dU = (uRange.second - uRange.first) / (fMeshSize - 1);
341  const Double_t dV = (vRange.second - vRange.first) / (fMeshSize - 1);
342  const Double_t dd = 0.001;
343  Double_t u = uRange.first;
344 
345  TGLVertex3 min;
346  fEquation->EvalVertex(min, uRange.first, vRange.first);
347  TGLVertex3 max(min), newVert, v1, v2;
348  using namespace TMath;
349 
350  for (Int_t i = 0; i < fMeshSize; ++i) {
351  Double_t v = vRange.first;
352  for (Int_t j = 0; j < fMeshSize; ++j) {
353  fEquation->EvalVertex(newVert, u, v);
354  min.X() = Min(min.X(), newVert.X());
355  max.X() = Max(max.X(), newVert.X());
356  min.Y() = Min(min.Y(), newVert.Y());
357  max.Y() = Max(max.Y(), newVert.Y());
358  min.Z() = Min(min.Z(), newVert.Z());
359  max.Z() = Max(max.Z(), newVert.Z());
360 
361  fMesh[i][j].fPos = newVert;
362 
363  v += dV;
364  }
365  u += dU;
366  }
367 
368  TH3F hist("tmp", "tmp", 2, -1., 1., 2, -1., 1., 2, -1., 1.);
369  hist.SetDirectory(0);
370  //TAxis has a lot of attributes, defaults, set by ctor,
371  //are not enough to be correctly painted by TGaxis object.
372  //To simplify their initialization - I use temporary histogram.
373  hist.GetXaxis()->Copy(fCartesianXAxis);
374  hist.GetYaxis()->Copy(fCartesianYAxis);
375  hist.GetZaxis()->Copy(fCartesianZAxis);
376 
377  fCartesianXAxis.Set(fMeshSize, min.X(), max.X());
378  fCartesianXAxis.SetTitle("x");//it's lost when copying from temp. hist.
379  fCartesianYAxis.Set(fMeshSize, min.Y(), max.Y());
380  fCartesianYAxis.SetTitle("y");
381  fCartesianZAxis.Set(fMeshSize, min.Z(), max.Z());
382  fCartesianZAxis.SetTitle("z");
383 
384  if (!fCoord->SetRanges(&fCartesianXAxis, &fCartesianYAxis, &fCartesianZAxis))
385  return kFALSE;
386 
387  for (Int_t i = 0; i < fMeshSize; ++i) {
388  for (Int_t j = 0; j < fMeshSize; ++j) {
389  TGLVertex3 &ver = fMesh[i][j].fPos;
390  ver.X() *= fCoord->GetXScale(), ver.Y() *= fCoord->GetYScale(), ver.Z() *= fCoord->GetZScale();
391  }
392  }
393 
394  u = uRange.first;
395  for (Int_t i = 0; i < fMeshSize; ++i) {
396  Double_t v = vRange.first;
397  for (Int_t j = 0; j < fMeshSize; ++j) {
398  TGLVertex3 &ver = fMesh[i][j].fPos;
399  fEquation->EvalVertex(v1, u + dd, v);
400  fEquation->EvalVertex(v2, u, v + dd);
401  v1.X() *= fCoord->GetXScale(), v1.Y() *= fCoord->GetYScale(), v1.Z() *= fCoord->GetZScale();
402  v2.X() *= fCoord->GetXScale(), v2.Y() *= fCoord->GetYScale(), v2.Z() *= fCoord->GetZScale();
403  Normal2Plane(ver.CArr(), v1.CArr(), v2.CArr(), fMesh[i][j].fNormal.Arr());
404  v += dV;
405  }
406  u += dU;
407  }
408 
409  fBackBox.SetPlotBox(fCoord->GetXRangeScaled(),
410  fCoord->GetYRangeScaled(),
411  fCoord->GetZRangeScaled());
412  if (fCamera) fCamera->SetViewVolume(fBackBox.Get3DBox());
413  }
414 
415  return kTRUE;
416 }
417 
418 ////////////////////////////////////////////////////////////////////////////////
419 ///User clicks right mouse button (in a pad).
420 
421 void TGLParametricPlot::StartPan(Int_t px, Int_t py)
422 {
423  fMousePosition.fX = px;
424  fMousePosition.fY = fCamera->GetHeight() - py;
425  fCamera->StartPan(px, py);
426  fBoxCut.StartMovement(px, fCamera->GetHeight() - py);
427 }
428 
429 ////////////////////////////////////////////////////////////////////////////////
430 ///User's moving mouse cursor, with middle mouse button pressed (for pad).
431 ///Calculate 3d shift related to 2d mouse movement.
432 
433 void TGLParametricPlot::Pan(Int_t px, Int_t py)
434 {
435  if (fSelectedPart) {
436  SaveModelviewMatrix();
437  SaveProjectionMatrix();
438 
439  fCamera->SetCamera();
440  fCamera->Apply(fPadPhi, fPadTheta);
441 
442  if (fBoxCut.IsActive() && (fSelectedPart >= kXAxis && fSelectedPart <= kZAxis))
443  fBoxCut.MoveBox(px, fCamera->GetHeight() - py, fSelectedPart);
444  else
445  fCamera->Pan(px, py);
446 
447  RestoreProjectionMatrix();
448  RestoreModelviewMatrix();
449  }
450 
451  fUpdateSelection = kTRUE;//
452 }
453 
454 ////////////////////////////////////////////////////////////////////////////////
455 ///No object info yet.
456 
457 char *TGLParametricPlot::GetPlotInfo(Int_t /*px*/, Int_t /*py*/)
458 {
459  static char mess[] = { "parametric surface" };
460  return mess;
461 }
462 
463 ////////////////////////////////////////////////////////////////////////////////
464 ///No additional options for parametric surfaces.
465 
466 void TGLParametricPlot::AddOption(const TString &/*option*/)
467 {
468 }
469 
470 ////////////////////////////////////////////////////////////////////////////////
471 ///Change color/mesh size or switch on/off mesh/box cut.
472 ///Left double click - remove box cut.
473 
474 void TGLParametricPlot::ProcessEvent(Int_t event, Int_t /*px*/, Int_t py)
475 {
476  if (event == kButton1Double && fBoxCut.IsActive()) {
477  fBoxCut.TurnOnOff();
478  if (!gVirtualX->IsCmdThread())
479  gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%lx)->Paint()", (ULong_t)this));
480  else
481  Paint();
482  } else if (event == kKeyPress) {
483  if (py == kKey_c || py == kKey_C) {
484  if (fHighColor)
485  Info("ProcessEvent", "Switch to true color to use box cut");
486  else {
487  fBoxCut.TurnOnOff();
488  fUpdateSelection = kTRUE;
489  }
490  } else if (py == kKey_s || py == kKey_S) {
491  fColorScheme == 20 ? fColorScheme = -1 : ++fColorScheme;
492  InitColors();//color scheme was changed! recalculate vertices colors.
493  } else if (py == kKey_w || py == kKey_W) {
494  fShowMesh = !fShowMesh;
495  } else if (py == kKey_l || py == kKey_L) {
496  fMeshSize == kHigh ? fMeshSize = kLow : fMeshSize += 15;
497  InitGeometry();
498  InitColors();
499  }
500  }
501 }
502 
503 ////////////////////////////////////////////////////////////////////////////////
504 ///Initialize gl state.
505 
506 void TGLParametricPlot::InitGL()const
507 {
508  glEnable(GL_DEPTH_TEST);
509  glEnable(GL_LIGHTING);
510  glEnable(GL_LIGHT0);
511  glDisable(GL_CULL_FACE);
512  glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
513 }
514 
515 ////////////////////////////////////////////////////////////////////////////////
516 ///Initialize gl state.
517 
518 void TGLParametricPlot::DeInitGL()const
519 {
520  glDisable(GL_DEPTH_TEST);
521  glDisable(GL_LIGHTING);
522  glDisable(GL_LIGHT0);
523  glDisable(GL_CULL_FACE);
524  glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
525 }
526 
527 ////////////////////////////////////////////////////////////////////////////////
528 ///Draw parametric surface.
529 
530 void TGLParametricPlot::DrawPlot()const
531 {
532  //Shift plot to point of origin.
533  const Rgl::PlotTranslation trGuard(this);
534 
535  if (!fSelectionPass) {
536  SetSurfaceColor();
537  if (fShowMesh) {
538  glEnable(GL_POLYGON_OFFSET_FILL);
539  glPolygonOffset(1.f, 1.f);
540  }
541  } else {
542  Rgl::ObjectIDToColor(fSelectionBase, fHighColor);
543  }
544 
545  glBegin(GL_TRIANGLES);
546 
547  for (Int_t i = 0; i < fMeshSize - 1; ++i) {
548  for (Int_t j = 0; j < fMeshSize - 1; ++j) {
549  if (fBoxCut.IsActive()) {
550  using TMath::Min;
551  using TMath::Max;
552  const Double_t xMin = Min(Min(fMesh[i][j].fPos.X(), fMesh[i + 1][j].fPos.X()), Min(fMesh[i][j + 1].fPos.X(), fMesh[i + 1][j + 1].fPos.X()));
553  const Double_t xMax = Max(Max(fMesh[i][j].fPos.X(), fMesh[i + 1][j].fPos.X()), Max(fMesh[i][j + 1].fPos.X(), fMesh[i + 1][j + 1].fPos.X()));
554  const Double_t yMin = Min(Min(fMesh[i][j].fPos.Y(), fMesh[i + 1][j].fPos.Y()), Min(fMesh[i][j + 1].fPos.Y(), fMesh[i + 1][j + 1].fPos.Y()));
555  const Double_t yMax = Max(Max(fMesh[i][j].fPos.Y(), fMesh[i + 1][j].fPos.Y()), Max(fMesh[i][j + 1].fPos.Y(), fMesh[i + 1][j + 1].fPos.Y()));
556  const Double_t zMin = Min(Min(fMesh[i][j].fPos.Z(), fMesh[i + 1][j].fPos.Z()), Min(fMesh[i][j + 1].fPos.Z(), fMesh[i + 1][j + 1].fPos.Z()));
557  const Double_t zMax = Max(Max(fMesh[i][j].fPos.Z(), fMesh[i + 1][j].fPos.Z()), Max(fMesh[i][j + 1].fPos.Z(), fMesh[i + 1][j + 1].fPos.Z()));
558 
559  if (fBoxCut.IsInCut(xMin, xMax, yMin, yMax, zMin, zMax))
560  continue;
561  }
562 
563  glNormal3dv(fMesh[i + 1][j + 1].fNormal.CArr());
564  if(fColorScheme != -1)
565  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, fMesh[i + 1][j + 1].fRGBA);
566  glVertex3dv(fMesh[i + 1][j + 1].fPos.CArr());
567 
568  glNormal3dv(fMesh[i][j + 1].fNormal.CArr());
569  if(fColorScheme != -1)
570  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, fMesh[i][j + 1].fRGBA);
571  glVertex3dv(fMesh[i][j + 1].fPos.CArr());
572 
573  glNormal3dv(fMesh[i][j].fNormal.CArr());
574  if(fColorScheme != -1)
575  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, fMesh[i][j].fRGBA);
576  glVertex3dv(fMesh[i][j].fPos.CArr());
577 
578  glNormal3dv(fMesh[i + 1][j].fNormal.CArr());
579  if(fColorScheme != -1)
580  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, fMesh[i + 1][j].fRGBA);
581  glVertex3dv(fMesh[i + 1][j].fPos.CArr());
582 
583  glNormal3dv(fMesh[i + 1][j + 1].fNormal.CArr());
584  if(fColorScheme != -1)
585  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, fMesh[i + 1][j + 1].fRGBA);
586  glVertex3dv(fMesh[i + 1][j + 1].fPos.CArr());
587 
588  glNormal3dv(fMesh[i][j].fNormal.CArr());
589  if(fColorScheme != -1)
590  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, fMesh[i][j].fRGBA);
591  glVertex3dv(fMesh[i][j].fPos.CArr());
592  }
593  }
594 
595  glEnd();
596 
597  if (!fSelectionPass && fShowMesh) {
598  glDisable(GL_POLYGON_OFFSET_FILL);
599  const TGLDisableGuard lightGuard(GL_LIGHTING);
600  const TGLEnableGuard blendGuard(GL_BLEND);
601  const TGLEnableGuard smoothGuard(GL_LINE_SMOOTH);
602 
603  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
604  glColor4d(0., 0., 0., 0.5);
605  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
606 
607  for (Int_t i = 0; i < fMeshSize - 1; ++i) {
608  for (Int_t j = 0; j < fMeshSize - 1; ++j) {
609  if (fBoxCut.IsActive()) {
610  using TMath::Min;
611  using TMath::Max;
612  const Double_t xMin = Min(Min(fMesh[i][j].fPos.X(), fMesh[i + 1][j].fPos.X()), Min(fMesh[i][j + 1].fPos.X(), fMesh[i + 1][j + 1].fPos.X()));
613  const Double_t xMax = Max(Max(fMesh[i][j].fPos.X(), fMesh[i + 1][j].fPos.X()), Max(fMesh[i][j + 1].fPos.X(), fMesh[i + 1][j + 1].fPos.X()));
614  const Double_t yMin = Min(Min(fMesh[i][j].fPos.Y(), fMesh[i + 1][j].fPos.Y()), Min(fMesh[i][j + 1].fPos.Y(), fMesh[i + 1][j + 1].fPos.Y()));
615  const Double_t yMax = Max(Max(fMesh[i][j].fPos.Y(), fMesh[i + 1][j].fPos.Y()), Max(fMesh[i][j + 1].fPos.Y(), fMesh[i + 1][j + 1].fPos.Y()));
616  const Double_t zMin = Min(Min(fMesh[i][j].fPos.Z(), fMesh[i + 1][j].fPos.Z()), Min(fMesh[i][j + 1].fPos.Z(), fMesh[i + 1][j + 1].fPos.Z()));
617  const Double_t zMax = Max(Max(fMesh[i][j].fPos.Z(), fMesh[i + 1][j].fPos.Z()), Max(fMesh[i][j + 1].fPos.Z(), fMesh[i + 1][j + 1].fPos.Z()));
618 
619  if (fBoxCut.IsInCut(xMin, xMax, yMin, yMax, zMin, zMax))
620  continue;
621  }
622  glBegin(GL_POLYGON);
623  glVertex3dv(fMesh[i][j].fPos.CArr());
624  glVertex3dv(fMesh[i][j + 1].fPos.CArr());
625  glVertex3dv(fMesh[i + 1][j + 1].fPos.CArr());
626  glVertex3dv(fMesh[i + 1][j].fPos.CArr());
627  glEnd();
628  }
629  }
630 
631  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
632  }
633 
634  if (fBoxCut.IsActive())
635  fBoxCut.DrawBox(fSelectionPass, fSelectedPart);
636 }
637 
638 ////////////////////////////////////////////////////////////////////////////////
639 ///Calculate colors for vertices,
640 ///using one of 20 color themes.
641 ///-1 simple 'metal' surface.
642 
643 void TGLParametricPlot::InitColors()
644 {
645  if (fColorScheme == -1)
646  return;
647 
648  const Rgl::Range_t uRange(fEquation->GetURange());
649 
650  const Float_t dU = Float_t((uRange.second - uRange.first) / (fMeshSize - 1));
651  Float_t u = Float_t(uRange.first);
652 
653  for (Int_t i = 0; i < fMeshSize; ++i) {
654  for (Int_t j = 0; j < fMeshSize; ++j)
655  Rgl::GetColor(u, uRange.first, uRange.second, fColorScheme, fMesh[i][j].fRGBA);
656  u += dU;
657  }
658 }
659 
660 ////////////////////////////////////////////////////////////////////////////////
661 ///No such sections.
662 
663 void TGLParametricPlot::DrawSectionXOZ()const
664 {
665 }
666 
667 ////////////////////////////////////////////////////////////////////////////////
668 ///No such sections.
669 
670 void TGLParametricPlot::DrawSectionYOZ()const
671 {
672 }
673 
674 ////////////////////////////////////////////////////////////////////////////////
675 ///No such sections.
676 
677 void TGLParametricPlot::DrawSectionXOY()const
678 {
679 }
680 
681 ////////////////////////////////////////////////////////////////////////////////
682 ///Set material properties.
683 
684 void TGLParametricPlot::SetSurfaceColor()const
685 {
686  const Float_t specular[] = {1.f, 1.f, 1.f, 1.f};
687  glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
688  glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 20.f);
689 
690  if (fColorScheme == -1) {
691  const Float_t outerDiff[] = {0.5f, 0.42f, 0.f, 1.f};
692  glMaterialfv(GL_FRONT, GL_DIFFUSE, outerDiff);
693  const Float_t innerDiff[] = {0.5f, 0.2f, 0.f, 1.f};
694  glMaterialfv(GL_BACK, GL_DIFFUSE, innerDiff);
695  }
696 }