Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TPainter3dAlgorithms.cxx
Go to the documentation of this file.
1 // @(#)root/histpainter:$Id$
2 // Author: Rene Brun, Evgueni Tcherniaev, Olivier Couet 12/12/94
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 
12 /*! \class TPainter3dAlgorithms
13 \ingroup Histpainter
14 \brief The Legos and Surfaces painter class.
15 
16 3D graphics representations package.
17 
18 This package was originally written by Evgueni Tcherniaev from IHEP/Protvino.
19 
20 The original Fortran implementation was adapted to HIGZ/PAW by Olivier Couet
21 and Evgueni Tcherniaev.
22 
23 This class is a subset of the original system. It has been converted to a C++
24 class by Rene Brun.
25 */
26 
27 #include <stdlib.h>
28 
29 #include "TROOT.h"
30 #include "TPainter3dAlgorithms.h"
31 #include "TVirtualPad.h"
32 #include "THistPainter.h"
33 #include "TH1.h"
34 #include "TF3.h"
35 #include "TView.h"
36 #include "TVirtualX.h"
37 #include "Hoption.h"
38 #include "Hparam.h"
39 #include "TMath.h"
40 #include "TStyle.h"
41 #include "TObjArray.h"
42 #include "THLimitsFinder.h"
43 #include "TColor.h"
44 
45 const Double_t kRad = TMath::ATan(1)*Double_t(4)/Double_t(180);
46 const Double_t kFdel = 0.;
47 const Double_t kDel = 0.0001;
48 const Int_t kNiso = 4;
49 const Int_t kNmaxp = kNiso*13;
50 const Int_t kNmaxt = kNiso*12;
51 const Int_t kLmax = 12;
52 const Int_t kF3FillColor1 = 201;
53 const Int_t kF3FillColor2 = 202;
54 const Int_t kF3LineColor = 203;
55 
56 Int_t TPainter3dAlgorithms::fgF3Clipping = 0;
57 Double_t TPainter3dAlgorithms::fgF3XClip = 0.;
58 Double_t TPainter3dAlgorithms::fgF3YClip = 0.;
59 Double_t TPainter3dAlgorithms::fgF3ZClip = 0.;
60 TF3 *TPainter3dAlgorithms::fgCurrentF3 = 0;
61 
62 // Static arrays used to paint stacked lego plots.
63 const Int_t kVSizeMax = 20;
64 static Double_t gV[kVSizeMax];
65 static Double_t gTT[4*kVSizeMax];
66 static Int_t gColorMain[kVSizeMax+1];
67 static Int_t gColorDark[kVSizeMax+1];
68 static Int_t gEdgeColor[kVSizeMax+1];
69 static Int_t gEdgeStyle[kVSizeMax+1];
70 static Int_t gEdgeWidth[kVSizeMax+1];
71 
72 extern TH1 *gCurrentHist; //these 3 globals should be replaced by class members
73 extern Hoption_t Hoption;
74 extern Hparam_t Hparam;
75 
76 ClassImp(TPainter3dAlgorithms);
77 
78 ////////////////////////////////////////////////////////////////////////////////
79 /// Lego default constructor
80 
81 TPainter3dAlgorithms::TPainter3dAlgorithms(): TObject(), TAttLine(1,1,1), TAttFill(1,0)
82 {
83  Int_t i;
84  fAphi = 0;
85  fNaphi = 0;
86  fIfrast = 0;
87  fMesh = 1;
88  fRaster = 0;
89  fColorTop = 1;
90  fColorBottom = 1;
91  fEdgeIdx = -1;
92  fNlevel = 0;
93  fSystem = kCARTESIAN;
94  fDrawFace = 0;
95  fLegoFunction = 0;
96  fSurfaceFunction = 0;
97 
98  TList *stack = 0;
99  if (gCurrentHist) stack = gCurrentHist->GetPainter()->GetStack();
100  fNStack = 0;
101  if (stack) fNStack = stack->GetSize();
102  if (fNStack > kVSizeMax) {
103  fColorMain = new Int_t[fNStack+1];
104  fColorDark = new Int_t[fNStack+1];
105  fEdgeColor = new Int_t[fNStack+1];
106  fEdgeStyle = new Int_t[fNStack+1];
107  fEdgeWidth = new Int_t[fNStack+1];
108  } else {
109  fColorMain = &gColorMain[0];
110  fColorDark = &gColorDark[0];
111  fEdgeColor = &gEdgeColor[0];
112  fEdgeStyle = &gEdgeStyle[0];
113  fEdgeWidth = &gEdgeWidth[0];
114  }
115 
116  for (i=0;i<fNStack;i++) { fColorMain[i] = 1; fColorDark[i] = 1; fEdgeColor[i] = 1; fEdgeStyle[i] = 1; fEdgeWidth[i] = 1; }
117  for (i=0;i<3;i++) { fRmin[i] = 0; fRmax[i] = 1; }
118  for (i=0;i<4;i++) { fYls[i] = 0; }
119 
120  for (i=0;i<30;i++) { fJmask[i] = 0; }
121  for (i=0;i<200;i++) { fLevelLine[i] = 0; }
122  for (i=0;i<465;i++) { fMask[i] = 0; }
123  for (i=0;i<258;i++) { fColorLevel[i] = 0; }
124  for (i=0;i<1200;i++) { fPlines[i] = 0.; }
125  for (i=0;i<200;i++) { fT[i] = 0.; }
126  for (i=0;i<2*NumOfSlices;i++) { fU[i] = 0.; fD[i] = 0.; }
127  for (i=0;i<12;i++) { fVls[i] = 0.; }
128  for (i=0;i<257;i++) { fFunLevel[i] = 0.; }
129  for (i=0;i<8;i++) { fF8[i] = 0.; }
130 
131  fLoff = 0;
132  fNT = 0;
133  fNcolor = 0;
134  fNlines = 0;
135  fNqs = 0;
136  fNxrast = 0;
137  fNyrast = 0;
138  fIc1 = 0;
139  fIc2 = 0;
140  fIc3 = 0;
141  fQA = 0.;
142  fQD = 0.;
143  fQS = 0.;
144  fX0 = 0.;
145  fYdl = 0.;
146  fXrast = 0.;
147  fYrast = 0.;
148  fFmin = 0.;
149  fFmax = 0.;
150  fDXrast = 0.;
151  fDYrast = 0.;
152  fDX = 0.;
153 }
154 
155 ////////////////////////////////////////////////////////////////////////////////
156 /// Normal default constructor
157 ///
158 /// rmin[3], rmax[3] are the limits of the lego object depending on
159 /// the selected coordinate system
160 
161 TPainter3dAlgorithms::TPainter3dAlgorithms(Double_t *rmin, Double_t *rmax, Int_t system)
162  : TObject(), TAttLine(1,1,1), TAttFill(1,0)
163 {
164  Int_t i;
165  Double_t psi;
166 
167  fAphi = 0;
168  fNaphi = 0;
169  fIfrast = 0;
170  fMesh = 1;
171  fRaster = 0;
172  fColorTop = 1;
173  fColorBottom = 1;
174  fEdgeIdx = -1;
175  fNlevel = 0;
176  fSystem = system;
177  if (system == kCARTESIAN || system == kPOLAR) psi = 0;
178  else psi = 90;
179  fDrawFace = 0;
180  fLegoFunction = 0;
181  fSurfaceFunction = 0;
182 
183  TList *stack = gCurrentHist->GetPainter()->GetStack();
184  fNStack = 0;
185  if (stack) fNStack = stack->GetSize();
186  if (fNStack > kVSizeMax) {
187  fColorMain = new Int_t[fNStack+1];
188  fColorDark = new Int_t[fNStack+1];
189  fEdgeColor = new Int_t[fNStack+1];
190  fEdgeStyle = new Int_t[fNStack+1];
191  fEdgeWidth = new Int_t[fNStack+1];
192  } else {
193  fColorMain = &gColorMain[0];
194  fColorDark = &gColorDark[0];
195  fEdgeColor = &gEdgeColor[0];
196  fEdgeStyle = &gEdgeStyle[0];
197  fEdgeWidth = &gEdgeWidth[0];
198  }
199 
200  for (i=0;i<fNStack;i++) { fColorMain[i] = 1; fColorDark[i] = 1; fEdgeColor[i] = 1; fEdgeStyle[i] = 1; fEdgeWidth[i] = 1; }
201  for (i=0;i<3;i++) { fRmin[i] = rmin[i]; fRmax[i] = rmax[i]; }
202  for (i=0;i<4;i++) { fYls[i] = 0; }
203 
204  for (i=0;i<30;i++) { fJmask[i] = 0; }
205  for (i=0;i<200;i++) { fLevelLine[i] = 0; }
206  for (i=0;i<465;i++) { fMask[i] = 0; }
207  for (i=0;i<258;i++) { fColorLevel[i] = 0; }
208  for (i=0;i<1200;i++) { fPlines[i] = 0.; }
209  for (i=0;i<200;i++) { fT[i] = 0.; }
210  for (i=0;i<2*NumOfSlices;i++) { fU[i] = 0.; fD[i] = 0.; }
211  for (i=0;i<12;i++) { fVls[i] = 0.; }
212  for (i=0;i<257;i++) { fFunLevel[i] = 0.; }
213  for (i=0;i<8;i++) { fF8[i] = 0.; }
214 
215  fLoff = 0;
216  fNT = 0;
217  fNcolor = 0;
218  fNlines = 0;
219  fNqs = 0;
220  fNxrast = 0;
221  fNyrast = 0;
222  fIc1 = 0;
223  fIc2 = 0;
224  fIc3 = 0;
225  fQA = 0.;
226  fQD = 0.;
227  fQS = 0.;
228  fX0 = 0.;
229  fYdl = 0.;
230  fXrast = 0.;
231  fYrast = 0.;
232  fFmin = 0.;
233  fFmax = 0.;
234  fDXrast = 0.;
235  fDYrast = 0.;
236  fDX = 0.;
237 
238  TView *view = 0;
239  if (gPad) view = gPad->GetView();
240  if (!view) view = TView::CreateView(fSystem, rmin, rmax);
241  if (view) {
242  view->SetView(gPad->GetPhi(), gPad->GetTheta(), psi, i);
243  view->SetRange(rmin,rmax);
244  }
245 }
246 
247 ////////////////////////////////////////////////////////////////////////////////
248 /// Lego default destructor
249 
250 TPainter3dAlgorithms::~TPainter3dAlgorithms()
251 {
252  if (fAphi) { delete [] fAphi; fAphi = 0; }
253  if (fRaster) { delete [] fRaster; fRaster = 0; }
254  if (fNStack > kVSizeMax) {
255  delete [] fColorMain;
256  delete [] fColorDark;
257  delete [] fEdgeColor;
258  delete [] fEdgeStyle;
259  delete [] fEdgeWidth;
260  }
261 }
262 
263 ////////////////////////////////////////////////////////////////////////////////
264 /// Draw back surfaces of surrounding box
265 ///
266 /// \param[in] ang angle between X and Y axis
267 
268 void TPainter3dAlgorithms::BackBox(Double_t ang)
269 {
270  static Int_t iface1[4] = { 1, 4, 8, 5 };
271  static Int_t iface2[4] = { 4, 3, 7, 8 };
272 
273  TView *view = 0;
274  if (gPad) view = gPad->GetView();
275  if (!view) {
276  Error("BackBox", "no TView in current pad");
277  return;
278  }
279 
280  // Get corners of surrounding box
281  Double_t r[3*8], av[3*8];
282  Int_t ix1, ix2, iy1, iy2, iz1, iz2;
283  Double_t cosa = TMath::Cos(kRad*ang);
284  Double_t sina = TMath::Sin(kRad*ang);
285  view->AxisVertex(ang, av, ix1, ix2, iy1, iy2, iz1, iz2);
286  for (Int_t i = 0; i < 8; ++i) {
287  r[i*3 + 0] = av[i*3 + 0] + av[i*3 + 1]*cosa;
288  r[i*3 + 1] = av[i*3 + 1]*sina;
289  r[i*3 + 2] = av[i*3 + 2];
290  }
291 
292  // Draw back faces
293  Int_t icodes[3] = { 0, 0, 0 };
294  Double_t tt[4];
295  tt[0] = r[(iface1[0]-1)*3 + 2];
296  tt[1] = r[(iface1[1]-1)*3 + 2];
297  tt[2] = r[(iface1[2]-1)*3 + 2];
298  tt[3] = r[(iface1[3]-1)*3 + 2];
299  (this->*fDrawFace)(icodes, r, 4, iface1, tt);
300  tt[0] = r[(iface2[0]-1)*3 + 2];
301  tt[1] = r[(iface2[1]-1)*3 + 2];
302  tt[2] = r[(iface2[2]-1)*3 + 2];
303  tt[3] = r[(iface2[3]-1)*3 + 2];
304  (this->*fDrawFace)(icodes, r, 4, iface2, tt);
305 }
306 
307 ////////////////////////////////////////////////////////////////////////////////
308 /// Draw front surfaces of surrounding box & axes
309 ///
310 /// \param[in] ang angle between X and Y axis
311 
312 void TPainter3dAlgorithms::FrontBox(Double_t ang)
313 {
314  static Int_t iface1[4] = { 1, 2, 6, 5 };
315  static Int_t iface2[4] = { 2, 3, 7, 6 };
316 
317  TView *view = 0;
318  if (gPad) view = gPad->GetView();
319  if (!view) {
320  Error("FrontBox", "no TView in current pad");
321  return;
322  }
323 
324  // Get corners of surrounding box
325  Double_t r[3*8], av[3*8], x[4], y[4];
326  Int_t ix1, ix2, iy1, iy2, iz1, iz2;
327  Double_t cosa = TMath::Cos(kRad*ang);
328  Double_t sina = TMath::Sin(kRad*ang);
329  view->AxisVertex(ang, av, ix1, ix2, iy1, iy2, iz1, iz2);
330  for (Int_t i = 0; i < 8; ++i) {
331  r[i*3 + 0] = av[i*3 + 0] + av[i*3 + 1]*cosa;
332  r[i*3 + 1] = av[i*3 + 1]*sina;
333  r[i*3 + 2] = av[i*3 + 2];
334  view->WCtoNDC(&r[i*3],&r[i*3]);
335  }
336 
337  // Draw frame
338  SetLineColor(1);
339  SetLineStyle(1);
340  SetLineWidth(1);
341  TAttLine::Modify();
342  for (Int_t i = 0; i < 4; ++i) {
343  Int_t k = iface1[i] - 1;
344  x[i] = r[k*3 + 0];
345  y[i] = r[k*3 + 1];
346  }
347  gPad->PaintPolyLine(4, x, y);
348  for (Int_t i = 0; i < 4; ++i) {
349  Int_t k = iface2[i] - 1;
350  x[i] = r[k*3 + 0];
351  y[i] = r[k*3 + 1];
352  }
353  gPad->PaintPolyLine(4, x, y);
354 }
355 
356 ////////////////////////////////////////////////////////////////////////////////
357 /// Clear screen
358 
359 void TPainter3dAlgorithms::ClearRaster()
360 {
361  Int_t nw = (fNxrast*fNyrast + 29) / 30;
362  for (Int_t i = 0; i < nw; ++i) fRaster[i] = 0;
363  fIfrast = 0;
364 }
365 
366 ////////////////////////////////////////////////////////////////////////////////
367 /// Set correspondence between function and color levels
368 ///
369 /// \param[in] nl number of levels
370 /// \param[in] fl function levels
371 /// \param[in] icl colors for levels
372 ///
373 /// \param[out] irep return code (0 OK, -1 error).
374 
375 void TPainter3dAlgorithms::ColorFunction(Int_t nl, Double_t *fl, Int_t *icl, Int_t &irep)
376 {
377  static const char *where = "ColorFunction";
378 
379  irep = 0;
380  if (nl == 0) {
381  fNlevel = 0;
382  return;
383  }
384 
385  // Check parameters
386  if (nl < 0 || nl > 256) {
387  Error(where, "illegal number of levels (%d)", nl);
388  irep = -1;
389  return;
390  }
391 
392  for (Int_t i = 1; i < nl; ++i) {
393  if (fl[i] <= fl[i - 1]) {
394  // Error(where, "function levels must be in increasing order");
395  irep = -1;
396  return;
397  }
398  }
399 
400  for (Int_t i = 0; i < nl; ++i) {
401  if (icl[i] < 0) {
402  // Error(where, "negative color index (%d)", icl[i]);
403  irep = -1;
404  return;
405  }
406  }
407 
408  // Set levels
409  fNlevel = nl;
410  for (Int_t i = 0; i < fNlevel; ++i) fFunLevel[i] = Hparam.factor*fl[i];
411  for (Int_t i = 0; i < fNlevel+1; ++i) fColorLevel[i] = icl[i];
412 }
413 
414 ////////////////////////////////////////////////////////////////////////////////
415 /// Define the grid levels drawn in the background of surface and lego plots.
416 /// The grid levels are aligned on the Z axis' main tick marks.
417 
418 void TPainter3dAlgorithms::DefineGridLevels(Int_t ndivz)
419 {
420  TView *view = 0;
421  if (gPad) view = gPad->GetView();
422  if (!view) {
423  Error("GridLevels", "no TView in current pad");
424  return;
425  }
426 
427  // Find the main tick marks positions
428  Int_t nbins = 0;
429  Double_t binLow = 0, binHigh = 0, binWidth = 0;
430  Double_t *rmin = view->GetRmin();
431  Double_t *rmax = view->GetRmax();
432  if (!rmin || !rmax) return;
433  if (ndivz > 0) {
434  THLimitsFinder::Optimize(rmin[2], rmax[2], ndivz,
435  binLow, binHigh, nbins, binWidth, " ");
436  } else {
437  nbins = TMath::Abs(ndivz);
438  binLow = rmin[2];
439  binHigh = rmax[2];
440  binWidth = (binHigh - binLow)/nbins;
441  }
442 
443  // Define the grid levels
444  fNlevel = nbins + 1;
445  for (Int_t i = 0; i < fNlevel; ++i) {
446  fFunLevel[i] = binLow + i*binWidth;
447  }
448 }
449 
450 ////////////////////////////////////////////////////////////////////////////////
451 /// Draw face - 1st variant (2 colors: 1st for external surface, 2nd for internal)
452 ///
453 /// \param[in] icodes set of codes for the line (not used in this method)
454 /// \param[in] xyz coordinates of nodes
455 /// \param[in] np number of nodes in face
456 /// \param[in] iface face
457 /// \param[in] t additional function defined on this face (not used in this method)
458 
459 void TPainter3dAlgorithms::DrawFaceMode1(Int_t *, Double_t *xyz, Int_t np, Int_t *iface, Double_t *)
460 {
461  TView *view = 0;
462  if (gPad) view = gPad->GetView();
463  if (!view) return;
464 
465  // Transfer to normalised coordinates
466  Bool_t ifneg = false;
467  Double_t x[12+1] = {0}, y[12+1] = {0}, p3[3];
468  for (Int_t i = 0; i < np; ++i) {
469  Int_t k = iface[i];
470  if (k < 0) { k = -k; ifneg = true; }
471  view->WCtoNDC(&xyz[(k-1)*3], p3);
472  x[i] = p3[0]; y[i] = p3[1];
473  }
474  x[np] = x[0]; y[np] = y[0];
475 
476  // Find normal
477  Double_t z = 0;
478  for (Int_t i = 0; i < np; ++i) {
479  z += y[i]*x[i+1] - x[i]*y[i+1];
480  }
481 
482  // Draw face
483  SetFillColor((z > 0) ? kF3FillColor1 : kF3FillColor2);
484  SetFillStyle(1001);
485  TAttFill::Modify();
486  gPad->PaintFillArea(np, x, y);
487 
488  // Draw border
489  SetLineColor(kF3LineColor);
490  TAttLine::Modify();
491  if (ifneg) {
492  for (Int_t i = 0; i < np; ++i) { // draw visible edges, skip invisible
493  if (iface[i] > 0) gPad->PaintPolyLine(2, &x[i], &y[i]);
494  }
495  } else {
496  gPad->PaintPolyLine(np+1, x, y); // all edges are visible
497  }
498 }
499 
500 ////////////////////////////////////////////////////////////////////////////////
501 /// Draw face - 2nd option (fill in correspondence with function levels)
502 ///
503 /// \param[in] icodes set of codes for the line (not used in this method)
504 /// \param[in] xyz coordinates of nodes
505 /// \param[in] np number of nodes
506 /// \param[in] iface face
507 /// \param[in] t additional function defined on this face
508 
509 void TPainter3dAlgorithms::DrawFaceMode2(Int_t *, Double_t *xyz, Int_t np, Int_t *iface, Double_t *t)
510 {
511  TView *view = 0;
512  if (gPad) view = gPad->GetView();
513  if (!view) return;
514 
515  // Transfer to normalised coordinates
516  Double_t x[12+1] = {0}, y[12+1] = {0}, p3[3*12];
517  for (Int_t i = 0; i < np; ++i) {
518  Int_t k = iface[i];
519  view->WCtoNDC(&xyz[(k-1)*3], &p3[i*3]);
520  x[i] = p3[i*3+0]; y[i] = p3[i*3+1];
521  }
522  x[np] = x[0]; y[np] = y[0];
523 
524  // Draw face
525  SetLineColor(fEdgeColor[fEdgeIdx]);
526  SetLineStyle(fEdgeStyle[fEdgeIdx]);
527  SetLineWidth(fEdgeWidth[fEdgeIdx]);
528  TAttLine::Modify();
529  if (np == 4) {
530  Double_t ttt[5] = { t[0], t[1], t[2], t[3], t[0] };
531  for (Int_t i = 0; i<3; ++i) { p3[3*4+i] = p3[i]; }
532  Int_t k1 = 0, k2 = 2;
533  Double_t z1 = (x[k1+1] - x[k1+0])*(y[k1+2] - y[k1+1]) - (y[k1+1] - y[k1+0])*(x[k1+2] - x[k1+1]);
534  Double_t z2 = (x[k2+1] - x[k2+0])*(y[k2+2] - y[k2+1]) - (y[k2+1] - y[k2+0])*(x[k2+2] - x[k2+1]);
535  if (z1 > z2) { k1 = 2; k2 = 0; }
536  FillPolygon(3, &p3[3*k1], &ttt[k1]);
537  if (fMesh == 1) { // Draw border
538  gPad->PaintPolyLine(3, &x[k1], &y[k1]);
539  }
540  FillPolygon(3, &p3[3*k2], &ttt[k2]);
541  if (fMesh == 1) { // Draw border
542  gPad->PaintPolyLine(3, &x[k2], &y[k2]);
543  if (z1*z2 <= 0) { // Draw middle line
544  x[1] = x[2]; y[1] = y[2];
545  gPad->PaintPolyLine(2, &x[0], &y[0]);
546  }
547  }
548  } else {
549  FillPolygon(np, p3, t);
550  if (fMesh == 1) { // Draw border
551  gPad->PaintPolyLine(np+1, x, y);
552  }
553  }
554 }
555 
556 ////////////////////////////////////////////////////////////////////////////////
557 /// Draw face - 3rd option (draw face for stacked lego plot)
558 ///
559 /// \param[in] icodes set of codes for the line
560 /// \param[in] xyz coordinates of nodes
561 /// \param[in] np number of nodes
562 /// \param[in] iface face
563 /// \param[in] t additional function defined on this face (not used in this method)
564 
565 void TPainter3dAlgorithms::DrawFaceMode3(Int_t *icodes, Double_t *xyz, Int_t np, Int_t *iface, Double_t *)
566 {
567  TView *view = 0;
568  if (gPad) view = gPad->GetView();
569  if (!view) return;
570 
571  // Transfer to normalised coordinates
572  Double_t x[4+1] = {0}, y[4+1] = {0}, p3[3];
573  for (Int_t i = 0; i < np; ++i) {
574  Int_t k = iface[i];
575  view->WCtoNDC(&xyz[(k-1)*3], p3);
576  x[i] = p3[0]; y[i] = p3[1];
577  }
578  x[np] = x[0]; y[np] = y[0];
579 
580  // Draw face
581  Int_t icol = 0;
582  if (icodes[3] == 6) icol = fColorTop;
583  if (icodes[3] == 5) icol = fColorBottom;
584  if (icodes[3] == 1) icol = fColorMain[icodes[2] - 1];
585  if (icodes[3] == 2) icol = fColorDark[icodes[2] - 1];
586  if (icodes[3] == 3) icol = fColorMain[icodes[2] - 1];
587  if (icodes[3] == 4) icol = fColorDark[icodes[2] - 1];
588  SetFillStyle(1001);
589  SetFillColor(icol);
590  TAttFill::Modify();
591  gPad->PaintFillArea(np, x, y);
592 
593  // Draw border
594  if (fMesh) {
595  SetLineColor(fEdgeColor[fEdgeIdx]);
596  SetLineStyle(fEdgeStyle[fEdgeIdx]);
597  SetLineWidth(fEdgeWidth[fEdgeIdx]);
598  TAttLine::Modify();
599  gPad->PaintPolyLine(np+1, x, y);
600  }
601 }
602 
603 ////////////////////////////////////////////////////////////////////////////////
604 /// Draw face - 1st variant for "MOVING SCREEN" algorithm (draw face with level lines)
605 ///
606 /// \param[in] icodes set of codes for the line
607 /// \param[in] xyz coordinates of nodes
608 /// \param[in] np number of nodes
609 /// \param[in] iface face
610 /// \param[in] tt additional function defined on this face
611 
612 void TPainter3dAlgorithms::DrawFaceMove1(Int_t *icodes, Double_t *xyz, Int_t np,
613  Int_t *iface, Double_t *tt)
614 {
615  TView *view = 0;
616  if (gPad) view = gPad->GetView();
617  if (!view) return;
618 
619  // Copy points to array
620  Double_t p3[3*12] = {0};
621  for (Int_t i = 0; i < np; ++i) {
622  Int_t k = iface[i];
623  p3[i*3 + 0] = xyz[(k-1)*3 + 0];
624  p3[i*3 + 1] = xyz[(k-1)*3 + 1];
625  p3[i*3 + 2] = xyz[(k-1)*3 + 2];
626  }
627 
628  // Find level lines
629  FindLevelLines(np, p3, tt);
630 
631  // Draw level lines
632  Double_t p1[3], p2[3], x[2], y[2];
633  SetLineStyle(3);
634  if (icodes[2] == 0) { // front & back boxes
635  SetLineColor(1);
636  SetLineWidth(1);
637  } else {
638  SetLineColor(fEdgeColor[fEdgeIdx]);
639  SetLineWidth(fEdgeWidth[fEdgeIdx]);
640  }
641  TAttLine::Modify();
642  for (Int_t il = 0; il < fNlines; ++il) {
643  FindVisibleDraw(&fPlines[6*il + 0], &fPlines[6*il + 3]);
644  view->WCtoNDC(&fPlines[6*il + 0], p1);
645  view->WCtoNDC(&fPlines[6*il + 3], p2);
646  Double_t xdel = p2[0] - p1[0];
647  Double_t ydel = p2[1] - p1[1];
648  for (Int_t it = 0; it < fNT; ++it) {
649  x[0] = p1[0] + xdel*fT[2*it + 0];
650  y[0] = p1[1] + ydel*fT[2*it + 0];
651  x[1] = p1[0] + xdel*fT[2*it + 1];
652  y[1] = p1[1] + ydel*fT[2*it + 1];
653  gPad->PaintPolyLine(2, x, y);
654  }
655  }
656 
657  // Draw face
658  if (icodes[2] == 0) { // front & back boxes
659  SetLineColor(1);
660  SetLineStyle(1);
661  SetLineWidth(1);
662  } else {
663  SetLineColor(fEdgeColor[fEdgeIdx]);
664  SetLineStyle(fEdgeStyle[fEdgeIdx]);
665  SetLineWidth(fEdgeWidth[fEdgeIdx]);
666  }
667  TAttLine::Modify();
668  for (Int_t i = 0; i < np; ++i) {
669  Int_t i1 = i;
670  Int_t i2 = (i == np-1) ? 0 : i + 1;
671  FindVisibleDraw(&p3[i1*3], &p3[i2*3]);
672  view->WCtoNDC(&p3[i1*3], p1);
673  view->WCtoNDC(&p3[i2*3], p2);
674  Double_t xdel = p2[0] - p1[0];
675  Double_t ydel = p2[1] - p1[1];
676  for (Int_t it = 0; it < fNT; ++it) {
677  x[0] = p1[0] + xdel*fT[2*it + 0];
678  y[0] = p1[1] + ydel*fT[2*it + 0];
679  x[1] = p1[0] + xdel*fT[2*it + 1];
680  y[1] = p1[1] + ydel*fT[2*it + 1];
681  gPad->PaintPolyLine(2, x, y);
682  }
683  }
684 
685  // Modify screen
686  for (Int_t i = 0; i < np; ++i) {
687  Int_t i1 = i;
688  Int_t i2 = (i == np-1) ? 0 : i + 1;
689  ModifyScreen(&p3[i1*3], &p3[i2*3]);
690  }
691 }
692 
693 ////////////////////////////////////////////////////////////////////////////////
694 /// Draw face - 2nd variant for "MOVING SCREEN" algorithm (draw face for stacked lego plot)
695 ///
696 /// \param[in] icodes set of codes for the line
697 /// \param[in] xyz coordinates of nodes
698 /// \param[in] np number of nodes
699 /// \param[in] iface face
700 /// \param[in] tt additional function defined on this face (not used in this method)
701 
702 void TPainter3dAlgorithms::DrawFaceMove2(Int_t *icodes, Double_t *xyz, Int_t np, Int_t *iface, Double_t *)
703 {
704  TView *view = 0;
705  if (gPad) view = gPad->GetView();
706  if (!view) return;
707 
708  // Copy points to array
709  Double_t p3[3*12];
710  for (Int_t i = 0; i < np; ++i) {
711  Int_t k = iface[i];
712  p3[i*3 + 0] = xyz[(k-1)*3 + 0];
713  p3[i*3 + 1] = xyz[(k-1)*3 + 1];
714  p3[i*3 + 2] = xyz[(k-1)*3 + 2];
715  }
716 
717  // Draw face
718  Double_t p1[3], p2[3], x[2], y[2];
719  if (icodes[2] == 0) { // front & back boxes
720  SetLineColor(1);
721  SetLineStyle(1);
722  SetLineWidth(1);
723  } else {
724  SetLineColor(fEdgeColor[fEdgeIdx]);
725  SetLineStyle(fEdgeStyle[fEdgeIdx]);
726  SetLineWidth(fEdgeWidth[fEdgeIdx]);
727  }
728  TAttLine::Modify();
729  for (Int_t i = 0; i < np; ++i) {
730  Int_t i1 = i;
731  Int_t i2 = (i == np-1) ? 0 : i + 1;
732  FindVisibleDraw(&p3[i1*3], &p3[i2*3]);
733  view->WCtoNDC(&p3[i1*3], p1);
734  view->WCtoNDC(&p3[i2*3], p2);
735  Double_t xdel = p2[0] - p1[0];
736  Double_t ydel = p2[1] - p1[1];
737  for (Int_t it = 0; it < fNT; ++it) {
738  x[0] = p1[0] + xdel*fT[2*it + 0];
739  y[0] = p1[1] + ydel*fT[2*it + 0];
740  x[1] = p1[0] + xdel*fT[2*it + 1];
741  y[1] = p1[1] + ydel*fT[2*it + 1];
742  gPad->PaintPolyLine(2, x, y);
743  }
744  }
745 
746  // Modify screen
747  for (Int_t i = 0; i < np; ++i) {
748  Int_t i1 = i;
749  Int_t i2 = (i == np-1) ? 0 : i + 1;
750  ModifyScreen(&p3[i1*3], &p3[i2*3]);
751  }
752 }
753 
754 ////////////////////////////////////////////////////////////////////////////////
755 /// Draw face - 3rd variant for "MOVING SCREEN" algorithm (draw level lines only)
756 ///
757 /// \param[in] icodes set of codes for the line
758 /// \param[in] xyz coordinates of nodes
759 /// \param[in] np number of nodes
760 /// \param[in] iface face
761 /// \param[in] tt additional function defined on this face
762 
763 void TPainter3dAlgorithms::DrawFaceMove3(Int_t *icodes, Double_t *xyz, Int_t np,
764  Int_t *iface, Double_t *tt)
765 {
766  TView *view = 0;
767  if (gPad) view = gPad->GetView();
768  if (!view) return;
769 
770  // Set graphics attributes
771  if (icodes[2] == 0) { // frame
772  SetLineColor(1);
773  SetLineStyle(1);
774  SetLineWidth(1);
775  } else {
776  SetLineColor(fEdgeColor[fEdgeIdx]);
777  SetLineStyle(fEdgeStyle[fEdgeIdx]);
778  SetLineWidth(fEdgeWidth[fEdgeIdx]);
779  }
780  TAttLine::Modify();
781 
782  // Copy points to array
783  Double_t p3[3*12] = {0}, ttt[12] = {0};
784  for (Int_t i = 0; i < np; ++i) {
785  Int_t k = iface[i];
786  p3[i*3 + 0] = xyz[(k-1)*3 + 0];
787  p3[i*3 + 1] = xyz[(k-1)*3 + 1];
788  p3[i*3 + 2] = xyz[(k-1)*3 + 2];
789  ttt[i] = tt[i];
790  }
791 
792  // Subdivide quadrilateral in two triangles
793  Int_t npol[2] = { np, 0 }; // number of vertices in subpolygons
794  Int_t ipol[2] = { 0, 0 }; // first vertices in subpolygons
795  if (np == 4 && icodes[2] != 0) {
796  p3[4*3 + 0] = p3[0];
797  p3[4*3 + 1] = p3[1];
798  p3[4*3 + 2] = p3[2];
799  ttt[4] = tt[0];
800  npol[0] = 3; npol[1] = 3;
801  ipol[0] = 0; ipol[1] = 2;
802  }
803 
804  Double_t p1[3], p2[3], x[2], y[2];
805  for (Int_t kpol = 0; kpol < 2; ++kpol) {
806  if (npol[kpol] == 0) continue;
807  Int_t nv = npol[kpol];
808  Int_t iv = ipol[kpol];
809 
810  // Find level lines
811  FindLevelLines(nv, &p3[3*iv], &ttt[iv]);
812 
813  // Draw level lines
814  for (Int_t il = 0; il < fNlines; ++il) {
815  FindVisibleDraw(&fPlines[6*il + 0], &fPlines[6*il + 3]);
816  view->WCtoNDC(&fPlines[6*il + 0], p1);
817  view->WCtoNDC(&fPlines[6*il + 3], p2);
818  Double_t xdel = p2[0] - p1[0];
819  Double_t ydel = p2[1] - p1[1];
820  for (Int_t it = 0; it < fNT; ++it) {
821  x[0] = p1[0] + xdel*fT[2*it + 0];
822  y[0] = p1[1] + ydel*fT[2*it + 0];
823  x[1] = p1[0] + xdel*fT[2*it + 1];
824  y[1] = p1[1] + ydel*fT[2*it + 1];
825  gPad->PaintPolyLine(2, x, y);
826  }
827  }
828  }
829 
830  // Modify screen
831  for (Int_t i = 0; i < np; ++i) {
832  Int_t i1 = i;
833  Int_t i2 = (i == np - 1) ? 0 : i1 + 1;
834  ModifyScreen(&p3[i1*3], &p3[i2*3]);
835  }
836 }
837 
838 ////////////////////////////////////////////////////////////////////////////////
839 /// Draw level lines without hidden line removal
840 ///
841 /// \param[in] icodes set of codes for the line
842 /// \param[in] xyz coordinates of nodes
843 /// \param[in] np number of nodes
844 /// \param[in] iface face
845 /// \param[in] tt additional function defined on this face
846 
847 void TPainter3dAlgorithms::DrawLevelLines(Int_t *icodes, Double_t *xyz, Int_t np,
848  Int_t *iface, Double_t *tt)
849 {
850  TView *view = 0;
851  if (gPad) view = gPad->GetView();
852  if (!view) return;
853 
854  // Set graphics attributes
855  if (icodes[2] == 0) { // frame
856  SetLineColor(1);
857  SetLineStyle(1);
858  SetLineWidth(1);
859  } else {
860  SetLineColor(fEdgeColor[fEdgeIdx]);
861  SetLineStyle(fEdgeStyle[fEdgeIdx]);
862  SetLineWidth(fEdgeWidth[fEdgeIdx]);
863  }
864  TAttLine::Modify();
865 
866  // Copy points to array
867  Double_t p3[3*12] = {0}, ttt[12] = {0};
868  for (Int_t i = 0; i < np; ++i) {
869  Int_t k = iface[i];
870  p3[i*3 + 0] = xyz[(k-1)*3 + 0];
871  p3[i*3 + 1] = xyz[(k-1)*3 + 1];
872  p3[i*3 + 2] = xyz[(k-1)*3 + 2];
873  ttt[i] = tt[i];
874  }
875 
876  // Subdivide quadrilateral in two triangles
877  Int_t npol[2] = { np, 0 }; // number of vertices in subpolygons
878  Int_t ipol[2] = { 0, 0 }; // first vertices in subpolygons
879  if (np == 4 && icodes[2] != 0) {
880  p3[4*3 + 0] = p3[0];
881  p3[4*3 + 1] = p3[1];
882  p3[4*3 + 2] = p3[2];
883  ttt[4] = tt[0];
884  npol[0] = 3; npol[1] = 3;
885  ipol[0] = 0; ipol[1] = 2;
886  }
887 
888  Double_t p1[3], p2[3], x[2], y[2];
889  for (Int_t kpol = 0; kpol < 2; ++kpol) {
890  if (npol[kpol] == 0) continue;
891  Int_t nv = npol[kpol];
892  Int_t iv = ipol[kpol];
893 
894  // Find level lines
895  FindLevelLines(nv, &p3[3*iv], &ttt[iv]);
896 
897  // Draw level lines
898  for (Int_t il = 0; il < fNlines; ++il) {
899  view->WCtoNDC(&fPlines[6*il + 0], p1);
900  view->WCtoNDC(&fPlines[6*il + 3], p2);
901  x[0] = p1[0]; y[0] = p1[1];
902  x[1] = p2[0]; y[1] = p2[1];
903  gPad->PaintPolyLine(2, x, y);
904  }
905  }
906 }
907 
908 ////////////////////////////////////////////////////////////////////////////////
909 /// Draw face - 1st variant for "RASTER SCREEN" algorithm (draw face with level lines)
910 ///
911 /// \param[in] icodes set of codes for the line
912 /// \param[in] xyz coordinates of nodes
913 /// \param[in] np number of nodes
914 /// \param[in] iface face
915 /// \param[in] tt additional function defined on this face
916 
917 void TPainter3dAlgorithms::DrawFaceRaster1(Int_t *icodes, Double_t *xyz, Int_t np, Int_t *iface, Double_t *tt)
918 {
919  TView *view = 0;
920  if (gPad) view = gPad->GetView();
921  if (!view) return;
922 
923  // Copy vertices to array
924  Double_t p3[3*12] = {0}, pp[2*12] = {0};
925  for (Int_t i = 0; i < np; ++i) {
926  Int_t k = iface[i];
927  if (k < 0) k = -k;
928  p3[i*3 + 0] = xyz[(k-1)*3 + 0];
929  p3[i*3 + 1] = xyz[(k-1)*3 + 1];
930  p3[i*3 + 2] = xyz[(k-1)*3 + 2];
931  Double_t p[3];
932  view->WCtoNDC(&p3[i*3], p);
933  pp[2*i + 0] = p[0];
934  pp[2*i + 1] = p[1];
935  }
936 
937  // Find level lines
938  FindLevelLines(np, p3, tt);
939 
940  // Draw level lines
941  Double_t p1[3], p2[3], x[2], y[2];
942  SetLineStyle(3);
943  if (icodes[2] == 0) { // front & back boxes
944  SetLineColor(1);
945  SetLineWidth(1);
946  } else {
947  SetLineColor(fEdgeColor[fEdgeIdx]);
948  SetLineWidth(fEdgeWidth[fEdgeIdx]);
949  }
950  TAttLine::Modify();
951  for (Int_t il = 0; il < fNlines; ++il) {
952  view->WCtoNDC(&fPlines[6*il + 0], p1);
953  view->WCtoNDC(&fPlines[6*il + 3], p2);
954  FindVisibleLine(p1, p2, 100, fNT, fT);
955  Double_t xdel = p2[0] - p1[0];
956  Double_t ydel = p2[1] - p1[1];
957  for (Int_t it = 0; it < fNT; ++it) {
958  x[0] = p1[0] + xdel*fT[2*it + 0];
959  y[0] = p1[1] + ydel*fT[2*it + 0];
960  x[1] = p1[0] + xdel*fT[2*it + 1];
961  y[1] = p1[1] + ydel*fT[2*it + 1];
962  gPad->PaintPolyLine(2, x, y);
963  }
964  }
965 
966  // Draw face
967  if (icodes[2] == 0) { // front & back boxes
968  SetLineColor(1);
969  SetLineStyle(1);
970  SetLineWidth(1);
971  } else {
972  SetLineColor(fEdgeColor[fEdgeIdx]);
973  SetLineStyle(fEdgeStyle[fEdgeIdx]);
974  SetLineWidth(fEdgeWidth[fEdgeIdx]);
975  }
976  TAttLine::Modify();
977  for (Int_t i = 0; i < np; ++i) {
978  if (iface[i] < 0) continue;
979  Int_t i1 = i;
980  Int_t i2 = (i == np-1) ? 0 : i + 1;
981  FindVisibleLine(&pp[2*i1], &pp[2*i2], 100, fNT, fT);
982  Double_t xdel = pp[2*i2 + 0] - pp[2*i1 + 0];
983  Double_t ydel = pp[2*i2 + 1] - pp[2*i1 + 1];
984  for (Int_t it = 0; it < fNT; ++it) {
985  x[0] = pp[2*i1 + 0] + xdel*fT[2*it + 0];
986  y[0] = pp[2*i1 + 1] + ydel*fT[2*it + 0];
987  x[1] = pp[2*i1 + 0] + xdel*fT[2*it + 1];
988  y[1] = pp[2*i1 + 1] + ydel*fT[2*it + 1];
989  gPad->PaintPolyLine(2, x, y);
990  }
991  }
992 
993  // Modify raster screen
994  FillPolygonBorder(np, pp);
995 }
996 
997 ////////////////////////////////////////////////////////////////////////////////
998 /// Draw face - 2nd variant for "RASTER SCREEN" algorithm (draw face for stacked lego plot)
999 ///
1000 /// \param[in] icodes set of codes for the line (not used in this method)
1001 /// \param[in] xyz coordinates of nodes
1002 /// \param[in] np number of nodes
1003 /// \param[in] iface face
1004 /// \param[in] tt additional function defined on this face (not used in this method)
1005 
1006 void TPainter3dAlgorithms::DrawFaceRaster2(Int_t *, Double_t *xyz, Int_t np, Int_t *iface, Double_t *)
1007 {
1008  TView *view = 0;
1009  if (gPad) view = gPad->GetView();
1010  if (!view) return;
1011 
1012  // Copy vertices to array
1013  Double_t x[2], y[2], pp[2*12];
1014  for (Int_t i = 0; i < np; ++i) {
1015  Int_t k = iface[i];
1016  if (k < 0) k = -k;
1017  Double_t p[3];
1018  view->WCtoNDC(&xyz[(k-1)*3], p);
1019  pp[2*i + 0] = p[0];
1020  pp[2*i + 1] = p[1];
1021  }
1022 
1023  // Draw face
1024  SetLineColor(fEdgeColor[fEdgeIdx]);
1025  SetLineStyle(fEdgeStyle[fEdgeIdx]);
1026  SetLineWidth(fEdgeWidth[fEdgeIdx]);
1027  TAttLine::Modify();
1028  for (Int_t i = 0; i < np; ++i) {
1029  if (iface[i] < 0) continue;
1030  Int_t i1 = i;
1031  Int_t i2 = (i == np-1) ? 0 : i + 1;
1032  FindVisibleLine(&pp[2*i1], &pp[2*i2], 100, fNT, fT);
1033  Double_t xdel = pp[2*i2 + 0] - pp[2*i1 + 0];
1034  Double_t ydel = pp[2*i2 + 1] - pp[2*i1 + 1];
1035  for (Int_t it = 0; it < fNT; ++it) {
1036  x[0] = pp[2*i1 + 0] + xdel*fT[2*it + 0];
1037  y[0] = pp[2*i1 + 1] + ydel*fT[2*it + 0];
1038  x[1] = pp[2*i1 + 0] + xdel*fT[2*it + 1];
1039  y[1] = pp[2*i1 + 1] + ydel*fT[2*it + 1];
1040  gPad->PaintPolyLine(2, x, y);
1041  }
1042  }
1043 
1044  // Modify raster screen
1045  FillPolygonBorder(np, pp);
1046 }
1047 
1048 ////////////////////////////////////////////////////////////////////////////////
1049 /// Fill polygon with function values at vertexes
1050 ///
1051 /// \param[in] n number of vertexes
1052 /// \param[in] p polygon
1053 /// \param[in] f function values at nodes
1054 ///
1055 /// Errors:
1056 /// - illegal number of vertexes in polygon
1057 /// - illegal call of FillPolygon: no levels
1058 
1059 void TPainter3dAlgorithms::FillPolygon(Int_t n, Double_t *p, Double_t *f)
1060 {
1061  Int_t ilev, i, k, icol, i1, i2, nl, np;
1062  Double_t fmin, fmax;
1063  Double_t x[12], y[12], f1, f2;
1064  Double_t p3[36] /* was [3][12] */;
1065  Double_t funmin, funmax;
1066 
1067  /* Parameter adjustments */
1068  --f;
1069  p -= 4;
1070 
1071  if (n < 3) {
1072  Error("FillPolygon", "illegal number of vertices in polygon (%d)", n);
1073  return;
1074  }
1075 
1076  if (fNlevel == 0) {
1077  // Illegal call of FillPolygon: no levels
1078  return;
1079  }
1080  np = n;
1081  nl = fNlevel;
1082  if (nl < 0) nl = -nl;
1083  fmin = f[1];
1084  fmax = f[1];
1085  for (i = 2; i <= np; ++i) {
1086  if (fmin > f[i]) fmin = f[i];
1087  if (fmax < f[i]) fmax = f[i];
1088  }
1089  funmin = fFunLevel[0] - 1;
1090  if (fmin < funmin) funmin = fmin - 1;
1091  funmax = fFunLevel[nl - 1] + 1;
1092  if (fmax > funmax) funmax = fmax + 1;
1093 
1094  // F I N D A N D D R A W S U B P O L Y G O N S
1095  f2 = funmin;
1096  for (ilev = 1; ilev <= nl+1; ++ilev) {
1097  // S E T L E V E L L I M I T S
1098  f1 = f2;
1099  if (ilev == nl + 1) f2 = funmax;
1100  else f2 = fFunLevel[ilev - 1];
1101  if (fmax < f1) return;
1102  if (fmin > f2) continue;
1103  // F I N D S U B P O L Y G O N
1104  k = 0;
1105  for (i = 1; i <= np; ++i) {
1106  i1 = i;
1107  i2 = i + 1;
1108  if (i == np) i2 = 1;
1109  FindPartEdge(&p[i1*3 + 1], &p[i2*3 + 1], f[i1], f[i2], f1, f2, k, p3);
1110  }
1111  // D R A W S U B P O L Y G O N
1112  if (k < 3) continue;
1113  for (i = 1; i <= k; ++i) {
1114  x[i-1] = p3[i*3-3];
1115  y[i-1] = p3[i*3-2];
1116  if (TMath::IsNaN(x[i-1]) || TMath::IsNaN(y[i-1])) return;
1117  }
1118  if (ilev==1) {
1119  icol=gPad->GetFillColor();
1120  } else {
1121  icol = fColorLevel[ilev - 2];
1122  }
1123  SetFillColor(icol);
1124  SetFillStyle(1001);
1125  TAttFill::Modify();
1126  gPad->PaintFillArea(k, x, y);
1127  }
1128 }
1129 
1130 ////////////////////////////////////////////////////////////////////////////////
1131 /// Fill a polygon including border ("RASTER SCREEN")
1132 ///
1133 /// \param[in] nn number of polygon nodes
1134 /// \param[in] xy polygon nodes
1135 
1136 void TPainter3dAlgorithms::FillPolygonBorder(Int_t nn, Double_t *xy)
1137 {
1138  Int_t kbit, nbit, step, ymin, ymax, test[kLmax], xcur[kLmax], xnex[kLmax],
1139  i, j, k, n, ibase, t, x, y, xscan[24] /* was [2][kLmax] */,
1140  yscan, x1[kLmax+2], y1[kLmax+2], x2[kLmax+2], y2[kLmax+2],
1141  ib, nb, dx, dy, iw, nx, xx, yy, signdx, nstart, xx1, xx2, nxa, nxb;
1142 
1143  // T R A N S F E R T O S C R E E N C O O R D I N A T E S
1144  /* Parameter adjustments */
1145  xy -= 3;
1146 
1147  if (fIfrast) return;
1148 
1149  n = nn;
1150  x1[0] = 0;
1151  y1[0] = 0;
1152  for (i = 1; i <= n; ++i) {
1153  x1[i - 1] = Int_t(fNxrast*((xy[2*i + 1] - fXrast) /fDXrast) - 0.01);
1154  y1[i - 1] = Int_t(fNyrast*((xy[2*i + 2] - fYrast) /fDYrast) - 0.01);
1155  }
1156  x1[n] = x1[0];
1157  y1[n] = y1[0];
1158 
1159  // F I N D Y - M I N A N D Y - M A X
1160  // S E T R I G H T E D G E O R I E N T A T I O N
1161  ymin = y1[0];
1162  ymax = y1[0];
1163  for (i = 1; i <= n; ++i) {
1164  if (ymin > y1[i - 1]) ymin = y1[i - 1];
1165  if (ymax < y1[i - 1]) ymax = y1[i - 1];
1166  if (y1[i - 1] <= y1[i]) {x2[i - 1] = x1[i]; y2[i - 1] = y1[i];}
1167  else {
1168  x2[i - 1] = x1[i - 1];
1169  y2[i - 1] = y1[i - 1];
1170  x1[i - 1] = x1[i];
1171  y1[i - 1] = y1[i];
1172  }
1173  }
1174  if (ymin >= fNyrast) return;
1175  if (ymax < 0) return;
1176  if (ymax >= fNyrast) ymax = fNyrast - 1;
1177 
1178  // S O R T L I N E S
1179  for (i = 1; i < n; ++i) {
1180  if (y1[i] >= y1[i - 1]) continue;
1181  y = y1[i];
1182  k = 1;
1183  for (j = i - 1; j >= 1; --j) {
1184  if (y < y1[j - 1]) continue;
1185  k = j + 1;
1186  break;
1187  }
1188  x = x1[i];
1189  xx = x2[i];
1190  yy = y2[i];
1191  for (j = i; j >= k; --j) {
1192  x1[j] = x1[j - 1];
1193  y1[j] = y1[j - 1];
1194  x2[j] = x2[j - 1];
1195  y2[j] = y2[j - 1];
1196  }
1197  x1[k - 1] = x;
1198  y1[k - 1] = y;
1199  x2[k - 1] = xx;
1200  y2[k - 1] = yy;
1201  }
1202 
1203  // S E T I N I T I A L V A L U E S
1204  for (i = 1; i <= n; ++i) {
1205  xcur[i - 1] = x1[i - 1];
1206  dy = y2[i - 1] - y1[i - 1];
1207  dx = x2[i - 1] - x1[i - 1];
1208  signdx = 1;
1209  if (dx < 0) signdx = -1;
1210  if (dx < 0) dx = -dx;
1211  if (dx <= dy) {
1212  t = -(dy + 1) / 2 + dx;
1213  if (t < 0) {
1214  test[i - 1] = t;
1215  xnex[i - 1] = xcur[i - 1];
1216  } else {
1217  test[i - 1] = t - dy;
1218  xnex[i - 1] = xcur[i - 1] + signdx;
1219  }
1220  } else if (dy != 0) {
1221  step = (dx - 1) / (dy + dy) + 1;
1222  test[i - 1] = step*dy - (dx + 1) / 2 - dx;
1223  xnex[i - 1] = xcur[i - 1] + signdx*step;
1224  }
1225  }
1226 
1227  // L O O P O N S C A N L I N E S
1228  nstart = 1;
1229  for (yscan = ymin; yscan <= ymax; ++yscan) {
1230  nx = 0;
1231  nxa = 0;
1232  nxb = kLmax + 1;
1233  for (i = nstart; i <= n; ++i) {
1234  if (y1[i - 1] > yscan) goto L500;
1235  if (y2[i - 1] <= yscan) {
1236  if (i == nstart) ++nstart;
1237  if (y2[i - 1] != yscan)continue;
1238  --nxb;
1239  if (x2[i - 1] >= xcur[i - 1]) {
1240  xscan[2*nxb - 2] = xcur[i - 1];
1241  xscan[2*nxb - 1] = x2[i - 1];
1242  } else {
1243  xscan[2*nxb - 2] = x2[i - 1];
1244  xscan[2*nxb - 1] = xcur[i - 1];
1245  }
1246  continue;
1247  }
1248 
1249  // S T O R E C U R R E N T X
1250  // P R E P A R E X F O R N E X T S C A N - L I N E
1251  ++nxa;
1252  dy = y2[i - 1] - y1[i - 1];
1253  dx = x2[i - 1] - x1[i - 1];
1254  if (dx >= 0) {
1255  signdx = 1;
1256  xscan[2*nxa - 2] = xcur[i - 1];
1257  xscan[2*nxa - 1] = xnex[i - 1];
1258  if (xscan[2*nxa - 2] != xscan[2*nxa - 1]) {
1259  --xscan[2*nxa - 1];
1260  }
1261  } else {
1262  dx = -dx;
1263  signdx = -1;
1264  xscan[2*nxa - 2] = xnex[i - 1];
1265  xscan[2*nxa - 1] = xcur[i - 1];
1266  if (xscan[2*nxa - 2] != xscan[2*nxa - 1]) {
1267  ++xscan[2*nxa - 2];
1268  }
1269  }
1270  xcur[i - 1] = xnex[i - 1];
1271  if (dx <= dy) {
1272  test[i - 1] += dx;
1273  if (test[i - 1] < 0) continue;
1274  test[i - 1] -= dy;
1275  xnex[i - 1] += signdx;
1276  continue;
1277  }
1278  step = dx / dy;
1279  t = test[i - 1] + step*dy;
1280  if (t >= 0) {
1281  test[i - 1] = t - dx;
1282  xnex[i - 1] += signdx*step;
1283  } else {
1284  test[i - 1] = t + dy - dx;
1285  xnex[i - 1] += signdx*(step + 1);
1286  }
1287  }
1288 
1289  // S O R T P O I N T S A L O N G X
1290 L500:
1291  if (yscan < 0) continue;
1292  ibase = yscan*fNxrast;
1293  if (nxa >= 2) {
1294  for (i = 1; i < nxa; ++i) {
1295  for (j = i; j >= 1; --j) {
1296  if (xscan[2*j] >= xscan[2*j - 2]) continue;
1297  x = xscan[2*j];
1298  xscan[2*j] = xscan[2*j - 2];
1299  xscan[2*j - 2] = x;
1300  x = xscan[2*j - 1];
1301  xscan[2*j + 1] = xscan[2*j - 1];
1302  xscan[2*j - 1] = x;
1303  }
1304  }
1305  for (i = 1; i <= nxa; i += 2) {
1306  ++nx;
1307  xscan[2*nx - 2] = xscan[2*i - 2];
1308  x = xscan[2*i + 1];
1309  if (xscan[2*i - 1] > x) x = xscan[2*i - 1];
1310  xscan[2*nx - 1] = x;
1311  }
1312  }
1313  if (nxb <= kLmax) {
1314  for (i = nxb; i <= kLmax; ++i) {
1315  ++nx;
1316  xscan[2*nx - 2] = xscan[2*i - 2];
1317  xscan[2*nx - 1] = xscan[2*i - 1];
1318  }
1319  }
1320  // C O N C A T E N A T E A N D F I L L
1321  while (nx) {
1322  xx1 = xscan[2*nx - 2];
1323  xx2 = xscan[2*nx - 1];
1324  --nx;
1325  k = 1;
1326  while (k <= nx) {
1327  if ((xscan[2*k - 2] <= xx2 + 1) && (xscan[2*k - 1] >= xx1 - 1)) {
1328  if (xscan[2*k - 2] < xx1) xx1 = xscan[2*k - 2];
1329  if (xscan[2*k - 1] > xx2) xx2 = xscan[2*k - 1];
1330  xscan[2*k - 2] = xscan[2*nx - 2];
1331  xscan[2*k - 1] = xscan[2*nx - 1];
1332  --nx;
1333  } else ++k;
1334  }
1335  if (xx1 < 0) xx1 = 0;
1336  if (xx2 >= fNxrast) xx2 = fNxrast - 1;
1337  nbit = xx2 - xx1 + 1;
1338  kbit = ibase + xx1;
1339  iw = kbit / 30;
1340  ib = kbit - iw*30 + 1;
1341  iw = iw + 1;
1342  nb = 30 - ib + 1;
1343  if (nb > nbit) nb = nbit;
1344  fRaster[iw - 1] = fRaster[iw - 1] | fMask[fJmask[nb - 1] + ib - 1];
1345  nbit -= nb;
1346  if (nbit) {
1347  while(nbit > 30) {
1348  fRaster[iw] = fMask[464];
1349  ++iw;
1350  nbit += -30;
1351  }
1352  fRaster[iw] = fRaster[iw] | fMask[fJmask[nbit - 1]];
1353  ++iw;
1354  }
1355  }
1356  }
1357 }
1358 
1359 ////////////////////////////////////////////////////////////////////////////////
1360 /// Find level lines for face
1361 ///
1362 /// \param[in] np number of nodes
1363 /// \param[in] f face
1364 /// \param[in] t additional function
1365 ///
1366 /// Error: number of points for line not equal 2
1367 
1368 void TPainter3dAlgorithms::FindLevelLines(Int_t np, Double_t *f, Double_t *t)
1369 {
1370  fNlines = 0;
1371  if (fNlevel == 0) return;
1372  Int_t nl = TMath::Abs(fNlevel);
1373 
1374  // Find Tmin and Tmax
1375  Double_t tmin = t[0];
1376  Double_t tmax = t[0];
1377  for (Int_t i = 1; i < np; ++i) {
1378  if (t[i] < tmin) tmin = t[i];
1379  if (t[i] > tmax) tmax = t[i];
1380  }
1381  if (tmin >= fFunLevel[nl - 1]) return;
1382  if (tmax <= fFunLevel[0]) return;
1383 
1384  // Find level lines
1385  for (Int_t il = 1; il <= nl; ++il) {
1386  if (tmin >= fFunLevel[il - 1]) continue;
1387  if (tmax < fFunLevel[il - 1]) return;
1388  if (fNlines >= 200) return;
1389  fNlines++;
1390  fLevelLine[fNlines - 1] = il;
1391  Int_t kp = 0;
1392  for (Int_t i = 0; i < np; ++i) {
1393  Int_t i1 = i;
1394  Int_t i2 = (i == np-1) ? 0 : i+1;
1395  Double_t d1 = t[i1] - fFunLevel[il - 1];
1396  Double_t d2 = t[i2] - fFunLevel[il - 1];
1397  if (d1 == 0) d1 = 1e-99;
1398  if (d2 == 0) d2 = 1e-99;
1399  if (d1*d2 > 0) continue;
1400 
1401  // find point
1402  kp++;
1403  d1 /= t[i2] - t[i1];
1404  d2 /= t[i2] - t[i1];
1405  fPlines[(kp + 2*fNlines)*3 - 9] = d2*f[i1*3 + 0] - d1*f[i2*3 + 0];
1406  fPlines[(kp + 2*fNlines)*3 - 8] = d2*f[i1*3 + 1] - d1*f[i2*3 + 1];
1407  fPlines[(kp + 2*fNlines)*3 - 7] = d2*f[i1*3 + 2] - d1*f[i2*3 + 2];
1408  if (kp == 2) break;
1409  }
1410  if (kp != 2) {
1411  Error("FindLevelLines", "number of points for line not equal 2");
1412  fNlines--;
1413  }
1414  }
1415 }
1416 
1417 ////////////////////////////////////////////////////////////////////////////////
1418 /// Find part of edge where function defined on this edge has value from
1419 /// `fmin` to `fmax`
1420 ///
1421 /// \param[in] p1 1st point
1422 /// \param[in] p2 2nd point
1423 /// \param[in] f1 function value at 1st point
1424 /// \param[in] f2 function value at 2nd point
1425 /// \param[in] fmin min value of layer
1426 /// \param[in] fmax max value of layer
1427 ///
1428 /// \param[out] kpp current number of point
1429 /// \param[out] pp coordinates of new face
1430 
1431 void TPainter3dAlgorithms::FindPartEdge(Double_t *p1, Double_t *p2, Double_t f1,
1432  Double_t f2, Double_t fmin,
1433  Double_t fmax, Int_t &kpp, Double_t *pp)
1434 {
1435  Double_t d1, d2;
1436  Int_t k1, k2, kk;
1437 
1438  /* Parameter adjustments */
1439  pp -= 4;
1440  --p2;
1441  --p1;
1442 
1443  k1 = 0;
1444  if (f1 < fmin) k1 = -2;
1445  if (f1 == fmin) k1 = -1;
1446  if (f1 == fmax) k1 = 1;
1447  if (f1 > fmax) k1 = 2;
1448  k2 = 0;
1449  if (f2 < fmin) k2 = -2;
1450  if (f2 == fmin) k2 = -1;
1451  if (f2 == fmax) k2 = 1;
1452  if (f2 > fmax) k2 = 2;
1453  kk = (k1 + 2)*5 + (k2 + 2) + 1;
1454 
1455  // K2: -2 -1 0 +1 +2
1456  // K1: -2 -1 0 +1 +2
1457  switch ((int)kk) {
1458  case 1: return;
1459  case 2: return;
1460  case 3: goto L200;
1461  case 4: goto L200;
1462  case 5: goto L600;
1463  case 6: goto L100;
1464  case 7: goto L100;
1465  case 8: goto L100;
1466  case 9: goto L100;
1467  case 10: goto L500;
1468  case 11: goto L400;
1469  case 12: goto L100;
1470  case 13: goto L100;
1471  case 14: goto L100;
1472  case 15: goto L500;
1473  case 16: goto L400;
1474  case 17: goto L100;
1475  case 18: goto L100;
1476  case 19: goto L100;
1477  case 20: goto L100;
1478  case 21: goto L700;
1479  case 22: goto L300;
1480  case 23: goto L300;
1481  case 24: return;
1482  case 25: return;
1483  }
1484 
1485  // 1 - S T P O I N T
1486 L100:
1487  ++kpp;
1488  pp[kpp*3 + 1] = p1[1];
1489  pp[kpp*3 + 2] = p1[2];
1490  pp[kpp*3 + 3] = p1[3];
1491  return;
1492 
1493  // I N T E R S E C T I O N W I T H Fmin
1494 L200:
1495  ++kpp;
1496  d1 = (fmin - f1) / (f1 - f2);
1497  d2 = (fmin - f2) / (f1 - f2);
1498  pp[kpp*3 + 1] = d2*p1[1] - d1*p2[1];
1499  pp[kpp*3 + 2] = d2*p1[2] - d1*p2[2];
1500  pp[kpp*3 + 3] = d2*p1[3] - d1*p2[3];
1501  return;
1502 
1503  // I N T E R S E C T I O N W I T H Fmax
1504 L300:
1505  ++kpp;
1506  d1 = (fmax - f1) / (f1 - f2);
1507  d2 = (fmax - f2) / (f1 - f2);
1508  pp[kpp*3 + 1] = d2*p1[1] - d1*p2[1];
1509  pp[kpp*3 + 2] = d2*p1[2] - d1*p2[2];
1510  pp[kpp*3 + 3] = d2*p1[3] - d1*p2[3];
1511  return;
1512 
1513  // 1 - S T P O I N T, I N T E R S E C T I O N WITH Fmin
1514 L400:
1515  ++kpp;
1516  pp[kpp*3 + 1] = p1[1];
1517  pp[kpp*3 + 2] = p1[2];
1518  pp[kpp*3 + 3] = p1[3];
1519  ++kpp;
1520  d1 = (fmin - f1) / (f1 - f2);
1521  d2 = (fmin - f2) / (f1 - f2);
1522  pp[kpp*3 + 1] = d2*p1[1] - d1*p2[1];
1523  pp[kpp*3 + 2] = d2*p1[2] - d1*p2[2];
1524  pp[kpp*3 + 3] = d2*p1[3] - d1*p2[3];
1525  return;
1526 
1527  // 1 - S T P O I N T, I N T E R S E C T I O N WITH Fmax
1528 L500:
1529  ++kpp;
1530  pp[kpp*3 + 1] = p1[1];
1531  pp[kpp*3 + 2] = p1[2];
1532  pp[kpp*3 + 3] = p1[3];
1533  ++kpp;
1534  d1 = (fmax - f1) / (f1 - f2);
1535  d2 = (fmax - f2) / (f1 - f2);
1536  pp[kpp*3 + 1] = d2*p1[1] - d1*p2[1];
1537  pp[kpp*3 + 2] = d2*p1[2] - d1*p2[2];
1538  pp[kpp*3 + 3] = d2*p1[3] - d1*p2[3];
1539  return;
1540 
1541  // I N T E R S E C T I O N W I T H Fmin, Fmax
1542 L600:
1543  ++kpp;
1544  d1 = (fmin - f1) / (f1 - f2);
1545  d2 = (fmin - f2) / (f1 - f2);
1546  pp[kpp*3 + 1] = d2*p1[1] - d1*p2[1];
1547  pp[kpp*3 + 2] = d2*p1[2] - d1*p2[2];
1548  pp[kpp*3 + 3] = d2*p1[3] - d1*p2[3];
1549  ++kpp;
1550  d1 = (fmax - f1) / (f1 - f2);
1551  d2 = (fmax - f2) / (f1 - f2);
1552  pp[kpp*3 + 1] = d2*p1[1] - d1*p2[1];
1553  pp[kpp*3 + 2] = d2*p1[2] - d1*p2[2];
1554  pp[kpp*3 + 3] = d2*p1[3] - d1*p2[3];
1555  return;
1556 
1557  // I N T E R S E C T I O N W I T H Fmax, Fmin
1558 L700:
1559  ++kpp;
1560  d1 = (fmax - f1) / (f1 - f2);
1561  d2 = (fmax - f2) / (f1 - f2);
1562  pp[kpp*3 + 1] = d2*p1[1] - d1*p2[1];
1563  pp[kpp*3 + 2] = d2*p1[2] - d1*p2[2];
1564  pp[kpp*3 + 3] = d2*p1[3] - d1*p2[3];
1565  ++kpp;
1566  d1 = (fmin - f1) / (f1 - f2);
1567  d2 = (fmin - f2) / (f1 - f2);
1568  pp[kpp*3 + 1] = d2*p1[1] - d1*p2[1];
1569  pp[kpp*3 + 2] = d2*p1[2] - d1*p2[2];
1570  pp[kpp*3 + 3] = d2*p1[3] - d1*p2[3];
1571 }
1572 
1573 ////////////////////////////////////////////////////////////////////////////////
1574 /// Find visible parts of line (draw line)
1575 ///
1576 /// \param[in] r1 1-st point of the line
1577 /// \param[in] r2 2-nd point of the line
1578 
1579 void TPainter3dAlgorithms::FindVisibleDraw(Double_t *r1, Double_t *r2)
1580 {
1581  Double_t yy1u, yy2u;
1582  Int_t i, icase, i1, i2, icase1, icase2, iv, ifback;
1583  Double_t x1, x2, y1, y2, z1, z2, dd, di;
1584  Double_t dt, dy;
1585  Double_t tt, uu, ww, yy, yy1, yy2, yy1d, yy2d;
1586  Double_t *tn = 0;
1587  const Double_t kEpsil = 1.e-6;
1588  /* Parameter adjustments */
1589  --r2;
1590  --r1;
1591  TView *view = 0;
1592 
1593  if (gPad) view = gPad->GetView();
1594  if (view) {
1595  tn = view->GetTN();
1596  if (tn) {
1597  x1 = tn[0]*r1[1] + tn[1]*r1[2] + tn[2]*r1[3] + tn[3];
1598  x2 = tn[0]*r2[1] + tn[1]*r2[2] + tn[2]*r2[3] + tn[3];
1599  y1 = tn[4]*r1[1] + tn[5]*r1[2] + tn[6]*r1[3] + tn[7];
1600  y2 = tn[4]*r2[1] + tn[5]*r2[2] + tn[6]*r2[3] + tn[7];
1601  z1 = tn[8]*r1[1] + tn[9]*r1[2] + tn[10]*r1[3] + tn[11];
1602  z2 = tn[8]*r2[1] + tn[9]*r2[2] + tn[10]*r2[3] + tn[11];
1603  } else {
1604  Error("FindVisibleDraw", "invalid TView in current pad");
1605  return;
1606  }
1607  } else {
1608  Error("FindVisibleDraw", "no TView in current pad");
1609  return;
1610  }
1611 
1612  ifback = 0;
1613  if (x1 >= x2) {
1614  ifback = 1;
1615  ww = x1;
1616  x1 = x2;
1617  x2 = ww;
1618  ww = y1;
1619  y1 = y2;
1620  y2 = ww;
1621  ww = z1;
1622  z1 = z2;
1623  z2 = ww;
1624  }
1625  fNT = 0;
1626  i1 = Int_t((x1 - fX0) / fDX) + 15;
1627  i2 = Int_t((x2 - fX0) / fDX) + 15;
1628  x1 = fX0 + (i1 - 1)*fDX;
1629  x2 = fX0 + (i2 - 1)*fDX;
1630  if (i1 != i2) {
1631 
1632  // F I N D V I S I B L E P A R T S O F T H E L I N E
1633  di = (Double_t) (i2 - i1);
1634  dy = (y2 - y1) / di;
1635  dt = 1 / di;
1636  iv = -1;
1637  for (i = i1; i <= i2 - 1; ++i) {
1638  yy1 = y1 + dy*(i - i1);
1639  yy2 = yy1 + dy;
1640  yy1u = yy1 - fU[2*i - 2];
1641  yy1d = yy1 - fD[2*i - 2];
1642  yy2u = yy2 - fU[2*i - 1];
1643  yy2d = yy2 - fD[2*i - 1];
1644  tt = dt*(i - i1);
1645  // A N A L I Z E L E F T S I D E
1646  icase1 = 1;
1647  if (yy1u > kEpsil) icase1 = 0;
1648  if (yy1d < -kEpsil) icase1 = 2;
1649  if ((icase1 == 0 || icase1 == 2) && iv <= 0) {
1650  iv = 1;
1651  ++fNT;
1652  fT[2*fNT - 2] = tt;
1653  }
1654  if (icase1 == 1 && iv >= 0) {
1655  iv = -1;
1656  fT[2*fNT - 1] = tt;
1657  }
1658  // A N A L I Z E R I G H T S I D E
1659  icase2 = 1;
1660  if (yy2u > kEpsil) icase2 = 0;
1661  if (yy2d < -kEpsil) icase2 = 2;
1662  icase = icase1*3 + icase2;
1663  if (icase == 1) {
1664  iv = -1;
1665  fT[2*fNT - 1] = tt + dt*(yy1u / (yy1u - yy2u));
1666  }
1667  if (icase == 2) {
1668  fT[2*fNT - 1] = tt + dt*(yy1u / (yy1u - yy2u));
1669  ++fNT;
1670  fT[2*fNT - 2] = tt + dt*(yy1d / (yy1d - yy2d));
1671  }
1672  if (icase == 3) {
1673  iv = 1;
1674  ++fNT;
1675  fT[2*fNT - 2] = tt + dt*(yy1u / (yy1u - yy2u));
1676  }
1677  if (icase == 5) {
1678  iv = 1;
1679  ++fNT;
1680  fT[2*fNT - 2] = tt + dt*(yy1d / (yy1d - yy2d));
1681  }
1682  if (icase == 6) {
1683  fT[2*fNT - 1] = tt + dt*(yy1d / (yy1d - yy2d));
1684  ++fNT;
1685  fT[2*fNT - 2] = tt + dt*(yy1u / (yy1u - yy2u));
1686  }
1687  if (icase == 7) {
1688  iv = -1;
1689  fT[2*fNT - 1] = tt + dt*(yy1d / (yy1d - yy2d));
1690  }
1691  if (fNT + 1 >= 100) break;
1692  }
1693  if (iv > 0) fT[2*fNT - 1] = 1;
1694  } else {
1695 
1696  // V E R T I C A L L I N E
1697  fNT = 1;
1698  fT[0] = 0;
1699  fT[1] = 1;
1700  if (y2 <= y1) {
1701  if (y2 == y1) { fNT = 0; return;}
1702  ifback = 1 - ifback;
1703  yy = y1;
1704  y1 = y2;
1705  y2 = yy;
1706  }
1707  uu = fU[2*i1 - 2];
1708  dd = fD[2*i1 - 2];
1709  if (i1 != 1) {
1710  if (uu < fU[2*i1 - 3]) uu = fU[2*i1 - 3];
1711  if (dd > fD[2*i1 - 3]) dd = fD[2*i1 - 3];
1712  }
1713  // F I N D V I S I B L E P A R T O F L I N E
1714  if (y1 < uu && y2 > dd) {
1715  if (y1 >= dd && y2 <= uu) {fNT = 0; return;}
1716  fNT = 0;
1717  if (dd > y1) {
1718  ++fNT;
1719  fT[2*fNT - 2] = 0;
1720  fT[2*fNT - 1] = (dd - y1) / (y2 - y1);
1721  }
1722  if (uu < y2) {
1723  ++fNT;
1724  fT[2*fNT - 2] = (uu - y1) / (y2 - y1);
1725  fT[2*fNT - 1] = 1;
1726  }
1727  }
1728  }
1729 
1730  if (ifback == 0) return;
1731  if (fNT == 0) return;
1732  for (i = 1; i <= fNT; ++i) {
1733  fT[2*i - 2] = 1 - fT[2*i - 2];
1734  fT[2*i - 1] = 1 - fT[2*i - 1];
1735  }
1736 }
1737 
1738 ////////////////////////////////////////////////////////////////////////////////
1739 /// Find visible part of a line ("RASTER SCREEN")
1740 ///
1741 /// \param[in] p1 1st point of the line
1742 /// \param[in] p2 2nd point of the line
1743 /// \param[in] ntmax max allowed number of visible segments
1744 ///
1745 /// \param[out] nt number of visible segments of the line
1746 /// \param[out] t visible segments
1747 
1748 void TPainter3dAlgorithms::FindVisibleLine(Double_t *p1, Double_t *p2, Int_t ntmax, Int_t &nt, Double_t *t)
1749 {
1750  Double_t ddtt;
1751  Double_t tcur;
1752  Int_t i, incrx, ivis, x1, y1, x2, y2, ib, kb, dx, dy, iw, ix, iy, ifinve, dx2, dy2;
1753  Double_t t1, t2;
1754  Double_t dt;
1755  Double_t tt;
1756  /* Parameter adjustments */
1757  t -= 3;
1758  --p2;
1759  --p1;
1760 
1761  if (fIfrast) {
1762  nt = 1;
1763  t[3] = 0;
1764  t[4] = 1;
1765  return;
1766  }
1767  x1 = Int_t(fNxrast*((p1[1] - fXrast) / fDXrast) - 0.01);
1768  y1 = Int_t(fNyrast*((p1[2] - fYrast) / fDYrast) - 0.01);
1769  x2 = Int_t(fNxrast*((p2[1] - fXrast) / fDXrast) - 0.01);
1770  y2 = Int_t(fNyrast*((p2[2] - fYrast) / fDYrast) - 0.01);
1771  ifinve = 0;
1772  if (y1 > y2) {
1773  ifinve = 1;
1774  iw = x1;
1775  x1 = x2;
1776  x2 = iw;
1777  iw = y1;
1778  y1 = y2;
1779  y2 = iw;
1780  }
1781  nt = 0;
1782  ivis = 0;
1783  if (y1 >= fNyrast) return;
1784  if (y2 < 0) return;
1785  if (x1 >= fNxrast && x2 >= fNxrast) return;
1786  if (x1 < 0 && x2 < 0) return;
1787 
1788  // S E T I N I T I A L V A L U E S
1789  incrx = 1;
1790  dx = x2 - x1;
1791  if (dx < 0) {
1792  dx = -dx;
1793  incrx = -1;
1794  }
1795  dy = y2 - y1;
1796  dx2 = dx + dx;
1797  dy2 = dy + dy;
1798  if (dy > dx) goto L200;
1799 
1800  // D X . G T . D Y
1801  dt = 1./ (Double_t)(dx + 1.);
1802  ddtt = dt*(float).5;
1803  tcur = -(Double_t)dt;
1804  tt = (Double_t) (-(dx + dy2));
1805  iy = y1;
1806  kb = iy*fNxrast + x1 - incrx;
1807  for (ix = x1; incrx < 0 ? ix >= x2 : ix <= x2; ix += incrx) {
1808  kb += incrx;
1809  tcur += dt;
1810  tt += dy2;
1811  if (tt >= 0) {
1812  ++iy;
1813  tt -= dx2;
1814  kb += fNxrast;
1815  }
1816  if (iy < 0) goto L110;
1817  if (iy >= fNyrast) goto L110;
1818  if (ix < 0) goto L110;
1819  if (ix >= fNxrast) goto L110;
1820  iw = kb / 30;
1821  ib = kb - iw*30 + 1;
1822  if (fRaster[iw] & fMask[ib - 1]) goto L110;
1823  if (ivis > 0) continue;
1824  ivis = 1;
1825  ++nt;
1826  t[2*nt + 1] = tcur;
1827  continue;
1828 L110:
1829  if (ivis == 0) continue;
1830  ivis = 0;
1831  t[2*nt + 2] = tcur;
1832  if (nt == ntmax) goto L300;
1833  }
1834  if (ivis > 0) t[2*nt + 2] = tcur + dt + ddtt;
1835  goto L300;
1836 
1837  // D Y . G T . D X
1838 L200:
1839  dt = 1. / (Double_t)(dy + 1.);
1840  ddtt = dt*(float).5;
1841  tcur = -(Double_t)dt;
1842  tt = (Double_t) (-(dy + dx2));
1843  ix = x1;
1844  if (y2 >= fNyrast) y2 = fNyrast - 1;
1845  kb = (y1 - 1)*fNxrast + ix;
1846  for (iy = y1; iy <= y2; ++iy) {
1847  kb += fNxrast;
1848  tcur += dt;
1849  tt += dx2;
1850  if (tt >= 0) {
1851  ix += incrx;
1852  tt -= dy2;
1853  kb += incrx;
1854  }
1855  if (iy < 0) goto L210;
1856  if (ix < 0) goto L210;
1857  if (ix >= fNxrast) goto L210;
1858  iw = kb / 30;
1859  ib = kb - iw*30 + 1;
1860  if (fRaster[iw] & fMask[ib - 1]) goto L210;
1861  if (ivis > 0) continue;
1862  ivis = 1;
1863  ++nt;
1864  t[2*nt + 1] = tcur;
1865  continue;
1866 L210:
1867  if (ivis == 0) continue;
1868  ivis = 0;
1869  t[2*nt + 2] = tcur;
1870  if (nt == ntmax) goto L300;
1871  }
1872  if (ivis > 0) t[2*nt + 2] = tcur + dt;
1873 
1874  // C H E C K D I R E C T I O N O F P A R A M E T E R
1875 L300:
1876  if (nt == 0) return;
1877  dt *= 1.1;
1878  if (t[3] <= dt) t[3] = 0;
1879  if (t[2*nt + 2] >= 1 - dt) t[2*nt + 2] = 1;
1880  if (ifinve == 0) return;
1881  for (i = 1; i <= nt; ++i) {
1882  t1 = t[2*i + 1];
1883  t2 = t[2*i + 2];
1884  t[2*i + 1] = 1 - t2;
1885  t[2*i + 2] = 1 - t1;
1886  }
1887 }
1888 
1889 ////////////////////////////////////////////////////////////////////////////////
1890 /// Find part of surface with luminosity in the corners. This method is used for
1891 /// Gouraud shading
1892 
1893 void TPainter3dAlgorithms::GouraudFunction(Int_t ia, Int_t ib, Double_t *face, Double_t *t)
1894 {
1895  Int_t iphi;
1896  static Double_t f[108]; /* was [3][4][3][3] */
1897  Int_t i, j, k;
1898  Double_t r, s, x[36]; /* was [4][3][3] */
1899  Double_t y[36]; /* was [4][3][3] */
1900  Double_t z[36]; /* was [4][3][3] */
1901  Int_t incrx[3], incry[3];
1902 
1903  Double_t x1, x2, y1, y2, z1, z2, th, an[27]; /* was [3][3][3] */
1904  Double_t bn[12]; /* was [3][2][2] */
1905 
1906  Double_t rad;
1907  Double_t phi;
1908  Int_t ixt, iyt;
1909 
1910  /* Parameter adjustments */
1911  --t;
1912  face -= 4;
1913 
1914  iphi = 1;
1915  rad = TMath::ATan(1) * (float)4 / (float)180;
1916 
1917  // Find real cell indexes
1918  ixt = ia + Hparam.xfirst - 1;
1919  iyt = ib + Hparam.yfirst - 1;
1920 
1921  // Find increments of neighboring cells
1922  incrx[0] = -1;
1923  incrx[1] = 0;
1924  incrx[2] = 1;
1925  if (ixt == 1) incrx[0] = 0;
1926  if (ixt == Hparam.xlast - 1) incrx[2] = 0;
1927  incry[0] = -1;
1928  incry[1] = 0;
1929  incry[2] = 1;
1930  if (iyt == 1) incry[0] = 0;
1931  if (iyt == Hparam.ylast - 1) incry[2] = 0;
1932 
1933  // Find neighboring faces
1934  Int_t i1, i2;
1935  for (j = 1; j <= 3; ++j) {
1936  for (i = 1; i <= 3; ++i) {
1937  i1 = ia + incrx[i - 1];
1938  i2 = ib + incry[j - 1];
1939  SurfaceFunction(i1, i2, &f[(((i + j*3) << 2) + 1)*3 - 51], &t[1]);
1940  }
1941  }
1942 
1943  // Set face
1944  for (k = 1; k <= 4; ++k) {
1945  for (i = 1; i <= 3; ++i) {
1946  face[i + k*3] = f[i + (k + 32)*3 - 52];
1947  }
1948  }
1949 
1950  // Find coordinates and normales
1951  for (j = 1; j <= 3; ++j) {
1952  for (i = 1; i <= 3; ++i) {
1953  for (k = 1; k <= 4; ++k) {
1954  if (Hoption.System == kPOLAR) {
1955  phi = f[iphi + (k + ((i + j*3) << 2))*3 - 52]*rad;
1956  r = f[3 - iphi + (k + ((i + j*3) << 2))*3 - 52];
1957  x[k + ((i + j*3) << 2) - 17] = r * TMath::Cos(phi);
1958  y[k + ((i + j*3) << 2) - 17] = r * TMath::Sin(phi);
1959  z[k + ((i + j*3) << 2) - 17] = f[(k + ((i + j*3) << 2))*3 - 49];
1960  } else if (Hoption.System == kCYLINDRICAL) {
1961  phi = f[iphi + (k + ((i + j*3) << 2))*3 - 52]*rad;
1962  r = f[(k + ((i + j*3) << 2))*3 - 49];
1963  x[k + ((i + j*3) << 2) - 17] = r*TMath::Cos(phi);
1964  y[k + ((i + j*3) << 2) - 17] = r*TMath::Sin(phi);
1965  z[k + ((i + j*3) << 2) - 17] = f[3 - iphi + (k + ((i + j*3) << 2))*3 - 52];
1966  } else if (Hoption.System == kSPHERICAL) {
1967  phi = f[iphi + (k + ((i + j*3) << 2))*3 - 52]*rad;
1968  th = f[3 - iphi + (k + ((i + j*3) << 2))*3 - 52]*rad;
1969  r = f[(k + ((i + j*3) << 2))*3 - 49];
1970  x[k + ((i + j*3) << 2) - 17] = r*TMath::Sin(th)*TMath::Cos(phi);
1971  y[k + ((i + j*3) << 2) - 17] = r*TMath::Sin(th)*TMath::Sin(phi);
1972  z[k + ((i + j*3) << 2) - 17] = r*TMath::Cos(th);
1973  } else if (Hoption.System == kRAPIDITY) {
1974  phi = f[iphi + (k + ((i + j*3) << 2))*3 - 52]*rad;
1975  th = f[3 - iphi + (k + ((i + j*3) << 2))*3 - 52]*rad;
1976  r = f[(k + ((i + j*3) << 2))*3 - 49];
1977  x[k + ((i + j*3) << 2) - 17] = r*TMath::Cos(phi);
1978  y[k + ((i + j*3) << 2) - 17] = r*TMath::Sin(phi);
1979  z[k + ((i + j*3) << 2) - 17] = r*TMath::Cos(th) / TMath::Sin(th);
1980  } else {
1981  x[k + ((i + j*3) << 2) - 17] = f[(k + ((i + j*3) << 2))*3 - 51];
1982  y[k + ((i + j*3) << 2) - 17] = f[(k + ((i + j*3) << 2))*3 - 50];
1983  z[k + ((i + j*3) << 2) - 17] = f[(k + ((i + j*3) << 2))*3 - 49];
1984  }
1985  }
1986  x1 = x[((i + j*3) << 2) - 14] - x[((i + j*3) << 2) - 16];
1987  x2 = x[((i + j*3) << 2) - 13] - x[((i + j*3) << 2) - 15];
1988  y1 = y[((i + j*3) << 2) - 14] - y[((i + j*3) << 2) - 16];
1989  y2 = y[((i + j*3) << 2) - 13] - y[((i + j*3) << 2) - 15];
1990  z1 = z[((i + j*3) << 2) - 14] - z[((i + j*3) << 2) - 16];
1991  z2 = z[((i + j*3) << 2) - 13] - z[((i + j*3) << 2) - 15];
1992  an[(i + j*3)*3 - 12] = y1*z2 - y2*z1;
1993  an[(i + j*3)*3 - 11] = z1*x2 - z2*x1;
1994  an[(i + j*3)*3 - 10] = x1*y2 - x2*y1;
1995  s = TMath::Sqrt(an[(i + j*3)*3 - 12]*an[(i + j*3)*3 - 12] + an[
1996  (i + j*3)*3 - 11]*an[(i + j*3)*3 - 11] + an[(i
1997  + j*3)*3 - 10]*an[(i + j*3)*3 - 10]);
1998 
1999  an[(i + j*3)*3 - 12] /= s;
2000  an[(i + j*3)*3 - 11] /= s;
2001  an[(i + j*3)*3 - 10] /= s;
2002  }
2003  }
2004 
2005  // Find average normals
2006  for (j = 1; j <= 2; ++j) {
2007  for (i = 1; i <= 2; ++i) {
2008  for (k = 1; k <= 3; ++k) {
2009  bn[k + (i + 2*j)*3 - 10] = an[k + (i + j*3)*3 - 13]
2010  + an[k + (i + 1 + j*3)*3 - 13] + an[k + (i + 1 +
2011  (j + 1)*3)*3 - 13] + an[k + (i + (j + 1)*3)*3 - 13];
2012  }
2013  }
2014  }
2015 
2016  // Set luminosity
2017  Luminosity(bn, t[1]);
2018  Luminosity(&bn[3], t[2]);
2019  Luminosity(&bn[9], t[3]);
2020  Luminosity(&bn[6], t[4]);
2021 }
2022 
2023 ////////////////////////////////////////////////////////////////////////////////
2024 /// Initialize "MOVING SCREEN" method
2025 ///
2026 /// \param[in] xmin left boundary
2027 /// \param[in] xmax right boundary
2028 
2029 void TPainter3dAlgorithms::InitMoveScreen(Double_t xmin, Double_t xmax)
2030 {
2031  const Double_t VERY_BIG = 9e+99;
2032  fX0 = xmin;
2033  fDX = (xmax - xmin) / NumOfSlices;
2034  for (Int_t i = 0; i < NumOfSlices; ++i) {
2035  fU[2*i + 0] = -VERY_BIG;
2036  fU[2*i + 1] = -VERY_BIG;
2037  fD[2*i + 0] = VERY_BIG;
2038  fD[2*i + 1] = VERY_BIG;
2039  }
2040 }
2041 
2042 ////////////////////////////////////////////////////////////////////////////////
2043 /// Initialize hidden lines removal algorithm (RASTER SCREEN)
2044 ///
2045 /// \param[in] xmin Xmin in the normalized coordinate system
2046 /// \param[in] ymin Ymin in the normalized coordinate system
2047 /// \param[in] xmax Xmax in the normalized coordinate system
2048 /// \param[in] ymax Ymax in the normalized coordinate system
2049 /// \param[in] nx number of pixels along X
2050 /// \param[in] ny number of pixels along Y
2051 
2052 void TPainter3dAlgorithms::InitRaster(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax, Int_t nx, Int_t ny )
2053 {
2054  Int_t i, j, k, ib, nb;
2055 
2056  fNxrast = nx;
2057  fNyrast = ny;
2058  fXrast = xmin;
2059  fDXrast = xmax - xmin;
2060  fYrast = ymin;
2061  fDYrast = ymax - ymin;
2062 
2063  // Create buffer for raster
2064  Int_t buffersize = nx*ny/30 + 1;
2065  fRaster = new Int_t[buffersize];
2066 
2067  // S E T M A S K S
2068  k = 0;
2069  Int_t pow2 = 1;
2070  for (i = 1; i <= 30; ++i) {
2071  fJmask[i - 1] = k;
2072  k = k + 30 - i + 1;
2073  fMask[i - 1] = pow2;
2074  pow2 *= 2;
2075  }
2076  j = 30;
2077  for (nb = 2; nb <= 30; ++nb) {
2078  for (ib = 1; ib <= 30 - nb + 1; ++ib) {
2079  k = 0;
2080  for (i = ib; i <= ib + nb - 1; ++i) k = k | fMask[i - 1];
2081  ++j;
2082  fMask[j - 1] = k;
2083  }
2084  }
2085 
2086  // C L E A R R A S T E R S C R E E N
2087  ClearRaster();
2088 }
2089 
2090 ////////////////////////////////////////////////////////////////////////////////
2091 /// Service function for Legos
2092 
2093 void TPainter3dAlgorithms::LegoFunction(Int_t ia, Int_t ib, Int_t &nv, Double_t *ab, Double_t *vv, Double_t *t)
2094 {
2095  Int_t i, j, ixt, iyt;
2096  Double_t yval1l, yval2l;
2097  Double_t xlab1l, xlab2l, ylab1l, ylab2l;
2098  Double_t rinrad = gStyle->GetLegoInnerR();
2099  Double_t dangle = 10; //Delta angle for Rapidity option
2100 
2101  /* Parameter adjustments */
2102  t -= 5;
2103  --vv;
2104  ab -= 3;
2105 
2106  ixt = ia + Hparam.xfirst - 1;
2107  iyt = ib + Hparam.yfirst - 1;
2108 
2109  // Compute the cell position in cartesian coordinates
2110  // and compute the LOG if necessary
2111  Double_t xwid = gCurrentHist->GetXaxis()->GetBinWidth(ixt);
2112  Double_t ywid = gCurrentHist->GetYaxis()->GetBinWidth(iyt);
2113  ab[3] = gCurrentHist->GetXaxis()->GetBinLowEdge(ixt) + xwid*Hparam.baroffset;
2114  ab[4] = gCurrentHist->GetYaxis()->GetBinLowEdge(iyt) + ywid*Hparam.baroffset;
2115  ab[5] = ab[3] + xwid*Hparam.barwidth;
2116  ab[8] = ab[4] + ywid*Hparam.barwidth;
2117 
2118  if (Hoption.Logx) {
2119  if (ab[3] > 0) ab[3] = TMath::Log10(ab[3]);
2120  else ab[3] = Hparam.xmin;
2121  if (ab[5] > 0) ab[5] = TMath::Log10(ab[5]);
2122  else ab[5] = Hparam.xmin;
2123  }
2124  // xval1l = Hparam.xmin;
2125  // xval2l = Hparam.xmax;
2126  if (Hoption.Logy) {
2127  if (ab[4] > 0) ab[4] = TMath::Log10(ab[4]);
2128  else ab[4] = Hparam.ymin;
2129  if (ab[8] > 0) ab[8] = TMath::Log10(ab[8]);
2130  else ab[8] = Hparam.ymin;
2131  }
2132  yval1l = Hparam.ymin;
2133  yval2l = Hparam.ymax;
2134 
2135  if (ab[3] < Hparam.xmin) ab[3] = Hparam.xmin;
2136  if (ab[4] < Hparam.ymin) ab[4] = Hparam.ymin;
2137  if (ab[5] > Hparam.xmax) ab[5] = Hparam.xmax;
2138  if (ab[8] > Hparam.ymax) ab[8] = Hparam.ymax;
2139  if (ab[5] < Hparam.xmin) ab[5] = Hparam.xmin;
2140  if (ab[8] < Hparam.ymin) ab[8] = Hparam.ymin;
2141 
2142  xlab1l = gCurrentHist->GetXaxis()->GetXmin();
2143  xlab2l = gCurrentHist->GetXaxis()->GetXmax();
2144  if (Hoption.Logx) {
2145  if (xlab2l>0) {
2146  if (xlab1l>0) xlab1l = TMath::Log10(xlab1l);
2147  else xlab1l = TMath::Log10(0.001*xlab2l);
2148  xlab2l = TMath::Log10(xlab2l);
2149  }
2150  }
2151  ylab1l = gCurrentHist->GetYaxis()->GetXmin();
2152  ylab2l = gCurrentHist->GetYaxis()->GetXmax();
2153  if (Hoption.Logy) {
2154  if (ylab2l>0) {
2155  if (ylab1l>0) ylab1l = TMath::Log10(ylab1l);
2156  else ylab1l = TMath::Log10(0.001*ylab2l);
2157  ylab2l = TMath::Log10(ylab2l);
2158  }
2159  }
2160 
2161  // Transform the cell position in the required coordinate system
2162  if (Hoption.System == kPOLAR) {
2163  ab[3] = 360*(ab[3] - xlab1l) / (xlab2l - xlab1l);
2164  ab[5] = 360*(ab[5] - xlab1l) / (xlab2l - xlab1l);
2165  ab[4] = (ab[4] - yval1l) / (yval2l - yval1l);
2166  ab[8] = (ab[8] - yval1l) / (yval2l - yval1l);
2167  } else if (Hoption.System == kCYLINDRICAL) {
2168  ab[3] = 360*(ab[3] - xlab1l) / (xlab2l - xlab1l);
2169  ab[5] = 360*(ab[5] - xlab1l) / (xlab2l - xlab1l);
2170  } else if (Hoption.System == kSPHERICAL) {
2171  ab[3] = 360*(ab[3] - xlab1l) / (xlab2l - xlab1l);
2172  ab[5] = 360*(ab[5] - xlab1l) / (xlab2l - xlab1l);
2173  ab[4] = 180*(ab[4] - ylab1l) / (ylab2l - ylab1l);
2174  ab[8] = 180*(ab[8] - ylab1l) / (ylab2l - ylab1l);
2175  } else if (Hoption.System == kRAPIDITY) {
2176  ab[3] = 360*(ab[3] - xlab1l) / (xlab2l - xlab1l);
2177  ab[5] = 360*(ab[5] - xlab1l) / (xlab2l - xlab1l);
2178  ab[4] = (180 - dangle*2)*(ab[4] - ylab1l) / (ylab2l - ylab1l) + dangle;
2179  ab[8] = (180 - dangle*2)*(ab[8] - ylab1l) / (ylab2l - ylab1l) + dangle;
2180  }
2181 
2182  // Complete the cell coordinates
2183  ab[6] = ab[4];
2184  ab[7] = ab[5];
2185  ab[9] = ab[3];
2186  ab[10] = ab[8];
2187 
2188  // Get the content of the table, and loop on the
2189  // stack if necessary.
2190  vv[1] = Hparam.zmin;
2191  vv[2] = Hparam.factor*gCurrentHist->GetBinContent(ixt, iyt);
2192 
2193  // In linear scale, 3D boxes all start from 0.
2194  if (Hparam.zmin<0 && !Hoption.Logz && Hoption.MinimumZero) {
2195  if (vv[2]<0) {
2196  vv[1] = vv[2];
2197  vv[2] = 0;
2198  } else {
2199  vv[1] = 0;
2200  }
2201  }
2202 
2203  TList *stack = gCurrentHist->GetPainter()->GetStack();
2204  Int_t nids = 0; //not yet implemented
2205  if (stack) nids = stack->GetSize();
2206  if (nids) {
2207  for (i = 2; i <= nids + 1; ++i) {
2208  TH1 *hid = (TH1*)stack->At(i-2);
2209  vv[i + 1] = Hparam.factor*hid->GetBinContent(ixt, iyt) + vv[i];
2210  vv[i + 1] = TMath::Max(Hparam.zmin, vv[i + 1]);
2211  //vv[i + 1] = TMath::Min(Hparam.zmax, vv[i + 1]);
2212  }
2213  }
2214 
2215  nv = nids + 2;
2216  for (i = 2; i <= nv; ++i) {
2217  if (Hoption.Logz) {
2218  if (vv[i] > 0)
2219  vv[i] = TMath::Max(Hparam.zmin, (Double_t)TMath::Log10(vv[i]));
2220  else
2221  vv[i] = Hparam.zmin;
2222  vv[i] = TMath::Min(vv[i], Hparam.zmax);
2223  } else {
2224  vv[i] = TMath::Max(Hparam.zmin, vv[i]);
2225  vv[i] = TMath::Min(Hparam.zmax, vv[i]);
2226  }
2227  }
2228 
2229  if (!Hoption.Logz) {
2230  i = 3;
2231  while (i <= nv) {
2232  if (vv[i] < vv[i - 1]) {
2233  vv[i - 1] = vv[i];
2234  i = 3;
2235  continue;
2236  }
2237  ++i;
2238  }
2239  }
2240 
2241  // For cylindrical, spherical and pseudo-rapidity, the content
2242  // is mapped onto the radius
2243  if (Hoption.System == kCYLINDRICAL || Hoption.System == kSPHERICAL || Hoption.System == kRAPIDITY) {
2244  for (i = 1; i <= nv; ++i) {
2245  vv[i] = (1 - rinrad)*((vv[i] - Hparam.zmin) /
2246  (Hparam.zmax - Hparam.zmin)) + rinrad;
2247  }
2248  }
2249 
2250  for (i = 1; i <= nv; ++i) {
2251  for (j = 1; j <= 4; ++j) t[j + (i << 2)] = vv[i];
2252  }
2253 }
2254 
2255 ////////////////////////////////////////////////////////////////////////////////
2256 /// Draw stack of lego-plots in cartesian coordinates
2257 ///
2258 /// \param[in] ang angle between X ang Y (not used in this method)
2259 /// \param[in] nx number of cells along X
2260 /// \param[in] ny number of cells along Y
2261 ///
2262 /// - `chopt` = 'BF' from BACK to FRONT
2263 /// - `chopt` = 'FB' from FRONT to BACK
2264 
2265 void TPainter3dAlgorithms::LegoCartesian(Double_t, Int_t nx, Int_t ny, const char *chopt)
2266 {
2267  Int_t icodes[4], iface[4];
2268  Double_t xy[4*2], xyz[8*3], tface[4];
2269  Int_t firstStackNumberDrawn=-1 ; // necessary to compute fColorBottom when the 0 option is set and when the stack is seen from below (bottomview, theta<0.)
2270 
2271  TView *view = 0;
2272  if (gPad) view = gPad->GetView();
2273  if (!view) {
2274  Error("LegoCartesian", "no TView in current pad");
2275  return;
2276  }
2277  Double_t *tnorm = view->GetTnorm();
2278  if (!tnorm) return;
2279 
2280  // Allocate v and tt arrays
2281  Double_t *v, *tt;
2282  Int_t vSize = fNStack+2;
2283  if (vSize > kVSizeMax) {
2284  v = new Double_t[vSize];
2285  tt = new Double_t[4*vSize];
2286  } else {
2287  vSize = kVSizeMax;
2288  v = &gV[0];
2289  tt = &gTT[0];
2290  }
2291 
2292  // Define order of drawing
2293  Int_t incrx = (tnorm[8] < 0.) ? -1 : +1;
2294  Int_t incry = (tnorm[9] < 0.) ? -1 : +1;
2295  if (*chopt != 'B' && *chopt != 'b') { // front to back
2296  incrx = -incrx; incry = -incry;
2297  }
2298  Int_t ix1 = (incrx == +1) ? 1 : nx;
2299  Int_t iy1 = (incry == +1) ? 1 : ny;
2300  Int_t ix2 = (incrx == +1) ? nx : 1;
2301  Int_t iy2 = (incry == +1) ? ny : 1;
2302 
2303  // Find visibility of sides
2304  Double_t zn;
2305  Int_t ivis[6] = { 0,0,0,0,0,0 };
2306  view->FindNormal(0, 1, 0, zn);
2307  if (zn < 0) ivis[0] = 1;
2308  if (zn > 0) ivis[2] = 1;
2309  view->FindNormal(1, 0, 0, zn);
2310  if (zn > 0) ivis[1] = 1;
2311  if (zn < 0) ivis[3] = 1;
2312  view->FindNormal(0, 0, 1, zn);
2313  if (zn > 0) ivis[5] = 1;
2314  if (zn < 0) ivis[4] = 1;
2315 
2316  // Draw stack of lego-plots
2317  Int_t nv = 0;
2318  THistPainter *painter = (THistPainter*)gCurrentHist->GetPainter();
2319  for (Int_t iy = iy1; iy != iy2+incry; iy += incry) {
2320  for (Int_t ix = ix1; ix != ix2+incrx; ix += incrx) {
2321  if (!painter->IsInside(ix,iy)) continue;
2322  (this->*fLegoFunction)(ix, iy, nv, xy, v, tt);
2323  if (nv < 2 || nv > vSize) continue;
2324  if (Hoption.Zero) {
2325  Double_t total_content = 0;
2326  for (Int_t iv = 1; iv < nv; ++iv) { total_content += v[iv]; }
2327  if (total_content <= Hparam.zmin) continue;
2328  }
2329  icodes[0] = ix;
2330  icodes[1] = iy;
2331  for (Int_t i = 1; i <= 4; ++i) {
2332  xyz[i*3 - 3] = xy[2*i - 2];
2333  xyz[i*3 - 2] = xy[2*i - 1];
2334  xyz[(i + 4)*3 - 3] = xyz[i*3 - 3];
2335  xyz[(i + 4)*3 - 2] = xyz[i*3 - 2];
2336  }
2337  // Draw stack
2338  firstStackNumberDrawn = -1;
2339  for (Int_t iv = 1; iv < nv; ++iv) {
2340  for (Int_t i = 1; i <= 4; ++i) {
2341  xyz[i*3 - 1] = v[iv - 1];
2342  xyz[(i + 4)*3 - 1] = v[iv];
2343  }
2344  if (v[iv - 1] == v[iv]) continue;
2345  icodes[2] = iv;
2346  for (Int_t i = 1; i <= 4; ++i) {
2347  if (ivis[i - 1] == 0) continue;
2348  Int_t k1 = i;
2349  Int_t k2 = i + 1;
2350  if (i == 4) k2 = 1;
2351  icodes[3] = k1;
2352  iface[0] = k1;
2353  iface[1] = k2;
2354  iface[2] = k2 + 4;
2355  iface[3] = k1 + 4;
2356  tface[0] = tt[k1 + (iv << 2) - 5];
2357  tface[1] = tt[k2 + (iv << 2) - 5];
2358  tface[2] = tt[k2 + ((iv + 1) << 2) - 5];
2359  tface[3] = tt[k1 + ((iv + 1) << 2) - 5];
2360  fEdgeIdx = iv-1;
2361  (this->*fDrawFace)(icodes, xyz, 4, iface, tface);
2362  }
2363  if ( firstStackNumberDrawn==-1 ) firstStackNumberDrawn = fEdgeIdx;
2364  }
2365  // Draw bottom face
2366  if (ivis[4] > 0) {
2367  icodes[2] = 1;
2368  icodes[3] = 5;
2369  for (Int_t i = 1; i <= 4; ++i) {
2370  xyz[i*3 - 1] = v[0];
2371  iface[i - 1] = 5 - i;
2372  tface[i - 1] = tt[5 - i - 1];
2373  }
2374  if (!Hoption.Zero) fEdgeIdx = 0;
2375  else {
2376  fEdgeIdx = firstStackNumberDrawn;
2377  fColorBottom = fColorMain[fEdgeIdx];
2378  }
2379  (this->*fDrawFace)(icodes, xyz, 4, iface, tface);
2380  }
2381  // Draw top face
2382  if (ivis[5] > 0) {
2383  icodes[2] = nv - 1;
2384  icodes[3] = 6;
2385  for (Int_t i = 1; i <= 4; ++i) {
2386  iface[i - 1] = i + 4;
2387  tface[i - 1] = tt[i + (nv << 2) - 5];
2388  }
2389  Int_t cs = fColorTop;
2390  if ( nv <= 3 ) fEdgeIdx = 0 ; // no stack or stack with only one histo
2391  else {
2392  if ( nv > 2 && (v[nv-1] == v[nv-2])) {
2393  for (Int_t iv = nv-1; iv > 2; --iv) {
2394  if (v[nv-1] == v[iv-1]) {
2395  fColorTop = fColorMain[iv-2];
2396  fEdgeIdx = iv - 2;
2397  }
2398  }
2399  }
2400  }
2401  (this->*fDrawFace)(icodes, xyz, 4, iface, tface);
2402  fColorTop = cs;
2403  }
2404  }
2405  }
2406  if (vSize > kVSizeMax) {
2407  delete [] v;
2408  delete [] tt;
2409  }
2410 }
2411 
2412 ////////////////////////////////////////////////////////////////////////////////
2413 /// Draw stack of lego-plots in polar coordinates
2414 ///
2415 /// \param[in] iordr order of variables (0 - R,PHI; 1 - PHI,R)
2416 /// \param[in] na number of steps along 1st variable
2417 /// \param[in] nb number of steps along 2nd variable
2418 ///
2419 /// - `chopt` = 'BF' from BACK to FRONT
2420 /// - `chopt` = 'FB' from FRONT to BACK
2421 
2422 void TPainter3dAlgorithms::LegoPolar(Int_t iordr, Int_t na, Int_t nb, const char *chopt)
2423 {
2424 
2425  Int_t iphi, jphi, kphi, incr, nphi, ivis[6], iopt, iphi1, iphi2, iface[4], i, j;
2426  Double_t tface[4];
2427  Int_t incrr, k1, k2, ia, ib, ir1, ir2;
2428  Double_t ab[8]; // was [2][4]
2429  Int_t ir, jr, iv, nr, nv, icodes[4];
2430  Double_t xyz[24]; // was [3][8]
2431  ia = ib = 0;
2432  TView *view = 0;
2433  Int_t firstStackNumberDrawn=-1 ; // necessary to compute fColorBottom when the 0 option is set and when the stack is seen from below (bottomview, theta<0.)
2434 
2435  if (gPad) view = gPad->GetView();
2436  if (!view) {
2437  Error("LegoPolar", "no TView in current pad");
2438  return;
2439  }
2440 
2441  if (iordr == 0) {
2442  jr = 1;
2443  jphi = 2;
2444  nr = na;
2445  nphi = nb;
2446  } else {
2447  jr = 2;
2448  jphi = 1;
2449  nr = nb;
2450  nphi = na;
2451  }
2452  if (fNaphi < nphi + 3) {
2453  if (fAphi) { delete [] fAphi; fAphi = 0; }
2454  fNaphi = nphi + 3;
2455  fAphi = new Double_t[fNaphi];
2456  }
2457  if (fAphi == 0) {
2458  Error("LegoPolar", "failed to allocate array fAphi[%d]", fNaphi);
2459  fNaphi = 0;
2460  return;
2461  }
2462  iopt = 2;
2463  if (*chopt == 'B' || *chopt == 'b') iopt = 1;
2464 
2465  // Allocate v and tt arrays
2466  Double_t *v, *tt;
2467  Int_t vSize = fNStack+2;
2468  if (vSize > kVSizeMax) {
2469  v = new Double_t[vSize];
2470  tt = new Double_t[4*vSize];
2471  } else {
2472  vSize = kVSizeMax;
2473  v = &gV[0];
2474  tt = &gTT[0];
2475  }
2476 
2477  // P R E P A R E P H I A R R A Y
2478  // F I N D C R I T I C A L S E C T O R S
2479  nv = 0;
2480  kphi = nphi;
2481  if (iordr == 0) ia = nr;
2482  if (iordr != 0) ib = nr;
2483  for (i = 1; i <= nphi; ++i) {
2484  if (iordr == 0) ib = i;
2485  if (iordr != 0) ia = i;
2486  (this->*fLegoFunction)(ia, ib, nv, ab, v, tt);
2487  if (i == 1) fAphi[0] = ab[jphi - 1];
2488  fAphi[i - 1] = (fAphi[i - 1] + ab[jphi - 1]) / (float)2.;
2489  fAphi[i] = ab[jphi + 3];
2490  }
2491  view->FindPhiSectors(iopt, kphi, fAphi, iphi1, iphi2);
2492 
2493  // E N C O D E V I S I B I L I T Y O F S I D E S
2494  // A N D O R D E R A L O N G R
2495  for (i = 1; i <= nphi; ++i) {
2496  if (!iordr) ib = i;
2497  if (iordr) ia = i;
2498  (this->*fLegoFunction)(ia, ib, nv, ab, v, tt);
2499  SideVisibilityEncode(iopt, ab[jphi - 1]*kRad, ab[jphi + 3]*kRad, fAphi[i - 1]);
2500  }
2501 
2502  // D R A W S T A C K O F L E G O - P L O T S
2503  incr = 1;
2504  iphi = iphi1;
2505 L100:
2506  if (iphi > nphi) goto L300;
2507 
2508  // D E C O D E V I S I B I L I T Y O F S I D E S
2509  SideVisibilityDecode(fAphi[iphi - 1], ivis[0], ivis[1], ivis[2], ivis[3], ivis[4], ivis[5], incrr);
2510  ir1 = 1;
2511  if (incrr < 0) ir1 = nr;
2512  ir2 = nr - ir1 + 1;
2513  // D R A W L E G O S F O R S E C T O R
2514  for (ir = ir1; incrr < 0 ? ir >= ir2 : ir <= ir2; ir += incrr) {
2515  if (iordr == 0) { ia = ir; ib = iphi; }
2516  else { ia = iphi; ib = ir; }
2517  (this->*fLegoFunction)(ia, ib, nv, ab, v, tt);
2518  if (nv < 2 || nv > vSize) continue;
2519  if (Hoption.Zero) {
2520  Double_t total_content=0;
2521  for (iv = 1; iv < nv; ++iv) total_content += v[iv];
2522  if (total_content==0) continue;
2523  }
2524  icodes[0] = ia;
2525  icodes[1] = ib;
2526  for (i = 1; i <= 4; ++i) {
2527  j = i;
2528  if (iordr != 0 && i == 2) j = 4;
2529  if (iordr != 0 && i == 4) j = 2;
2530  xyz[j*3 - 3] = ab[jr + 2*i - 3]*TMath::Cos(ab[jphi + 2*i - 3]*kRad);
2531  xyz[j*3 - 2] = ab[jr + 2*i - 3]*TMath::Sin(ab[jphi + 2*i - 3]*kRad);
2532  xyz[(j + 4)*3 - 3] = xyz[j*3 - 3];
2533  xyz[(j + 4)*3 - 2] = xyz[j*3 - 2];
2534  }
2535  // D R A W S T A C K
2536  firstStackNumberDrawn = -1;
2537  for (iv = 1; iv < nv; ++iv) {
2538  for (i = 1; i <= 4; ++i) {
2539  xyz[i*3 - 1] = v[iv - 1];
2540  xyz[(i + 4)*3 - 1] = v[iv];
2541  }
2542  if (v[iv - 1] >= v[iv]) continue;
2543  icodes[2] = iv;
2544  for (i = 1; i <= 4; ++i) {
2545  if (ivis[i - 1] == 0) continue;
2546  k1 = i - 1;
2547  if (i == 1) k1 = 4;
2548  k2 = i;
2549  if (xyz[k1*3 - 3] == xyz[k2*3 - 3] && xyz[k1*3 - 2] ==
2550  xyz[k2*3 - 2]) continue;
2551  iface[0] = k1;
2552  iface[1] = k2;
2553  iface[2] = k2 + 4;
2554  iface[3] = k1 + 4;
2555  tface[0] = tt[k1 + (iv << 2) - 5];
2556  tface[1] = tt[k2 + (iv << 2) - 5];
2557  tface[2] = tt[k2 + ((iv + 1) << 2) - 5];
2558  tface[3] = tt[k1 + ((iv + 1) << 2) - 5];
2559  icodes[3] = i;
2560  fEdgeIdx = iv-1;
2561  (this->*fDrawFace)(icodes, xyz, 4, iface, tface);
2562  }
2563  if ( firstStackNumberDrawn==-1 ) firstStackNumberDrawn = fEdgeIdx;
2564  }
2565  // D R A W B O T T O M F A C E
2566  if (ivis[4] != 0) {
2567  icodes[2] = 1;
2568  icodes[3] = 5;
2569  for (i = 1; i <= 4; ++i) {
2570  xyz[i*3 - 1] = v[0];
2571  iface[i - 1] = 5 - i;
2572  tface[i - 1] = tt[5 - i - 1];
2573  }
2574  if (!Hoption.Zero) fEdgeIdx = 0;
2575  else {
2576  fEdgeIdx = firstStackNumberDrawn;
2577  fColorBottom = fColorMain[fEdgeIdx];
2578  }
2579  (this->*fDrawFace)(icodes, xyz, 4, iface, tface);
2580  }
2581  // D R A W T O P F A C E
2582  if (ivis[5] != 0) {
2583  icodes[2] = nv - 1;
2584  icodes[3] = 6;
2585  for (i = 1; i <= 4; ++i) {
2586  iface[i - 1] = i + 4;
2587  tface[i - 1] = tt[i + (nv << 2) - 5];
2588  }
2589  Int_t cs = fColorTop;
2590  if ( nv <= 3 ) fEdgeIdx = 0 ; // no stack or stack with only one histo
2591  else {
2592  if ( nv > 2 && (v[nv-1] == v[nv-2])) {
2593  for (iv = nv-1; iv>2; iv--) {
2594  if (v[nv-1] == v[iv-1]) {
2595  fColorTop = fColorMain[iv-2];
2596  fEdgeIdx = iv-2;
2597  }
2598  }
2599  }
2600  }
2601  (this->*fDrawFace)(icodes, xyz, 4, iface, tface);
2602  fColorTop = cs;
2603  }
2604  }
2605  // N E X T P H I
2606 L300:
2607  iphi += incr;
2608  if (iphi == 0) iphi = kphi;
2609  if (iphi > kphi) iphi = 1;
2610  if (iphi != iphi2) goto L100;
2611  if (incr == 0) {
2612  if (vSize > kVSizeMax) {
2613  delete [] v;
2614  delete [] tt;
2615  }
2616  return;
2617  }
2618  if (incr < 0) {
2619  incr = 0;
2620  goto L100;
2621  }
2622  incr = -1;
2623  iphi = iphi1;
2624  goto L300;
2625 }
2626 
2627 ////////////////////////////////////////////////////////////////////////////////
2628 /// Draw stack of lego-plots in cylindrical coordinates
2629 ///
2630 /// \param[in] iordr order of variables (0 - Z,PHI; 1 - PHI,Z)
2631 /// \param[in] na number of steps along 1st variable
2632 /// \param[in] nb number of steps along 2nd variable
2633 ///
2634 /// - `chopt` = 'BF' from BACK to FRONT
2635 /// - `chopt` = 'FB' from FRONT to BACK
2636 
2637 void TPainter3dAlgorithms::LegoCylindrical(Int_t iordr, Int_t na, Int_t nb, const char *chopt)
2638 {
2639 
2640 
2641  Int_t iphi, jphi, kphi, incr, nphi, ivis[6], iopt, iphi1, iphi2, iface[4], i, j;
2642  Double_t tface[4], z;
2643  Double_t ab[8]; // was [2][4]
2644  Int_t ia, ib, idummy, iz1, iz2, nz, incrz, k1, k2, nv;
2645  Int_t iv, iz, jz, icodes[4];
2646  Double_t cosphi[4];
2647  Double_t sinphi[4];
2648  Double_t xyz[24]; // was [3][8]
2649  ia = ib = 0;
2650  TView *view = 0;
2651  Int_t firstStackNumberDrawn=-1 ; // necessary to compute fColorBottom when the 0 option is set and when the stack is seen from below (bottomview, theta<0.)
2652 
2653  if (gPad) view = gPad->GetView();
2654  if (!view) {
2655  Error("LegoCylindrical", "no TView in current pad");
2656  return;
2657  }
2658 
2659  if (iordr == 0) {
2660  jz = 1;
2661  jphi = 2;
2662  nz = na;
2663  nphi = nb;
2664  } else {
2665  jz = 2;
2666  jphi = 1;
2667  nz = nb;
2668  nphi = na;
2669  }
2670  if (fNaphi < nphi + 3) {
2671  if (fAphi) { delete [] fAphi; fAphi = 0; }
2672  fNaphi = nphi + 3;
2673  fAphi = new Double_t[fNaphi];
2674  }
2675  if (fAphi == 0) {
2676  Error("LegoCylindrical", "failed to allocate array fAphi[%d]", fNaphi);
2677  fNaphi = 0;
2678  return;
2679  }
2680  iopt = 2;
2681  if (*chopt == 'B' || *chopt == 'b') iopt = 1;
2682 
2683  // Allocate v and tt arrays
2684  Double_t *v, *tt;
2685  Int_t vSize = fNStack+2;
2686  if (vSize > kVSizeMax) {
2687  v = new Double_t[vSize];
2688  tt = new Double_t[4*vSize];
2689  } else {
2690  vSize = kVSizeMax;
2691  v = &gV[0];
2692  tt = &gTT[0];
2693  }
2694 
2695  // P R E P A R E P H I A R R A Y
2696  // F I N D C R I T I C A L S E C T O R S
2697  nv = 0;
2698  kphi = nphi;
2699  if (iordr == 0) ia = nz;
2700  if (iordr != 0) ib = nz;
2701  for (i = 1; i <= nphi; ++i) {
2702  if (iordr == 0) ib = i;
2703  if (iordr != 0) ia = i;
2704  (this->*fLegoFunction)(ia, ib, nv, ab, v, tt);
2705  if (i == 1) fAphi[0] = ab[jphi - 1];
2706  fAphi[i - 1] = (fAphi[i - 1] + ab[jphi - 1]) / (float)2.;
2707  fAphi[i] = ab[jphi + 3];
2708  }
2709  view->FindPhiSectors(iopt, kphi, fAphi, iphi1, iphi2);
2710 
2711  // E N C O D E V I S I B I L I T Y O F S I D E S
2712  // A N D O R D E R A L O N G R
2713  for (i = 1; i <= nphi; ++i) {
2714  if (iordr == 0) ib = i;
2715  if (iordr != 0) ia = i;
2716  (this->*fLegoFunction)(ia, ib, nv, ab, v, tt);
2717  SideVisibilityEncode(iopt, ab[jphi - 1]*kRad, ab[jphi + 3]*kRad, fAphi[i - 1]);
2718  }
2719 
2720  // F I N D O R D E R A L O N G Z
2721  incrz = 1;
2722  iz1 = 1;
2723  view->FindNormal(0, 0, 1, z);
2724  if ((z <= 0 && iopt == 1) || (z > 0 && iopt == 2)) {
2725  incrz = -1;
2726  iz1 = nz;
2727  }
2728  iz2 = nz - iz1 + 1;
2729 
2730  // D R A W S T A C K O F L E G O - P L O T S
2731  incr = 1;
2732  iphi = iphi1;
2733 L100:
2734  if (iphi > nphi) goto L400;
2735  // D E C O D E V I S I B I L I T Y O F S I D E S
2736  idummy = 0;
2737  SideVisibilityDecode(fAphi[iphi - 1], ivis[4], ivis[1], ivis[5], ivis[3], ivis[0], ivis[2], idummy);
2738  for (iz = iz1; incrz < 0 ? iz >= iz2 : iz <= iz2; iz += incrz) {
2739  if (iordr == 0) {ia = iz; ib = iphi;}
2740  else {ia = iphi; ib = iz;}
2741  (this->*fLegoFunction)(ia, ib, nv, ab, v, tt);
2742  if (nv < 2 || nv > vSize) continue;
2743  icodes[0] = ia;
2744  icodes[1] = ib;
2745  for (i = 1; i <= 4; ++i) {
2746  j = i;
2747  if (iordr != 0 && i == 2) j = 4;
2748  if (iordr != 0 && i == 4) j = 2;
2749  cosphi[j - 1] = TMath::Cos(ab[jphi + 2*i - 3]*kRad);
2750  sinphi[j - 1] = TMath::Sin(ab[jphi + 2*i - 3]*kRad);
2751  xyz[j*3 - 1] = ab[jz + 2*i - 3];
2752  xyz[(j + 4)*3 - 1] = ab[jz + 2*i - 3];
2753  }
2754  // D R A W S T A C K
2755  firstStackNumberDrawn = -1;
2756  for (iv = 1; iv < nv; ++iv) {
2757  for (i = 1; i <= 4; ++i) {
2758  xyz[i*3 - 3] = v[iv - 1]*cosphi[i - 1];
2759  xyz[i*3 - 2] = v[iv - 1]*sinphi[i - 1];
2760  xyz[(i + 4)*3 - 3] = v[iv]*cosphi[i - 1];
2761  xyz[(i + 4)*3 - 2] = v[iv]*sinphi[i - 1];
2762  }
2763  if (v[iv - 1] >= v[iv]) continue;
2764  icodes[2] = iv;
2765  for (i = 1; i <= 4; ++i) {
2766  if (ivis[i - 1] == 0) continue;
2767  k1 = i;
2768  k2 = i - 1;
2769  if (i == 1) k2 = 4;
2770  iface[0] = k1;
2771  iface[1] = k2;
2772  iface[2] = k2 + 4;
2773  iface[3] = k1 + 4;
2774  tface[0] = tt[k1 + (iv << 2) - 5];
2775  tface[1] = tt[k2 + (iv << 2) - 5];
2776  tface[2] = tt[k2 + ((iv + 1) << 2) - 5];
2777  tface[3] = tt[k1 + ((iv + 1) << 2) - 5];
2778  icodes[3] = i;
2779  fEdgeIdx = iv-1;
2780  (this->*fDrawFace)(icodes, xyz, 4, iface, tface);
2781  }
2782  if ( firstStackNumberDrawn==-1 ) firstStackNumberDrawn = fEdgeIdx;
2783  }
2784  // D R A W B O T T O M F A C E
2785  if (ivis[4] != 0 && v[0] > 0) {
2786  icodes[2] = 1;
2787  icodes[3] = 5;
2788  for (i = 1; i <= 4; ++i) {
2789  xyz[i*3 - 3] = v[0]*cosphi[i - 1];
2790  xyz[i*3 - 2] = v[0]*sinphi[i - 1];
2791  iface[i - 1] = i;
2792  tface[i - 1] = tt[i - 1];
2793  }
2794  if (!Hoption.Zero) fEdgeIdx = 0;
2795  else {
2796  fEdgeIdx = firstStackNumberDrawn;
2797  fColorBottom = fColorMain[fEdgeIdx];
2798  }
2799  (this->*fDrawFace)(icodes, xyz, 4, iface, tface);
2800  }
2801  // D R A W T O P F A C E
2802  if (ivis[5] != 0 && v[nv - 1] > 0) {
2803  icodes[2] = nv - 1;
2804  icodes[3] = 6;
2805  for (i = 1; i <= 4; ++i) {
2806  iface[i - 1] = 5 - i + 4;
2807  tface[i - 1] = tt[5 - i + (nv << 2) - 5];
2808  }
2809  Int_t cs = fColorTop;
2810  if ( nv <= 3 ) fEdgeIdx = 0 ; // no stack or stack with only one histo
2811  else {
2812  if ( nv > 2 && (v[nv-1] == v[nv-2])) {
2813  for (iv = nv-1; iv>2; iv--) {
2814  if (v[nv-1] == v[iv-1]) {
2815  fColorTop = fColorMain[iv-2];
2816  fEdgeIdx = iv-2;
2817  }
2818  }
2819  }
2820  }
2821  (this->*fDrawFace)(icodes, xyz, 4, iface, tface);
2822  fColorTop = cs;
2823  }
2824  }
2825  // N E X T P H I
2826 L400:
2827  iphi += incr;
2828  if (iphi == 0) iphi = kphi;
2829  if (iphi > kphi) iphi = 1;
2830  if (iphi != iphi2) goto L100;
2831  if (incr == 0) {
2832  if (vSize > kVSizeMax) {
2833  delete [] v;
2834  delete [] tt;
2835  }
2836  return;
2837  }
2838  if (incr < 0) {
2839  incr = 0;
2840  goto L100;
2841  }
2842  incr = -1;
2843  iphi = iphi1;
2844  goto L400;
2845 }
2846 
2847 ////////////////////////////////////////////////////////////////////////////////
2848 /// Draw stack of lego-plots spheric coordinates
2849 ///
2850 /// \param[in] ipsdr pseudo-rapidity flag
2851 /// \param[in] iordr order of variables (0 - THETA,PHI; 1 - PHI,THETA)
2852 /// \param[in] na number of steps along 1st variable
2853 /// \param[in] nb number of steps along 2nd variable
2854 ///
2855 /// - `chopt` = 'BF' from BACK to FRONT
2856 /// - `chopt` = 'FB' from FRONT to BACK
2857 
2858 void TPainter3dAlgorithms::LegoSpherical(Int_t ipsdr, Int_t iordr, Int_t na, Int_t nb, const char *chopt)
2859 {
2860  Int_t iphi, jphi, kphi, incr, nphi, ivis[6], iopt, iphi1, iphi2, iface[4], i, j;
2861  Double_t tface[4], costh[4];
2862  Double_t sinth[4];
2863  Int_t k1, k2, ia, ib, incrth, ith, jth, kth, nth, mth, ith1, ith2, nv;
2864  Double_t ab[8]; // was [2][4]
2865  Double_t th;
2866  Int_t iv, icodes[4];
2867  Double_t zn, cosphi[4];
2868  Double_t sinphi[4], th1, th2, phi;
2869  Double_t xyz[24]; // was [3][8]
2870  Double_t phi1, phi2;
2871  ia = ib = 0;
2872  TView *view = 0;
2873  Int_t firstStackNumberDrawn=-1 ; // necessary to compute fColorBottom when the 0 option is set and when the stack is seen from below (bottomview, theta<0.)
2874 
2875  if (gPad) view = gPad->GetView();
2876  if (!view) {
2877  Error("LegoSpherical", "no TView in current pad");
2878  return;
2879  }
2880 
2881  if (iordr == 0) {
2882  jth = 1;
2883  jphi = 2;
2884  nth = na;
2885  nphi = nb;
2886  } else {
2887  jth = 2;
2888  jphi = 1;
2889  nth = nb;
2890  nphi = na;
2891  }
2892  if (fNaphi < nth + 3 || fNaphi < nphi + 3) {
2893  if (fAphi) { delete [] fAphi; fAphi = 0; }
2894  fNaphi = TMath::Max(nth, nphi) + 3;
2895  fAphi = new Double_t[fNaphi];
2896  }
2897  if (fAphi == 0) {
2898  Error("LegoSpherical", "failed to allocate array fAphi[%d]", fNaphi);
2899  fNaphi = 0;
2900  return;
2901  }
2902  iopt = 2;
2903  if (*chopt == 'B' || *chopt == 'b') iopt = 1;
2904 
2905  // Allocate v and tt arrays
2906  Double_t *v, *tt;
2907  Int_t vSize = fNStack+2;
2908  if (vSize > kVSizeMax) {
2909  v = new Double_t[vSize];
2910  tt = new Double_t[4*vSize];
2911  } else {
2912  vSize = kVSizeMax;
2913  v = &gV[0];
2914  tt = &gTT[0];
2915  }
2916 
2917  // P R E P A R E P H I A R R A Y
2918  // F I N D C R I T I C A L P H I S E C T O R S
2919  nv = 0;
2920  kphi = nphi;
2921  mth = nth / 2;
2922  if (mth == 0) mth = 1;
2923  if (iordr == 0) ia = mth;
2924  if (iordr != 0) ib = mth;
2925  for (i = 1; i <= nphi; ++i) {
2926  if (iordr == 0) ib = i;
2927  if (iordr != 0) ia = i;
2928  (this->*fLegoFunction)(ia, ib, nv, ab, v, tt);
2929  if (i == 1) fAphi[0] = ab[jphi - 1];
2930  fAphi[i - 1] = (fAphi[i - 1] + ab[jphi - 1]) / (float)2.;
2931  fAphi[i] = ab[jphi + 3];
2932  }
2933  view->FindPhiSectors(iopt, kphi, fAphi, iphi1, iphi2);
2934 
2935  // P R E P A R E T H E T A A R R A Y
2936  if (iordr == 0) ib = 1;
2937  if (iordr != 0) ia = 1;
2938  for (i = 1; i <= nth; ++i) {
2939  if (iordr == 0) ia = i;
2940  if (iordr != 0) ib = i;
2941  (this->*fLegoFunction)(ia, ib, nv, ab, v, tt);
2942  if (i == 1) fAphi[0] = ab[jth - 1];
2943  fAphi[i - 1] = (fAphi[i - 1] + ab[jth - 1]) / (float)2.;
2944  fAphi[i] = ab[jth + 3];
2945  }
2946 
2947  // D R A W S T A C K O F L E G O - P L O T S
2948  kth = nth;
2949 
2950  incr = 1;
2951  iphi = iphi1;
2952 L100:
2953  if (iphi > nphi) goto L500;
2954 
2955  // F I N D C R I T I C A L T H E T A S E C T O R S
2956  if (!iordr) {ia = mth; ib = iphi; }
2957  else {ia = iphi;ib = mth; }
2958  (this->*fLegoFunction)(ia, ib, nv, ab, v, tt);
2959  phi = (ab[jphi - 1] + ab[jphi + 3]) / (float)2.;
2960  view->FindThetaSectors(iopt, phi, kth, fAphi, ith1, ith2);
2961  incrth = 1;
2962  ith = ith1;
2963 L200:
2964  if (ith > nth) goto L400;
2965  if (iordr == 0) ia = ith;
2966  if (iordr != 0) ib = ith;
2967  (this->*fLegoFunction)(ia, ib, nv, ab, v, tt);
2968  if (nv < 2 || nv > vSize) goto L400;
2969 
2970  // D E F I N E V I S I B I L I T Y O F S I D E S
2971  for (i = 1; i <= 6; ++i) ivis[i - 1] = 0;
2972 
2973  phi1 = kRad*ab[jphi - 1];
2974  phi2 = kRad*ab[jphi + 3];
2975  th1 = kRad*ab[jth - 1];
2976  th2 = kRad*ab[jth + 3];
2977  view->FindNormal(TMath::Sin(phi1), -TMath::Cos(phi1), 0, zn);
2978  if (zn > 0) ivis[1] = 1;
2979  view->FindNormal(-TMath::Sin(phi2), TMath::Cos(phi2), 0, zn);
2980  if (zn > 0) ivis[3] = 1;
2981  phi = (phi1 + phi2) / (float)2.;
2982  view->FindNormal(-TMath::Cos(phi)*TMath::Cos(th1), -TMath::Sin(phi)*TMath::Cos(th1), TMath::Sin(th1), zn);
2983  if (zn > 0) ivis[0] = 1;
2984  view->FindNormal(TMath::Cos(phi)*TMath::Cos(th2), TMath::Sin(phi)*TMath::Cos(th2), -TMath::Sin(th2), zn);
2985  if (zn > 0) ivis[2] = 1;
2986  th = (th1 + th2) / (float)2.;
2987  if (ipsdr == 1) th = kRad*90;
2988  view->FindNormal(TMath::Cos(phi)*TMath::Sin(th), TMath::Sin(phi)*TMath::Sin(th), TMath::Cos(th), zn);
2989  if (zn < 0) ivis[4] = 1;
2990  if (zn > 0) ivis[5] = 1;
2991 
2992  // D R A W S T A C K
2993  icodes[0] = ia;
2994  icodes[1] = ib;
2995  for (i = 1; i <= 4; ++i) {
2996  j = i;
2997  if (iordr != 0 && i == 2) j = 4;
2998  if (iordr != 0 && i == 4) j = 2;
2999  costh[j - 1] = TMath::Cos(kRad*ab[jth + 2*i - 3]);
3000  sinth[j - 1] = TMath::Sin(kRad*ab[jth + 2*i - 3]);
3001  cosphi[j - 1] = TMath::Cos(kRad*ab[jphi + 2*i - 3]);
3002  sinphi[j - 1] = TMath::Sin(kRad*ab[jphi + 2*i - 3]);
3003  }
3004  firstStackNumberDrawn = -1;
3005  for (iv = 1; iv < nv; ++iv) {
3006  if (ipsdr == 1) {
3007  for (i = 1; i <= 4; ++i) {
3008  xyz[i*3 - 3] = v[iv - 1]*cosphi[i - 1];
3009  xyz[i*3 - 2] = v[iv - 1]*sinphi[i - 1];
3010  xyz[i*3 - 1] = v[iv - 1]*costh[i - 1] / sinth[i - 1];
3011  xyz[(i + 4)*3 - 3] = v[iv]*cosphi[i - 1];
3012  xyz[(i + 4)*3 - 2] = v[iv]*sinphi[i - 1];
3013  xyz[(i + 4)*3 - 1] = v[iv]*costh[i - 1] / sinth[i - 1];
3014  }
3015  } else {
3016  for (i = 1; i <= 4; ++i) {
3017  xyz[i*3 - 3] = v[iv - 1]*sinth[i - 1]*cosphi[i - 1];
3018  xyz[i*3 - 2] = v[iv - 1]*sinth[i - 1]*sinphi[i - 1];
3019  xyz[i*3 - 1] = v[iv - 1]*costh[i - 1];
3020  xyz[(i + 4)*3 - 3] = v[iv]*sinth[i - 1]*cosphi[i - 1];
3021  xyz[(i + 4)*3 - 2] = v[iv]*sinth[i - 1]*sinphi[i - 1];
3022  xyz[(i + 4)*3 - 1] = v[iv]*costh[i - 1];
3023  }
3024  }
3025  if (v[iv - 1] >= v[iv]) continue;
3026  icodes[2] = iv;
3027  for (i = 1; i <= 4; ++i) {
3028  if (ivis[i - 1] == 0) continue;
3029  k1 = i - 1;
3030  if (i == 1) k1 = 4;
3031  k2 = i;
3032  iface[0] = k1;
3033  iface[1] = k2;
3034  iface[2] = k2 + 4;
3035  iface[3] = k1 + 4;
3036  tface[0] = tt[k1 + (iv << 2) - 5];
3037  tface[1] = tt[k2 + (iv << 2) - 5];
3038  tface[2] = tt[k2 + ((iv + 1) << 2) - 5];
3039  tface[3] = tt[k1 + ((iv + 1) << 2) - 5];
3040  icodes[3] = i;
3041  fEdgeIdx = iv-1;
3042  (this->*fDrawFace)(icodes, xyz, 4, iface, tface);
3043  }
3044  if ( firstStackNumberDrawn==-1 ) firstStackNumberDrawn = fEdgeIdx;
3045  }
3046  // D R A W B O T T O M F A C E
3047  if (ivis[4] != 0 && v[0] > 0) {
3048  icodes[2] = 1;
3049  icodes[3] = 5;
3050  for (i = 1; i <= 4; ++i) {
3051  if (ipsdr == 1) {
3052  xyz[i*3 - 3] = v[0]*cosphi[i - 1];
3053  xyz[i*3 - 2] = v[0]*sinphi[i - 1];
3054  xyz[i*3 - 1] = v[0]*costh[i - 1] / sinth[i - 1];
3055  } else {
3056  xyz[i*3 - 3] = v[0]*sinth[i - 1]*cosphi[i - 1];
3057  xyz[i*3 - 2] = v[0]*sinth[i - 1]*sinphi[i - 1];
3058  xyz[i*3 - 1] = v[0]*costh[i - 1];
3059  }
3060  iface[i - 1] = 5 - i;
3061  tface[i - 1] = tt[5 - i - 1];
3062  }
3063  if (!Hoption.Zero) fEdgeIdx = 0;
3064  else {
3065  fEdgeIdx = firstStackNumberDrawn;
3066  fColorBottom = fColorMain[fEdgeIdx];
3067  }
3068  (this->*fDrawFace)(icodes, xyz, 4, iface, tface);
3069  }
3070  // D R A W T O P F A C E
3071  if (ivis[5] != 0 && v[nv - 1] > 0) {
3072  icodes[2] = nv - 1;
3073  icodes[3] = 6;
3074  for (i = 1; i <= 4; ++i) {
3075  iface[i - 1] = i + 4;
3076  tface[i - 1] = tt[i + 4 + 2*nv - 5];
3077  }
3078  Int_t cs = fColorTop;
3079  if ( nv <= 3 ) fEdgeIdx = 0 ; // no stack or stack with only one histo
3080  else {
3081  if ( nv > 2 && (v[nv-1] == v[nv-2])) {
3082  for (iv = nv-1; iv>2; iv--) {
3083  if (v[nv-1] == v[iv-1]) {
3084  fColorTop = fColorMain[iv-2];
3085  fEdgeIdx = iv-2;
3086  }
3087  }
3088  }
3089  }
3090  (this->*fDrawFace)(icodes, xyz, 4, iface, tface);
3091  fColorTop = cs;
3092  }
3093  // N E X T T H E T A
3094 L400:
3095  ith += incrth;
3096  if (ith == 0) ith = kth;
3097  if (ith > kth) ith = 1;
3098  if (ith != ith2) goto L200;
3099  if (incrth == 0) goto L500;
3100  if (incrth < 0) {
3101  incrth = 0;
3102  goto L200;
3103  }
3104  incrth = -1;
3105  ith = ith1;
3106  goto L400;
3107  // N E X T P H I
3108 L500:
3109  iphi += incr;
3110  if (iphi == 0) iphi = kphi;
3111  if (iphi > kphi) iphi = 1;
3112  if (iphi != iphi2) goto L100;
3113  if (incr == 0) {
3114  if (vSize > kVSizeMax) {
3115  delete [] v;
3116  delete [] tt;
3117  }
3118  return;
3119  }
3120  if (incr < 0) {
3121  incr = 0;
3122  goto L100;
3123  }
3124  incr = -1;
3125  iphi = iphi1;
3126  goto L500;
3127 }
3128 
3129 ////////////////////////////////////////////////////////////////////////////////
3130 /// Set light source
3131 ///
3132 /// \param[in] nl source number: 1 off all light sources, 0 set diffused light
3133 /// \param[in] xl intensity of the light source
3134 /// \param[in] xscr `yscr` `zscr` direction of the light (in respect of the screen)
3135 ///
3136 /// \param[out] irep reply (0 - O.K, -1 error)
3137 
3138 
3139 void TPainter3dAlgorithms::LightSource(Int_t nl, Double_t yl, Double_t xscr,
3140  Double_t yscr, Double_t zscr, Int_t &irep)
3141 {
3142  /* Local variables */
3143  Int_t i;
3144  Double_t s;
3145 
3146  irep = 0;
3147  if (nl < 0) goto L100;
3148  else if (nl == 0) goto L200;
3149  else goto L300;
3150 
3151  // S W I T C H O F F L I G H T S
3152 L100:
3153  fLoff = 1;
3154  fYdl = 0;
3155  for (i = 1; i <= 4; ++i) {
3156  fYls[i - 1] = 0;
3157  }
3158  return;
3159  // S E T D I F F U S E D L I G H T
3160 L200:
3161  if (yl < 0) {
3162  Error("LightSource", "negative light intensity");
3163  irep = -1;
3164  return;
3165  }
3166  fYdl = yl;
3167  goto L400;
3168  // S E T L I G H T S O U R C E
3169 L300:
3170  if (nl > 4 || yl < 0) {
3171  Error("LightSource", "illegal light source number (nl=%d, yl=%f)", nl, yl);
3172  irep = -1;
3173  return;
3174  }
3175  s = TMath::Sqrt(xscr*xscr + yscr*yscr + zscr*zscr);
3176  if (s == 0) {
3177  Error("LightSource", "light source is placed at origin");
3178  irep = -1;
3179  return;
3180  }
3181  fYls[nl - 1] = yl;
3182  fVls[nl*3 - 3] = xscr / s;
3183  fVls[nl*3 - 2] = yscr / s;
3184  fVls[nl*3 - 1] = zscr / s;
3185  // C H E C K L I G H T S
3186 L400:
3187  fLoff = 0;
3188  if (fYdl != 0) return;
3189  for (i = 1; i <= 4; ++i) {
3190  if (fYls[i - 1] != 0) return;
3191  }
3192  fLoff = 1;
3193 }
3194 
3195 ////////////////////////////////////////////////////////////////////////////////
3196 /// Find surface luminosity at given point
3197 ///
3198 /// \param[in] anorm surface normal at given point
3199 ///
3200 /// \param[out] flum luminosity
3201 
3202 void TPainter3dAlgorithms::Luminosity(Double_t *anorm, Double_t &flum)
3203 {
3204  /* Local variables */
3205  Double_t cosn, cosr;
3206  Int_t i;
3207  Double_t s, vl[3], vn[3];
3208  TView *view = 0;
3209 
3210  if (gPad) view = gPad->GetView();
3211  if (!view) return;
3212 
3213  /* Parameter adjustments */
3214  --anorm;
3215 
3216  flum = 0;
3217  if (fLoff != 0) return;
3218 
3219  // T R A N S F E R N O R M A L T O SCREEN COORDINATES
3220  view->NormalWCtoNDC(&anorm[1], vn);
3221  s = TMath::Sqrt(vn[0]*vn[0] + vn[1]*vn[1] + vn[2]*vn[2]);
3222  if (vn[2] < 0) s = -(Double_t)s;
3223  vn[0] /= s;
3224  vn[1] /= s;
3225  vn[2] /= s;
3226 
3227  // F I N D L U M I N O S I T Y
3228  flum = fYdl*fQA;
3229  for (i = 1; i <= 4; ++i) {
3230  if (fYls[i - 1] <= 0) continue;
3231  vl[0] = fVls[i*3 - 3];
3232  vl[1] = fVls[i*3 - 2];
3233  vl[2] = fVls[i*3 - 1];
3234  cosn = vl[0]*vn[0] + vl[1]*vn[1] + vl[2]*vn[2];
3235  if (cosn < 0) continue;
3236  cosr = vn[1]*(vn[2]*vl[1] - vn[1]*vl[2]) - vn[0]*(vn[0]*vl[2]
3237  - vn[2]*vl[0]) + vn[2]*cosn;
3238  if (cosr <= 0) cosr = 0;
3239  flum += fYls[i - 1]*(fQD*cosn + fQS*TMath::Power(cosr, fNqs));
3240  }
3241 }
3242 
3243 ////////////////////////////////////////////////////////////////////////////////
3244 /// Modify SCREEN
3245 ///
3246 /// \param[in] r1 1-st point of the line
3247 /// \param[in] r2 2-nd point of the line
3248 
3249 void TPainter3dAlgorithms::ModifyScreen(Double_t *r1, Double_t *r2)
3250 {
3251  /* Local variables */
3252  Int_t i, i1, i2;
3253  Double_t x1, x2, y1, y2, dy, ww, yy1, yy2, *tn;
3254 
3255  /* Parameter adjustments */
3256  --r2;
3257  --r1;
3258 
3259  TView *view = 0;
3260  if (gPad) view = gPad->GetView();
3261 
3262  if (view) {
3263  tn = view->GetTN();
3264  if (tn) {
3265  x1 = tn[0]*r1[1] + tn[1]*r1[2] + tn[2]*r1[3] + tn[3];
3266  x2 = tn[0]*r2[1] + tn[1]*r2[2] + tn[2]*r2[3] + tn[3];
3267  y1 = tn[4]*r1[1] + tn[5]*r1[2] + tn[6]*r1[3] + tn[7];
3268  y2 = tn[4]*r2[1] + tn[5]*r2[2] + tn[6]*r2[3] + tn[7];
3269  } else {
3270  Error("ModifyScreen", "invalid TView in current pad");
3271  return;
3272  }
3273  } else {
3274  Error("ModifyScreen", "no TView in current pad");
3275  return;
3276  }
3277 
3278  if (x1 >= x2) {
3279  ww = x1;
3280  x1 = x2;
3281  x2 = ww;
3282  ww = y1;
3283  y1 = y2;
3284  y2 = ww;
3285  }
3286  i1 = Int_t((x1 - fX0) / fDX) + 15;
3287  i2 = Int_t((x2 - fX0) / fDX) + 15;
3288  if (i1 == i2) return;
3289 
3290  // M O D I F Y B O U N D A R I E S OF THE SCREEN
3291  dy = (y2 - y1) / (i2 - i1);
3292  for (i = i1; i <= i2 - 1; ++i) {
3293  yy1 = y1 + dy*(i - i1);
3294  yy2 = yy1 + dy;
3295  if (fD[2*i - 2] > yy1) fD[2*i - 2] = yy1;
3296  if (fD[2*i - 1] > yy2) fD[2*i - 1] = yy2;
3297  if (fU[2*i - 2] < yy1) fU[2*i - 2] = yy1;
3298  if (fU[2*i - 1] < yy2) fU[2*i - 1] = yy2;
3299  }
3300 }
3301 
3302 ////////////////////////////////////////////////////////////////////////////////
3303 /// Store pointer to current algorithm to draw faces
3304 
3305 void TPainter3dAlgorithms::SetDrawFace(DrawFaceFunc_t drface)
3306 {
3307  fDrawFace = drface;
3308 }
3309 
3310 ////////////////////////////////////////////////////////////////////////////////
3311 /// Store pointer to current lego function
3312 
3313 void TPainter3dAlgorithms::SetLegoFunction(LegoFunc_t fun)
3314 {
3315  fLegoFunction = fun;
3316 }
3317 
3318 ////////////////////////////////////////////////////////////////////////////////
3319 /// Store pointer to current surface function
3320 
3321 void TPainter3dAlgorithms::SetSurfaceFunction(SurfaceFunc_t fun)
3322 {
3323  fSurfaceFunction = fun;
3324 }
3325 
3326 ////////////////////////////////////////////////////////////////////////////////
3327 /// Static function
3328 /// Store pointer to current implicit function
3329 
3330 void TPainter3dAlgorithms::SetF3(TF3 *f3)
3331 {
3332  fgCurrentF3 = f3;
3333 }
3334 
3335 ////////////////////////////////////////////////////////////////////////////////
3336 /// Static function
3337 /// Set the implicit function clipping box "off".
3338 
3339 void TPainter3dAlgorithms::SetF3ClippingBoxOff()
3340 {
3341  fgF3Clipping = 0;
3342 }
3343 
3344 ////////////////////////////////////////////////////////////////////////////////
3345 /// Static function
3346 /// Set the implicit function clipping box "on" and define the clipping box.
3347 /// xclip, yclip and zclip is a point within the function range. All the
3348 /// function value having x<=xclip and y<=yclip and z>=zclip are clipped.
3349 
3350 void TPainter3dAlgorithms::SetF3ClippingBoxOn(Double_t xclip,
3351  Double_t yclip, Double_t zclip)
3352 {
3353  fgF3Clipping = 1;
3354  fgF3XClip = xclip;
3355  fgF3YClip = yclip;
3356  fgF3ZClip = zclip;
3357 }
3358 
3359 ////////////////////////////////////////////////////////////////////////////////
3360 /// Store dark color for stack number n
3361 
3362 void TPainter3dAlgorithms::SetColorDark(Color_t color, Int_t n)
3363 {
3364  if (n < 0 ) {fColorBottom = color; return;}
3365  if (n > fNStack ) {fColorTop = color; return;}
3366  fColorDark[n] = color;
3367 }
3368 
3369 ////////////////////////////////////////////////////////////////////////////////
3370 /// Store color for stack number n
3371 
3372 void TPainter3dAlgorithms::SetColorMain(Color_t color, Int_t n)
3373 {
3374  if (n < 0 ) {fColorBottom = color; return;}
3375  if (n > fNStack ) {fColorTop = color; return;}
3376  fColorMain[n] = color;
3377 }
3378 
3379 ////////////////////////////////////////////////////////////////////////////////
3380 
3381 void TPainter3dAlgorithms::SetEdgeAtt(Color_t color, Style_t style, Width_t width, Int_t n)
3382 {
3383  // Store edge attributes
3384 
3385  fEdgeColor[n] = color;
3386  fEdgeStyle[n] = style;
3387  fEdgeWidth[n] = width;
3388 }
3389 
3390 ////////////////////////////////////////////////////////////////////////////////
3391 /// Decode side visibilities and order along R for sector
3392 ///
3393 /// \param[in] val encoded value
3394 ///
3395 /// \param[out] iv1-iv6 visibility of the sides
3396 /// \param[out] ir increment along R
3397 
3398 void TPainter3dAlgorithms::SideVisibilityDecode(Double_t val, Int_t &iv1, Int_t &iv2, Int_t &iv3, Int_t &iv4, Int_t &iv5, Int_t &iv6, Int_t &ir)
3399 {
3400  Int_t ivis[6], i, k, num;
3401 
3402  k = Int_t(val);
3403  num = 128;
3404  for (i = 1; i <= 6; ++i) {
3405  ivis[i - 1] = 0;
3406  num /= 2;
3407  if (k < num) continue;
3408  k -= num;
3409  ivis[i - 1] = 1;
3410  }
3411  ir = 1;
3412  if (k == 1) ir = -1;
3413  iv1 = ivis[5];
3414  iv2 = ivis[4];
3415  iv3 = ivis[3];
3416  iv4 = ivis[2];
3417  iv5 = ivis[1];
3418  iv6 = ivis[0];
3419 }
3420 
3421 ////////////////////////////////////////////////////////////////////////////////
3422 /// Encode side visibilities and order along R for sector
3423 ///
3424 /// \param[in] iopt options: 1: from BACK to FRONT 'BF', 2: from FRONT to BACK 'FB'
3425 /// \param[in] phi1 1st phi of sector
3426 /// \param[in] phi2 2nd phi of sector
3427 ///
3428 /// \param[out] val encoded value
3429 
3430 void TPainter3dAlgorithms::SideVisibilityEncode(Int_t iopt, Double_t phi1, Double_t phi2, Double_t &val)
3431 {
3432  /* Local variables */
3433  Double_t zn, phi;
3434  Int_t k = 0;
3435  TView *view = 0;
3436 
3437  if (gPad) view = gPad->GetView();
3438  if (!view) {
3439  Error("SideVisibilityEncode", "no TView in current pad");
3440  return;
3441  }
3442 
3443  view->FindNormal(0, 0, 1, zn);
3444  if (zn > 0) k += 64;
3445  if (zn < 0) k += 32;
3446  view->FindNormal(-TMath::Sin(phi2), TMath::Cos(phi2), 0, zn);
3447  if (zn > 0) k += 16;
3448  view->FindNormal(TMath::Sin(phi1), -TMath::Cos(phi1), 0, zn);
3449  if (zn > 0) k += 4;
3450  phi = (phi1 + phi2) / (float)2.;
3451  view->FindNormal(TMath::Cos(phi), TMath::Sin(phi), 0, zn);
3452  if (zn > 0) k += 8;
3453  if (zn < 0) k += 2;
3454  if ((zn <= 0 && iopt == 1) || (zn > 0 && iopt == 2)) ++k;
3455  val = Double_t(k);
3456 }
3457 
3458 ////////////////////////////////////////////////////////////////////////////////
3459 /// Set Spectrum
3460 ///
3461 /// \param[in] nl number of levels
3462 /// \param[in] fmin MIN function value
3463 /// \param[in] fmax MAX function value
3464 /// \param[in] ic initial color index (for 1st level)
3465 /// \param[in] idc color index increment
3466 ///
3467 /// \param[out] irep reply (0 O.K., -1 error)
3468 
3469 void TPainter3dAlgorithms::Spectrum(Int_t nl, Double_t fmin, Double_t fmax, Int_t ic, Int_t idc, Int_t &irep)
3470 {
3471  static const char *where = "Spectrum";
3472 
3473  /* Local variables */
3474  Double_t delf;
3475  Int_t i;
3476 
3477  irep = 0;
3478  if (nl == 0) {fNlevel = 0; return; }
3479 
3480  // C H E C K P A R A M E T E R S
3481  if (fmax <= fmin) {
3482  Error(where, "fmax (%f) less than fmin (%f)", fmax, fmin);
3483  irep = -1;
3484  return;
3485  }
3486  if (nl < 0 || nl > 256) {
3487  Error(where, "illegal number of levels (%d)", nl);
3488  irep = -1;
3489  return;
3490  }
3491  if (ic < 0) {
3492  Error(where, "initial color index is negative");
3493  irep = -1;
3494  return;
3495  }
3496  if (idc < 0) {
3497  Error(where, "color index increment must be positive");
3498  irep = -1;
3499  }
3500 
3501  // S E T S P E C T R
3502  const Int_t kMAXCOL = 50;
3503  delf = (fmax - fmin) / nl;
3504  fNlevel = -(nl + 1);
3505  for (i = 1; i <= nl+1; ++i) {
3506  fFunLevel[i - 1] = fmin + (i - 1)*delf;
3507  fColorLevel[i] = ic + (i - 1)*idc;
3508  if (ic <= kMAXCOL && fColorLevel[i] > kMAXCOL) fColorLevel[i] -= kMAXCOL;
3509  }
3510  fColorLevel[0] = fColorLevel[1];
3511  fColorLevel[nl + 1] = fColorLevel[nl];
3512 }
3513 
3514 ////////////////////////////////////////////////////////////////////////////////
3515 /// Draw surface in cartesian coordinate system
3516 ///
3517 /// \param[in] ang angle between X ang Y (not used in this method)
3518 /// \param[in] nx number of steps along X
3519 /// \param[in] ny number of steps along Y
3520 ///
3521 /// - `chopt` = 'BF' from BACK to FRONT
3522 /// - `chopt` = 'FB' from FRONT to BACK
3523 
3524 void TPainter3dAlgorithms::SurfaceCartesian(Double_t, Int_t nx, Int_t ny, const char *chopt)
3525 {
3526  Int_t iface[4] = { 1,2,3,4 };
3527  Int_t icodes[3];
3528  Double_t f[4*3], tt[4], xyz[4*3];
3529 
3530  TView *view = 0;
3531  if (gPad) view = gPad->GetView();
3532  if (!view) {
3533  Error("SurfaceCartesian", "no TView in current pad");
3534  return;
3535  }
3536  Double_t *tnorm = view->GetTnorm();
3537  if (!tnorm) return;
3538 
3539  // Define order of drawing
3540  Int_t incrx = (tnorm[8] < 0.) ? -1 : +1;
3541  Int_t incry = (tnorm[9] < 0.) ? -1 : +1;
3542  if (*chopt != 'B' && *chopt != 'b') { // front to back
3543  incrx = -incrx; incry = -incry;
3544  }
3545  Int_t ix1 = (incrx == +1) ? 1 : nx;
3546  Int_t iy1 = (incry == +1) ? 1 : ny;
3547  Int_t ix2 = (incrx == +1) ? nx : 1;
3548  Int_t iy2 = (incry == +1) ? ny : 1;
3549 
3550  // Draw surface
3551  THistPainter *painter = (THistPainter*)gCurrentHist->GetPainter();
3552  for (Int_t iy = iy1; iy != iy2+incry; iy += incry) {
3553  for (Int_t ix = ix1; ix != ix2+incrx; ix += incrx) {
3554  if (!painter->IsInside(ix,iy)) continue;
3555  (this->*fSurfaceFunction)(ix, iy, f, tt);
3556  for (Int_t i = 0; i < 4; ++i) {
3557  xyz[i*3 + 0] = f[i*3 + 0];
3558  xyz[i*3 + 1] = f[i*3 + 1];
3559  xyz[i*3 + 2] = f[i*3 + 2];
3560  // added EJB -->
3561  Double_t al, ab;
3562  if (Hoption.Proj == 1 ) {
3563  THistPainter::ProjectAitoff2xy(xyz[i*3 + 0], xyz[i*3 + 1], al, ab);
3564  xyz[i*3 + 0] = al;
3565  xyz[i*3 + 1] = ab;
3566  } else if (Hoption.Proj == 2 ) {
3567  THistPainter::ProjectMercator2xy(xyz[i*3 + 0], xyz[i*3 + 1], al, ab);
3568  xyz[i*3 + 0] = al;
3569  xyz[i*3 + 1] = ab;
3570  } else if (Hoption.Proj == 3) {
3571  THistPainter::ProjectSinusoidal2xy(xyz[i*3 + 0], xyz[i*3 + 1], al, ab);
3572  xyz[i*3 + 0] = al;
3573  xyz[i*3 + 1] = ab;
3574  } else if (Hoption.Proj == 4) {
3575  THistPainter::ProjectParabolic2xy(xyz[i*3 + 0], xyz[i*3 + 1], al, ab);
3576  xyz[i*3 + 0] = al;
3577  xyz[i*3 + 1] = ab;
3578  }
3579  }
3580  icodes[0] = ix;
3581  icodes[1] = iy;
3582  icodes[2] = -1; // -1 for data, 0 for front a back boxes
3583  fEdgeIdx = 0; // constant since stacks are not (yet?) handled for surfaces
3584  (this->*fDrawFace)(icodes, xyz, 4, iface, tt);
3585  }
3586  }
3587 }
3588 
3589 ////////////////////////////////////////////////////////////////////////////////
3590 /// Service function for Surfaces
3591 
3592 void TPainter3dAlgorithms::SurfaceFunction(Int_t ia, Int_t ib, Double_t *f, Double_t *t)
3593 {
3594  static Int_t ixadd[4] = { 0,1,1,0 };
3595  static Int_t iyadd[4] = { 0,0,1,1 };
3596 
3597  Double_t rinrad = gStyle->GetLegoInnerR();
3598  Double_t dangle = 10; //Delta angle for Rapidity option
3599  Double_t yval1l, yval2l;
3600  Double_t xlab1l, xlab2l, ylab1l, ylab2l;
3601  Int_t i, ixa, iya, icx, ixt, iyt;
3602 
3603  /* Parameter adjustments */
3604  --t;
3605  f -= 4;
3606 
3607  ixt = ia + Hparam.xfirst - 1;
3608  iyt = ib + Hparam.yfirst - 1;
3609 
3610  // xval1l = Hparam.xmin;
3611  // xval2l = Hparam.xmax;
3612  yval1l = Hparam.ymin;
3613  yval2l = Hparam.ymax;
3614 
3615  xlab1l = gCurrentHist->GetXaxis()->GetXmin();
3616  xlab2l = gCurrentHist->GetXaxis()->GetXmax();
3617  if (Hoption.Logx) {
3618  if (xlab2l>0) {
3619  if (xlab1l>0) xlab1l = TMath::Log10(xlab1l);
3620  else xlab1l = TMath::Log10(0.001*xlab2l);
3621  xlab2l = TMath::Log10(xlab2l);
3622  }
3623  }
3624  ylab1l = gCurrentHist->GetYaxis()->GetXmin();
3625  ylab2l = gCurrentHist->GetYaxis()->GetXmax();
3626  if (Hoption.Logy) {
3627  if (ylab2l>0) {
3628  if (ylab1l>0) ylab1l = TMath::Log10(ylab1l);
3629  else ylab1l = TMath::Log10(0.001*ylab2l);
3630  ylab2l = TMath::Log10(ylab2l);
3631  }
3632  }
3633 
3634  for (i = 1; i <= 4; ++i) {
3635  ixa = ixadd[i - 1];
3636  iya = iyadd[i - 1];
3637  Double_t xwid = gCurrentHist->GetXaxis()->GetBinWidth(ixt+ixa);
3638  Double_t ywid = gCurrentHist->GetYaxis()->GetBinWidth(iyt+iya);
3639 
3640  // Compute the cell position in cartesian coordinates
3641  // and compute the LOG if necessary
3642  f[i*3 + 1] = gCurrentHist->GetXaxis()->GetBinLowEdge(ixt+ixa) + 0.5*xwid;
3643  f[i*3 + 2] = gCurrentHist->GetYaxis()->GetBinLowEdge(iyt+iya) + 0.5*ywid;
3644  if (Hoption.Logx) {
3645  if (f[i*3 + 1] > 0) f[i*3 + 1] = TMath::Log10(f[i*3 + 1]);
3646  else f[i*3 + 1] = Hparam.xmin;
3647  }
3648  if (Hoption.Logy) {
3649  if (f[i*3 + 2] > 0) f[i*3 + 2] = TMath::Log10(f[i*3 + 2]);
3650  else f[i*3 + 2] = Hparam.ymin;
3651  }
3652 
3653  // Transform the cell position in the required coordinate system
3654  if (Hoption.System == kPOLAR) {
3655  f[i*3 + 1] = 360*(f[i*3 + 1] - xlab1l) / (xlab2l - xlab1l);
3656  f[i*3 + 2] = (f[i*3 + 2] - yval1l) / (yval2l - yval1l);
3657  } else if (Hoption.System == kCYLINDRICAL) {
3658  f[i*3 + 1] = 360*(f[i*3 + 1] - xlab1l) / (xlab2l - xlab1l);
3659  } else if (Hoption.System == kSPHERICAL) {
3660  f[i*3 + 1] = 360*(f[i*3 + 1] - xlab1l) / (xlab2l - xlab1l);
3661  f[i*3 + 2] = 360*(f[i*3 + 2] - ylab1l) / (ylab2l - ylab1l);
3662  } else if (Hoption.System == kRAPIDITY) {
3663  f[i*3 + 1] = 360*(f[i*3 + 1] - xlab1l) / (xlab2l - xlab1l);
3664  f[i*3 + 2] = (180 - dangle*2)*(f[i*3 + 2] - ylab1l) / (ylab2l - ylab1l) + dangle;
3665  }
3666 
3667  // Get the content of the table. If the X index (ICX) is
3668  // greater than the X size of the table (NCX), that's mean
3669  // IGTABL tried to close the surface and in this case the
3670  // first channel should be used. */
3671  icx = ixt + ixa;
3672  if (icx > Hparam.xlast) icx = 1;
3673  f[i*3+3] = Hparam.factor*gCurrentHist->GetBinContent(icx, iyt + iya);
3674  if (Hoption.Logz) {
3675  if (f[i*3+3] > 0) f[i*3+3] = TMath::Log10(f[i*3+3]);
3676  else f[i*3+3] = Hparam.zmin;
3677  if (f[i*3+3] < Hparam.zmin) f[i*3+3] = Hparam.zmin;
3678  if (f[i*3+3] > Hparam.zmax) f[i*3+3] = Hparam.zmax;
3679  } else {
3680  f[i*3+3] = TMath::Max(Hparam.zmin, f[i*3+3]);
3681  f[i*3+3] = TMath::Min(Hparam.zmax, f[i*3+3]);
3682  }
3683 
3684  // The colors on the surface can represent the content or the errors.
3685  // if (fSumw2.fN) t[i] = gCurrentHist->GetBinError(icx, iyt + iya);
3686  // else t[i] = f[i * 3 + 3];
3687  t[i] = f[i * 3 + 3];
3688  }
3689 
3690  // Define the position of the colored contours for SURF3
3691  if (Hoption.Surf == 23) {
3692  for (i = 1; i <= 4; ++i) f[i * 3 + 3] = fRmax[2];
3693  }
3694 
3695  if (Hoption.System == kCYLINDRICAL || Hoption.System == kSPHERICAL || Hoption.System == kRAPIDITY) {
3696  for (i = 1; i <= 4; ++i) {
3697  f[i*3 + 3] = (1 - rinrad)*((f[i*3 + 3] - Hparam.zmin) /
3698  (Hparam.zmax - Hparam.zmin)) + rinrad;
3699  }
3700  }
3701 }
3702 
3703 ////////////////////////////////////////////////////////////////////////////////
3704 /// Draw surface in polar coordinates
3705 ///
3706 /// \param[in] iordr order of variables (0 - R,PHI, 1 - PHI,R)
3707 /// \param[in] na number of steps along 1st variable
3708 /// \param[in] nb number of steps along 2nd variable
3709 ///
3710 /// - `chopt` = 'BF' from BACK to FRONT
3711 /// - `chopt` = 'FB' from FRONT to BACK
3712 
3713 void TPainter3dAlgorithms::SurfacePolar(Int_t iordr, Int_t na, Int_t nb, const char *chopt)
3714 {
3715  /* Initialized data */
3716  static Int_t iface[4] = { 1,2,3,4 };
3717  TView *view = 0;
3718 
3719  if (gPad) view = gPad->GetView();
3720  if (!view) {
3721  Error("SurfacePolar", "no TView in current pad");
3722  return;
3723  }
3724 
3725  Int_t iphi, jphi, kphi, incr, nphi, iopt, iphi1, iphi2;
3726  Double_t f[12] /* was [3][4] */;
3727  Int_t i, j, incrr, ir1, ir2;
3728  Double_t z;
3729  Int_t ia, ib, ir, jr, nr, icodes[3]; // was icode[2]. One element more to differentiate front & back boxes from data
3730  Double_t tt[4];
3731  Double_t phi, ttt[4], xyz[12] /* was [3][4] */;
3732  ia = ib = 0;
3733 
3734  if (iordr == 0) {
3735  jr = 1;
3736  jphi = 2;
3737  nr = na;
3738  nphi = nb;
3739  } else {
3740  jr = 2;
3741  jphi = 1;
3742  nr = nb;
3743  nphi = na;
3744  }
3745  if (fNaphi < nphi + 3) {
3746  if (fAphi) { delete [] fAphi; fAphi = 0; }
3747  fNaphi =nphi + 3;
3748  fAphi = new Double_t[fNaphi];
3749  }
3750  if (fAphi == 0) {
3751  Error("SurfacePolar", "failed to allocate array fAphi[%d]", fNaphi);
3752  fNaphi = 0;
3753  return;
3754  }
3755  iopt = 2;
3756  if (*chopt == 'B' || *chopt == 'b') iopt = 1;
3757 
3758  // P R E P A R E P H I A R R A Y
3759  // F I N D C R I T I C A L S E C T O R S
3760  kphi = nphi;
3761  if (iordr == 0) ia = nr;
3762  if (iordr != 0) ib = nr;
3763  for (i = 1; i <= nphi; ++i) {
3764  if (iordr == 0) ib = i;
3765  if (iordr != 0) ia = i;
3766  (this->*fSurfaceFunction)(ia, ib, f, tt);
3767  if (i == 1) fAphi[0] = f[jphi - 1];
3768  fAphi[i - 1] = (fAphi[i - 1] + f[jphi - 1]) / (float)2.;
3769  fAphi[i] = f[jphi + 5];
3770  }
3771  view->FindPhiSectors(iopt, kphi, fAphi, iphi1, iphi2);
3772 
3773  // D R A W S U R F A C E
3774  icodes[2] = -1; // -1 for data, 0 for front a back boxes
3775  fEdgeIdx = 0; // constant since stacks are not (yet?) handled for surfaces
3776  incr = 1;
3777  iphi = iphi1;
3778 L100:
3779  if (iphi > nphi) goto L300;
3780 
3781  // F I N D O R D E R A L O N G R
3782  if (iordr == 0) {ia = nr; ib = iphi;}
3783  else {ia = iphi;ib = nr;}
3784 
3785  (this->*fSurfaceFunction)(ia, ib, f, tt);
3786  phi = kRad*((f[jphi - 1] + f[jphi + 5]) / 2);
3787  view->FindNormal(TMath::Cos(phi), TMath::Sin(phi), 0, z);
3788  incrr = 1;
3789  ir1 = 1;
3790  if ((z <= 0 && iopt == 1) || (z > 0 && iopt == 2)) {
3791  incrr = -1;
3792  ir1 = nr;
3793  }
3794  ir2 = nr - ir1 + 1;
3795  // D R A W S U R F A C E F O R S E C T O R
3796  for (ir = ir1; incrr < 0 ? ir >= ir2 : ir <= ir2; ir += incrr) {
3797  if (iordr == 0) ia = ir;
3798  if (iordr != 0) ib = ir;
3799 
3800  (this->*fSurfaceFunction)(ia, ib, f, tt);
3801  for (i = 1; i <= 4; ++i) {
3802  j = i;
3803  if (iordr != 0 && i == 2) j = 4;
3804  if (iordr != 0 && i == 4) j = 2;
3805  xyz[j*3 - 3] = f[jr + i*3 - 4]*TMath::Cos(f[jphi + i*3 - 4]*kRad);
3806  xyz[j*3 - 2] = f[jr + i*3 - 4]*TMath::Sin(f[jphi + i*3 - 4]*kRad);
3807  xyz[j*3 - 1] = f[i*3 - 1];
3808  ttt[j - 1] = tt[i - 1];
3809  }
3810  icodes[0] = ia;
3811  icodes[1] = ib;
3812  (this->*fDrawFace)(icodes, xyz, 4, iface, ttt);
3813  }
3814  // N E X T P H I
3815 L300:
3816  iphi += incr;
3817  if (iphi == 0) iphi = kphi;
3818  if (iphi > kphi) iphi = 1;
3819  if (iphi != iphi2) goto L100;
3820  if (incr == 0) return;
3821  if (incr < 0) {
3822  incr = 0;
3823  goto L100;
3824  }
3825  incr = -1;
3826  iphi = iphi1;
3827  goto L300;
3828 }
3829 
3830 ////////////////////////////////////////////////////////////////////////////////
3831 /// Draw surface in cylindrical coordinates
3832 ///
3833 /// \param[in] iordr order of variables (0 - Z,PHI; 1 - PHI,Z)
3834 /// \param[in] na number of steps along 1st variable
3835 /// \param[in] nb number of steps along 2nd variable
3836 ///
3837 /// - `chopt` = 'BF' from BACK to FRONT
3838 /// - `chopt` = 'FB' from FRONT to BACK
3839 
3840 void TPainter3dAlgorithms::SurfaceCylindrical(Int_t iordr, Int_t na, Int_t nb, const char *chopt)
3841 {
3842 
3843 
3844  /* Initialized data */
3845  static Int_t iface[4] = { 1,2,3,4 };
3846 
3847  Int_t iphi, jphi, kphi, incr, nphi, iopt, iphi1, iphi2;
3848  Int_t i, j, incrz, nz, iz1, iz2;
3849  Int_t ia, ib, iz, jz, icodes[3]; // was icode[2]. One element more to differentiate front & back boxes from data
3850  Double_t f[12] /* was [3][4] */;
3851  Double_t z;
3852  Double_t tt[4];
3853  Double_t ttt[4], xyz[12] /* was [3][4] */;
3854  ia = ib = 0;
3855  TView *view = 0;
3856 
3857  if (gPad) view = gPad->GetView();
3858  if (!view) {
3859  Error("SurfaceCylindrical", "no TView in current pad");
3860  return;
3861  }
3862 
3863  if (iordr == 0) {
3864  jz = 1;
3865  jphi = 2;
3866  nz = na;
3867  nphi = nb;
3868  } else {
3869  jz = 2;
3870  jphi = 1;
3871  nz = nb;
3872  nphi = na;
3873  }
3874  if (fNaphi < nphi + 3) {
3875  if (fAphi) { delete [] fAphi; fAphi = 0; }
3876  fNaphi =nphi + 3;
3877  fAphi = new Double_t[fNaphi];
3878  }
3879  if (fAphi == 0) {
3880  Error("SurfaceCylindrical", "failed to allocate array fAphi[%d]", fNaphi);
3881  fNaphi = 0;
3882  return;
3883  }
3884  iopt = 2;
3885  if (*chopt == 'B' || *chopt == 'b') iopt = 1;
3886 
3887  // P R E P A R E P H I A R R A Y
3888  // F I N D C R I T I C A L S E C T O R S
3889  kphi = nphi;
3890  if (iordr == 0) ia = nz;
3891  if (iordr != 0) ib = nz;
3892  for (i = 1; i <= nphi; ++i) {
3893  if (iordr == 0) ib = i;
3894  if (iordr != 0) ia = i;
3895  (this->*fSurfaceFunction)(ia, ib, f, tt);
3896  if (i == 1) fAphi[0] = f[jphi - 1];
3897  fAphi[i - 1] = (fAphi[i - 1] + f[jphi - 1]) / (float)2.;
3898  fAphi[i] = f[jphi + 5];
3899  }
3900  view->FindPhiSectors(iopt, kphi, fAphi, iphi1, iphi2);
3901 
3902  // F I N D O R D E R A L O N G Z
3903  incrz = 1;
3904  iz1 = 1;
3905  view->FindNormal(0, 0, 1, z);
3906  if ((z <= 0 && iopt == 1) || (z > 0 && iopt == 2)) {
3907  incrz = -1;
3908  iz1 = nz;
3909  }
3910  iz2 = nz - iz1 + 1;
3911 
3912  // D R A W S U R F A C E
3913  icodes[2] = -1; // -1 for data, 0 for front a back boxes
3914  fEdgeIdx = 0; // constant since stacks are not (yet?) handled for surfaces
3915  incr = 1;
3916  iphi = iphi1;
3917 L100:
3918  if (iphi > nphi) goto L400;
3919  for (iz = iz1; incrz < 0 ? iz >= iz2 : iz <= iz2; iz += incrz) {
3920  if (iordr == 0) {ia = iz; ib = iphi;}
3921  else {ia = iphi; ib = iz;}
3922  (this->*fSurfaceFunction)(ia, ib, f, tt);
3923  for (i = 1; i <= 4; ++i) {
3924  j = i;
3925  if (iordr == 0 && i == 2) j = 4;
3926  if (iordr == 0 && i == 4) j = 2;
3927  xyz[j*3 - 3] = f[i*3 - 1]*TMath::Cos(f[jphi + i*3 - 4]*kRad);
3928  xyz[j*3 - 2] = f[i*3 - 1]*TMath::Sin(f[jphi + i*3 - 4]*kRad);
3929  xyz[j*3 - 1] = f[jz + i*3 - 4];
3930  ttt[j - 1] = tt[i - 1];
3931  }
3932  icodes[0] = ia;
3933  icodes[1] = ib;
3934  (this->*fDrawFace)(icodes, xyz, 4, iface, ttt);
3935  }
3936  // N E X T P H I
3937 L400:
3938  iphi += incr;
3939  if (iphi == 0) iphi = kphi;
3940  if (iphi > kphi) iphi = 1;
3941  if (iphi != iphi2) goto L100;
3942  if (incr == 0) return;
3943  if (incr < 0) {
3944  incr = 0;
3945  goto L100;
3946  }
3947  incr = -1;
3948  iphi = iphi1;
3949  goto L400;
3950 }
3951 
3952 ////////////////////////////////////////////////////////////////////////////////
3953 /// Draw surface in spheric coordinates
3954 ///
3955 /// \param[in] ipsdr pseudo-rapidity flag
3956 /// \param[in] iordr order of variables (0 - THETA,PHI; 1 - PHI,THETA)
3957 /// \param[in] na number of steps along 1st variable
3958 /// \param[in] nb number of steps along 2nd variable
3959 ///
3960 /// - `chopt` = 'BF' from BACK to FRONT
3961 /// - `chopt` = 'FB' from FRONT to BACK
3962 
3963 void TPainter3dAlgorithms::SurfaceSpherical(Int_t ipsdr, Int_t iordr, Int_t na, Int_t nb, const char *chopt)
3964 {
3965  /* Initialized data */
3966  static Int_t iface[4] = { 1,2,3,4 };
3967 
3968  Int_t iphi, jphi, kphi, incr, nphi, iopt, iphi1, iphi2;
3969  Int_t i, j, incrth, ith, jth, kth, nth, mth, ith1, ith2;
3970  Int_t ia, ib, icodes[3]; // was icode[2]. One element more to differentiate front & back boxes from data
3971  Double_t f[12] /* was [3][4] */;
3972  Double_t tt[4];
3973  Double_t phi;
3974  Double_t ttt[4], xyz[12] /* was [3][4] */;
3975  ia = ib = 0;
3976  TView *view = 0;
3977 
3978  if (gPad) view = gPad->GetView();
3979  if (!view) {
3980  Error("SurfaceSpherical", "no TView in current pad");
3981  return;
3982  }
3983 
3984  if (iordr == 0) {
3985  jth = 1;
3986  jphi = 2;
3987  nth = na;
3988  nphi = nb;
3989  } else {
3990  jth = 2;
3991  jphi = 1;
3992  nth = nb;
3993  nphi = na;
3994  }
3995  if (fNaphi < nth + 3 || fNaphi < nphi + 3) {
3996  if (fAphi) { delete [] fAphi; fAphi = 0; }
3997  fNaphi = TMath::Max(nth, nphi) + 3;
3998  fAphi = new Double_t[fNaphi];
3999  }
4000  if (fAphi == 0) {
4001  Error("SurfaceSpherical", "failed to allocate array fAphi[%d]", fNaphi);
4002  fNaphi = 0;
4003  return;
4004  }
4005  iopt = 2;
4006  if (*chopt == 'B' || *chopt == 'b') iopt = 1;
4007 
4008  // P R E P A R E P H I A R R A Y
4009  // F I N D C R I T I C A L P H I S E C T O R S
4010  kphi = nphi;
4011  mth = nth / 2;
4012  if (mth == 0) mth = 1;
4013  if (iordr == 0) ia = mth;
4014  if (iordr != 0) ib = mth;
4015  for (i = 1; i <= nphi; ++i) {
4016  if (iordr == 0) ib = i;
4017  if (iordr != 0) ia = i;
4018  (this->*fSurfaceFunction)(ia, ib, f, tt);
4019  if (i == 1) fAphi[0] = f[jphi - 1];
4020  fAphi[i - 1] = (fAphi[i - 1] + f[jphi - 1]) / (float)2.;
4021  fAphi[i] = f[jphi + 5];
4022  }
4023  view->FindPhiSectors(iopt, kphi, fAphi, iphi1, iphi2);
4024 
4025  // P R E P A R E T H E T A A R R A Y
4026  if (iordr == 0) ib = 1;
4027  if (iordr != 0) ia = 1;
4028  for (i = 1; i <= nth; ++i) {
4029  if (iordr == 0) ia = i;
4030  if (iordr != 0) ib = i;
4031 
4032  (this->*fSurfaceFunction)(ia, ib, f, tt);
4033  if (i == 1) fAphi[0] = f[jth - 1];
4034  fAphi[i - 1] = (fAphi[i - 1] + f[jth - 1]) / (float)2.;
4035  fAphi[i] = f[jth + 5];
4036  }
4037 
4038  // D R A W S U R F A C E
4039  icodes[2] = -1; // -1 for data, 0 for front a back boxes
4040  fEdgeIdx = 0; // constant since stacks are not (yet?) handled for surfaces
4041  kth = nth;
4042  incr = 1;
4043  iphi = iphi1;
4044 L100:
4045  if (iphi > nphi) goto L500;
4046 
4047  // F I N D C R I T I C A L T H E T A S E C T O R S
4048  if (iordr == 0) {ia = mth; ib = iphi;}
4049  else {ia = iphi;ib = mth;}
4050 
4051  (this->*fSurfaceFunction)(ia, ib, f, tt);
4052  phi = (f[jphi - 1] + f[jphi + 5]) / (float)2.;
4053  view->FindThetaSectors(iopt, phi, kth, fAphi, ith1, ith2);
4054  incrth = 1;
4055  ith = ith1;
4056 L200:
4057  if (ith > nth) goto L400;
4058  if (iordr == 0) ia = ith;
4059  if (iordr != 0) ib = ith;
4060 
4061  (this->*fSurfaceFunction)(ia, ib, f, tt);
4062  if (ipsdr == 1) {
4063  for (i = 1; i <= 4; ++i) {
4064  j = i;
4065  if (iordr != 0 && i == 2) j = 4;
4066  if (iordr != 0 && i == 4) j = 2;
4067  xyz[j * 3 - 3] = f[i*3 - 1]*TMath::Cos(f[jphi + i*3 - 4]*kRad);
4068  xyz[j * 3 - 2] = f[i*3 - 1]*TMath::Sin(f[jphi + i*3 - 4]*kRad);
4069  xyz[j * 3 - 1] = f[i*3 - 1]*TMath::Cos(f[jth + i*3 - 4]*kRad) /
4070  TMath::Sin(f[jth + i*3 - 4]*kRad);
4071  ttt[j - 1] = tt[i - 1];
4072  }
4073  } else {
4074  for (i = 1; i <= 4; ++i) {
4075  j = i;
4076  if (iordr != 0 && i == 2) j = 4;
4077  if (iordr != 0 && i == 4) j = 2;
4078  xyz[j*3 - 3] = f[i*3 - 1]*TMath::Sin(f[jth + i*3 - 4]*kRad)*TMath::Cos(f[jphi + i*3 - 4]*kRad);
4079  xyz[j*3 - 2] = f[i*3 - 1]*TMath::Sin(f[jth + i*3 - 4]*kRad)*TMath::Sin(f[jphi + i*3 - 4]*kRad);
4080  xyz[j*3 - 1] = f[i*3 - 1]*TMath::Cos(f[jth + i*3 - 4]*kRad);
4081  ttt[j - 1] = tt[i - 1];
4082  }
4083  }
4084  icodes[0] = ia;
4085  icodes[1] = ib;
4086  (this->*fDrawFace)(icodes, xyz, 4, iface, ttt);
4087  // N E X T T H E T A
4088 L400:
4089  ith += incrth;
4090  if (ith == 0) ith = kth;
4091  if (ith > kth) ith = 1;
4092  if (ith != ith2) goto L200;
4093  if (incrth == 0) goto L500;
4094  if (incrth < 0) {
4095  incrth = 0;
4096  goto L200;
4097  }
4098  incrth = -1;
4099  ith = ith1;
4100  goto L400;
4101  // N E X T P H I
4102 L500:
4103  iphi += incr;
4104  if (iphi == 0) iphi = kphi;
4105  if (iphi > kphi) iphi = 1;
4106  if (iphi != iphi2) goto L100;
4107  if (incr == 0) return;
4108  if (incr < 0) {
4109  incr = 0;
4110  goto L100;
4111  }
4112  incr = -1;
4113  iphi = iphi1;
4114  goto L500;
4115 }
4116 
4117 ////////////////////////////////////////////////////////////////////////////////
4118 /// Set surface property coefficients
4119 ///
4120 /// \param[in] qqa diffusion coefficient for diffused light [0.,1.]
4121 /// \param[in] qqd diffusion coefficient for direct light [0.,1.]
4122 /// \param[in] qqs diffusion coefficient for reflected light [0.,1.]
4123 /// \param[in] nncs power coefficient for reflected light (.GE.1)
4124 ///
4125 /// Lightness model formula: Y = YD*QA + > YLi*(QD*cosNi+QS*cosRi)
4126 ///
4127 /// \param[out] irep reply (0 - O.K, -1 error)
4128 
4129 void TPainter3dAlgorithms::SurfaceProperty(Double_t qqa, Double_t qqd, Double_t qqs, Int_t nnqs, Int_t &irep)
4130 {
4131  irep = 0;
4132  if (qqa < 0 || qqa > 1 || qqd < 0 || qqd > 1 || qqs < 0 || qqs > 1 || nnqs < 1) {
4133  Error("SurfaceProperty", "error in coefficients");
4134  irep = -1;
4135  return;
4136  }
4137  fQA = qqa;
4138  fQD = qqd;
4139  fQS = qqs;
4140  fNqs = nnqs;
4141 }
4142 
4143 ////////////////////////////////////////////////////////////////////////////////
4144 /// Draw implicit function FUN(X,Y,Z) = 0 in cartesian coordinates using
4145 /// hidden surface removal algorithm "Painter".
4146 ///
4147 /// \param[in] rmin min scope coordinates
4148 /// \param[in] rmax max scope coordinates
4149 /// \param[in] nx number of steps along X
4150 /// \param[in] ny number of steps along Y
4151 /// \param[in] nz number of steps along Z
4152 ///
4153 /// - `chopt` = 'BF' from BACK to FRONT
4154 /// - `chopt` = 'FB' from FRONT to BACK
4155 
4156 void TPainter3dAlgorithms::ImplicitFunction(Double_t *rmin, Double_t *rmax,
4157  Int_t nx, Int_t ny, Int_t nz, const char *chopt)
4158 {
4159  Int_t ix, iy, iz;
4160  Int_t ix1, iy1, iz1;
4161  Int_t ix2, iy2, iz2;
4162  Int_t incr, incrx, incry, incrz;
4163  Int_t icodes[3], i, i1, i2, k, nnod, ntria;
4164  Double_t x1=0, x2=0, y1, y2, z1, z2;
4165  Double_t dx, dy, dz;
4166  Double_t p[8][3], pf[8], pn[8][3], t[3], fsurf, w;
4167 
4168  Double_t xyz[kNmaxp][3], xyzn[kNmaxp][3], grad[kNmaxp][3];
4169  Double_t dtria[kNmaxt][6], abcd[kNmaxt][4];
4170  Int_t itria[kNmaxt][3], iorder[kNmaxt];
4171  TView *view = 0;
4172 
4173  if (gPad) view = gPad->GetView();
4174  if (!view) {
4175  Error("ImplicitFunction", "no TView in current pad");
4176  return;
4177  }
4178  Double_t *tnorm = view->GetTnorm();
4179  if (!tnorm) return;
4180 
4181  // D E F I N E O R D E R O F D R A W I N G
4182  if (*chopt == 'B' || *chopt == 'b') {
4183  incrx = +1;
4184  incry = +1;
4185  incrz = +1;
4186  } else {
4187  incrx = -1;
4188  incry = -1;
4189  incrz = -1;
4190  }
4191  if (tnorm[8] < 0.) incrx =-incrx;
4192  if (tnorm[9] < 0.) incry =-incry;
4193  if (tnorm[10] < 0.) incrz =-incrz;
4194  ix1 = 1;
4195  iy1 = 1;
4196  iz1 = 1;
4197  if (incrx == -1) ix1 = nx;
4198  if (incry == -1) iy1 = ny;
4199  if (incrz == -1) iz1 = nz;
4200  ix2 = nx - ix1 + 1;
4201  iy2 = ny - iy1 + 1;
4202  iz2 = nz - iz1 + 1;
4203  dx = (rmax[0]-rmin[0]) / nx;
4204  dy = (rmax[1]-rmin[1]) / ny;
4205  dz = (rmax[2]-rmin[2]) / nz;
4206 
4207  // Define the colors used to draw the function
4208  Float_t r=0., g=0., b=0., hue, light, satur, light2;
4209  TColor *colref = gROOT->GetColor(fgCurrentF3->GetFillColor());
4210  if (colref) colref->GetRGB(r, g, b);
4211  TColor::RGBtoHLS(r, g, b, hue, light, satur);
4212  TColor *acol;
4213  acol = gROOT->GetColor(kF3FillColor1);
4214  if (acol) acol->SetRGB(r, g, b);
4215  if (light >= 0.5) {
4216  light2 = .5*light;
4217  } else {
4218  light2 = 1-.5*light;
4219  }
4220  TColor::HLStoRGB(hue, light2, satur, r, g, b);
4221  acol = gROOT->GetColor(kF3FillColor2);
4222  if (acol) acol->SetRGB(r, g, b);
4223  colref = gROOT->GetColor(fgCurrentF3->GetLineColor());
4224  if (colref) colref->GetRGB(r, g, b);
4225  acol = gROOT->GetColor(kF3LineColor);
4226  if (acol) acol->SetRGB(r, g, b);
4227 
4228  // D R A W F U N C T I O N
4229  for (iz = iz1; incrz < 0 ? iz >= iz2 : iz <= iz2; iz += incrz) {
4230  z1 = (iz-1)*dz + rmin[2];
4231  z2 = z1 + dz;
4232  p[0][2] = z1;
4233  p[1][2] = z1;
4234  p[2][2] = z1;
4235  p[3][2] = z1;
4236  p[4][2] = z2;
4237  p[5][2] = z2;
4238  p[6][2] = z2;
4239  p[7][2] = z2;
4240  for (iy = iy1; incry < 0 ? iy >= iy2 : iy <= iy2; iy += incry) {
4241  y1 = (iy-1)*dy + rmin[1];
4242  y2 = y1 + dy;
4243  p[0][1] = y1;
4244  p[1][1] = y1;
4245  p[2][1] = y2;
4246  p[3][1] = y2;
4247  p[4][1] = y1;
4248  p[5][1] = y1;
4249  p[6][1] = y2;
4250  p[7][1] = y2;
4251  if (incrx == +1) {
4252  x2 = rmin[0];
4253  pf[1] = fgCurrentF3->Eval(x2,y1,z1);
4254  pf[2] = fgCurrentF3->Eval(x2,y2,z1);
4255  pf[5] = fgCurrentF3->Eval(x2,y1,z2);
4256  pf[6] = fgCurrentF3->Eval(x2,y2,z2);
4257  } else {
4258  x1 = rmax[0];
4259  pf[0] = fgCurrentF3->Eval(x1,y1,z1);
4260  pf[3] = fgCurrentF3->Eval(x1,y2,z1);
4261  pf[4] = fgCurrentF3->Eval(x1,y1,z2);
4262  pf[7] = fgCurrentF3->Eval(x1,y2,z2);
4263  }
4264  for (ix = ix1; incrx < 0 ? ix >= ix2 : ix <= ix2; ix += incrx) {
4265  icodes[0] = ix;
4266  icodes[1] = iy;
4267  icodes[2] = iz;
4268  if (incrx == +1) {
4269  x1 = x2;
4270  x2 = x2 + dx;
4271  pf[0] = pf[1];
4272  pf[3] = pf[2];
4273  pf[4] = pf[5];
4274  pf[7] = pf[6];
4275  pf[1] = fgCurrentF3->Eval(x2,y1,z1);
4276  pf[2] = fgCurrentF3->Eval(x2,y2,z1);
4277  pf[5] = fgCurrentF3->Eval(x2,y1,z2);
4278  pf[6] = fgCurrentF3->Eval(x2,y2,z2);
4279  } else {
4280  x2 = x1;
4281  x1 = x1 - dx;
4282  pf[1] = pf[0];
4283  pf[2] = pf[3];
4284  pf[5] = pf[4];
4285  pf[6] = pf[7];
4286  pf[0] = fgCurrentF3->Eval(x1,y1,z1);
4287  pf[3] = fgCurrentF3->Eval(x1,y2,z1);
4288  pf[4] = fgCurrentF3->Eval(x1,y1,z2);
4289  pf[7] = fgCurrentF3->Eval(x1,y2,z2);
4290  }
4291  if (pf[0] >= -kFdel) goto L110;
4292  if (pf[1] >= -kFdel) goto L120;
4293  if (pf[2] >= -kFdel) goto L120;
4294  if (pf[3] >= -kFdel) goto L120;
4295  if (pf[4] >= -kFdel) goto L120;
4296  if (pf[5] >= -kFdel) goto L120;
4297  if (pf[6] >= -kFdel) goto L120;
4298  if (pf[7] >= -kFdel) goto L120;
4299  goto L510;
4300 L110:
4301  if (pf[1] < -kFdel) goto L120;
4302  if (pf[2] < -kFdel) goto L120;
4303  if (pf[3] < -kFdel) goto L120;
4304  if (pf[4] < -kFdel) goto L120;
4305  if (pf[5] < -kFdel) goto L120;
4306  if (pf[6] < -kFdel) goto L120;
4307  if (pf[7] < -kFdel) goto L120;
4308  goto L510;
4309 L120:
4310  p[0][0] = x1;
4311  p[1][0] = x2;
4312  p[2][0] = x2;
4313  p[3][0] = x1;
4314  p[4][0] = x1;
4315  p[5][0] = x2;
4316  p[6][0] = x2;
4317  p[7][0] = x1;
4318 
4319  // F I N D G R A D I E N T S
4320  // Find X-gradient
4321  if (ix == 1) {
4322  pn[0][0] = (pf[1] - pf[0]) / dx;
4323  pn[3][0] = (pf[2] - pf[3]) / dx;
4324  pn[4][0] = (pf[5] - pf[4]) / dx;
4325  pn[7][0] = (pf[6] - pf[7]) / dx;
4326  } else {
4327  pn[0][0] = (pf[1] - fgCurrentF3->Eval(x1-dx,y1,z1)) / (dx + dx);
4328  pn[3][0] = (pf[2] - fgCurrentF3->Eval(x1-dx,y2,z1)) / (dx + dx);
4329  pn[4][0] = (pf[5] - fgCurrentF3->Eval(x1-dx,y1,z2)) / (dx + dx);
4330  pn[7][0] = (pf[6] - fgCurrentF3->Eval(x1-dx,y2,z2)) / (dx + dx);
4331  }
4332  if (ix == nx) {
4333  pn[1][0] = (pf[1] - pf[0]) / dx;
4334  pn[2][0] = (pf[2] - pf[3]) / dx;
4335  pn[5][0] = (pf[5] - pf[4]) / dx;
4336  pn[6][0] = (pf[6] - pf[7]) / dx;
4337  } else {
4338  pn[1][0] = (fgCurrentF3->Eval(x2+dx,y1,z1) - pf[0]) / (dx + dx);
4339  pn[2][0] = (fgCurrentF3->Eval(x2+dx,y2,z1) - pf[3]) / (dx + dx);
4340  pn[5][0] = (fgCurrentF3->Eval(x2+dx,y1,z2) - pf[4]) / (dx + dx);
4341  pn[6][0] = (fgCurrentF3->Eval(x2+dx,y2,z2) - pf[7]) / (dx + dx);
4342  }
4343  // Find Y-gradient
4344  if (iy == 1) {
4345  pn[0][1] = (pf[3] - pf[0]) / dy;
4346  pn[1][1] = (pf[2] - pf[1]) / dy;
4347  pn[4][1] = (pf[7] - pf[4]) / dy;
4348  pn[5][1] = (pf[6] - pf[5]) / dy;
4349  } else {
4350  pn[0][1] = (pf[3] - fgCurrentF3->Eval(x1,y1-dy,z1)) / (dy + dy);
4351  pn[1][1] = (pf[2] - fgCurrentF3->Eval(x2,y1-dy,z1)) / (dy + dy);
4352  pn[4][1] = (pf[7] - fgCurrentF3->Eval(x1,y1-dy,z2)) / (dy + dy);
4353  pn[5][1] = (pf[6] - fgCurrentF3->Eval(x2,y1-dy,z2)) / (dy + dy);
4354  }
4355  if (iy == ny) {
4356  pn[2][1] = (pf[2] - pf[1]) / dy;
4357  pn[3][1] = (pf[3] - pf[0]) / dy;
4358  pn[6][1] = (pf[6] - pf[5]) / dy;
4359  pn[7][1] = (pf[7] - pf[4]) / dy;
4360  } else {
4361  pn[2][1] = (fgCurrentF3->Eval(x2,y2+dy,z1) - pf[1]) / (dy + dy);
4362  pn[3][1] = (fgCurrentF3->Eval(x1,y2+dy,z1) - pf[0]) / (dy + dy);
4363  pn[6][1] = (fgCurrentF3->Eval(x2,y2+dy,z2) - pf[5]) / (dy + dy);
4364  pn[7][1] = (fgCurrentF3->Eval(x1,y2+dy,z2) - pf[4]) / (dy + dy);
4365  }
4366  // Find Z-gradient
4367  if (iz == 1) {
4368  pn[0][2] = (pf[4] - pf[0]) / dz;
4369  pn[1][2] = (pf[5] - pf[1]) / dz;
4370  pn[2][2] = (pf[6] - pf[2]) / dz;
4371  pn[3][2] = (pf[7] - pf[3]) / dz;
4372  } else {
4373  pn[0][2] = (pf[4] - fgCurrentF3->Eval(x1,y1,z1-dz)) / (dz + dz);
4374  pn[1][2] = (pf[5] - fgCurrentF3->Eval(x2,y1,z1-dz)) / (dz + dz);
4375  pn[2][2] = (pf[6] - fgCurrentF3->Eval(x2,y2,z1-dz)) / (dz + dz);
4376  pn[3][2] = (pf[7] - fgCurrentF3->Eval(x1,y2,z1-dz)) / (dz + dz);
4377  }
4378  if (iz == nz) {
4379  pn[4][2] = (pf[4] - pf[0]) / dz;
4380  pn[5][2] = (pf[5] - pf[1]) / dz;
4381  pn[6][2] = (pf[6] - pf[2]) / dz;
4382  pn[7][2] = (pf[7] - pf[3]) / dz;
4383  } else {
4384  pn[4][2] = (fgCurrentF3->Eval(x1,y1,z2+dz) - pf[0]) / (dz + dz);
4385  pn[5][2] = (fgCurrentF3->Eval(x2,y1,z2+dz) - pf[1]) / (dz + dz);
4386  pn[6][2] = (fgCurrentF3->Eval(x2,y2,z2+dz) - pf[2]) / (dz + dz);
4387  pn[7][2] = (fgCurrentF3->Eval(x1,y2,z2+dz) - pf[3]) / (dz + dz);
4388  }
4389  fsurf = 0.;
4390  MarchingCube(fsurf, p, pf, pn, nnod, ntria, xyz, grad, itria);
4391  if (ntria == 0) goto L510;
4392 
4393  for ( i=1 ; i<=nnod ; i++ ) {
4394  view->WCtoNDC(&xyz[i-1][0], &xyzn[i-1][0]);
4395  Luminosity(&grad[i-1][0], w);
4396  grad[i-1][0] = w;
4397  }
4398  ZDepth(xyzn, ntria, itria, dtria, abcd, (Int_t*)iorder);
4399  if (ntria == 0) goto L510;
4400  incr = 1;
4401  if (*chopt == 'B' || *chopt == 'b') incr =-1;
4402  i1 = 1;
4403  if (incr == -1) i1 = ntria;
4404  i2 = ntria - i1 + 1;
4405  // If clipping box is on do not draw the triangles
4406  if (fgF3Clipping) {
4407  if(x2<=fgF3XClip && y2 <=fgF3YClip && z2>=fgF3ZClip) goto L510;
4408  }
4409  // Draw triangles
4410  for (i=i1; incr < 0 ? i >= i2 : i <= i2; i += incr) {
4411  k = iorder[i-1];
4412  t[0] = grad[TMath::Abs(itria[k-1][0])-1][0];
4413  t[1] = grad[TMath::Abs(itria[k-1][1])-1][0];
4414  t[2] = grad[TMath::Abs(itria[k-1][2])-1][0];
4415  (this->*fDrawFace)(icodes, (Double_t*)xyz, 3, &itria[k-1][0], t);
4416  }
4417 L510:
4418  continue;
4419  }
4420  }
4421  }
4422 }
4423 
4424 ////////////////////////////////////////////////////////////////////////////////
4425 /// Topological decider for "Marching Cubes" algorithm Find set of triangles
4426 /// approximating the iso-surface F(x,y,z)=Fiso inside the cube
4427 ///
4428 /// \param[in] fiso function value for iso-surface
4429 /// \param[in] p cube vertexes
4430 /// \param[in] f function values at the vertexes
4431 /// \param[in] g function gradients at the vertexes
4432 ///
4433 /// \param[out] nnod number of nodes (maximum 13)
4434 /// \param[out] ntria number of triangles (maximum 12)
4435 /// \param[out] xyz nodes
4436 /// \param[out] grad node normales (not normalized)
4437 /// \param[out] itria triangles
4438 
4439 void TPainter3dAlgorithms::MarchingCube(Double_t fiso, Double_t p[8][3],
4440  Double_t f[8], Double_t g[8][3],
4441  Int_t &nnod, Int_t &ntria,
4442  Double_t xyz[][3],
4443  Double_t grad[][3],
4444  Int_t itria[][3])
4445 {
4446  static Int_t irota[24][8] = { { 1,2,3,4,5,6,7,8 }, { 2,3,4,1,6,7,8,5 },
4447  { 3,4,1,2,7,8,5,6 }, { 4,1,2,3,8,5,6,7 },
4448  { 6,5,8,7,2,1,4,3 }, { 5,8,7,6,1,4,3,2 },
4449  { 8,7,6,5,4,3,2,1 }, { 7,6,5,8,3,2,1,4 },
4450  { 2,6,7,3,1,5,8,4 }, { 6,7,3,2,5,8,4,1 },
4451  { 7,3,2,6,8,4,1,5 }, { 3,2,6,7,4,1,5,8 },
4452  { 5,1,4,8,6,2,3,7 }, { 1,4,8,5,2,3,7,6 },
4453  { 4,8,5,1,3,7,6,2 }, { 8,5,1,4,7,6,2,3 },
4454  { 5,6,2,1,8,7,3,4 }, { 6,2,1,5,7,3,4,8 },
4455  { 2,1,5,6,3,4,8,7 }, { 1,5,6,2,4,8,7,3 },
4456  { 4,3,7,8,1,2,6,5 }, { 3,7,8,4,2,6,5,1 },
4457  { 7,8,4,3,6,5,1,2 }, { 8,4,3,7,5,1,2,6 } };
4458 
4459  static Int_t iwhat[21] = { 1,3,5,65,50,67,74,51,177,105,113,58,165,178,
4460  254,252,250,190,205,188,181 };
4461  Int_t j, i, i1, i2, i3, ir, irt=0, k, k1, k2, incr, icase=0, n;
4462  Int_t itr[3];
4463 
4464  nnod = 0;
4465  ntria = 0;
4466 
4467  // F I N D C O N F I G U R A T I O N T Y P E
4468  for ( i=1; i<=8 ; i++) {
4469  fF8[i-1] = f[i-1] - fiso;
4470  }
4471  for ( ir=1 ; ir<=24 ; ir++ ) {
4472  k = 0;
4473  incr = 1;
4474  for ( i=1 ; i<=8 ; i++ ) {
4475  if (fF8[irota[ir-1][i-1]-1] >= 0.) k = k + incr;
4476  incr = incr + incr;
4477  }
4478  if (k==0 || k==255) return;
4479  for ( i=1 ; i<=21 ; i++ ) {
4480  if (k != iwhat[i-1]) continue;
4481  icase = i;
4482  irt = ir;
4483  goto L200;
4484  }
4485  }
4486 
4487  // R O T A T E C U B E
4488 L200:
4489  for ( i=1 ; i<=8 ; i++ ) {
4490  k = irota[irt-1][i-1];
4491  fF8[i-1] = f[k-1] - fiso;
4492  fP8[i-1][0] = p[k-1][0];
4493  fP8[i-1][1] = p[k-1][1];
4494  fP8[i-1][2] = p[k-1][2];
4495  fG8[i-1][0] = g[k-1][0];
4496  fG8[i-1][1] = g[k-1][1];
4497  fG8[i-1][2] = g[k-1][2];
4498  }
4499 
4500  // V A R I O U S C O N F I G U R A T I O N S
4501  n = 0;
4502  switch ((int)icase) {
4503  case 1:
4504  case 15:
4505  MarchingCubeCase00(1, 4, 9, 0, 0, 0, nnod, ntria, xyz, grad, itria);
4506  goto L400;
4507  case 2:
4508  case 16:
4509  MarchingCubeCase00(2, 4, 9, 10, 0, 0, nnod, ntria, xyz, grad, itria);
4510  goto L400;
4511  case 3:
4512  case 17:
4513  MarchingCubeCase03(nnod, ntria, xyz, grad, itria);
4514  goto L400;
4515  case 4:
4516  case 18:
4517  MarchingCubeCase04(nnod, ntria, xyz, grad, itria);
4518  goto L400;
4519  case 5:
4520  case 19:
4521  MarchingCubeCase00(6, 2, 1, 9, 8, 0, nnod, ntria, xyz, grad, itria);
4522  goto L400;
4523  case 6:
4524  case 20:
4525  MarchingCubeCase06(nnod, ntria, xyz, grad, itria);
4526  goto L400;
4527  case 7:
4528  case 21:
4529  MarchingCubeCase07(nnod, ntria, xyz, grad, itria);
4530  goto L400;
4531  case 8:
4532  MarchingCubeCase00(2, 4, 8, 6, 0, 0, nnod, ntria, xyz, grad, itria);
4533  goto L500;
4534  case 9:
4535  MarchingCubeCase00(1, 4, 12, 7, 6, 10, nnod, ntria, xyz, grad, itria);
4536  goto L500;
4537  case 0:
4538  MarchingCubeCase10(nnod, ntria, xyz, grad, itria);
4539  goto L500;
4540  case 11:
4541  MarchingCubeCase00(1, 4, 8, 7, 11, 10, nnod, ntria, xyz, grad, itria);
4542  goto L500;
4543  case 12:
4544  MarchingCubeCase12(nnod, ntria, xyz, grad, itria);
4545  goto L500;
4546  case 13:
4547  MarchingCubeCase13(nnod, ntria, xyz, grad, itria);
4548  goto L500;
4549  case 14:
4550  MarchingCubeCase00(1, 9, 12, 7, 6, 2, nnod, ntria, xyz, grad, itria);
4551  goto L500;
4552  }
4553 
4554  // I F N E E D E D , I N V E R T T R I A N G L E S
4555 L400:
4556  if (ntria == 0) return;
4557  if (icase <= 14) goto L500;
4558  for ( i=1; i<=ntria ; i++ ) {
4559  i1 = TMath::Abs(itria[i-1][0]);
4560  i2 = TMath::Abs(itria[i-1][1]);
4561  i3 = TMath::Abs(itria[i-1][2]);
4562  if (itria[i-1][2] < 0) i1 =-i1;
4563  if (itria[i-1][1] < 0) i3 =-i3;
4564  if (itria[i-1][0] < 0) i2 =-i2;
4565  itria[i-1][0] = i1;
4566  itria[i-1][1] = i3;
4567  itria[i-1][2] = i2;
4568  }
4569 
4570  // R E M O V E V E R Y S M A L L T R I A N G L E S
4571 L500:
4572  n = n + 1;
4573 L510:
4574  if (n > ntria) return;
4575  for ( i=1 ; i<=3 ; i++ ) {
4576  i1 = i;
4577  i2 = i + 1;
4578  if (i2 == 4) i2 = 1;
4579  k1 = TMath::Abs(itria[n-1][i1-1]);
4580  k2 = TMath::Abs(itria[n-1][i2-1]);
4581  if (TMath::Abs(xyz[k1-1][0]-xyz[k2-1][0]) > kDel) continue;
4582  if (TMath::Abs(xyz[k1-1][1]-xyz[k2-1][1]) > kDel) continue;
4583  if (TMath::Abs(xyz[k1-1][2]-xyz[k2-1][2]) > kDel) continue;
4584  i3 = i - 1;
4585  if (i3 == 0) i3 = 3;
4586  goto L530;
4587  }
4588  goto L500;
4589 
4590  // R E M O V E T R I A N G L E
4591 L530:
4592  for ( i=1 ; i<=3 ; i++ ) {
4593  itr[i-1] = itria[n-1][i-1];
4594  itria[n-1][i-1] = itria[ntria-1][i-1];
4595  }
4596  ntria = ntria - 1;
4597  if (ntria == 0) return;
4598  if (itr[i2-1]*itr[i3-1] > 0) goto L510;
4599 
4600  // C O R R E C T O T H E R T R I A N G L E S
4601  if (itr[i2-1] < 0) {
4602  k1 =-itr[i2-1];
4603  k2 =-TMath::Abs(itr[i3-1]);
4604  }
4605  if (itr[i3-1] < 0) {
4606  k1 =-itr[i3-1];
4607  k2 =-TMath::Abs(itr[i1-1]);
4608  }
4609  for ( j=1 ; j<=ntria ; j++ ) {
4610  for ( i=1 ; i<=3 ; i++ ) {
4611  if (itria[j-1][i-1] != k2) continue;
4612  i2 = TMath::Abs(itria[j-1][0]);
4613  if (i != 3) i2 = TMath::Abs(itria[j-1][i]);
4614  if (i2 == k1) itria[j-1][i-1] =-itria[j-1][i-1];
4615  goto L560;
4616  }
4617 L560:
4618  continue;
4619  }
4620  goto L510;
4621 }
4622 
4623 ////////////////////////////////////////////////////////////////////////////////
4624 /// Consideration of trivial cases: 1,2,5,8,9,11,14
4625 ///
4626 /// \param[in] k1-k6 edges intersected with iso-surface
4627 
4628 void TPainter3dAlgorithms::MarchingCubeCase00(Int_t k1, Int_t k2, Int_t k3,
4629  Int_t k4, Int_t k5, Int_t k6,
4630  Int_t &nnod, Int_t &ntria,
4631  Double_t xyz[52][3],
4632  Double_t grad[52][3],
4633  Int_t itria[48][3])
4634 {
4635  static Int_t it[4][4][3] = { { { 1,2, 3 }, { 0,0, 0 }, { 0,0, 0 }, { 0,0, 0 } },
4636  { { 1,2,-3 }, {-1,3, 4 }, { 0,0, 0 }, { 0,0, 0 } },
4637  { { 1,2,-3 }, {-1,3,-4 }, {-1,4, 5 }, { 0,0, 0 } },
4638  { { 1,2,-3 }, {-1,3,-4 }, {-4,6,-1 }, { 4,5,-6 } }
4639  };
4640  Int_t it2[4][3], i, j;
4641 
4642  Int_t ie[6];
4643 
4644  // S E T N O D E S & N O R M A L E S
4645  ie[0] = k1;
4646  ie[1] = k2;
4647  ie[2] = k3;
4648  ie[3] = k4;
4649  ie[4] = k5;
4650  ie[5] = k6;
4651  nnod = 6;
4652  if (ie[5] == 0) nnod = 5;
4653  if (ie[4] == 0) nnod = 4;
4654  if (ie[3] == 0) nnod = 3;
4655  MarchingCubeFindNodes(nnod, ie, xyz, grad);
4656 
4657  // S E T T R I A N G L E S
4658  ntria = nnod - 2;
4659  // Copy "it" into a 2D matrix to be passed to MarchingCubeSetTriangles
4660  for ( i=0; i<3 ; i++) {
4661  for ( j=0; j<4 ; j++) {
4662  it2[j][i] = it[ntria-1][j][i];
4663  }
4664  }
4665  MarchingCubeSetTriangles(ntria, it2, itria);
4666 }
4667 
4668 ////////////////////////////////////////////////////////////////////////////////
4669 /// Consider case No 3
4670 
4671 void TPainter3dAlgorithms::MarchingCubeCase03(Int_t &nnod, Int_t &ntria,
4672  Double_t xyz[52][3], Double_t grad[52][3], Int_t itria[48][3])
4673 {
4674  Double_t f0;
4675  static Int_t ie[6] = { 4,9,1, 2,11,3 };
4676  static Int_t it1[2][3] = { { 1,2,3 }, { 4,5,6 } };
4677  static Int_t it2[4][3] = { { 1,2,-5 }, { -1,5,6 }, { 5,-2,4 }, { -4,2,3 } };
4678 
4679  // S E T N O D E S & N O R M A L E S
4680  nnod = 6;
4681  MarchingCubeFindNodes(nnod, ie, xyz, grad);
4682 
4683  // F I N D C O N F I G U R A T I O N
4684  f0 = (fF8[0]*fF8[2]-fF8[1]*fF8[3]) / (fF8[0]+fF8[2]-fF8[1]-fF8[3]);
4685  if (f0>=0. && fF8[0]>=0.) goto L100;
4686  if (f0<0. && fF8[0]<0.) goto L100;
4687  ntria = 2;
4688  MarchingCubeSetTriangles(ntria, it1, itria);
4689  return;
4690 
4691  // N O T S E P A R A T E D F R O N T F A C E
4692 L100:
4693  ntria = 4;
4694  MarchingCubeSetTriangles(ntria, it2, itria);
4695 }
4696 
4697 ////////////////////////////////////////////////////////////////////////////////
4698 /// Consider case No 4
4699 
4700 void TPainter3dAlgorithms::MarchingCubeCase04(Int_t &nnod, Int_t &ntria,
4701  Double_t xyz[52][3], Double_t grad[52][3], Int_t itria[48][3])
4702 {
4703  Int_t irep;
4704  static Int_t ie[6] = { 4,9,1, 7,11,6 };
4705  static Int_t it1[2][3] = { { 1,2,3 }, { 4,5,6 } };
4706  static Int_t it2[6][3] = { { 1,2,4 }, { 2,3,6 }, { 3,1,5 },
4707  { 4,5,1 }, { 5,6,3 }, { 6,4,2 } };
4708 
4709  // S E T N O D E S & N O R M A L E S
4710  nnod = 6;
4711  MarchingCubeFindNodes(nnod, ie, xyz, grad);
4712 
4713  // I S T H E R E S U R F A C E P E N E T R A T I O N ?
4714  MarchingCubeSurfacePenetration(fF8[0], fF8[1], fF8[2], fF8[3],
4715  fF8[4], fF8[5], fF8[6], fF8[7], irep);
4716  if (irep == 0) {
4717  ntria = 2;
4718  MarchingCubeSetTriangles(ntria, it1, itria);
4719  } else {
4720  ntria = 6;
4721  MarchingCubeSetTriangles(ntria, it2, itria);
4722  }
4723 }
4724 
4725 ////////////////////////////////////////////////////////////////////////////////
4726 /// Consider case No 6
4727 
4728 void TPainter3dAlgorithms::MarchingCubeCase06(Int_t &nnod, Int_t &ntria,
4729  Double_t xyz[52][3], Double_t grad[52][3], Int_t itria[48][3])
4730 {
4731  Double_t f0;
4732  Int_t irep;
4733 
4734  static Int_t ie[7] = { 2,4,9,10, 6,7,11 };
4735  static Int_t it1[5][3] = { { 6,7,-1 }, { -6,1,2 }, { 6,2,3 }, { 6,3,-4 }, { -6,4,5 } };
4736  static Int_t it2[3][3] = { { 1,2,-3 }, { -1,3,4 }, { 5,6,7 } };
4737  static Int_t it3[7][3] = { { 6,7,-1 }, { -6,1,2 }, { 6,2,3 }, { 6,3,-4 }, { -6,4,5 },
4738  { 1,7,-5 }, { -1,5,4 } };
4739 
4740  // S E T N O D E S & N O R M A L E S
4741  nnod = 7;
4742  MarchingCubeFindNodes(nnod, ie, xyz, grad);
4743 
4744  // F I N D C O N F I G U R A T I O N
4745  f0 = (fF8[1]*fF8[6]-fF8[5]*fF8[2]) / (fF8[1]+fF8[6]-fF8[5]-fF8[2]);
4746  if (f0>=0. && fF8[1]>=0.) goto L100;
4747  if (f0<0. && fF8[1]<0.) goto L100;
4748 
4749  // I S T H E R E S U R F A C E P E N E T R A T I O N ?
4750  MarchingCubeSurfacePenetration(fF8[2], fF8[1], fF8[5], fF8[6],
4751  fF8[3], fF8[0], fF8[4], fF8[7], irep);
4752  if (irep == 1) {
4753  ntria = 7;
4754  MarchingCubeSetTriangles(ntria, it3, itria);
4755  } else {
4756  ntria = 3;
4757  MarchingCubeSetTriangles(ntria, it2, itria);
4758  }
4759  return;
4760 
4761  // N O T S E P A R A T E D R I G H T F A C E
4762 L100:
4763  ntria = 5;
4764  MarchingCubeSetTriangles(ntria, it1, itria);
4765 }
4766 
4767 ////////////////////////////////////////////////////////////////////////////////
4768 /// Consider case No 7
4769 
4770 void TPainter3dAlgorithms::MarchingCubeCase07(Int_t &nnod, Int_t &ntria,
4771  Double_t xyz[52][3], Double_t grad[52][3],
4772  Int_t itria[48][3])
4773 {
4774  Double_t f1, f2, f3;
4775  Int_t icase, irep;
4776  static Int_t ie[9] = { 3,12,4, 1,10,2, 11,6,7 };
4777  static Int_t it[9][9][3] = {
4778  {{ 1,2,3}, { 4,5,6}, { 7,8,9}, { 0,0,0}, { 0,0,0}, { 0,0,0}, { 0,0,0}, { 0,0,0}, { 0,0,0}},
4779  {{ 1,2,3}, { 4,9,-7}, { -4,7,6}, { 9,4,-5}, { -9,5,8}, { 0,0,0}, { 0,0,0}, { 0,0,0}, { 0,0,0}},
4780  {{ 4,5,6}, { 8,3,-1}, { -8,1,7}, { 3,8,-9}, { -3,9,2}, { 0,0,0}, { 0,0,0}, { 0,0,0}, { 0,0,0}},
4781  {{-10,2,3}, {10,3,-1}, {-10,1,7}, {10,7,-6}, {-10,6,4}, {10,4,-5}, {-10,5,8}, { 10,8,9}, {10,9,-2}},
4782  {{ 7,8,9}, { 2,5,-6}, { -2,6,1}, { 5,2,-3}, { -5,3,4}, { 0,0,0}, { 0,0,0}, { 0,0,0}, { 0,0,0}},
4783  {{-10,1,2}, {10,2,-3}, {-10,3,4}, { 10,4,5}, {10,5,-8}, {-10,8,9}, {10,9,-7}, {-10,7,6}, {10,6,-1}},
4784  {{ 10,2,3}, {10,3,-4}, {-10,4,5}, {10,5,-6}, {-10,6,1}, {10,1,-7}, {-10,7,8}, {10,8,-9}, {-10,9,2}},
4785  {{ 1,7,6}, { -4,2,3}, {-4,9,-2}, {-9,4,-5}, { -9,5,8}, { 0,0,0}, { 0,0,0}, { 0,0,0}, { 0,0,0}},
4786  {{ -1,9,2}, { 1,2,3}, { 1,3,-4}, { 6,-1,4}, { 6,4,5}, { 6,-5,7}, { -7,5,8}, { 7,8,9}, { 7,-9,1}}
4787  };
4788 
4789  Int_t it2[9][3], i, j;
4790 
4791  // S E T N O D E S & N O R M A L E S
4792  nnod = 9;
4793  MarchingCubeFindNodes(nnod, ie, xyz, grad);
4794 
4795  // F I N D C O N F I G U R A T I O N
4796  f1 = (fF8[2]*fF8[5]-fF8[1]*fF8[6]) / (fF8[2]+fF8[5]-fF8[1]-fF8[6]);
4797  f2 = (fF8[2]*fF8[7]-fF8[3]*fF8[6]) / (fF8[2]+fF8[7]-fF8[3]-fF8[6]);
4798  f3 = (fF8[2]*fF8[0]-fF8[1]*fF8[3]) / (fF8[2]+fF8[0]-fF8[1]-fF8[3]);
4799  icase = 1;
4800  if (f1>=0. && fF8[2] <0.) icase = icase + 1;
4801  if (f1 <0. && fF8[2]>=0.) icase = icase + 1;
4802  if (f2>=0. && fF8[2] <0.) icase = icase + 2;
4803  if (f2 <0. && fF8[2]>=0.) icase = icase + 2;
4804  if (f3>=0. && fF8[2] <0.) icase = icase + 4;
4805  if (f3 <0. && fF8[2]>=0.) icase = icase + 4;
4806  ntria = 5;
4807 
4808  switch ((int)icase) {
4809  case 1: goto L100;
4810  case 2: goto L400;
4811  case 3: goto L400;
4812  case 4: goto L200;
4813  case 5: goto L400;
4814  case 6: goto L200;
4815  case 7: goto L200;
4816  case 8: goto L300;
4817  }
4818 
4819 L100:
4820  ntria = 3;
4821  goto L400;
4822 
4823  // F I N D A D D I T I O N A L P O I N T
4824 L200:
4825  nnod = 10;
4826  ntria = 9;
4827 
4828  // Copy "it" into a 2D matrix to be passed to MarchingCubeMiddlePoint
4829  for ( i=0; i<3 ; i++) {
4830  for ( j=0; j<9 ; j++) {
4831  it2[j][i] = it[icase-1][j][i];
4832  }
4833  }
4834  MarchingCubeMiddlePoint(9, xyz, grad, it2, &xyz[nnod-1][0], &grad[nnod-1][0]);
4835  goto L400;
4836 
4837  // I S T H E R E S U R F A C E P E N E T R A T I O N ?
4838 L300:
4839  MarchingCubeSurfacePenetration(fF8[3], fF8[2], fF8[6], fF8[7],
4840  fF8[0], fF8[1], fF8[5], fF8[4], irep);
4841  if (irep != 2) goto L400;
4842  ntria = 9;
4843  icase = 9;
4844 
4845  // S E T T R I A N G L E S
4846 L400:
4847  // Copy "it" into a 2D matrix to be passed to MarchingCubeSetTriangles
4848  for ( i=0; i<3 ; i++) {
4849  for ( j=0; j<9 ; j++) {
4850  it2[j][i] = it[icase-1][j][i];
4851  }
4852  }
4853  MarchingCubeSetTriangles(ntria, it2, itria);
4854 }
4855 
4856 ////////////////////////////////////////////////////////////////////////////////
4857 /// Consider case No 10
4858 
4859 void TPainter3dAlgorithms::MarchingCubeCase10(Int_t &nnod, Int_t &ntria,
4860  Double_t xyz[52][3], Double_t grad[52][3], Int_t itria[48][3])
4861 {
4862  Double_t f1, f2;
4863  Int_t icase, irep;
4864  static Int_t ie[8] = { 1,3,12,9, 5,7,11,10 };
4865  static Int_t it[6][8][3] = {
4866  {{1,2,-3}, {-1,3,4}, {5,6,-7}, {-5,7,8}, { 0,0,0}, { 0,0,0}, { 0,0,0}, { 0,0,0}},
4867  {{ 9,1,2}, { 9,2,3}, { 9,3,4}, { 9,4,5}, { 9,5,6}, { 9,6,7}, { 9,7,8}, { 9,8,1}},
4868  {{ 9,1,2}, { 9,4,1}, { 9,3,4}, { 9,6,3}, { 9,5,6}, { 9,8,5}, { 9,7,8}, { 9,2,7}},
4869  {{1,2,-7}, {-1,7,8}, {5,6,-3}, {-5,3,4}, { 0,0,0}, { 0,0,0}, { 0,0,0}, { 0,0,0}},
4870  {{1,2,-7}, {-1,7,8}, {2,3,-6}, {-2,6,7}, {3,4,-5}, {-3,5,6}, {4,1,-8}, {-4,8,5}},
4871  {{1,2,-3}, {-1,3,4}, {2,7,-6}, {-2,6,3}, {7,8,-5}, {-7,5,6}, {8,1,-4}, {-8,4,5}}
4872  };
4873  Int_t it2[8][3], i, j;
4874 
4875  // S E T N O D E S & N O R M A L E S
4876  nnod = 8;
4877  MarchingCubeFindNodes(nnod, ie, xyz, grad);
4878 
4879  // F I N D C O N F I G U R A T I O N
4880  f1 = (fF8[0]*fF8[5]-fF8[1]*fF8[4]) / (fF8[0]+fF8[5]-fF8[1]-fF8[4]);
4881  f2 = (fF8[3]*fF8[6]-fF8[2]*fF8[7]) / (fF8[3]+fF8[6]-fF8[2]-fF8[5]);
4882  icase = 1;
4883  if (f1 >= 0.) icase = icase + 1;
4884  if (f2 >= 0.) icase = icase + 2;
4885  if (icase==1 || icase==4) goto L100;
4886 
4887  // D I F F E R E N T T O P A N D B O T T O M
4888  nnod = 9;
4889  ntria = 8;
4890  // Copy "it" into a 2D matrix to be passed to MarchingCubeMiddlePoint
4891  for ( i=0; i<3 ; i++) {
4892  for ( j=0; j<8 ; j++) {
4893  it2[j][i] = it[icase-1][j][i];
4894  }
4895  }
4896  MarchingCubeMiddlePoint(8, xyz, grad, it2, &xyz[nnod-1][0], &grad[nnod-1][0]);
4897  goto L200;
4898 
4899  // I S T H E R E S U R F A C E P E N E T R A T I O N ?
4900 L100:
4901  MarchingCubeSurfacePenetration(fF8[0], fF8[1], fF8[5], fF8[4],
4902  fF8[3], fF8[2], fF8[6], fF8[7], irep);
4903  ntria = 4;
4904  if (irep == 0) goto L200;
4905  // "B O T T L E N E C K"
4906  ntria = 8;
4907  if (icase == 1) icase = 5;
4908  if (icase == 4) icase = 6;
4909 
4910  // S E T T R I A N G L E S
4911 L200:
4912  // Copy "it" into a 2D matrix to be passed to MarchingCubeSetTriangles
4913  for ( i=0; i<3 ; i++) {
4914  for ( j=0; j<8 ; j++) {
4915  it2[j][i] = it[icase-1][j][i];
4916  }
4917  }
4918  MarchingCubeSetTriangles(ntria, it2, itria);
4919 }
4920 
4921 ////////////////////////////////////////////////////////////////////////////////
4922 /// Consider case No 12
4923 
4924 void TPainter3dAlgorithms::MarchingCubeCase12(Int_t &nnod, Int_t &ntria,
4925  Double_t xyz[52][3], Double_t grad[52][3], Int_t itria[48][3])
4926 {
4927  Double_t f1, f2;
4928  Int_t icase, irep;
4929  static Int_t ie[8] = { 3,12,4, 1,9,8,6,2 };
4930  static Int_t it[6][8][3] = {
4931  {{ 1,2,3}, {4,5,-6}, {-4,6,8}, { 6,7,8}, { 0,0,0}, { 0,0,0}, { 0,0,0}, { 0,0,0}},
4932  {{-9,1,2}, {9,2,-3}, {-9,3,4}, {9,4,-5}, {-9,5,6}, {9,6,-7}, {-9,7,8}, {9,8,-1}},
4933  {{9,1,-2}, {-9,2,6}, {9,6,-7}, {-9,7,8}, {9,8,-4}, {-9,4,5}, {9,5,-3}, {-9,3,1}},
4934  {{ 3,4,5}, {1,2,-6}, {-1,6,8}, { 6,7,8}, { 0,0,0}, { 0,0,0}, { 0,0,0}, { 0,0,0}},
4935  {{ 7,8,6}, {6,8,-1}, {-6,1,2}, {3,1,-8}, {-3,8,4}, { 3,4,5}, {3,5,-6}, {-3,6,2}},
4936  {{ 7,8,6}, {6,8,-4}, {-6,4,5}, {3,4,-8}, {-3,8,1}, { 3,1,2}, {3,2,-6}, {-3,6,5}}
4937  };
4938  Int_t it2[8][3], i, j;
4939 
4940  // S E T N O D E S & N O R M A L E S
4941  nnod = 8;
4942  MarchingCubeFindNodes(nnod, ie, xyz, grad);
4943 
4944  // F I N D C O N F I G U R A T I O N
4945  f1 = (fF8[0]*fF8[2]-fF8[1]*fF8[3]) / (fF8[0]+fF8[2]-fF8[1]-fF8[3]);
4946  f2 = (fF8[0]*fF8[7]-fF8[3]*fF8[4]) / (fF8[0]+fF8[7]-fF8[3]-fF8[4]);
4947  icase = 1;
4948  if (f1 >= 0.) icase = icase + 1;
4949  if (f2 >= 0.) icase = icase + 2;
4950  if (icase==1 || icase==4) goto L100;
4951 
4952  // F I N D A D D I T I O N A L P O I N T
4953  nnod = 9;
4954  ntria = 8;
4955  // Copy "it" into a 2D matrix to be passed to MarchingCubeMiddlePoint
4956  for ( i=0; i<3 ; i++) {
4957  for ( j=0; j<8 ; j++) {
4958  it2[j][i] = it[icase-1][j][i];
4959  }
4960  }
4961  MarchingCubeMiddlePoint(8, xyz, grad, it2, &xyz[nnod-1][0], &grad[nnod-1][0]);
4962  goto L200;
4963 
4964  // I S T H E R E S U R F A C E P E N E T R A T I O N ?
4965 L100:
4966  MarchingCubeSurfacePenetration(fF8[0], fF8[1], fF8[2], fF8[3],
4967  fF8[4], fF8[5], fF8[6], fF8[7], irep);
4968  ntria = 4;
4969  if (irep != 1) goto L200;
4970  // "B O T T L E N E C K"
4971  ntria = 8;
4972  if (icase == 1) icase = 5;
4973  if (icase == 4) icase = 6;
4974 
4975  // S E T T R I A N G L E S
4976 L200:
4977  // Copy "it" into a 2D matrix to be passed to MarchingCubeSetTriangles
4978  for ( i=0; i<3 ; i++) {
4979  for ( j=0; j<8 ; j++) {
4980  it2[j][i] = it[icase-1][j][i];
4981  }
4982  }
4983  MarchingCubeSetTriangles(ntria, it2, itria);
4984 }
4985 
4986 ////////////////////////////////////////////////////////////////////////////////
4987 /// Consider case No 13
4988 
4989 void TPainter3dAlgorithms::MarchingCubeCase13(Int_t &nnod, Int_t &ntria,
4990  Double_t xyz[52][3], Double_t grad[52][3], Int_t itria[48][3])
4991 {
4992  Double_t ff[8];
4993  Double_t f1, f2, f3, f4;
4994  Int_t nr, nf, i, k, incr, n, kr, icase, irep;
4995  static Int_t irota[12][8] = {
4996  {1,2,3,4,5,6,7,8}, {1,5,6,2,4,8,7,3}, {1,4,8,5,2,3,7,6},
4997  {3,7,8,4,2,6,5,1}, {3,2,6,7,4,1,5,8}, {3,4,1,2,7,8,5,6},
4998  {6,7,3,2,5,8,4,1}, {6,5,8,7,2,1,4,3}, {6,2,1,5,7,3,4,8},
4999  {8,4,3,7,5,1,2,6}, {8,5,1,4,7,6,2,3}, {8,7,6,5,4,3,2,1} };
5000  static Int_t iwhat[8] = { 63,62,54,26,50,9,1,0 };
5001  static Int_t ie[12] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
5002  static Int_t iface[6][4] = {
5003  {1,2,3,4}, {5,6,7,8}, {1,2,6,5}, {2,6,7,3}, {4,3,7,8}, {1,5,8,4} };
5004  static Int_t it1[4][3] = { {1,2,10}, {9,5,8}, {6,11,7}, {3,4,12} };
5005  static Int_t it2[4][3] = { {5,6,10}, {1,4,9}, {2,11,3}, {7,8,12} };
5006  static Int_t it3[6][3] = { {10,12,-3}, {-10,3,2}, {12,10,-1}, {-12,1,4},
5007  {9,5,8}, {6,11,7} };
5008  static Int_t it4[6][3] = { {11,9,-1}, {-11,1,2}, {9,11,-3}, {-9,3,4},
5009  {5,6,10}, {7,8,12} };
5010  static Int_t it5[10][3] = { {13,2,-11}, {-13,11,7}, {13,7,-6}, {-13,6,10},
5011  {13,10,1}, {13,1,-4}, {-13,4,12}, {13,12,-3}, {-13,3,2}, {5,8,9} };
5012  static Int_t it6[10][3] = { {13,2,-10}, {-13,10,5}, {13,5,-6}, {-13,6,11},
5013  {13,11,3}, {13,3,-4}, {-13,4,9}, {13,9,-1}, {-13,1,2}, {12,7,8} };
5014  static Int_t it7[12][3] = { {13,2,-11}, {-13,11,7}, {13,7,-6}, {-13,6,10},
5015  {13,10,-5}, {-13,5,8}, {13,8,-9}, {-13,9,1},
5016  {13,1,-4}, {-13,4,12}, {13,12,-3}, {-13,3,2} };
5017  static Int_t it8[6][3] = { {3,8,12}, {3,-2,-8}, {-2,5,-8}, {2,10,-5},
5018  {7,6,11}, {1,4,9} };
5019  static Int_t it9[10][3] = { {7,12,-3}, {-7,3,11}, {11,3,2}, {6,11,-2}, {-6,2,10},
5020  {6,10,5}, {7,6,-5}, {-7,5,8}, {7,8,12}, {1,4,9} };
5021  static Int_t it10[10][3] = { {9,1,-10}, {-9,10,5}, {9,5,8}, {4,9,-8}, {-4,8,12},
5022  {4,12,3}, {1,4,-3}, {-1,3,2}, {1,2,10}, {7,6,11} };
5023 
5024  nnod = 0;
5025  ntria = 0;
5026 
5027  // F I N D C O N F I G U R A T I O N T Y P E
5028  for ( nr=1 ; nr<=12 ; nr++ ) {
5029  k = 0;
5030  incr = 1;
5031  for ( nf=1 ; nf<=6 ; nf++ ) {
5032  f1 = fF8[irota[nr-1][iface[nf-1][0]-1]-1];
5033  f2 = fF8[irota[nr-1][iface[nf-1][1]-1]-1];
5034  f3 = fF8[irota[nr-1][iface[nf-1][2]-1]-1];
5035  f4 = fF8[irota[nr-1][iface[nf-1][3]-1]-1];
5036  if ((f1*f3-f2*f4)/(f1+f3-f2-f4) >= 0.) k = k + incr;
5037  incr = incr + incr;
5038  }
5039  for ( i=1 ; i<=8 ; i++ ) {
5040  if (k != iwhat[i-1]) continue;
5041  icase = i;
5042  kr = nr;
5043  goto L200;
5044  }
5045  }
5046  Error("MarchingCubeCase13", "configuration is not found");
5047  return;
5048 
5049  // R O T A T E C U B E
5050 L200:
5051  if (icase==1 || icase==8) goto L300;
5052  for ( n=1 ; n<=8 ; n++) {
5053  k = irota[kr-1][n-1];
5054  ff[n-1] = fF8[k-1];
5055  for ( i=1 ; i<=3 ; i++ ) {
5056  xyz[n-1][i-1] = fP8[k-1][i-1];
5057  grad[n-1][i-1] = fG8[k-1][i-1];
5058  }
5059  }
5060  for ( n=1 ; n<=8 ; n++ ) {
5061  fF8[n-1] = ff[n-1];
5062  for ( i=1 ; i<=3 ; i++ ) {
5063  fP8[n-1][i-1] = xyz[n-1][i-1];
5064  fG8[n-1][i-1] = grad[n-1][i-1];
5065  }
5066  }
5067 
5068  // S E T N O D E S & N O R M A L E S
5069 L300:
5070  nnod = 12;
5071  MarchingCubeFindNodes(nnod, ie, xyz, grad);
5072 
5073  // V A R I O U S C O N F I G U R A T I O N S
5074  switch ((int)icase) {
5075  case 1:
5076  ntria = 4;
5077  MarchingCubeSetTriangles(ntria, it1, itria);
5078  return;
5079  case 8:
5080  ntria = 4;
5081  MarchingCubeSetTriangles(ntria, it2, itria);
5082  return;
5083  case 2:
5084  ntria = 6;
5085  MarchingCubeSetTriangles(ntria, it3, itria);
5086  return;
5087  case 7:
5088  ntria = 6;
5089  MarchingCubeSetTriangles(ntria, it4, itria);
5090  return;
5091  case 3:
5092  nnod = 13;
5093  ntria = 10;
5094  MarchingCubeMiddlePoint(9, xyz, grad, it5,
5095  &xyz[nnod-1][0], &grad[nnod-1][0]);
5096  MarchingCubeSetTriangles(ntria, it5, itria);
5097  return;
5098  case 6:
5099  nnod = 13;
5100  ntria = 10;
5101  MarchingCubeMiddlePoint(9, xyz, grad, it6,
5102  &xyz[nnod-1][0], &grad[nnod-1][0]);
5103  MarchingCubeSetTriangles(ntria, it6, itria);
5104  return;
5105  case 5:
5106  nnod = 13;
5107  ntria = 12;
5108  MarchingCubeMiddlePoint(12, xyz, grad, it7,
5109  &xyz[nnod-1][0], &grad[nnod-1][0]);
5110  MarchingCubeSetTriangles(ntria, it7, itria);
5111  return;
5112  // I S T H E R E S U R F A C E P E N E T R A T I O N ?
5113  case 4:
5114  MarchingCubeSurfacePenetration(fF8[2], fF8[3], fF8[0], fF8[1],
5115  fF8[6], fF8[7], fF8[4], fF8[5], irep);
5116  switch ((int)(irep+1)) {
5117  case 1:
5118  ntria = 6;
5119  MarchingCubeSetTriangles(ntria, it8, itria);
5120  return;
5121  case 2:
5122  ntria = 10;
5123  MarchingCubeSetTriangles(ntria, it9, itria);
5124  return;
5125  case 3:
5126  ntria = 10;
5127  MarchingCubeSetTriangles(ntria, it10, itria);
5128  }
5129  }
5130 }
5131 
5132 ////////////////////////////////////////////////////////////////////////////////
5133 /// Set triangles (if parameter IALL=1, all edges will be visible)
5134 ///
5135 /// \param[in] ntria number of triangles
5136 /// \param[in] it triangles
5137 ///
5138 /// \param[out] itria triangles
5139 
5140 void TPainter3dAlgorithms::MarchingCubeSetTriangles(Int_t ntria, Int_t it[][3],
5141  Int_t itria[48][3])
5142 {
5143  Int_t n, i, k;
5144 
5145  for ( n=1 ; n<=ntria ; n++ ) {
5146  for ( i=1 ; i<=3 ; i++ ) {
5147  k = it[n-1][i-1];
5148  itria[n-1][i-1] = k;
5149  }
5150  }
5151 }
5152 
5153 ////////////////////////////////////////////////////////////////////////////////
5154 /// Find middle point of a polygon
5155 ///
5156 /// \param[in] nnod number of nodes in the polygon
5157 /// \param[in] xyz node coordinates
5158 /// \param[in] grad node normales
5159 /// \param[in] it division of the polygons into triangles
5160 ///
5161 /// \param[out] pxyz middle point coordinates
5162 /// \param[out] pgrad middle point normale
5163 
5164 void TPainter3dAlgorithms::MarchingCubeMiddlePoint(Int_t nnod, Double_t xyz[52][3],
5165  Double_t grad[52][3],
5166  Int_t it[][3], Double_t *pxyz,
5167  Double_t *pgrad)
5168 {
5169  Double_t p[3], g[3];
5170  Int_t i, n, k;
5171 
5172  for ( i=1 ; i<=3 ; i++ ) {
5173  p[i-1] = 0.;
5174  g[i-1] = 0.;
5175  }
5176  for ( n=1 ; n<=nnod ; n++ ) {
5177  k = it[n-1][2];
5178  if (k < 0) k =-k;
5179  for ( i=1 ; i<=3 ; i++ ) {
5180  p[i-1] = p[i-1] + xyz[k-1][i-1];
5181  g[i-1] = g[i-1] + grad[k-1][i-1];
5182  }
5183  }
5184  for ( i=1 ; i<=3 ; i++ ) {
5185  pxyz[i-1] = p[i-1] / nnod;
5186  pgrad[i-1] = g[i-1] / nnod;
5187  }
5188 }
5189 
5190 ////////////////////////////////////////////////////////////////////////////////
5191 /// Check for surface penetration ("bottle neck")
5192 ///
5193 /// \param[in] axx vertex values for 1st face
5194 /// \param[in] bxx vertex values for opposite face
5195 ///
5196 /// \param[out] irep 1,2: there is surface penetration, 0: there is not surface penetration
5197 
5198 void TPainter3dAlgorithms::MarchingCubeSurfacePenetration(Double_t a00, Double_t a10,
5199  Double_t a11, Double_t a01,
5200  Double_t b00, Double_t b10,
5201  Double_t b11, Double_t b01,
5202  Int_t &irep)
5203 {
5204  Double_t a, b, c, d, s0, s1, s2;
5205  Int_t iposa, iposb;
5206 
5207  irep = 0;
5208  a = (a11-a01)*(b00-b10) - (a00-a10)*(b11-b01);
5209  if (a == 0.) return;
5210  b = a01*(b00-b10)-(a11-a01)*b00-(a00-a10)*b01+a00*(b11-b01);
5211  c = a00*b01 - a01*b00;
5212  d = b*b-4*a*c;
5213  if (d <= 0.) return;
5214  d = TMath::Sqrt(d);
5215  if (TMath::Abs(-b+d) > TMath::Abs(2*a)) return;
5216  s1 = (-b+d) / (2*a);
5217  if (s1<0. || s1>1.) return;
5218  if (TMath::Abs(-b-d) > TMath::Abs(2*a)) return;
5219  s2 = (-b-d) / (2*a);
5220  if (s2<0. || s2>1.) return;
5221 
5222  // C A S E N O 4 ?
5223  iposa = 0;
5224  if (a00 >= 0) iposa = iposa + 1;
5225  if (a01 >= 0) iposa = iposa + 2;
5226  if (a10 >= 0) iposa = iposa + 4;
5227  if (a11 >= 0) iposa = iposa + 8;
5228  if (iposa==6 || iposa==9) goto L100;
5229  irep = 1;
5230  return;
5231 
5232  // N O T C A S E N O 4
5233 L100:
5234  s0 = (a00-a01) / (a00+a11-a10-a01);
5235  if (s1>=s0 && s2<s0) return;
5236  if (s1<s0 && s2>=s0) return;
5237  irep = 1;
5238  if (s1 >= s0) irep = 2;
5239 
5240  // C A S E S N O 10, 13 ?
5241  iposb = 0;
5242  if (b00 >= 0) iposb = iposb + 1;
5243  if (b01 >= 0) iposb = iposb + 2;
5244  if (b10 >= 0) iposb = iposb + 4;
5245  if (b11 >= 0) iposb = iposb + 8;
5246  if (iposb!=6 && iposb!=9) return;
5247  s0 = (b00-b01) / (b00+b11-b10-b01);
5248  if (iposa != iposb) goto L200;
5249  // C A S E N O 10
5250  if (irep==1 && s1>s0) return;
5251  if (irep==2 && s1<s0) return;
5252  irep = 0;
5253  return;
5254  // C A S E N O 13
5255 L200:
5256  if (irep==1 && s1<s0) return;
5257  if (irep==2 && s1>s0) return;
5258  irep = 0;
5259 }
5260 
5261 ////////////////////////////////////////////////////////////////////////////////
5262 /// Find nodes and normales
5263 ///
5264 /// \param[in] nnod number of nodes
5265 /// \param[in] ie edges which have section node
5266 ///
5267 /// \param[out] xyz nodes
5268 /// \param[out] grad ode normales (not normalized)
5269 
5270 void TPainter3dAlgorithms::MarchingCubeFindNodes(Int_t nnod,
5271  Int_t *ie, Double_t xyz[52][3],
5272  Double_t grad[52][3])
5273 {
5274  Int_t n, k, i, n1, n2;
5275  Double_t t;
5276  static Int_t iedge[12][2] = {
5277  {1,2}, {2,3}, {3,4}, {4,1}, {5,6}, {6,7}, {7,8}, {8,5}, {1,5}, {2,6}, {3,7}, {4,8} };
5278 
5279  for ( n=1 ; n<=nnod ; n++ ) {
5280  k = ie[n-1];
5281  if (k < 0) k =-k;
5282  n1 = iedge[k-1][0];
5283  n2 = iedge[k-1][1];
5284  t = fF8[n1-1] / (fF8[n1-1]-fF8[n2-1]);
5285  for ( i=1 ; i<=3 ; i++ ) {
5286  xyz[n-1][i-1] = (fP8[n2-1][i-1]-fP8[n1-1][i-1])*t + fP8[n1-1][i-1];
5287  grad[n-1][i-1] = (fG8[n2-1][i-1]-fG8[n1-1][i-1])*t + fG8[n1-1][i-1];
5288  }
5289  }
5290 }
5291 
5292 ////////////////////////////////////////////////////////////////////////////////
5293 /// Z-depth algorithm for set of triangles
5294 ///
5295 /// \param[in] xyz nodes
5296 /// \param[in] nface number of triangular faces
5297 /// \param[in] iface faces (triangles)
5298 ///
5299 /// \param[in] dface array for min-max scopes
5300 /// \param[in] abcd array for face plane equations
5301 ///
5302 /// \param[out] iorder face order
5303 
5304 void TPainter3dAlgorithms::ZDepth(Double_t xyz[52][3], Int_t &nface,
5305  Int_t iface[48][3], Double_t dface[48][6],
5306  Double_t abcd[48][4], Int_t *iorder)
5307 {
5308  Int_t n, nf, i1, i2, i3, i, icur, k, itst, kface, kf, irep;
5309  Int_t nn[3], kk[3];
5310  Double_t wmin, wmax, a, b, c, q, zcur;
5311  Double_t v[2][3], abcdn[4], abcdk[4];
5312 
5313  // S E T I N I T I A L O R D E R
5314  // I G N O R E V E R Y S M A L L F A C E S
5315  // S E T M I N - M A X S C O P E S
5316  // S E T F A C E P L A N E E Q U A T I O N S
5317  nf = 0;
5318  for ( n=1 ; n<=nface ; n++ ) {
5319  i1 = TMath::Abs(iface[n-1][0]);
5320  i2 = TMath::Abs(iface[n-1][1]);
5321  i3 = TMath::Abs(iface[n-1][2]);
5322  // A R E A T E S T
5323  if (TMath::Abs(xyz[i2-1][0]-xyz[i1-1][0])<=kDel &&
5324  TMath::Abs(xyz[i2-1][1]-xyz[i1-1][1])<=kDel &&
5325  TMath::Abs(xyz[i2-1][2]-xyz[i1-1][2])<=kDel) continue;
5326  if (TMath::Abs(xyz[i3-1][0]-xyz[i2-1][0])<=kDel &&
5327  TMath::Abs(xyz[i3-1][1]-xyz[i2-1][1])<=kDel &&
5328  TMath::Abs(xyz[i3-1][2]-xyz[i2-1][2])<=kDel) continue;
5329  if (TMath::Abs(xyz[i1-1][0]-xyz[i3-1][0])<=kDel &&
5330  TMath::Abs(xyz[i1-1][1]-xyz[i3-1][1])<=kDel &&
5331  TMath::Abs(xyz[i1-1][2]-xyz[i3-1][2])<=kDel) continue;
5332  // P R O J E C T I O N T E S T
5333  if (TMath::Abs(xyz[i2-1][0]-xyz[i1-1][0])<=kDel &&
5334  TMath::Abs(xyz[i2-1][1]-xyz[i1-1][1])<=kDel &&
5335  TMath::Abs(xyz[i3-1][0]-xyz[i2-1][0])<=kDel &&
5336  TMath::Abs(xyz[i3-1][1]-xyz[i2-1][1])<=kDel &&
5337  TMath::Abs(xyz[i1-1][0]-xyz[i3-1][0])<=kDel &&
5338  TMath::Abs(xyz[i1-1][1]-xyz[i3-1][1])<=kDel) continue;
5339  nf = nf + 1;
5340  iorder[nf-1] = n;
5341  // F I N D M I N - M A X
5342  for ( i=1 ; i<=3 ; i++ ) {
5343  wmin = xyz[i1-1][i-1];
5344  wmax = xyz[i1-1][i-1];
5345  if (wmin > xyz[i2-1][i-1]) wmin = xyz[i2-1][i-1];
5346  if (wmax < xyz[i2-1][i-1]) wmax = xyz[i2-1][i-1];
5347  if (wmin > xyz[i3-1][i-1]) wmin = xyz[i3-1][i-1];
5348  if (wmax < xyz[i3-1][i-1]) wmax = xyz[i3-1][i-1];
5349  dface[n-1][i-1] = wmin;
5350  dface[n-1][i+2] = wmax;
5351  }
5352  // F I N D F A C E E Q U A T I O N
5353  for ( i=1 ; i<=3 ; i++ ) {
5354  v[0][i-1] = xyz[i2-1][i-1] - xyz[i1-1][i-1];
5355  v[1][i-1] = xyz[i3-1][i-1] - xyz[i2-1][i-1];
5356  }
5357  a = (v[0][1]*v[1][2] - v[0][2]*v[1][1]);
5358  b = (v[0][2]*v[1][0] - v[0][0]*v[1][2]);
5359  c = (v[0][0]*v[1][1] - v[0][1]*v[1][0]);
5360  q = TMath::Sqrt(a*a+b*b+c*c);
5361  if (c < 0.) q =-q;
5362  a = a / q;
5363  b = b / q;
5364  c = c / q;
5365  abcd[n-1][0] = a;
5366  abcd[n-1][1] = b;
5367  abcd[n-1][2] = c;
5368  abcd[n-1][3] =-(a*xyz[i1-1][0] + b*xyz[i1-1][1] + c*xyz[i1-1][2]);
5369  }
5370  nface = nf;
5371  if (nf <= 1) return;
5372 
5373  // S O R T T R I A N G L E S A L O N G Z - M I N
5374  for ( icur=2 ; icur<=nface ; icur++ ) {
5375  k = iorder[icur-1];
5376  zcur = dface[k-1][2];
5377  for ( itst=icur-1 ; itst>=1 ; itst-- ) {
5378  k = iorder[itst-1];
5379  if (zcur < dface[k-1][2]) break;
5380  k = iorder[itst-1];
5381  iorder[itst-1] = iorder[itst];
5382  iorder[itst] = k;
5383  }
5384  }
5385 
5386  // Z - D E P T H A L G O R I T H M
5387  kface = nface;
5388 L300:
5389  if (kface == 1) goto L900;
5390  nf = iorder[kface-1];
5391  if (nf < 0) nf =-nf;
5392  abcdn[0] = abcd[nf-1][0];
5393  abcdn[1] = abcd[nf-1][1];
5394  abcdn[2] = abcd[nf-1][2];
5395  abcdn[3] = abcd[nf-1][3];
5396  nn[0] = TMath::Abs(iface[nf-1][0]);
5397  nn[1] = TMath::Abs(iface[nf-1][1]);
5398  nn[2] = TMath::Abs(iface[nf-1][2]);
5399 
5400  // I N T E R N A L L O O P
5401  for ( k=kface-1 ; k>=1 ; k-- ) {
5402  kf = iorder[k-1];
5403  if (kf < 0) kf =-kf;
5404  if (dface[nf-1][5] > dface[kf-1][2]+kDel) goto L400;
5405  if (iorder[k-1] > 0) goto L900;
5406  goto L800;
5407 
5408  // M I N - M A X T E S T
5409 L400:
5410  if (dface[kf-1][0] >= dface[nf-1][3]-kDel) goto L800;
5411  if (dface[kf-1][3] <= dface[nf-1][0]+kDel) goto L800;
5412  if (dface[kf-1][1] >= dface[nf-1][4]-kDel) goto L800;
5413  if (dface[kf-1][4] <= dface[nf-1][1]+kDel) goto L800;
5414 
5415  // K F B E F O R E N F ?
5416  kk[0] = TMath::Abs(iface[kf-1][0]);
5417  kk[1] = TMath::Abs(iface[kf-1][1]);
5418  kk[2] = TMath::Abs(iface[kf-1][2]);
5419  if (abcdn[0]*xyz[kk[0]-1][0]+abcdn[1]*xyz[kk[0]-1][1]+
5420  abcdn[2]*xyz[kk[0]-1][2]+abcdn[3] < -kDel) goto L500;
5421  if (abcdn[0]*xyz[kk[1]-1][0]+abcdn[1]*xyz[kk[1]-1][1]+
5422  abcdn[2]*xyz[kk[1]-1][2]+abcdn[3] < -kDel) goto L500;
5423  if (abcdn[0]*xyz[kk[2]-1][0]+abcdn[1]*xyz[kk[2]-1][1]+
5424  abcdn[2]*xyz[kk[2]-1][2]+abcdn[3] < -kDel) goto L500;
5425  goto L800;
5426 
5427  // N F A F T E R K F ?
5428 L500:
5429  abcdk[0] = abcd[kf-1][0];
5430  abcdk[1] = abcd[kf-1][1];
5431  abcdk[2] = abcd[kf-1][2];
5432  abcdk[3] = abcd[kf-1][3];
5433  if (abcdk[0]*xyz[nn[0]-1][0]+abcdk[1]*xyz[nn[0]-1][1]+
5434  abcdk[2]*xyz[nn[0]-1][2]+abcdk[3] > kDel) goto L600;
5435  if (abcdk[0]*xyz[nn[1]-1][0]+abcdk[1]*xyz[nn[1]-1][1]+
5436  abcdk[2]*xyz[nn[1]-1][2]+abcdk[3] > kDel) goto L600;
5437  if (abcdk[0]*xyz[nn[2]-1][0]+abcdk[1]*xyz[nn[2]-1][1]+
5438  abcdk[2]*xyz[nn[2]-1][2]+abcdk[3] > kDel) goto L600;
5439  goto L800;
5440 
5441  // E D G E B Y E D G E T E S T
5442  // K F - E D G E S A G A I N S T N F
5443 L600:
5444  for ( i=1 ; i<=3 ; i++ ) {
5445  i1 = kk[i-1];
5446  i2 = kk[0];
5447  if (i != 3) i2 = kk[i];
5448  TestEdge(kDel, xyz, i1, i2, nn, abcdn, irep);
5449  if ( irep<0 ) goto L700;
5450  if ( irep==0 ) continue;
5451  if ( irep>0 ) goto L800;
5452  }
5453  // N F - E D G E S A G A I N S T K F
5454  for ( i=1 ; i<=3 ; i++ ) {
5455  i1 = nn[i-1];
5456  i2 = nn[0];
5457  if (i != 3) i2 = nn[i];
5458  TestEdge(kDel, xyz, i1, i2, kk, abcdk, irep);
5459  if ( irep<0 ) goto L800;
5460  if ( irep==0 ) continue;
5461  if ( irep>0 ) goto L700;
5462  }
5463  goto L800;
5464 
5465  // C H A N G E F A C E O R D E R
5466 L700:
5467  kf = iorder[k-1];
5468  for ( i=k+1 ; i<=kface ; i++ ) {
5469  iorder[i-2] = iorder[i-1];
5470  }
5471  iorder[kface-1] =-kf;
5472  if (kf > 0) goto L300;
5473  goto L900;
5474 L800:
5475  continue;
5476  }
5477 
5478  // N E X T F A C E
5479 L900:
5480  if (iorder[kface-1] < 0) iorder[kface-1] =-iorder[kface-1];
5481  kface = kface - 1;
5482  if (kface > 0) goto L300;
5483 }
5484 
5485 ////////////////////////////////////////////////////////////////////////////////
5486 /// Test edge against face (triangle)
5487 ///
5488 /// \param[in] del precision
5489 /// \param[in] xyz nodes
5490 /// \param[in] i1 1-st node of edge
5491 /// \param[in] i2 2-nd node of edge
5492 /// \param[in] iface triangular face
5493 /// \param[in] abcd face plane
5494 ///
5495 /// \param[out] irep 1: edge under face, 0: no decision, +1: edge before face
5496 
5497 void TPainter3dAlgorithms::TestEdge(Double_t del, Double_t xyz[52][3], Int_t i1, Int_t i2,
5498  Int_t iface[3], Double_t abcd[4], Int_t &irep)
5499 {
5500  Int_t k, k1, k2, ixy, i;
5501  Double_t a, b, c, d1, d2, dd, xy, tmin, tmax, tmid, x, y, z;
5502  Double_t d[3], delta[3], t[2];
5503 
5504  irep = 0;
5505 
5506  // F I N D I N T E R S E C T I O N P O I N T S
5507  delta[0] = xyz[i2-1][0] - xyz[i1-1][0];
5508  delta[1] = xyz[i2-1][1] - xyz[i1-1][1];
5509  delta[2] = xyz[i2-1][2] - xyz[i1-1][2];
5510  if (TMath::Abs(delta[0])<=del && TMath::Abs(delta[1])<=del) return;
5511  ixy = 1;
5512  if (TMath::Abs(delta[1]) > TMath::Abs(delta[0])) ixy = 2;
5513  a = delta[1];
5514  b =-delta[0];
5515  c =-(a*xyz[i1-1][0] + b*xyz[i1-1][1]);
5516  d[0] = a*xyz[iface[0]-1][0] + b*xyz[iface[0]-1][1] + c;
5517  d[1] = a*xyz[iface[1]-1][0] + b*xyz[iface[1]-1][1] + c;
5518  d[2] = a*xyz[iface[2]-1][0] + b*xyz[iface[2]-1][1] + c;
5519  k = 0;
5520  for ( i=1 ; i<=3 ; i++ ) {
5521  k1 = i;
5522  k2 = i + 1;
5523  if (i == 3) k2 = 1;
5524  if (d[k1-1]>=0. && d[k2-1]>=0.) continue;
5525  if (d[k1-1] <0. && d[k2-1] <0.) continue;
5526  d1 = d[k1-1] / (d[k1-1] - d[k2-1]);
5527  d2 = d[k2-1] / (d[k1-1] - d[k2-1]);
5528  xy = d1*xyz[iface[k2-1]-1][ixy-1] - d2*xyz[iface[k1-1]-1][ixy-1];
5529  k = k + 1;
5530  t[k-1] = (xy-xyz[i1-1][ixy-1]) / delta[ixy-1];
5531  if (k == 2) goto L200;
5532  }
5533  return;
5534 
5535  // C O M P A R E Z - D E P T H
5536 L200:
5537  tmin = TMath::Min(t[0],t[1]);
5538  tmax = TMath::Max(t[0],t[1]);
5539  if (tmin>1. || tmax<0) return;
5540  if (tmin < 0.) tmin = 0.;
5541  if (tmax > 1.) tmax = 1.;
5542  tmid = (tmin + tmax) / 2.;
5543  x = delta[0]*tmid + xyz[i1-1][0];
5544  y = delta[1]*tmid + xyz[i1-1][1];
5545  z = delta[2]*tmid + xyz[i1-1][2];
5546  dd = abcd[0]*x + abcd[1]*y + abcd[2]*z + abcd[3];
5547  if (dd > del) goto L997;
5548  if (dd <-del) goto L998;
5549  return;
5550 
5551 L997:
5552  irep =+1;
5553  return;
5554 L998:
5555  irep =-1;
5556 }
5557 
5558 ////////////////////////////////////////////////////////////////////////////////
5559 /// Draw set of iso-surfaces for a scalar function defined on a grid.
5560 ///
5561 /// \param[in] ns number of iso-surfaces
5562 /// \param[in] s iso-surface values
5563 /// \param[in] nx number of slices along X
5564 /// \param[in] ny number of slices along Y
5565 /// \param[in] nz number of slices along Z
5566 /// \param[in] x slices along X
5567 /// \param[in] y slices along Y
5568 /// \param[in] z slices along Z
5569 ///
5570 /// - chopt` = 'BF' from BACK to FRONT
5571 /// - chopt` = 'FB' from FRONT to BACK
5572 
5573 void TPainter3dAlgorithms::IsoSurface (Int_t ns, Double_t *s, Int_t nx,
5574  Int_t ny, Int_t nz,
5575  Double_t *x, Double_t *y, Double_t *z,
5576  const char *chopt)
5577 {
5578  Double_t p[8][3], pf[8], pn[8][3];
5579  Double_t p0[3], p1[3], p2[3], p3[3], t[3];
5580  Double_t fsurf, w, d1, d2, df1, df2;
5581  Int_t icodes[3];
5582  Int_t i, i1, i2, j, ibase, nnod, knod, ntria, ktria, iopt, iready;
5583  Int_t ixcrit, iycrit, izcrit, incrx, incry, incrz, incr;
5584  Int_t ix, ix1=0, ix2=0, iy, iy1=0, iy2=0, iz, iz1=0, iz2=0, k, kx, ky, kz, isurf, nsurf;
5585 
5586  Double_t xyz[kNmaxp][3], xyzn[kNmaxp][3], grad[kNmaxp][3];
5587  Double_t dtria[kNmaxt][6], abcd[kNmaxt][4];
5588  Int_t itria[kNmaxt][3], iorder[kNmaxt], iattr[kNmaxt];
5589 
5590  static Int_t ind[8][3] = { { 0,0,0 }, { 1,0,0 }, { 1,0,1 }, { 0,0,1 },
5591  { 0,1,0 }, { 1,1,0 }, { 1,1,1 }, { 0,1,1 } };
5592  for (i=0;i<kNmaxp;i++) {
5593  xyzn[i][0] = 0.;
5594  xyzn[i][1] = 0.;
5595  xyzn[i][2] = 0.;
5596  }
5597 
5598  TView *view = 0;
5599 
5600  if (gPad) view = gPad->GetView();
5601  if (!view) {
5602  Error("ImplicitFunction", "no TView in current pad");
5603  return;
5604  }
5605 
5606  nsurf = ns;
5607  if (nsurf > kNiso) {
5608  Warning("IsoSurface","Number of iso-surfaces too large. Increase kNiso");
5609  }
5610  iopt = 2;
5611  if (*chopt == 'B' || *chopt == 'b') iopt = 1;
5612 
5613  // F I N D X - , Y - , Z - C R I T I C A L
5614  // This logic works for parallel projection only.
5615  // For central projection another logic should be implemented.
5616  p0[0] = x[0];
5617  p0[1] = y[0];
5618  p0[2] = z[0];
5619  view->WCtoNDC(p0, p0);
5620  p1[0] = x[nx-1];
5621  p1[1] = y[0];
5622  p1[2] = z[0];
5623  view->WCtoNDC(p1, p1);
5624  p2[0] = x[0];
5625  p2[1] = y[ny-1];
5626  p2[2] = z[0];
5627  view->WCtoNDC(p2, p2);
5628  p3[0] = x[0];
5629  p3[1] = y[0];
5630  p3[2] = z[nz-1];
5631  view->WCtoNDC(p3, p3);
5632  ixcrit = nx;
5633  iycrit = ny;
5634  izcrit = nz;
5635  if (p1[2] < p0[2]) ixcrit = 1;
5636  if (p2[2] < p0[2]) iycrit = 1;
5637  if (p3[2] < p0[2]) izcrit = 1;
5638 
5639  // L O O P A L O N G G R I D
5640  // This logic works for both (parallel & central) projections.
5641  incrx = 1;
5642  incry = 1;
5643  incrz = 1;
5644 L110:
5645  if (incrz >= 0) {
5646  if (iopt == 1) iz1 = 1;
5647  if (iopt == 1) iz2 = izcrit-1;
5648  if (iopt == 2) iz1 = izcrit;
5649  if (iopt == 2) iz2 = nz - 1;
5650  } else {
5651  if (iopt == 1) iz1 = nz - 1;
5652  if (iopt == 1) iz2 = izcrit;
5653  if (iopt == 2) iz1 = izcrit-1;
5654  if (iopt == 2) iz2 = 1;
5655  }
5656  for (iz = iz1; incrz < 0 ? iz >= iz2 : iz <= iz2; iz += incrz) {
5657 L120:
5658  if (incry >= 0) {
5659  if (iopt == 1) iy1 = 1;
5660  if (iopt == 1) iy2 = iycrit-1;
5661  if (iopt == 2) iy1 = iycrit;
5662  if (iopt == 2) iy2 = ny - 1;
5663  } else {
5664  if (iopt == 1) iy1 = ny - 1;
5665  if (iopt == 1) iy2 = iycrit;
5666  if (iopt == 2) iy1 = iycrit-1;
5667  if (iopt == 2) iy2 = 1;
5668  }
5669  for (iy = iy1; incry < 0 ? iy >= iy2 : iy <= iy2; iy += incry) {
5670 L130:
5671  if (incrx >= 0) {
5672  if (iopt == 1) ix1 = 1;
5673  if (iopt == 1) ix2 = ixcrit-1;
5674  if (iopt == 2) ix1 = ixcrit;
5675  if (iopt == 2) ix2 = nx - 1;
5676  } else {
5677  if (iopt == 1) ix1 = nx - 1;
5678  if (iopt == 1) ix2 = ixcrit;
5679  if (iopt == 2) ix1 = ixcrit-1;
5680  if (iopt == 2) ix2 = 1;
5681  }
5682  for (ix = ix1; incrx < 0 ? ix >= ix2 : ix <= ix2; ix += incrx) {
5683  nnod = 0;
5684  ntria = 0;
5685  iready = 0;
5686  for ( isurf=1 ; isurf<=nsurf ; isurf++ ) {
5687  fsurf = s[isurf-1];
5688  if (gCurrentHist->GetBinContent(ix, iy, iz) >= fsurf)
5689  goto L210;
5690  if (gCurrentHist->GetBinContent(ix+1,iy, iz) >= fsurf)
5691  goto L220;
5692  if (gCurrentHist->GetBinContent(ix, iy+1,iz) >= fsurf)
5693  goto L220;
5694  if (gCurrentHist->GetBinContent(ix+1,iy+1,iz) >= fsurf)
5695  goto L220;
5696  if (gCurrentHist->GetBinContent(ix, iy, iz+1) >= fsurf)
5697  goto L220;
5698  if (gCurrentHist->GetBinContent(ix+1,iy, iz+1) >= fsurf)
5699  goto L220;
5700  if (gCurrentHist->GetBinContent(ix, iy+1,iz+1) >= fsurf)
5701  goto L220;
5702  if (gCurrentHist->GetBinContent(ix+1,iy+1,iz+1) >= fsurf)
5703  goto L220;
5704  continue;
5705 L210:
5706  if (gCurrentHist->GetBinContent(ix+1,iy, iz) < fsurf)
5707  goto L220;
5708  if (gCurrentHist->GetBinContent(ix, iy+1,iz) < fsurf)
5709  goto L220;
5710  if (gCurrentHist->GetBinContent(ix+1,iy+1,iz) < fsurf)
5711  goto L220;
5712  if (gCurrentHist->GetBinContent(ix, iy, iz+1) < fsurf)
5713  goto L220;
5714  if (gCurrentHist->GetBinContent(ix+1,iy, iz+1) < fsurf)
5715  goto L220;
5716  if (gCurrentHist->GetBinContent(ix, iy+1,iz+1) < fsurf)
5717  goto L220;
5718  if (gCurrentHist->GetBinContent(ix+1,iy+1,iz+1) < fsurf)
5719  goto L220;
5720  continue;
5721 
5722  // P R E P A R E C U B E ( P A R A L L E P I P E D )
5723 L220:
5724  if (iready !=0) goto L310;
5725  iready = 1;
5726  for ( i=1 ; i<=8 ; i++ ) {
5727  kx = ix + ind[i-1][0];
5728  ky = iy + ind[i-1][1];
5729  kz = iz + ind[i-1][2];
5730  p[i-1][0] = x[kx-1];
5731  p[i-1][1] = y[ky-1];
5732  p[i-1][2] = z[kz-1];
5733  pf[i-1] = gCurrentHist->GetBinContent(kx,ky,kz);
5734  // F I N D X - G R A D I E N T
5735  if (kx == 1) {
5736  pn[i-1][0] = (gCurrentHist->GetBinContent(2,ky,kz) -
5737  gCurrentHist->GetBinContent(1,ky,kz)) /
5738  (x[1]-x[0]);
5739  } else if (kx == nx) {
5740  pn[i-1][0] = (gCurrentHist->GetBinContent(kx,ky,kz) -
5741  gCurrentHist->GetBinContent(kx-1,ky,kz)) /
5742  (x[kx-1]-x[kx-2]);
5743  } else {
5744  d1 = x[kx-1] - x[kx-2];
5745  d2 = x[kx] - x[kx-1];
5746  if (d1 == d2) {
5747  pn[i-1][0] = (gCurrentHist->GetBinContent(kx+1,ky,kz) -
5748  gCurrentHist->GetBinContent(kx-1,ky,kz)) /
5749  (d1+d1);
5750  } else {
5751  df1 = gCurrentHist->GetBinContent(kx,ky,kz) -
5752  gCurrentHist->GetBinContent(kx-1,ky,kz);
5753  df2 = gCurrentHist->GetBinContent(kx+1,ky,kz) -
5754  gCurrentHist->GetBinContent(kx,ky,kz);
5755  pn[i-1][0] = (df1*d2*d2+df2*d1*d1)/(d1*d2*d2+d2*d1*d1);
5756  }
5757  }
5758  // F I N D Y - G R A D I E N T
5759  if (ky == 1) {
5760  pn[i-1][1] = (gCurrentHist->GetBinContent(kx,2,kz) -
5761  gCurrentHist->GetBinContent(kx,1,kz)) /
5762  (y[1]-y[0]);
5763  } else if (ky == ny) {
5764  pn[i-1][1] = (gCurrentHist->GetBinContent(kx,ky,kz) -
5765  gCurrentHist->GetBinContent(kx,ky-1,kz)) /
5766  (y[ky-1]-y[ky-2]);
5767  } else {
5768  d1 = y[ky-1] - y[ky-2];
5769  d2 = y[ky] - y[ky-1];
5770  if (d1 == d2) {
5771  pn[i-1][1] = (gCurrentHist->GetBinContent(kx,ky+1,kz) -
5772  gCurrentHist->GetBinContent(kx,ky-1,kz)) /
5773  (d1+d1);
5774  } else {
5775  df1 = gCurrentHist->GetBinContent(kx,ky,kz) -
5776  gCurrentHist->GetBinContent(kx,ky-1,kz);
5777  df2 = gCurrentHist->GetBinContent(kx,ky+1,kz) -
5778  gCurrentHist->GetBinContent(kx,ky,kz);
5779  pn[i-1][1] = (df1*d2*d2+df2*d1*d1)/(d1*d2*d2+d2*d1*d1);
5780  }
5781  }
5782  // F I N D Z - G R A D I E N T
5783  if (kz == 1) {
5784  pn[i-1][2] = (gCurrentHist->GetBinContent(kx,ky,2) -
5785  gCurrentHist->GetBinContent(kx,ky,1)) /
5786  (z[1]-z[0]);
5787  } else if (kz == nz) {
5788  pn[i-1][2] = (gCurrentHist->GetBinContent(kx,ky,kz) -
5789  gCurrentHist->GetBinContent(kx,ky,kz-1)) /
5790  (z[kz-1]-z[kz-2]);
5791  } else {
5792  d1 = z[kz-1] - z[kz-2];
5793  d2 = z[kz] - z[kz-1];
5794  if (d1 == d2) {
5795  pn[i-1][2] = (gCurrentHist->GetBinContent(kx,ky,kz+1) -
5796  gCurrentHist->GetBinContent(kx,ky,kz-1)) /
5797  (d1+d1);
5798  } else {
5799  df1 = gCurrentHist->GetBinContent(kx,ky,kz) -
5800  gCurrentHist->GetBinContent(kx,ky,kz-1);
5801  df2 = gCurrentHist->GetBinContent(kx,ky,kz+1) -
5802  gCurrentHist->GetBinContent(kx,ky,kz);
5803  pn[i-1][2] = (df1*d2*d2+df2*d1*d1)/(d1*d2*d2+d2*d1*d1);
5804  }
5805  }
5806  }
5807 
5808  // F I N D S E T O F T R I A N G L E S
5809 L310:
5810  Double_t xyz_tmp[kNmaxp][3], grad_tmp[kNmaxp][3];
5811  Int_t itria_tmp[kNmaxt][3], l;
5812 
5813  MarchingCube(s[isurf-1], p, pf, pn, knod, ktria,
5814  xyz_tmp, grad_tmp, itria_tmp);
5815 
5816  for( l=0 ; l<knod ; l++) {
5817  xyz[nnod+l][0] = xyz_tmp[l][0];
5818  xyz[nnod+l][1] = xyz_tmp[l][1];
5819  xyz[nnod+l][2] = xyz_tmp[l][2];
5820  grad[nnod+l][0] = grad_tmp[l][0];
5821  grad[nnod+l][1] = grad_tmp[l][1];
5822  grad[nnod+l][2] = grad_tmp[l][2];
5823  }
5824  for( l=0 ; l<ktria ; l++) {
5825  itria[ntria+l][0] = itria_tmp[l][0];
5826  itria[ntria+l][1] = itria_tmp[l][1];
5827  itria[ntria+l][2] = itria_tmp[l][2];
5828  }
5829 
5830  for ( i=ntria+1 ; i<=ntria+ktria ; i++ ) {
5831  for ( j=1 ; j<=3 ; j++ ){
5832  ibase = nnod;
5833  if (itria[i-1][j-1] < 0) ibase =-nnod;
5834  itria[i-1][j-1] = itria[i-1][j-1] + ibase;
5835  }
5836  iattr[i-1] = isurf;
5837  }
5838  nnod = nnod + knod;
5839  ntria = ntria + ktria;
5840  }
5841 
5842  // D E P T H S O R T, D R A W I N G
5843  if (ntria == 0) continue;
5844  for ( i=1 ; i<=nnod ; i++ ) {
5845  view->WCtoNDC(&xyz[i-1][0], &xyzn[i-1][0]);
5846  Luminosity(&grad[i-1][0], w);
5847  grad[i-1][0] = w;
5848  }
5849  ZDepth(xyzn, ntria, itria, dtria, abcd, (Int_t*)iorder);
5850  if (ntria == 0) continue;
5851  incr = 1;
5852  if (iopt == 1) incr = -1;
5853  i1 = 1;
5854  if (incr == -1) i1 = ntria;
5855  i2 = ntria - i1 + 1;
5856  for (i = i1; incr < 0 ? i >= i2 : i <= i2; i += incr) {
5857  k = iorder[i-1];
5858  t[0] = grad[TMath::Abs(itria[k-1][0])-1][0];
5859  t[1] = grad[TMath::Abs(itria[k-1][1])-1][0];
5860  t[2] = grad[TMath::Abs(itria[k-1][2])-1][0];
5861  icodes[0] = iattr[k-1];
5862  icodes[1] = iattr[k-1];
5863  icodes[2] = iattr[k-1];
5864  DrawFaceGouraudShaded(icodes, xyz, 3, &itria[k-1][0], t);
5865  }
5866  }
5867  incrx = -incrx;
5868  if (incrx < 0) goto L130;
5869  }
5870  incry = -incry;
5871  if (incry < 0) goto L120;
5872  }
5873  incrz = -incrz;
5874  if (incrz < 0) goto L110;
5875 }
5876 
5877 ////////////////////////////////////////////////////////////////////////////////
5878 /// Draw the faces for the Gouraud Shaded Iso surfaces
5879 
5880 void TPainter3dAlgorithms::DrawFaceGouraudShaded(Int_t *icodes,
5881  Double_t xyz[][3],
5882  Int_t np, Int_t *iface,
5883  Double_t *t)
5884 {
5885  Int_t i, k, irep;
5886  Double_t p3[12][3];
5887  TView *view = 0;
5888 
5889  if (gPad) view = gPad->GetView();
5890  if (!view) {
5891  Error("ImplicitFunction", "no TView in current pad");
5892  return;
5893  }
5894 
5895  if (icodes[0]==1) Spectrum(fNcolor, fFmin, fFmax, fIc1, 1, irep);
5896  if (icodes[0]==2) Spectrum(fNcolor, fFmin, fFmax, fIc2, 1, irep);
5897  if (icodes[0]==3) Spectrum(fNcolor, fFmin, fFmax, fIc3, 1, irep);
5898  for ( i=1 ; i<=np ; i++) {
5899  k = iface[i-1];
5900  if (k<0) k = -k;
5901  view->WCtoNDC(&xyz[k-1][0], &p3[i-1][0]);
5902  }
5903  FillPolygon(np, (Double_t *)p3, (Double_t *)t);
5904 }