8.6.  Visualization Attributes

Visualization attributes are extra pieces of information associated with the visualizable objects. This information is necessary only for visualization, and is not included in geometrical information such as shapes, position, and orientation. Typical examples of visualization attributes are Color, Visible/Invisible, Wireframe/Solid. For example, in visualizing a box, the Visualization Manager must know its colour. If an object to be visualized has not been assigned a set of visualization attributes, then an appropriate default set is used automatically.

A set of visualization attributes is held by an instance of class G4VisAttributes defined in the graphics_reps category. In the following, we explain the main fields of the G4VisAttributes one by one.

8.6.1.  Visibility

Visibility is a boolean flag to control the visibility of objects that are passed to the Visualization Manager for visualization. Visibility is set with the following access function:

     void G4VisAttributes::SetVisibility (G4bool visibility);

If you give false to the argument, and if culling is activated (see below), visualization is skipped for objects for which this set of visualization attributes is assigned. The default value of visibility is true.

Note that whether an object is visible or not is also affected by the current culling policy, which can be tuned with visualization commands.

By default the following public static function is defined:

     static const G4VisAttributes& GetInvisible();

which returns a reference to a const object in which visibility is set to false. It can be used as follows:

     experimentalHall_logical -> SetVisAttributes (G4VisAttributes::GetInvisible());

Direct access to the public static const data member G4VisAttributes::Invisible is also possible but deprecated on account of initialisation issues with dynamic libraries.

8.6.2.  Colour

8.6.2.1.  Construction

Class G4Colour (an equivalent class name, G4Color, is also available) has 4 fields, which represent the RGBA (red, green, blue, and alpha) components of colour. Each component takes a value between 0 and 1. If an irrelevant value, i.e., a value less than 0 or greater than 1, is given as an argument of the constructor, such a value is automatically clipped to 0 or 1. Alpha is opacity. Its default value 1 means "opaque".

A G4Colour object is instantiated by giving red, green, and blue components to its constructor, i.e.,

     G4Colour::G4Colour ( G4double r = 1.0, 
                          G4double g = 1.0, 
                          G4double b = 1.0, 
                          G4double a = 1.0);
                                  // 0<=red, green, blue <= 1.0 

The default value of each component is 1.0. That is to say, the default colour is "white" (opaque).

For example, colours which are often used can be instantiated as follows:

     G4Colour  white   ()              ;  // white
     G4Colour  white   (1.0, 1.0, 1.0) ;  // white
     G4Colour  gray    (0.5, 0.5, 0.5) ;  // gray
     G4Colour  black   (0.0, 0.0, 0.0) ;  // black
     G4Colour  red     (1.0, 0.0, 0.0) ;  // red
     G4Colour  green   (0.0, 1.0, 0.0) ;  // green
     G4Colour  blue    (0.0, 0.0, 1.0) ;  // blue
     G4Colour  cyan    (0.0, 1.0, 1.0) ;  // cyan
     G4Colour  magenta (1.0, 0.0, 1.0) ;  // magenta
     G4Colour  yellow  (1.0, 1.0, 0.0) ;  // yellow

It is also possible to instantiate common colours through static public data member functions:

     static const G4Colour& White   ();  
     static const G4Colour& Gray    ();  
     static const G4Colour& Grey    (); 
     static const G4Colour& Black   (); 
     static const G4Colour& Red     (); 
     static const G4Colour& Green   (); 
     static const G4Colour& Blue    (); 
     static const G4Colour& Cyan    (); 
     static const G4Colour& Magenta (); 
     static const G4Colour& Yellow  (); 

For example, a local G4Colour could be constructed as:

     G4Colour myRed(G4Colour::Red());

After instantiation of a G4Colour object, you can access to its components with the following access functions:

     G4double G4Colour::GetRed   () const ; // Get the red   component. 
     G4double G4Colour::GetGreen () const ; // Get the green component.
     G4double G4Colour::GetBlue  () const ; // Get the blue  component.

8.6.2.2.  Colour Map

G4Colour also provides a static colour map, giving access to predefined G4Colour's through a G4String key. The default mapping is:

     G4String           G4Colour
     ---------------------------------------
     white              G4Colour::White   ()
     gray               G4Colour::Gray    ()
     grey               G4Colour::Grey    ()
     black              G4Colour::Black   ()
     red                G4Colour::Red     ()
     green              G4Colour::Green   ()
     blue               G4Colour::Blue    ()
     cyan               G4Colour::Cyan    ()
     magenta            G4Colour::Magenta ()
     yellow             G4Colour::Yellow  ()

Colours can be retrieved through the GetColour method:

     bool G4Colour::GetColour(const G4String& key, G4Colour& result)

For example:

    G4Colour myColour(G4Colour::Black());
    if (G4Colour::GetColour("red", myColour)) {
      // Successfully retrieved colour "red". myColour is now red
    }
    else {
      // Colour did not exist in map. myColour is still black
    }

If the key is not registered in the colour map, a warning message is printed and the input colour is not changed. The colour map is case insensitive.

It is also possible to load user defined G4Colour's into the map through the public AddToMap method. For example:

    G4Colour myColour(0.2, 0.2, 0.2, 1);
    G4Colour::AddToMap("custom", myColour);

This loads a user defined G4Colour with key "custom" into the colour map.

8.6.2.3.  Colour and G4VisAttributes

Class G4VisAttributes holds its colour entry as an object of class G4Colour. A G4Colour object is passed to a G4VisAttributes object with the following access functions:

     //----- Set functions of G4VisAttributes.
     void G4VisAttributes::SetColour (const G4Colour& colour);
     void G4VisAttributes::SetColor (const G4Color& color );

We can also set RGBA components directly:

     //----- Set functions of G4VisAttributes
     void G4VisAttributes::SetColour ( G4double red   , 
                                       G4double green , 
                                       G4double blue  , 
                                       G4double alpha = 1.0);
  
     void G4VisAttributes::SetColor  ( G4double red   , 
                                       G4double green , 
                                       G4double blue  , 
                                       G4double alpha = 1.);

The following constructor with G4Colour as its argument is also supported:

     //----- Constructor of G4VisAttributes
     G4VisAttributes::G4VisAttributes (const G4Colour& colour);

Note that colour assigned to a G4VisAttributes object is not always the colour that ultimately appears in the visualization. The ultimate appearance may be affected by shading and lighting models applied in the selected visualization driver or stand-alone graphics system.

8.6.3.  Forcing attributes

As you will see later, you can select a "drawing style" from various options. For example, you can select your detector components to be visualized in "wireframe" or with "surfaces". In the former, only the edges of your detector are drawn and so the detector looks transparent. In the latter, your detector looks opaque with shading effects.

The forced wireframe and forced solid styles make it possible to mix the wireframe and surface visualization (if your selected graphics system supports such visualization). For example, you can make only the outer wall of your detector "wired" (transparent) and can see inside in detail.

Forced wireframe style is set with the following access function:

     void G4VisAttributes::SetForceWireframe (G4bool force);

If you give true as the argument, objects for which this set of visualization attributes is assigned are always visualized in wireframe even if in general, the surface drawing style has been requested. The default value of the forced wireframe style is false.

Similarly, forced solid style, i.e., to force that objects are always visualized with surfaces, is set with:

     void G4VisAttributes::SetForceSolid (G4bool force);

The default value of the forced solid style is false, too.

You can also force auxiliary edges to be visible. Normally they are not visible unless you set the appropriate view parameter. Forcing the auxiliary edges to be visible means that auxiliary edges will be seen whatever the view parameters.

Auxiliary edges are not genuine edges of the volume. They may be in a curved surface made out of polygons, for example, or in plane surface of complicated shape that has to be broken down into simpler polygons. HepPolyhedron breaks all surfaces into triangles or quadrilaterals. There will be auxiliary edges for any volumes with a curved surface, such as a tube or a sphere, or a volume resulting from a Boolean operation. Normally, they are not shown, but sometimes it is useful to see them. In particular, a sphere, because it has no egdes, will not be seen in wireframe mode in some graphics systems unless requested by the view parameters or forced, as described here.

To force auxiliary edges to be visible, use:

     void G4VisAttributes::SetForceAuxEdgeVisible (G4bool force);

The default value of the force auxiliary edges visible flag is false.

For volumes with edges that are parts of a circle, such as a tube (G4Tubs), etc., it is possible to force the precision of polyhedral representation for visualisation. This is recommended for volumes containing only a small angle of circle, for example, a thin tube segment.

For visualisation, a circle is represented by an N-sided polygon. The default is 24 sides or segments. The user may change this for all volumes in a particular viewer at run time with /vis/viewer/set/lineSegmentsPerCircle; alternatively it can be forced for a particular volume with:

     void G4VisAttributes::SetForceLineSegmentsPerCircle (G4int nSegments);

8.6.4.  Other attributes

Here is a list of Set methods for class G4VisAttributes:

  void SetVisibility          (G4bool);
  void SetDaughtersInvisible  (G4bool);
  void SetColour              (const G4Colour&);
  void SetColor               (const G4Color&);
  void SetColour              (G4double red, G4double green, G4double blue,
                               G4double alpha = 1.);
  void SetColor               (G4double red, G4double green, G4double blue,
                               G4double alpha = 1.);
  void SetLineStyle           (LineStyle);
  void SetLineWidth           (G4double);
  void SetForceWireframe      (G4bool);
  void SetForceSolid          (G4bool);
  void SetForceAuxEdgeVisible (G4bool);
  void SetForceLineSegmentsPerCircle (G4int nSegments);
  // Allows choice of circle approximation.  A circle of 360 degrees
  // will be composed of nSegments line segments.  If your solid has
  // curves of D degrees that you need to divide into N segments,
  // specify nSegments = N * 360 / D.
  void SetStartTime           (G4double);
  void SetEndTime             (G4double);
  void SetAttValues           (const std::vector<G4AttValue>*);
  void SetAttDefs             (const std::map<G4String,G4AttDef>*);

8.6.5.  Constructors of G4VisAttributes

The following constructors are supported for class G4VisAttributes:

     //----- Constructors of class G4VisAttributes
     G4VisAttributes (void);
     G4VisAttributes (G4bool visibility);
     G4VisAttributes (const G4Colour& colour);
     G4VisAttributes (G4bool visibility, const G4Colour& colour);

8.6.6.  How to assign G4VisAttributes to a logical volume

In constructing your detector components, you may assign a set of visualization attributes to each "logical volume" in order to visualize them later (if you do not do this, the graphics system will use a default set). You cannot make a solid such as G4Box hold a set of visualization attributes; this is because a solid should hold only geometrical information. At present, you cannot make a physical volume hold one, but there are plans to design a memory-efficient way to do it; however, you can visualize a transient piece of solid or physical volume with a temporary assigned set of visualization attributes.

Class G4LogicalVolume holds a pointer of G4VisAttributes. This field is set and referenced with the following access functions:

     //----- Set functions of G4VisAttributes
     void G4VisAttributes::SetVisAttributes (const G4VisAttributes* pVA);
     void G4VisAttributes::SetVisAttributes (const G4VisAttributes& VA);

     //----- Get functions of G4VisAttributes
     const G4VisAttributes* G4VisAttributes::GetVisAttributes () const;

The following is sample C++ source codes for assigning a set of visualization attributes with cyan colour and forced wireframe style to a logical volume:

     //----- C++ source codes: Assigning G4VisAttributes to a logical volume
     ...
          // Instantiation of a logical volume
     myTargetLog = new G4LogicalVolume( myTargetTube,BGO, "TLog", 0, 0, 0);
     ...
          // Instantiation of a set of visualization attributes with cyan colour
     G4VisAttributes * calTubeVisAtt = new G4VisAttributes(G4Colour(0.,1.,1.));
          // Set the forced wireframe style 
     calTubeVisAtt->SetForceWireframe(true);
          // Assignment of the visualization attributes to the logical volume
     myTargetLog->SetVisAttributes(calTubeVisAtt);

     //----- end of C++ source codes

Note that the life of the visualization attributes must be at least as long as the objects to which they are assigned; it is the users' responsibility to ensure this, and to delete the visualization attributes when they are no longer needed (or just leave them to die at the end of the job).

8.6.7.  Additional User-Defined Attributes

Geant4 Trajectories and Hits can be assigned additional arbitrary attributes that will be displayed when you click on the relevant object in the WIRED or FRED HepRep browsers. WIRED then lets you label objects by any of these attributes or cut visibility based on these attributes.

Define the attributes with lines such as:

     std::map<G4String,G4AttDef>* store = G4AttDefStore::GetInstance("G4Trajectory",isNew);     
     G4String PN("PN");    
     (*store)[PN] = G4AttDef(PN,"Particle Name","Physics","","G4String");     
     G4String IMom("IMom");     
     (*store)[IMom] = G4AttDef(IMom, "Momentum of track at start of trajectory", "Physics", "",
                                     "G4ThreeVector");

Then fill the attributes with lines such as:

     std::vector<G4AttValue>* values = new std::vector<G4AttValue>;
     values->push_back(G4AttValue("PN",ParticleName,""));
     s.seekp(std::ios::beg);
     s << G4BestUnit(initialMomentum,"Energy") << std::ends;
     values->push_back(G4AttValue("IMom",c,""));

See geant4/source/tracking/src/G4Trajectory.cc for a good example.

G4AttValue objects are light, containing just the value; for the long description and other sharable information the G4AttValue object refers to a G4AttDef object. They are based on the HepRep standard described at http://www.slac.stanford.edu/~perl/heprep/ . Geant4 also provides an G4AttDefStore.

Geant4 provides some default examples of the use of this facility in the trajectory classes in /source/tracking such as G4Trajectory, G4SmoothTrajectory. G4Trajectory::CreateAttValues shows how G4AttValue objects can be made and G4Trajectory::GetAttDefs shows how to make the corresponding G4AttDef objects and use the G4AttDefStore. Note that the "user" of CreateAttValues guarantees to destroy them; this is a way of allowing creation on demand and leaving the G4Trajectory object, for example, free of such objects in memory. The comments in G4VTrajectory.hh explain further and additional insights might be obtained by looking at two methods which use them, namely G4VTrajectory::DrawTrajectory and G4VTrajectory::ShowTrajectory.

Hits classes in examples /extended/analysis/A01 and /extended/runAndEvent/RE01 show how to do the same for your hits. The base class no-action methods CreateAttValues and GetAttDefs should be overridden in your concrete class. The comments in G4VHit.hh explain further.

In addition, the user is free to add a G4std::vector<G4AttValue>* and a G4std::vector<G4AttDef>* to a G4VisAttributes object as could, for example, be used by a G4LogicalVolume object.

At the time of writing, only the HepRep graphics systems are capable of displaying the G4AttValue information, but this information will become useful for all Geant4 visualization systems through improvements in release 8.1 or later.