Logo ROOT  
Reference Guide
TGL5DPainter.cxx
Go to the documentation of this file.
1// @(#)root/gl:$Id$
2// Author: Timur Pocheptsov 28/07/2009
3
4/*************************************************************************
5 * Copyright (C) 1995-2009, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12#include "KeySymbols.h"
13#include "TVirtualX.h"
14#include "Buttons.h"
15#include "TString.h"
16#include "TError.h"
17#include "TROOT.h"
18#include "TMath.h"
19
20#include "TGLPlotCamera.h"
21#include "TGL5DPainter.h"
22#include "TGLPadUtils.h"
23#include "TGLIncludes.h"
24#include "TGL5D.h"
25
26/** \class TGL5DPainter
27\ingroup opengl
28TGL5DPainter implements "gl5d" option for TTree::Draw.
29Data (4D) is visualized as a set of iso-surfaces. 5D.
30*/
31
32////////////////////////////////////////////////////////////////////////////////
33///Constructor.
34
36 : TGLPlotPainter(data, camera, coord),
37 fMeshBuilder(kTRUE),//kTRUE == average normals.
38 fInit(kFALSE),
39 fData(data),
40 fShowSlider(kFALSE),
41 fAlpha(0.4),
42 fNContours(kNContours)
43{
44 if (fData->fV4IsString)
45 fNContours = Int_t(fData->fV4MinMax.second) - Int_t(fData->fV4MinMax.first) + 1;
46}
47
48////////////////////////////////////////////////////////////////////////////////
49///Try to add new iso-surface.
50///If something goes wrong, return
51///iterator to the end of fIsos.
52
55 Double_t range, Int_t lownps)
56{
57 fData->SelectPoints(v4, range);
58
59 if (fData->SelectedSize() < size_type(lownps)) {
60 Warning("TGL5DPainter::AddSurface", "Too little points: %d", Int_t(fData->SelectedSize()));
61 return fIsos.end();//This is a valid iterator, but an invalid surface.
62 } else {
63 Info("TGL5DPainter::AddSurface", "Selected %d points", Int_t(fData->SelectedSize()));
64 }
65
66 fKDE.BuildModel(fData, sigma);//Prepare density estimator.
67
68 Info("TGL5DPainter::AddSurface", "Building the mesh ...");
69 //Prepare grid parameters.
73 fCoord->GetZScale());
75 fMeshBuilder.SetGeometry(fData);
76 //Build a new mesh.
77 fMeshBuilder.BuildMesh(&fKDE, geom, &mesh, iso);
78
79 Info("TGL5DPainter::AddSurface", "Mesh has %d vertices", Int_t(mesh.fVerts.size() / 3));
80
81 if (!mesh.fVerts.size())//I do not need an empty mesh.
82 return fIsos.end();
83 //Add surface with empty mesh and swap meshes.
84 fIsos.push_front(fDummy);
85
86 fIsos.front().fMesh.Swap(mesh);
87 fIsos.front().f4D = v4;
88 fIsos.front().fRange = range;
89 fIsos.front().fShowCloud = kFALSE;
90 fIsos.front().fHide = kFALSE;
91 fIsos.front().fColor = ci;
92
93 //Predictions for the 5-th variable.
94 //Not-implemented yet.
95 return fIsos.begin();
96}
97
98////////////////////////////////////////////////////////////////////////////////
99///Add new surface. Simplified version for ged.
100
102{
103 const Rgl::Range_t &v4R = fData->fV4MinMax;
104 const Bool_t isString = fData->fV4IsString;
105 const Double_t rms = TMath::RMS(fData->fNP, fData->fV4); //RMS of the N points.
106 const Double_t d = isString ? (v4R.second - v4R.first) / (fNContours - 1)
107 : 6 * rms / fNContours;
108 //alpha is in [0.1, 0.5], 1e-3 -s good for strings.
109 const Double_t range = isString ? 1e-3 : fAlpha * d;
110
111 AddSurface(v4, 1, 0.125, 0.05, range);
112}
113
114////////////////////////////////////////////////////////////////////////////////
115///Remove iso-surface.
116
118{
119 if (surf == fIsos.end()) {
120 Error("TGL5DPainter::RemoveSurface", "Invalid iterator, surface does not exist.");
121 return;
122 }
123
124 fIsos.erase(surf);
125}
126
127////////////////////////////////////////////////////////////////////////////////
128///Return info for plot part under cursor.
129
131{
132 static char mess[] = {"gl5d"};
133 return mess;
134}
135
136////////////////////////////////////////////////////////////////////////////////
137///Create mesh.
138///InitGeometry creates surfaces for auto-iso levels.
139///Called the first time and each time number of auto-levels is
140///reset via the editor.
141
143{
144 if (fInit)
145 return kTRUE;
146 //Only in cartesian.
148
150 return kFALSE;
151
152 fIsos.clear();
153
157 if (fCamera)
159
160 const Rgl::Range_t &v4R = fData->fV4MinMax;
161 const Bool_t isString = fData->fV4IsString;
162
163 //Rene's code to automatically find iso-levels.
164 const Double_t mean = TMath::Mean(fData->fNP, fData->fV4); //mean value of the NP points.
165 const Double_t rms = TMath::RMS(fData->fNP, fData->fV4); //RMS of the N points.
166 const Double_t min = isString ? v4R.first : mean - 3 * rms; //take a range +- 3*xrms
167 const Double_t d = isString ? (v4R.second - v4R.first) / (fNContours - 1)
168 : 6 * rms / fNContours;
169 //alpha is in [0.1, 0.5], 1e-3 -s good for strings.
170 const Double_t range = isString ? 1e-3 : fAlpha * d;
171
172 Info("InitGeometry", "min = %g, mean = %g, rms = %g, dx = %g", min, mean, rms, d);
173
174 for (Int_t j = 0; j < fNContours; ++j) {
175 const Double_t isoLevel = min + j * d;
176 Info("TGL5DPainter::InitGeometry", "Iso-level %g, range is %g ...", isoLevel, range);
177 const Color_t color = j * 6 + 1;
178 AddSurface(isoLevel, color, 0.125, 0.05, range);
179 }
180
181 if (fIsos.size())
183
184 return fInit = kTRUE;
185}
186
187////////////////////////////////////////////////////////////////////////////////
188///User clicks right mouse button (in a pad).
189
191{
192 fMousePosition.fX = px;
194 fCamera->StartPan(px, py);
196}
197
198////////////////////////////////////////////////////////////////////////////////
199///Mouse events handler.
200
202{
203 if (fSelectedPart >= fSelectionBase) {//Pan camera.
206
209 fCamera->Pan(px, py);
210
213 } else if (fSelectedPart > 0) {
214 //Convert py into bottom-top orientation.
215 py = fCamera->GetHeight() - py;
216
219
222
223 if (!fHighColor) {
226 }
227 }
228
231 }
232
235}
236
237////////////////////////////////////////////////////////////////////////////////
238///No additional options for TGL5DPainter.
239
240void TGL5DPainter::AddOption(const TString &/*option*/)
241{
242}
243
244////////////////////////////////////////////////////////////////////////////////
245
247{
248 //Change color scheme.
249 if (event == kKeyPress) {
250 if (py == kKey_c || py == kKey_C) {
251 if (fHighColor)
252 Info("ProcessEvent", "Cut box does not work in high color, please, switch to true color");
253 else {
256 }
257 }
258 } else if (event == kButton1Double && fBoxCut.IsActive()) {
259 if (fBoxCut.IsActive())
261 if (!gVirtualX->IsCmdThread())
262 gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%zx)->Paint()", (size_t)this));
263 else
264 Paint();
265 }
266}
267
268////////////////////////////////////////////////////////////////////////////////
269///Set selection range parameter.
270
272{
273 if (fAlpha != newVal && !fData->fV4IsString) {
274 fAlpha = newVal;
275 fInit = kFALSE;
276 InitGeometry();
277 }
278
279 if (fData->fV4IsString)
280 Warning("SetAlpha", "Alpha is not required for string data (your 4-th dimension is string).");
281}
282
283////////////////////////////////////////////////////////////////////////////////
284///Set the number of predefined contours.
285
287{
288 if (n <= 0) {
289 Warning("SetNContours", "Bad number of contours: %d", n);
290 return;
291 }
292
293 fNContours = n;
294 fInit = kFALSE;
295 InitGeometry();
296}
297
298////////////////////////////////////////////////////////////////////////////////
299///No need to create or delete meshes,
300///number of meshes (iso-levels) are
301///the same, but meshes must be rebuilt
302///in new ranges.
303///Only in cartesian.
304
306{
311 if (fCamera)
313 //Iterate through all surfaces and re-calculate them.
314 for (SurfIter_t surf = fIsos.begin(); surf != fIsos.end(); ++surf) {
315 fData->SelectPoints(surf->f4D, surf->fRange);
316 fKDE.BuildModel(fData, 0.05);//0.05 is sigma, will be controlled via GUI.
317 Info("TGL5DPainter::ResetGeometryRanges", "Building the mesh ...");
318 //Prepare grid parameters.
320 fCoord->GetXScale(),
321 fCoord->GetYScale(),
322 fCoord->GetZScale());
323 fMeshBuilder.SetGeometry(fData);
324 Mesh_t &mesh = surf->fMesh;
325 //Clear old data.
326 mesh.fVerts.clear();
327 mesh.fNorms.clear();
328 mesh.fTris.clear();
329 //Build new mesh.
330 fMeshBuilder.BuildMesh(&fKDE, geom, &mesh, 0.125);//0.125 will be set via GUI.
331 Info("TGL5DPainter::AddSurface", "Mesh has %d vertices", Int_t(mesh.fVerts.size() / 3));
332 }
333
335}
336
337////////////////////////////////////////////////////////////////////////////////
338///std::list::begin.
339
341{
342 return fIsos.begin();
343}
344
345////////////////////////////////////////////////////////////////////////////////
346///std::list::end.
347
349{
350 return fIsos.end();
351}
352
353////////////////////////////////////////////////////////////////////////////////
354///Initialize OpenGL state variables.
355
357{
358 glEnable(GL_LIGHTING);
359 glEnable(GL_LIGHT0);
360 glEnable(GL_DEPTH_TEST);
361 glDisable(GL_CULL_FACE);
362 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
363}
364
365////////////////////////////////////////////////////////////////////////////////
366///Return some gl states to original values.
367
369{
370 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
371 glDisable(GL_CULL_FACE);
372 glDisable(GL_DEPTH_TEST);
373 glDisable(GL_LIGHT0);
374 glDisable(GL_LIGHTING);
375}
376
377////////////////////////////////////////////////////////////////////////////////
378///Draw a set of meshes.
379
381{
382 //Shift plot to point of origin.
383 const Rgl::PlotTranslation trGuard(this);
384
386 //
387 if (!fIsos.size())
388 DrawCloud();
389 else {
390 //Two passes. First, non-transparent surfaces.
391 Bool_t needSecondPass = kFALSE;
392 for (ConstSurfIter_t it = fIsos.begin(); it != fIsos.end(); ++it) {
393 //
394 if (it->fHide)
395 continue;
396 if (it->fAlpha != 100) {
397 needSecondPass = kTRUE;
398 continue;
399 }
400 if (!fSelectionPass)
401 SetSurfaceColor(it);
402 glEnable(GL_POLYGON_OFFSET_FILL);
403 glPolygonOffset(1.f, 1.f);
404 DrawMesh(it);
405 glDisable(GL_POLYGON_OFFSET_FILL);
406
407 if (!fSelectionPass && it->fHighlight) {
408 const TGLDisableGuard lightGuard(GL_LIGHTING);
409 const TGLEnableGuard blendGuard(GL_BLEND);
410 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
411 glColor4d(1., 0.4, 0., 0.5);
412 DrawMesh(it);
413 }
414 }
415 //Second pass - semi-transparent surfaces.
416 if (needSecondPass) {
417 const TGLEnableGuard blendGuard(GL_BLEND);
418 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
419 glDepthMask(GL_FALSE);
420 for (ConstSurfIter_t it = fIsos.begin(); it != fIsos.end(); ++it) {
421 //
422 if (it->fAlpha == 100)
423 continue;
424 if (!fSelectionPass)
425 SetSurfaceColor(it);
426
427 glEnable(GL_POLYGON_OFFSET_FILL);
428 glPolygonOffset(1.f, 1.f);
429 DrawMesh(it);
430 glDisable(GL_POLYGON_OFFSET_FILL);
431
432 if (!fSelectionPass && it->fHighlight) {
433 const TGLDisableGuard lightGuard(GL_LIGHTING);
434 glColor4d(1., 0.4, 0., it->fAlpha / 150.);
435 DrawMesh(it);
436 }
437 }
438 glDepthMask(GL_TRUE);
439 }
440 }
441
442 if (fBoxCut.IsActive())
444}
445
446////////////////////////////////////////////////////////////////////////////////
447///Set the color for iso-surface.
448
450{
451 Color_t ind = it->fColor;
452 Float_t rgba[] = {0.f, 0.f, 0.f, static_cast<Float_t>(it->fAlpha / 100.)};
453 Rgl::Pad::ExtractRGBA(ind, rgba);
454 //Set color for surface.
455 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, rgba);
456 const Float_t specColor[] = {1.f, 1.f, 1.f, 1.f};
457 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specColor);
458 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 20.f);
459}
460
461////////////////////////////////////////////////////////////////////////////////
462///Draw full cloud of points.
463
465{
466 const TGLDisableGuard light(GL_LIGHTING);
467 const TGLDisableGuard depth(GL_DEPTH_TEST);
468
469 glColor3d(0.4, 0., 1.);
470 glPointSize(3.f);
471
472 glBegin(GL_POINTS);
473
474 const Double_t xs = fCoord->GetXScale();
475 const Double_t ys = fCoord->GetYScale();
476 const Double_t zs = fCoord->GetZScale();
477
478 for (Int_t i = 0; i < fData->fNP; ++i)
479 glVertex3d(fData->fV1[i] * xs, fData->fV2[i] * ys, fData->fV3[i] * zs);
480
481 glEnd();
482
483 glPointSize(1.f);
484}
485
486////////////////////////////////////////////////////////////////////////////////
487///Draw cloud for selected iso-surface.
488
490{
491 const TGLDisableGuard light(GL_LIGHTING);
492
493 Float_t rgba[4] = {};
494 Rgl::Pad::ExtractRGBA(ci, rgba);
495
496 glColor3fv(rgba);
497 glPointSize(3.f);
498
499 glBegin(GL_POINTS);
500
501 const Double_t xs = fCoord->GetXScale();
502 const Double_t ys = fCoord->GetYScale();
503 const Double_t zs = fCoord->GetZScale();
504
505 for (Int_t i = 0; i < fData->fNP; ++i)
506 if (TMath::Abs(fData->fV4[i] - v4) < range)
507 glVertex3d(fData->fV1[i] * xs, fData->fV2[i] * ys, fData->fV3[i] * zs);
508
509 glEnd();
510
511 glPointSize(1.f);
512}
513
514////////////////////////////////////////////////////////////////////////////////
515///Draw one iso-surface.
516
518{
519 const Mesh_t &m = surf->fMesh;
520
521 if (!fBoxCut.IsActive()) {
522 if (!fSelectionPass)
523 Rgl::DrawMesh(m.fVerts, m.fNorms, m.fTris);
524 else {
526 Rgl::DrawMesh(m.fVerts, m.fTris);
527 }
528 } else {
529 if (!fSelectionPass) {
530 Rgl::DrawMesh(m.fVerts, m.fNorms, m.fTris, fBoxCut);
531 } else {
533 Rgl::DrawMesh(m.fVerts, m.fTris, fBoxCut);
534 }
535 }
536}
@ kKeyPress
Definition: Buttons.h:20
@ kButton1Double
Definition: Buttons.h:24
#define GL_TRUE
Definition: GL_glu.h:262
#define GL_POINTS
Definition: GL_glu.h:283
#define GL_FALSE
Definition: GL_glu.h:261
@ kKey_C
Definition: KeySymbols.h:128
@ kKey_c
Definition: KeySymbols.h:160
#define d(i)
Definition: RSha256.hxx:102
#define e(i)
Definition: RSha256.hxx:103
int Int_t
Definition: RtypesCore.h:45
const Bool_t kFALSE
Definition: RtypesCore.h:101
bool Bool_t
Definition: RtypesCore.h:63
double Double_t
Definition: RtypesCore.h:59
short Color_t
Definition: RtypesCore.h:92
float Float_t
Definition: RtypesCore.h:57
const Bool_t kTRUE
Definition: RtypesCore.h:100
void Info(const char *location, const char *msgfmt,...)
Use this function for informational messages.
Definition: TError.cxx:220
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition: TError.cxx:187
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition: TError.cxx:231
@ kGLCartesian
Definition: TGLUtil.h:44
#define gROOT
Definition: TROOT.h:404
char * Form(const char *fmt,...)
#define gVirtualX
Definition: TVirtualX.h:338
void SelectPoints(Double_t v4Level, Double_t range)
"Select" sub-range from source data
Definition: TGL5D.cxx:144
Rgl::Range_t fV4MinMax
Definition: TGL5D.h:90
const Double_t * fV4
Definition: TGL5D.h:79
const Double_t * fV1
Definition: TGL5D.h:76
const Double_t * fV2
Definition: TGL5D.h:77
Bool_t fV4IsString
Definition: TGL5D.h:99
Long64_t fNP
Definition: TGL5D.h:75
UInt_t SelectedSize() const
Size of selected sub-range.
Definition: TGL5D.cxx:156
const Double_t * fV3
Definition: TGL5D.h:78
void StartPan(Int_t px, Int_t py)
User clicks right mouse button (in a pad).
void SetSurfaceColor(ConstSurfIter_t surf) const
Set the color for iso-surface.
void DrawMesh(ConstSurfIter_t surf) const
Draw one iso-surface.
SurfList_t fIsos
Definition: TGL5DPainter.h:71
void SetNContours(Int_t num)
Set the number of predefined contours.
void ResetGeometryRanges()
No need to create or delete meshes, number of meshes (iso-levels) are the same, but meshes must be re...
SurfList_t::iterator SurfIter_t
Definition: TGL5DPainter.h:61
SurfIter_t SurfacesBegin()
std::list::begin.
void RemoveSurface(SurfIter_t surf)
Remove iso-surface.
Rgl::Mc::TMeshBuilder< TKDEFGT, Float_t > fMeshBuilder
Definition: TGL5DPainter.h:66
SurfIter_t SurfacesEnd()
std::list::end.
char * GetPlotInfo(Int_t px, Int_t py)
Return info for plot part under cursor.
void DeInitGL() const
Return some gl states to original values.
void SetAlpha(Double_t newAlpha)
Set selection range parameter.
void DrawCloud() const
Draw full cloud of points.
SurfIter_t AddSurface(Double_t v4, Color_t ci, Double_t isoVal=1., Double_t sigma=1., Double_t range=1e-3, Int_t lowNumOfPoints=kNLowPts)
Try to add new iso-surface.
SurfList_t::const_iterator ConstSurfIter_t
Definition: TGL5DPainter.h:62
void AddOption(const TString &option)
No additional options for TGL5DPainter.
Int_t fNContours
Definition: TGL5DPainter.h:81
TKDEFGT fKDE
Definition: TGL5DPainter.h:65
void DrawSubCloud(Double_t v4, Double_t range, Color_t ci) const
Draw cloud for selected iso-surface.
Double_t fAlpha
Definition: TGL5DPainter.h:80
void Pan(Int_t px, Int_t py)
Mouse events handler.
void DrawPlot() const
Draw a set of meshes.
TGL5DPainter(TGL5DDataSet *data, TGLPlotCamera *camera, TGLPlotCoordinates *coord)
Constructor.
std::vector< Double_t >::size_type size_type
Definition: TGL5DPainter.h:74
TGL5DDataSet * fData
Definition: TGL5DPainter.h:72
void ProcessEvent(Int_t event, Int_t px, Int_t py)
void InitGL() const
Initialize OpenGL state variables.
Bool_t fInit
Definition: TGL5DPainter.h:69
const Surf_t fDummy
Definition: TGL5DPainter.h:68
Bool_t InitGeometry()
Create mesh.
void MoveBox(Int_t px, Int_t py, Int_t axisID)
Move box cut along selected direction.
void DrawBox(Bool_t selectionPass, Int_t selected) const
Draw cut as a semi-transparent box.
void TurnOnOff()
Turn the box cut on/off.
void StartMovement(Int_t px, Int_t py)
Start cut's movement.
Bool_t IsActive() const
void ResetBoxGeometry()
Set geometry using plot's back box.
void SetPlotBox(const Rgl::Range_t &xRange, const Rgl::Range_t &yRange, const Rgl::Range_t &zRange)
Set up a frame box.
Definition: TGLPlotBox.cxx:198
const TGLVertex3 * Get3DBox() const
Get 3D box.
Definition: TGLPlotBox.cxx:303
void DrawBox(Int_t selectedPart, Bool_t selectionPass, const std::vector< Double_t > &zLevels, Bool_t highColor) const
Draw back box for a plot.
Definition: TGLPlotBox.cxx:184
Camera for TGLPlotPainter and sub-classes.
Definition: TGLPlotCamera.h:22
void StartPan(Int_t px, Int_t py)
User clicks somewhere (px, py).
void Apply(Double_t phi, Double_t theta) const
Applies rotations and translations before drawing.
void SetCamera() const
Viewport and projection.
void Pan(Int_t px, Int_t py)
Pan camera.
Int_t GetHeight() const
viewport[3]
void SetViewVolume(const TGLVertex3 *box)
'box' is the TGLPlotPainter's back box's coordinates.
Helper class for plot-painters holding information about axis ranges, numbers of bins and flags if ce...
Bool_t SetRanges(const TH1 *hist, Bool_t errors=kFALSE, Bool_t zBins=kFALSE)
Set bin ranges, ranges.
Double_t GetYScale() const
const Rgl::Range_t & GetXRangeScaled() const
Scaled range.
const Rgl::Range_t & GetYRangeScaled() const
Scaled range.
void SetCoordType(EGLCoordType type)
If coord type was changed, plot must reset sections (if any), set fModified.
Double_t GetXScale() const
Double_t GetZScale() const
const Rgl::Range_t & GetZRangeScaled() const
Scaled range.
Base class for plot-painters that provide GL rendering of various 2D and 3D histograms,...
Double_t fPadTheta
std::vector< Double_t > fZLevels
void RestoreModelviewMatrix() const
TGLBoxCut fBoxCut
virtual void Paint()
Draw lego/surf/whatever you can.
TGLPlotCoordinates * fCoord
TGLPlotBox fBackBox
void SaveProjectionMatrix() const
void SaveModelviewMatrix() const
Bool_t fUpdateSelection
TGLPlotCamera * fCamera
void RestoreProjectionMatrix() const
void BuildModel(const std::vector< Double_t > &sources, Double_t sigma=1., UInt_t dim=3, UInt_t p=8, UInt_t k=0)
Calculate coefficients for FGT.
Definition: TKDEFGT.cxx:55
SCoord_t fY
Definition: TPoint.h:36
SCoord_t fX
Definition: TPoint.h:35
Basic string class.
Definition: TString.h:136
const Double_t sigma
const Int_t n
Definition: legend1.C:16
void ExtractRGBA(Color_t colorIndex, Float_t *rgba)
void ObjectIDToColor(Int_t objectID, Bool_t highColor)
Object id encoded as rgb triplet.
Definition: TGLUtil.cxx:2891
std::pair< Double_t, Double_t > Range_t
Definition: TGLUtil.h:1195
void DrawMesh(const std::vector< Float_t > &vs, const std::vector< Float_t > &ns, const std::vector< UInt_t > &ts)
Call function-template.
Definition: TGLIsoMesh.cxx:39
Double_t Mean(Long64_t n, const T *a, const Double_t *w=0)
Return the weighted mean of an array a with length n.
Definition: TMath.h:1023
Double_t RMS(Long64_t n, const T *a, const Double_t *w=0)
Return the Standard Deviation of an array a with length n.
Definition: TMath.h:1117
Short_t Abs(Short_t d)
Definition: TMathBase.h:120
Definition: triangle.c:632
auto * m
Definition: textangle.C:8