ROOT Version 5.04/00 Release Notes


A new development version ROOT 5.04/00 has been released September 20, 2005.

Binaries for all supported platforms are available at:

      http://root.cern.ch/root/Version504.html
Versions for AFS have also been updated. See the list of supported platforms:
      http://root.cern.ch/root/AFS.html

For more information, see:

      http://root.cern.ch

The following people have contributed to this new version:
Ilka Antcheva,
Maarten Ballintijn,
Bertrand Bellenot,
Zev Benjamin,
Marek Biskup,
Walter Brown,
Rene Brun,
Philippe Canal,
Olivier Couet,
Denis Favre-Laville,
Valeri Fine,
Mark Fishler,
Markus Frank,
Gerri Ganis,
Andrei Gheata,
Mihaela Gheata,
Masaharu Goto,
Christian Holm Christensen,
Anna Kreshuk,
Wim Lavrijsen,
Sergei Linev,
Jose Lo,
Richard Maunder,
Lorenzo Moneta,
Axel Naumann,
Eddy Offermann,
Valeriy Onuchin,
Andreas Peters,
Timur Pocheptsov,
Fons Rademakers,
Stefan Roiser,
Andras Zsenei


Base

License Change

With this release we've moved to the LPGL license. The LGPL is very liberal Open Source license with should not impede much our many long time commercial users, while at the same time put ROOT solidly in the Open Source domain.

New Class TMacro

This class allow for storing a C++ macro in a ROOT file. In addition to being stored in a ROOT file a TMacro can be executed, edited, etc. A macro can be built line by line by calling the AddLine() function, or it can be created directly from a file via a special constructor. A macro can be executed via the Exec() function. Arguments can be specified when calling Exec(). A macro can be drawn in a pad. When the pad is updated, the macro is automatically executed. The code in the macro can be saved via the SaveSource() function. If the macro is in the list of primitives of a pad/canvas, the macro will be saved in the script generated by TCanvas::SaveSource(). A macro can be written to a ROOT file via TObject::Write().

Examples:

   TMacro m("Peaks.C");  //macro m with name "Peaks" is created
                         //from file Peaks.C
   m.Exec();             //macro executed with default arguments
   m.Exec("4");          //macro executed with argument
   m.SaveSource("newPeaks.C");
   TFile f("mymacros.root","recreate");
   m.Write();            //macro saved to file with name "Peaks"

Multi-level TAB Completion

Support for multi-level TAB completion in the ROOT shell, like:
   obj->GetVariable1ptr()->GetVar2Ptr()->[tab]
Previously only the first level after obj-> could be expanded.

New Class TFileMerger

This new class allows for easy copying of two or more files using the many TFile plugins (i.e. it can copy from Castor to dCache, or from xrootd to Chirp, etc.). Its file merge functionality is taken from hadd.

To use it do, e.g.:

   TFileMerger m
   m->Cp("srcUrl", "destUrl")
or
   m->AddFile("url1")
   m->AddFile("url2")
   m->Merge()
The AddFile() and Merge() use the Cp() to copy the file locally before making the merge, and if the output file is remote the merged file will be copied back to the remote destination.

New TFile Feature

Support for opening files in raw mode when the file url contains the option string "filetype=raw", like "anyfile.tgz?filetype=raw". This allows TFile and its many remote access plugins to be used to open and read any file. This is used by the TFileMerger::Cp() method to copy any file from and to Grid storage elements (e.g. from Castor to dCache, from xrootd to a local file, and all possible permutations).

New TUrl Feature

Added support for file namespaces, like: /alien/user/rdm/bla.root, which will be split in protocol=alien, file=/user/rdm/bla.root. Special namespaces like /alien/ are added via [system].rootrc. This also allows us to directly support filenames like /castor/cern.ch/... instead of castor:/castor/cern.ch/...

XML DOM Parser

The DOM (Document Object Model) is a platform and language-neutral interface that will allow programs and scripts to dynamically access and update the content, structure and style of documents. The DOM parser, as the previously introduced SAX parser, are internally using libxml2.

The DOM parser comes with two new tutorials: DOMParsePerson.C and DOMRecursive.C.

Castor 2 Support in TCastorFile

Castor v2 is now supported by the TCastorFile class. Both protocols, Castor v1 and v2 ar supported. The plugin needs to be linked with the new castor-2.0.0 library.

New Ports

Finalized the port to MacOS X Tiger (10.4). On Tiger the default Fortran compiler is gfortran. Usage of the optional g95 is possible by setting g95 in ROOTBUILD, e.g.:
   export ROOTBUILD="debug g95"

New port to AIX5 with gcc and at the same time improved the port to xlC.

Thread Safety

Work has been done to make more classes thread safe, like when accessing global TROOT containers and classes like TDatime, TTimestamp, etc.

Developments in Trees

Misc.

We improved the performance of TBranchElement::SetAddress by increasing the caching of TClass pointers and offsets. Also leverage the use of TClassRef to reduce the number of calls to gROOT->GetClass. Optimize a couple of additional functions. The improvement is dramatic for the 2nd call to SetAddress on the same branch object (90%)!

We fixed a problem in the writing of fBits when it was writing in its own branch and the object were referenced. We improved on the support of nested TTree Friend (use multiple locks instead of only one). We enabled the browsing/Drawing of emulated std::map

Meta

Significantly improved the IsA lookup for foreign classes (i.e the lookup by typeid). It is inspired from the implementation used by POOL/Reflex. It uses a new abstract interface TVirtualIsAProxy.

We Improved performance of TClassRef.

Nested namespace are now alloed in a rootmap file.

Input/Output

We introduced a new feature allowing the customization of the constructor used by the I/O.

The constructor actually called by the ROOT I/O can be customized by using the rootcint pragma:

#pragma link C++ ioctortype UserClass;
For example, with this pragma and a class named MyClass, this method will called the first of the following 3 constructors which exists and is public:
MyClass(UserClass*);
MyClass(TRootIOCtor*);
MyClass(); // Or a constructor with all its arguments defaulted.
When more than one pragma ioctortype is used, the first seen as priority For example with:
#pragma link C++ ioctortype UserClass1;
#pragma link C++ ioctortype UserClass2;
We look for the first existing public constructor in the following order:
MyClass(UserClass1*);
MyClass(UserClass2*);
MyClass(TRootIoCtor*);
MyClass(); // Or a constructor with all its arguments defaulted.

New utility classs TDirectory::TContext to keep track and restore the current directory. With this construct C++ exceptions will be guaranteed to properly restore the current directory pointer.

We added a new member function, TDirectory::GetDirectory, which factors out the code of TDirectory::cd and its static counterpart TDirectory::Cd. TDirectory::GetDirectory can be used to quietly find out if a directory exist:

   TDirectory *mydir = myfile->GetDirectory(somepath);
   if (mydir==0) mydir->mkdir(somepath);
   myfile->cd(somepath);
We improved performance of reading of legacy ROOT 3 files. Improved streaming speed for std::string. Improve performance of STL container streaming.

TFormula

New implementation of the executor part of TFormula which minimizes the size of the existing switch statement by combining some operation and/or replacing some operations by a single indirect function call. This result in a significant speed-up of the execution.

The change is fully backward compatible since the new optimized operation are stored in an additional set of transient data members. (fExprOptimized and fOperOptimized).

Function with default paramater can not yet be properly handled via the faster function primitive mechanism.

We extended the syntax to allow to calls function whose names start (but are different from) gaus, landau, rndm or expo. Insured that the paramaters of the Formula are properly restored by TFormula::Streamer even if the formula contains calls to external C++ function (like TMath::Abs). Added support for the creation of TF1, TF2 and TF3 object from function with the signature

double (*)(const double*,const double*);
from compiled code. So far only
double (*)(double*,double*)
was supported

TTreeFormula

Add a new member function TTreeFormula::ResetLoading. This can be used instead of calling TTreeFormula::EvalInstance(0) to insure the proper loading of the branches. In particular this solves issues when the formula is invalid (invalid indices for example) for the first instance.

New class TTreeSQL

We introduced the first version of TTreeSQL facility. This new facility allows the storing and restoring of TTree to and from an SQL database:
   TSQLServer *dbserver =
TSQLServer::Connect("mysql://localhost:3306/rootDev","rootdevel",
"r00tg6ys");
   dbserver->Query("drop table ntuple;");
   ntuple  = new TTreeSQL(dbserver, "rootDev", "ntuple");
If the database contain a table named ntuple, this will connect to it and let you use any of TTree functionality on (Scan, Draw, etc.) If the database does not contain a table named ntuple, it will created once you called the first Fill on the TTree. This version supports the leaflist type of branches.

Proof

Support added for several new features.

Multi sessions

The limit to only one PROOF session per ROOT client session has been removed. Sessions are still started via TROOT::Proof(…), but a pointer to the started session is now returned, e.g.

root[0] TProof *p1 = gROOT->Proof(“lxa0123.cern.ch”)

root[1] TProof *p2 = gROOT->Proof(“lxb1234.cern.ch”,”proof.std.conf”)

The global gProof refers now to the last open session or to the session selected via TProof::cd().

The list of active PROOF sessions is available via gROOT->GetListOfProofs().

Each session has:

 

Asynchronous running mode

This feature makes possible to process selectors queries asynchronously, i.e. without blocking the client ROOT session. Process requests are sent to the PROOF top master and added to the internal queue. Queued requests are processed sequentially. At the end of processing a copy of the results is sent back to the client who can proceed to finalize the query using TProof::Finalize(), which internally calls  TSelector::Terminate(). Asynchronous running mode is activate by passing “ASYN” as option to TProof::Process(), e.g.

 

gProof->Process(mydataset, “MySelec.C”, “ASYN”).

By default processing is synchronous (blocking): the default mode can be modified with TProof::SetQueryMode(mode), e.g.

gProof->SetQueryMode(TProof::kAsync).

The status of the submitted queries can be displayed at any moment with TProof::ShowQueries().

To avoid screwing up the ROOT prompt, any printout occurring during asynchronous processing is redirected to a log file which can be browsed either at the ROOT prompt using TProof::ShowLog()or by clicking on the appropriate button on the GUI.

TQueryResult: a container for query information

This new class has been introduced to organize in one entity all the information available about a query.

It contains:

An instance of this class is created by the top master upon receipt of query processing request. The instance is updated each time an action is performed on the query. At the master of processing the master sends back a copy of the instance to the client who stores it in a list owned by the PROOF session. The master also saves a copy of the instance into the sandbox, in such a way that it may be re-accessed later on in case of need.

TProof::ShowQueries(Option_t *opt)

 

This method allows to display information about all queries known by the master, included those processed by other sessions and still having an entry in the remote sandbox. By default, ShowQueries() shows information only for the queries processed by the current session.

Available options are:

            A’:      show information about all the queries known by the master; this triggers a scan of the sandbox.

            L’:      show information about the queries already retrieved

            F’:       show all details available about the query; by default only a line with the head information is shown.

Options are case insensitive. If ‘L’ is specified ‘A’ is ignored.

The policy for keeping query results depends on the type of query as follows:

Finalize, Retrieve, Archive and Remove functionality

A set of new methods have been added to the TVirtualProof interface to administrate the available queries.

All these methods have as main argument either the unique query reference or the sequential number reported by TProof::ShowQueries

·        Finalize(Int_t query, Bool_t force) / Finalize(const char *queryref, Bool_t force)
With no arguments it finalizes the last query processed. Finalize can be run only once on the query instance received from the top master, because
TSelector::Terminate() modifies the initial output list. The boolean force can be used to force a new retrieval of the instance.

·        Retrieve(Int_t query, const char *file) / Retrieve(const char *queryref, const char *file).
Retrieve a query from the master and store it in memory. If a valid path is defined (i.e valid for
TFile::Open()), the TQueryResult instance is also streamed to a file defined by file.

·        Archive(Int_t query, const char *path) / Archive(const char *queryref, const char *path)
Archives at master the referenced query. The path has the format requested by
TFile::Open.
A default path can specified using “Default” as reference, e.g.
gProof->Archive(“Default”,”root://datasrv01.some.wh:6756//data001”).
If specified the default path is used to build a unique file name of the form
                               <default_path>/session-<session_tag>-<query_numer>.root
e.g.  ”root://datasrv01.some.wh:6756//data001/session-0-pcepsft43-1127127540-25793-2.root”.

·        Remove(Int_t query, Bool_t all) / Remove(const char *queryref, Bool_t all)
Removes the query on the master and, optionally, also locally.

An additional method CleanupSession(const char *sessiontag) is provided to remove all queries of session identified by sessiontag. If the session sesssiontag is still alive the request is ignored.

Other improvements

·        Progressive packetizer (TPacketizerProgressive). This class implements a new packetizer, a generator of packets to be processed on PROOF slave servers. A packet is an event range (begin entry and number of entries) or object range (first object and number of objects) in a TTree (entries) or a directory (objects) in a file. Packets are generated taking into account the performance of the remote machine, the time it took to process a previous packet on the remote machine, the locality of the database files, etc. This packetizer does not pre-open the files to calculate the total number of events, it just walks sequentially through the list of files.

Geometry package enhancements

Assemblies of volumes

New classes created to describe volume assemblies:
TGeoVolumeAssembly : public TGeoVolume
TGeoShapeAssembly  : public TGeoBBox
An assembly represents a union of more than 2 volumes positioned with respect to the local assembly reference frame. Assemblies behave like normal volumes, but their shape is defined as the union of the shapes of the volumes positioned inside. This shape is represented by the class TGeoShapeAssembly, which is automatically created and updated whenever a new node is added to the assembly content. This makes the assembly a self-contained volume in the sense that any point inside it is automatically inside one of the components. For this reason an assembly volume does not need a medium/material nor a shape to be defined. Creating an assembly can be done in a very similar way as creating a volume:
   TGeoVolumeAssembly *assembly = new TGeoVolumeAssembly("STRUCT"); // assembly volume
   assembly->AddNode(pVol1, id1, pMatrix1);                          // components of the assembly
   assembly->AddNode(pVol2, id2, pMatrix2);
   ...
The components have to obey the same rule of thumb as any positioned volume: they should not overlap each other. On the other hand they formally cannot extrude the assembly container since the later is defined by them. Assemblies can be positioned as nodes in any other volume and support nesting and replication. A detailed example of their usage can be found at:
  $ROOTSYS/tutorials/assembly.C
There are several advantages in using assemblies instead of normal volumes whenever the definition of a replicated complex structure is needed. In such cases generally it is difficult to define a container that perfectly fits to the structure, therefore one usualy defines a larger one with a simple shape. The problem may appear when positioning this container because it may overlap with other volumes (not allowed). To avoid this, people split the structure in many components and place them individually without defining a container, resulting in flat structures which are hard to optimize at certain geometry levels. All these can be avoided by using assemblies. The automatically-generated TGeoShapeAssembly uses the same optimization mechanisms for navigation as volumes.

Assemblies can be browsed as nodes in the geometry tree and generate an additional geometry level, but they are invisible during navigation. Any navigation query performed in a geometry having assemblies will end-up in non-assembly leafs. Tests demonstated that grouping the existing nodes of a volume with many components via assemblies improve navigation performance. Therefore there is no penalty in performance observed due to usage of assemblies.

Additions related to navigation

New combined querry: TGeoNode* TGeoManager::FindNextBoundaryAndStep(Double_t propStep=TGeoShape::Big(), Bool_t compSafe=kFALSE) The method was optimized to performs several navigation tasks in one go. Prior to its usage one have to initialize the current global point/direction and to locate the state:
  TGeoManager::InitTrack(Double_t *point, Double_t *dir);   // or a combination
                                                            // performing FindNode() task
After the initialization is completed, one can use the new method to propagate the current track to the next boundary. The input propStep is the maximum step allowed by the user for locating next boundary. If the boundary is found further away, the current point is propagated with propStep and the current node is returnes as final location. In case the user requires also computation of the safe distance, it has to provide compSafe = true.

If a boundary is found closer than the proposed step, the modeller will propagate the current state with the found distance and the state (TGeoNode) after crossing the boundary is returned. The propagation distance to the boundary can be retreived via:

   Double_t TGeoManager::GetStep()

To test if the boundary crossing really occured, one can use:

  Bool_t TGeoManager::IsOnBoundary()

If this is the case, the normal vector to the crossed surface can be computed via the "fast" approach:

  Double_t *TGeoManager::FindNormalFast()

One can use the new query method to propagate a ray from boundary to boundary until getting outside of the geometry. If this is the case, the computation of the safe distance make sense only for the first query (for subsequent ones it will be 0). To retreive the safe distance one should call:

  Double_t TGeoManager::GetSafeDistance()

Miscellaneous

Several improvements or fixes related to: navigation consistency near boundaries, graphics (mesh poligonal representation), matrix package, caching. Major developments related to OGL 3D viewer.

Reflex

Reflex is a new package in the ROOT environment since the 5.x release series. It provides reflection capabilities for C++. Reflection being the ability to introspect and interact with C++ "constructs" (e.g. types, scopes, members, etc.) at runtime in a generic way. With the use of dictionary libraries, which contain the meta information about C++ definitions, Reflex allows generic interaction withoug prior knowlegdge about original definitions.

For the time being Reflex is an optional package in ROOT. If the build of the Reflex library is wanted it has to be triggered with "--enable-reflex" at the configuration step of the ROOT build procedure. In a mini-workshop in May 2005 at CERN it was decided that Reflex will closely cooperate with CINT. Below you may find a brief overview of the features, way of interaction and main user types of the package. For any more details on the functionality of the package, the current status and future developments concerning this cooperation with CINT please check out the ROOT workshop presentation about Reflex.

The main features of Reflex are:

The usual way of generating dictionary information for and interacting with Reflex is as follows:

  1. The C++ files containing the definition of the types the dictionary information is wanted for are parsed and dictionary source code (in C++) is produced. There are two ways how this source code can be generated.
  2. The so generated C++ files are compiled into a library
  3. Through a Builder API the dictionary library will be loaded into the Reflex system
  4. The Reflex user API provides the reflection information about the original C++ definitions.

The main user types of the Reflex API are:

Cintex

Cintex is a new package in the ROOT environment since the 5.x release series. It provides a (uni-directonal) gateway from Reflex dictionary information to CINT dictionary information.

This gateway allows CINT users to interact seemlessly with Reflex dictionary information. As Reflex dictionary information is very small both in library size and memory allocation the additional overhead using this gateway is also small.

Enabling the Cintex gateway is done through the static function "Cintex::Enable()". Once this function has been called all Reflex dictionaries currently in memory or dictionaries loaded in the future will be propagated to CINT's internal memory structures.

For the time being Cintex is an optional package in ROOT. If the build of the Cintex library is wanted it has to be triggered with "--enable-cintex" at the configuration step of the ROOT build procedure. Cintex is an internal package to the ROOT framework and should not be visible for the "general" ROOT user.

PyROOT

There are several improvements to the pythonization of ROOT classes, the interaction with the interpreter environment, and the treatment of (low-level) C++ features.

Python/C++ language features

Support is added for inner classes, templated classes, pre-processor macro's of builtin types, ptr-to-ptr and ref-ptr argument types, object return-by-value, object argument-by-value, double/long argument-by-ref, array assignment, and the supported array/buffer types have been completed for all C++ builtins.

The memory policy has been extended to use either heuristics (default) or to be strict, the ownership of individual objects can be set by hand, addresses of objects can be taken, and all C++ typedefs now map onto the same python type. There is a dedicated NULL object that should be used explicitly to pass a null pointer, and typed null pointers (for use as value holders) can be created.

Interpreter environment

The python help() system is now supported: it will e.g. show the C++ signatures of functions. CINT errors/warnings are treated as python exceptions/warnings and error reporting has been improved, e.g. overloaded functions that fail show a message for each individual overload. The .L CINT command is supported, objects from TFile's can now be used directly, cf. CINT, and the initial startup environment is more closely mimicking RINT. Tab-completion is added for file names in the local directory structure. Further workarounds for IPython are provided.

Pythonization

TMinuit::SetFCN accepts python functions, as do TF2/3 (modeled after the support for TF1). TTree and TFile member templates are available: the appropriate casting is done internally, based on the available run-time type information. STL vector and string can be used with python-style iteration.

Fitting

Robust fitting - Least Trimmed Squares regression (LTS)

A new method for robust fitting was added to the TLinearFitter class, to be used for fitting linear functions in presense of outliers in the data. Even a single gross outlier can greatly influence the results of least- squares fitting procedure, and in this case use of robust(resistant) methods is recommended.

The method implemented here is based on the article and algorithm: Computing LTS Regression for Large Data Sets by P.J.Rousseeuw and Katrien Van Driessen. The idea of the method is to find the fitting coefficients for a subset of h observations (out of n) with the smallest sum of squared residuals. The size of the subset h should lie between (npoints + nparameters +1)/2 and n, and represents the minimal number of good points in the dataset. The default value is set to (npoints + nparameters +1)/2, but if you are sure that the data contains less outliers it's better to change h according to your data.

To perform a robust fit one can

Note, that standard errors on parameters are not computed!

TF1

Improvement of min/max finding routines. Now first a grid search is performed to bracket the extremum and then Brent's method is used for minimization. Brent's method is a combination of golden section search and parabolic interpolation.

MathCore Package


This is a new package introduced in ROOT version 5. It provides a collection of functions and C++ classes for HEP numerical computing. This library provides the basic and most used mathematical functionality, while MathMore provides more advanced functionality. MathCore contains up to now:

More detailed description of the current released software can be found at this location.

 


MathMore Package


It is a new package introduced in the present version of ROOT. It incorporates mathematical functionality which might be needed for an advanced user (as opposed to MathCore which addresses the primary needs of users). The need of separating the mathematical functionality is twofold. In order to keep the size of the core of ROOT reasonable only the most used mathematical functionality should be included in it. Secondly, there are licensing issues concerning some of the more advanced functionality which uses GSL. One of the design goals is to hide the implementation, i.e. presently for most of the mathematical functionality GSL is used underneath. However, it would be very easy to shift to another package, like CEPHES, or any other package appearing in the future, it would be completely transparent to the user and straightforward for the developer. As of now, MathMore is composed of the following major parts:



Obviously, as user needs might evolve, we intend to add new functionalities. More detailed description can be found at the MathMore reference documentation.



Disclaimer: as it is a new package, some user needs might have been ignored. As we will continually try to improve ROOT ther might be a slight evolution in the user interface in the initial stage if strong user needs arise to do so.

GUI

Style Manager

OpenGL developments: Features and Interaction

Performance / Quality

Major internal re-structuring of GL viewer to support:

Misc Internals

Added several debugging aids:

GL-in-TPad

3D Viewer Infrastructure Overview

The 3D Viewer infrastructure has had a re-design to better support more advanced viewers. It consists of:

Together these allow clients to publish objects to any one of the 3D viewers (currently OpenGL/x3d,TPad), free of viewer specific drawing code. They allow our simple x3d viewer, and considerably more sophisticated OpenGL one to both work with both geometry libraries (g3d and geom) efficiently.

Publishing to a viewer consists of the following steps:

  1. Create / obtain viewer handle
  2. Begin scene on viewer
  3. Fill mandatory parts of TBuffer3D describing object
  4. Add to viewer
  5. Fill optional parts of TBuffer3D if requested by viewer, and add again
    ... repeat 3/4/5 as required
  6. End scene on viewer

Creating / Obtaining Viewer

Create/obtain the viewer handle via local/global pad - the viewer is always bound to a TPad object at present [This may be removed as a restriction in the future] . You should perform the publishing to the viewer described below in the Paint() method of the object you attach to the pad (via Draw())

TVirtualViewer3D * v = gPad->GetViewer3D("xxxx");

" xxxx" is viewer type: OpenGL "ogl", X3D "x3d" or Pad "pad" (default). The viewer is created via the plugin manager, attached to pad, and the interface returned.

Begin / End Scene

Objects must be added to viewer between BeginScene/EndScene calls e.g.

v->BeginScene();
.....
v->AddObject(....);
v->AddObject(....);
.....
v->EndScene();

The BeginScene call will cause the viewer to suspend redraws etc, and after the EndScene the viewer will reset the camera to frame the new scene and redraw.

[x3d viewer does not support changing of scenes - objects added after the first Open/CloseScene pair will be ignored.]

Filling TBuffer3D and Adding to Viewer

The viewers behind the TVirtualViewer3D interface differ greatly in their capabilities e.g.

To cope with these situations the object buffer is filled out in negotiation with the viewer. TBuffer3D classes are conceptually divided into enumerated sections Core, BoundingBox, Raw etc (see TBuffer3D.h for more details).

The SectionsValid() / SetSectionsValid / ClearSectionsValid() methods of TBuffer3D are used to test/set/clear these section valid flags.

The sections found in TBuffer3D (Core/BoundingBox/Raw Sizes/Raw) are sufficient to describe any tessellated shape in a generic fashion. An additional ShapeSpecific section in derived shape specific classes allows a more abstract shape description ("a sphere of inner radius x, outer radius y"). This enables a viewer which knows how to draw (tessellate) the shape itself to do so, which can bring considerable performance and quality benefits, while providing a generic fallback suitable for all viewers.

The rules for client negotiation with the viewer are:

If the viewer requires more sections to be completed (Raw/RawSizes) AddObject() will return flags indicating which ones, otherwise it returns kNone. You must fill the buffer and mark these sections valid, and pass the buffer again. A typical code snippet would be:

TBuffer3DSphere sphereBuffer;
// Fill out kCore...
// Fill out kBoundingBox...
// Fill out kShapeSpecific for TBuffer3DSphere
// Try first add to viewer
Int_t reqSections = viewer->AddObject(buffer);
if (reqSections != TBuffer3D::kNone) {
  if (reqSections & TBuffer3D::kRawSizes) {
     // Fill out kRawSizes...
  }
  if (reqSections & TBuffer3D::kRaw) {
     // Fill out kRaw...
  }
  // Add second time to viewer - ignore return cannot do more
  viewer->AddObject(buffer);
  }
}

ShapeSpecific: If the viewer can directly display the buffer without filling of the kRaw/kRawSizes section it will not need to request client side tessellation. Currently we provide the following various shape specific classes, which the OpenGL viewer can take advantage of (see TBuffer3D.h and TBuffer3DTypes.h)

*OpenGL only supports solid spheres at present - cut/hollow ones will be requested tessellated.

Anyone is free to add new TBuffer3D classes, but it should be clear that the viewers require updating to be able to take advantage of them. The number of native shapes in OpenGL will be expanded over time.

BoundingBox: You are not obliged to complete this, as any viewer requiring one internally (OpenGL) will build one for you if you do not provide. However to do this the viewer will force you to provide the raw tessellation, and the resulting box will be axis aligned with the overall scene, which is non-ideal for rotated shapes.

As we need to support orientated (rotated) bounding boxes, TBuffer3D requires the 6 vertices of the box. We also provide a convenience function, SetAABoundingBox(), for simpler case of setting an axis aligned bounding box.

Master/Local Reference Frames

The Core section of TBuffer3D contains two members relating to reference frames: fLocalFrame & fLocalMaster. fLocalFrame indicates if any positions in the buffer (bounding box and tessellation vertexes) are in local or master (world frame). fLocalMaster is a standard 4x4 translation matrix (OpenGL colum major ordering) for placing the object into the 3D master frame.

If fLocalFrame is kFALSE, fLocalMaster should contain an identity matrix. This is set by default, and can be reset using SetLocalMasterIdentity() function.
Logical & Physical Objects

There are two cases of object addition:

The second case is very typical in geometry packages, GEANT4, where we have very large number repeated placements of relatively few logical (unique) shapes. Some viewers (OpenGL only at present) are able to take advantage of this by identifying unique logical shapes from the fID logical ID member of TBuffer3D. If repeated addition of the same fID is found, the shape is cached already - and the costly tessellation does not need to be sent again. The viewer can also perform internal GL specific caching with considerable performance gains in these cases.

For this to work correctly the logical object in must be described in TBuffer3D in the local reference frame, complete with the local/master translation. The viewer indicates this through the interface method

PreferLocalFrame()

If this returns kTRUE you can make repeated calls to AddObject(), with TBuffer3D containing the same fID, and different fLocalMaster placements.

For viewers supporting logical/physical objects, the TBuffer3D content refers to the properties of logical object, with the fLocalMaster transform and the fColor and fTransparency attributes, which can be varied for each physical object.

As a minimum requirement all clients must be capable of filling the raw tessellation of the object buffer, in the master reference frame. Conversely viewers must always be capable of displaying the object described by this buffer.

Scene Rebuilds

It should be understood that AddObject is not an explicit command to the viewer - it may for various reasons decide to ignore it:

In all these cases AddObject() returns kNone, as it does for successful addition, simply indicating it does not require you to provide further information about this object. You should not try to make any assumptions about what the viewer did with it.

This enables the viewer to be connected to a client which sends potentially millions of objects, and only accept those that are of interest at a certain time, caching the relatively small number of CPU/memory costly logical shapes, and retaining/discarding the physical placements as required. The viewer may decide to force the client to rebuild (republish) the scene (via a TPad repaint at present), and thus collect these objects if the internal viewer state changes. It does this presently by forcing a repaint on the attached TPad object - hence the reason for putting all publishing to the viewer in the attached pad objects Paint() method. We will likely remove this requirement in the future, indicating the rebuild request via a normal ROOT signal, which the client can detect.

Physical IDs

TVirtualViewer3D provides for two methods of object addition:virtual Int_t AddObject(const TBuffer3D & buffer, Bool_t * addChildren = 0)
virtual Int_t AddObject(UInt_t physicalID, const TBuffer3D & buffer, Bool_t * addChildren = 0)

If you use the first (simple) case a viewer using logical/physical pairs will generate IDs for each physical object internally. In the second you can specify a unique identifier from the client, which allows the viewer to be more efficient. It can now cache both logical and physical objects, and only discard physical objects no longer of interest as part of scene rebuilds.

Child Objects

In many geometries there is a rigid containment hierarchy, and so if the viewer is not interested in a certain object due to limits/size then it will also not be interest in any of the contained branch of descendents. Both AddObject() methods have an addChildren parameter. The viewer will complete this (if passed) indicating if children (contained within the one just sent) are worth adding.

Recyling TBuffer3D

Once add AddObject() has been called, the contents are copied to the viewer internally. You are free to destroy this object, or recycle it for the next object if suitable.

New printing facilities in batch via TASImage

TASImage is an interface to image processing library using libAfterImage. It allows reading and writing of images in different formats, several image manipulations (scaling, tiling, merging, etc.) and displaying in pads. The size of the image on the screen does not depend on the original size of the image but on the size of the pad. Therefore it is very easy to resize the image on the screen by resizing the pad.

Besides reading an image from a file an image can be defined by a two dimensional array of values. A palette defines the color of each value.

The image can be zoomed by defining a rectangle with the mouse. The color palette can be modified with a GUI, just select StartPaletteEditor() from the context menu.

The new class TImageDump using TASImage and derived from TVirtualPS allows to save canvas in GIF, JPEG etc, image formats in batch mode. Before this clas was intriduced it was not possible to generate bitmap files (in particular GIFfiles) in batch, such files were generated from a TCanvas. Now the method TPad::Print or TPad::SavesAs can be used in macro running in batch (root -b) to generated bitmap files (gif, jpeg, png, xpm, tiff). Example:

     $ root -b
     root [0] .x hsimple.C
     root [1] c1->Print("c1.gif");

The full description of TPad::Print options is now:

TPad::Print(const char *filename,  Option_t *option)
filename extension (or option) can be:
"ps"   - Postscript file is produced (see special cases below)
"eps"  - an Encapsulated Postscript file is produced
"pdf"  - a PDF file is produced
"svg"  - a SVG file is produced
"gif"  - a GIF file is produced
"xpm"  - a XPM file is produced
"png"  - a PNG file is produced
"jpg"  - a JPEG file is produced
"tiff" - a TIFF file is produced
"cxx"  - a C++ macro file is produced
"xml"  - a XML file
"root" - a ROOT binary file
Some extras options:
"Portrait"  - Postscript file is produced (Portrait)
"Landscape" - Postscript file is produced (Landscape)
"Preview"   - an Encapsulated Postscript file with preview is produced.
All these option (except "Preview") are availabe from the File menu in TCanvas.

TImageDump

TImageDump save canvas as an image (GIF, JPEG, PNG, XPM, TIFF etc.) It can be used in any mode (batch, interactive) as follows:
    TCanvas *c1;
    TImageDump *imgdump = new TImageDump("test.png");
    c1->Paint();
    imgdump->Close();

Other new features in the graphics area

TGraph2D

New option "Line" to paint TGraph2D. TGraph2D are connected with with a 3D polyline.

TStyle

TPaveStats

TPad

New method BuildLegend to automatically add a TLegend in a Pad.

TGraph2D

New method SetHistogram. It allows to define the histogram to be filled. This is useful to set the range of the X and Y axis.

Example:

	  void graph2dhist()
	  {
	     TCanvas *c = new TCanvas("c","Graph2D example",0,0,700,600);
	
	     Double_t x, y, z, P = 6.;
	     Int_t np = 300;    // generate this many nodes
	
	     TGraph2D *dt = new TGraph2D();
	     TH2D* h2 = new TH2D("h2","h2",40,-6,6,40,-10,10);
	     dt->SetHistogram(h2);
	
	     TRandom *r = new TRandom();
	
	     for (Int_t N=0; N<np; N++) {
	        x = 2*P*(r->Rndm(N))-P;
	        y = 2*P*(r->Rndm(N))-P;
	        z = (sin(x)/x)*(sin(y)/y)+0.2;
	        dt->SetPoint(N,x,y,z);
	     }
	     gStyle->SetPalette(1);
	
	     dt->Draw("TRI1 p0");
	  }
	

TASImage

PostScript / PDF

TArrow

It is now possible to draw "begin" and "end" bars on arrows.

TArrow, TCurlyArc,TCurlyLine

Implement default attributes values and the corresponding getters and setters

TArrow

	   static Float_t  fgDefaultAngle;        //default Arrow opening angle (degrees)
	   static Float_t  fgDefaultArrowSize;    //default Arrow Size
	   static TString  fgDefaultOption;       //default Arrow shapes
TCurlyArc
	   static Double_t fgDefaultWaveLength;   //default wavelength
	   static Double_t fgDefaultAmplitude;    //default amplitude
	   static Bool_t   fgDefaultIsCurly;      //default curly type
TCurlyLine
	   static Double_t fgDefaultWaveLength;   //default wavelength
	   static Double_t fgDefaultAmplitude;    //default amplitude
	   static Bool_t   fgDefaultIsCurly;      //default curly type
These default value are used at creation time for these primitives.

Bug fixes ad Improvments in Graphics area

TMultiGraph

Add a new function Option_t *TMultiGraph::GetGraphDrawOption(const TGraph *gr) const Which returns the draw option for the TGraph gr in this TMultiGraph. The return option is the one specified when calling TMultiGraph::Add(gr,option).

TStyle

In SetPalette: The DeepSea palette is defined only if needed. Without this protection the following macro went slower and slower.
  {
      for (int i=0; i<10; i++) {
         TStopwatch clock;
         clock.Start();
         gStyle->SetPalette(51, NULL);
         clock.Print();
      }
   }

TCreatePrimitives

Some log scales support was missing

TGraphDelaunay (TGraph2D drawing)

Postpone the creation of the triangles data structure and the hull finding. They are now done only when really needed. This increases the performances in cases where triangles and hull are not useful, for instance when a TGraph2D is drawn with option "P" only.

TH1

TH1::TH1() now uses UseCurrentStyle() to initialize the default histogram "style parameters". In particular it initializes properly the Histogram Fill Color to 0 which prevent the following three lines to generate a "X11 Fatal Error".
	  TH1D h
	  h.SetBins(5000000,0,1)
	  h.Draw()

TGraph

A better version of the TGraph constructor creating a TGraph from an input ascii file.

TArrow

Complete rewrite of TArrow::PaintArrow. The previous version used the pixel coordinates. This method generated many rounding errors. The visible effects on arrows were:
  1. distorted arrows' heads
  2. misplaced arrow compared to a Tline at the same coordinates.
The new TArrow::PaintArrow version fixes these two problems. Instead of using pixel coordinates it uses "true NDC" coordinates. The "ROOT NDC coordinates" are not appropriate in this case because X an Y axis are not normalized the same way, therefore angles are not kept during a rotation.

THStack

2D polygons clipping

Clip polygons using the Sutherland-Hodgman algorithm. The previous algorithm used (Cohen-Sutherland) is a line clipping algorithm which produces wrong results on polygons. This new algorithm is implemented in the function TPad::ClipPolygon used in the PaintFillArea method in its Double_t version ONLY. The Float_t version of PaintFillArea prints a warning.

Sutherland and Hodgman's polygon-clipping algorithm uses a divide-and-conquer strategy: It solves a series of simple and identical problems that, when combined, solve the overall problem. The simple problem is to clip a polygon against a single infinite clip edge. Four clip edges, each defining one boundary of the clip rectangle, successively clip a polygon against a clip rectangle.

Steps of Sutherland-Hodgman's polygon-clipping algorithm:

The clip boundary determines a visible and invisible region. The edges from vertex i to vertex i+1 can be one of four types:

PostScript

Protection added to TVirtualPS::PrinStr and TVirtualPS::PrintFast to take into account the terminating null character.

THistPainter::PaintErrors

The polygon drawn in case of option E3 (and E4) was wrongly clipped when a Y value was greater than the Y axis maximum.

TCanvas

The TCanvas size in interactive mode and batch mode were different (4 pixels horizontally and 28 vertically). Most of the time this was not a real problem. But in some cases the same macro produced a different result executed interactively or in batch. For instance the following macro executed in batch did not show the histogram title in the PostScript output. This patch make sure that batch interactive canvas sizes are the same.
	
	{
	   TCanvas *c2 = new TCanvas("c2","",0,0,600,900);
	   c2->Divide(3,3);
	   TH1F *h = new TH1F("h","This is a really long title for test purposes only
	hopefully long enough hehehe",100,0,100);
	   c2->cd(1);
	   h->Draw();
	   c2->Print("test.ps");
	}

TLegend

In case the user doesn't supply a label for the legend entry (or NULL pointer) the label for the entry is set to the title of the TObject referenced in the first argument.

TTF

Font wingding.ttf (number 14) was not working. Nothing was displayed.

TGraphErrors

The fill style for boxes (option 3) was ignored.

TGaxis

Always paint the axis title before painting the tick marks. This fixes a problem when setting the number of divisions to 0. In this case the axis title was not drawn.

TGraphErrors

If a point is outside the pad limits it is set to the limit it exceed. Previously it was not initialized. This produced random drawing with the following macro:
	{
	   const int n=200;
	   double x[n],y[n],e[n];
	   TCanvas *c1 = new TCanvas("c1", "Test",800,600);
	   for (int i=0;i<n;i++) {
	      x[i]=i;
	      y[i]=sqrt(i);
	      e[i]=y[i]/(i+1);
	   }
	   TH1D *Fond = new TH1D("Fond","",2,0,n);
	   Fond->SetMinimum(0);
	   Fond->SetMaximum(10);
	   Fond->Draw();
	   TGraphErrors *gr = new TGraphErrors(n,x,y,0,e);
	   gr->SetFillColor(17);
	   gr->Draw("    E3");
	}

GL/gl2ps

THistPainter

Problems in CONT4 contour option fixed: The axis for CONT4 are now drawn with THistPainter::PaintAxis(), not anymore using TPainter3dAlgorithms.

Qt interface

New tutorials



ROOT page - Class index - Top of the page