\chapter{Geometry}

\section{What can be extended ?}
{\sc Geant4} already allows a user to describe any desired solid,
and to use it in a detector description, in some cases, however,
the user may want or need to extend {\sc Geant4}'s geometry.
One reason can be that some methods and types in the geometry
are general and the user can utilise specialised knowledge about
his or her geometry to gain a speedup. The most evident case where
this can happen is when a particular type of solid is a key
element for a specific detector geometry and an investment in
improving its runtime performance may be worthwhile.

To extend the functionality of the Geometry in this way,
a toolkit developer must write a small number of methods for
the new solid.
We will document below these methods and their specifications.
Note that the implementation details for some methods are not a
trivial matter: these methods must provide the functionality of
finding whether a point is inside a solid, finding the
intersection of a line with it, and finding the distance to the
solid along any direction. However once the solid class has been
created with all its specifications fulfilled, it can be used like
any {\sc Geant4} solid, as it implements the abstract interface of G4VSolid.

Other additions can also potentially be achieved. For example, 
an advanced user could add a new way of creating physical volumes.
However, because each type of volume has a corresponding navigator
helper, this would require to create a new Navigator as well.
To do this the user would have to inherit from G4Navigator and
modify the new Navigator to handle this type of volumes.
This can certainly be done, but will probably be made easier to
achieve in the future versions of the {\sc Geant4} toolkit. 

\section{Adding a new type of Solid}
We list below the required methods for integrating a new type
of solid in {\sc Geant4}. Note that {\sc Geant4}'s specifications for a
solid pay significant attention to what happens at points that
are within a small distance (tolerance, {\em kCarTolerance} in
the code) of the surface. So special care must be taken to
handle these cases in considering all different possible
scenarios, in order to respect the specifications and allow
the solid to be used correctly by the other components of the
geometry module.

\paragraph{Creating a derived class of G4VSolid}
The solid must inherit from G4VSolid or one of its 
derived classes and implement its virtual functions. 

Mandatory member functions you must define are the following 
pure virtual of G4VSolid: 
\begin{verbatim}
 EInside Inside(const G4ThreeVector& p)
 G4double DistanceToIn(const G4ThreeVector& p)
 G4double DistanceToIn(const G4ThreeVector& p, const G4ThreeVector& v)
 G4ThreeVector SurfaceNormal(const G4ThreeVector& p)
 G4double DistanceToOut(const G4ThreeVector& p)
 G4double DistanceToOut(const G4ThreeVector& p, const G4ThreeVector& v,
                        const G4bool calcNorm=false,
                              G4bool *validNorm=0, G4ThreeVector *n)
 G4bool CalculateExtent(const EAxis pAxis,
                        const G4VoxelLimits& pVoxelLimit,
                        const G4AffineTransform& pTransform,
                              G4double& pMin,
                              G4double& pMax) const
 G4GeometryType GetEntityType() const
 std::ostream& StreamInfo(std::ostream& os) const
\end{verbatim}
They must perform the following functions 

\begin{verbatim}
  EInside Inside(const G4ThreeVector& p)
\end{verbatim}
This method must return: 
\begin{itemize}
\item kOutside if the point at offset p is outside the shape 
      boundaries plus Tolerance/2, 
\item kSurface if the point is $<=$ Tolerance/2 from a surface, or 
\item kInside otherwise. 
\end{itemize}

\begin{verbatim}
G4ThreeVector SurfaceNormal(const G4ThreeVector& p)
\end{verbatim}
Return the outwards pointing unit normal of the shape for the 
surface closest to the point at offset p.

\begin{verbatim}
G4double DistanceToIn(const G4ThreeVector& p)
\end{verbatim}
Calculate distance to nearest surface of shape from an outside 
point p. The distance can be an underestimate. 

\begin{verbatim}
G4double DistanceToIn(const G4ThreeVector& p, const G4ThreeVector& v)
\end{verbatim}
Return the distance along the normalised vector v to the shape, 
from the point at offset p. If there is no intersection, return
kInfinity. The first intersection resulting from `leaving' 
a surface/volume is discarded. Hence, this is tolerant of points on
surface of shape.

\begin{verbatim}
G4double DistanceToOut(const G4ThreeVector& p)
\end{verbatim}
Calculate distance to nearest surface of shape from an inside 
point. The distance can be an underestimate. 

\begin{verbatim}
G4double DistanceToOut(const G4ThreeVector& p, const G4ThreeVector& v,
                        const G4bool calcNorm=false,
                        G4bool *validNorm=0, G4ThreeVector *n=0);
\end{verbatim}
Return distance along the normalised vector v to the shape, from 
a point at an offset p inside or on the surface of the shape.
Intersections with surfaces, when the point is not greater than 
kCarTolerance/2 from a surface, must be ignored. 

If calcNorm is true, then it must also set validNorm to either 
\begin{itemize}
\item true, if the solid lies entirely behind or on the exiting 
      surface. Then it must set n to the outwards normal vector (the
      Magnitude of the vector is not defined). 
\item false, if the solid does not lie entirely behind or on the 
      exiting surface. 
\end{itemize}
If calcNorm is false, then validNorm and n are unused. 
\begin{verbatim}
G4bool CalculateExtent(const EAxis pAxis,
                        const G4VoxelLimits& pVoxelLimit,
                        const G4AffineTransform& pTransform,
                              G4double& pMin,
                              G4double& pMax) const
\end{verbatim}
Calculate the minimum and maximum extent of the solid, when under the
specified transform, and within the specified limits. If the solid
is not intersected by the region, return false, else return true.

\begin{verbatim}
G4GeometryType GetEntityType() const;
\end{verbatim}
Provide identification of the class of an object (required for
persistency and STEP interface).

\begin{verbatim}
std::ostream& StreamInfo(std::ostream& os) const
\end{verbatim}
Should dump the contents of the solid to an output stream.

The method:

\begin{verbatim}
G4double GetCubicVolume()
\end{verbatim}
should be implemented for every solid in order to cache the computed
value (and therefore reuse it for future calls to the method) and to
eventually implement a precise computation of the solid's volume. If
the method will not be overloaded, the default implementation from the
base class will be used (estimation through a Monte Carlo algorithm)
and the computed value will not be stored.

There are a few member functions to be defined for the purpose of 
visualisation. The first method is mandatory, and the next four are not. 

\begin{verbatim}
  // Mandatory
  virtual void DescribeYourselfTo (G4VGraphicsScene& scene) const = 0;

  // Not mandatory
  virtual G4VisExtent GetExtent() const;
  virtual G4Polyhedron* CreatePolyhedron () const;
  virtual G4NURBS*      CreateNURBS      () const;
  virtual G4Polyhedron* GetPolyhedron    () const;
\end{verbatim}
What these methods should do and how they should be implemented is
described here. 

\begin{verbatim}
 void DescribeYourselfTo (G4VGraphicsScene& scene) const;
\end{verbatim}
This method is required in order to identify the solid to the graphics scene. 
It is used for the purposes of ``double dispatch''. All implementations 
should be similar to the one for G4Box: 

\begin{verbatim}
void G4Box::DescribeYourselfTo (G4VGraphicsScene& scene) const
{
  scene.AddSolid (*this);
}
\end{verbatim}
The method:

\begin{verbatim}
 G4VisExtent GetExtent() const;
\end{verbatim}
provides extent (bounding box) as a possible hint to the graphics view. 
You must create it by finding a box that encloses your solid, and returning 
a VisExtent that is created from this. 
The G4VisExtent must presumably be given the minus x, plus x,
minus y, plus y, minus z and plus z extents of this ``box''. 
For example a cylinder can say 

\begin{verbatim}
G4VisExtent G4Tubs::GetExtent() const
{
  // Define the sides of the box into which the G4Tubs instance would fit.
  return G4VisExtent (-fRMax, fRMax, -fRMax, fRMax, -fDz, fDz);
}
\end{verbatim}
The method:

\begin{verbatim}
 G4Polyhedron* CreatePolyhedron () const;
\end{verbatim}
is required by the visualisation system, in order to create a 
realistic rendering of your solid. To create a G4Polyhedron for
your solid, consult G4Polyhedron.

While the method:

\begin{verbatim}
 G4Polyhedron* GetPolyhedron () const;
\end{verbatim}
is a ``smart'' access function that creates on requests a polyhedron
and stores it for future access and should be customised for every solid.

The method:

\begin{verbatim}
 G4NURBS* CreateNURBS () const;
\end{verbatim}
is not currently utilised, so you do not have to implement it. 

\section{Modifying the Navigator}
For the vast majority of use-cases, it is not indeed necessary
(and definitely not advised) to extend or modify the existing
classes for navigation in the geometry.
A possible use-case for which this may apply, is for the
description of a new kind of physical volume to be integrated.
We believe that our set of choices for creating physical volumes
is varied enough for nearly all needs.\newline 
Future extensions of the {\sc Geant4} toolkit will probably make
easier exchanging or extending the G4Navigator, by introducing an
abstraction level simplifying the customisation. At this time,
a simple abstraction level of the navigator is provided by allowing
overloading of the relevant functionalities.

\paragraph{Extending the Navigator}
The main responsibilities of the Navigator are: 
\begin{itemize}
\item locate a point in the tree of the geometrical volumes; 
\item compute the length a particle can travel from a point
      in a certain direction before encountering a volume
      boundary. 
\end{itemize}
The Navigator utilises one helper class for each type of physical 
volume that exists. You will have to reuse the helper classes provided
in the base Navigator or create new ones for the new type of physical volume. 

To extend G4Navigator you will have then to inherit from it 
and modify these functions in your ModifiedNavigator to
request the answers for your new physical volume type from the
new helper class. The ModifiedNavigator should delegate other
cases to the {\sc Geant4}'s standard Navigator. 

\paragraph{Replacing the Navigator}
Replacing the Navigator is another possible operation. It is 
similar to extending the Navigator, in that any types of physical
volume that will be allowed must be handled by it. The same 
functionality is required as described in the previous section. 

However the amount of work is probably potentially larger, if 
support for all the current types of physical volumes is required.

The Navigator utilises one helper class for each type of 
physical volume that exists. These could also potentially be 
replaced, allowing a simpler way to create a new navigation
system. 
