CMS 3D CMS Logo

VisG4VisSceneHandler.cc

Go to the documentation of this file.
00001 //<<<<<< INCLUDES                                                       >>>>>>
00002 
00003 #include "VisGeant4/VisG4Core/interface/VisG4VisSceneHandler.h"
00004 #include "VisGeant4/VisG4Core/interface/VisG4VisTransform3D.h"
00005 
00006 #include "Iguana/Inventor/interface/IgSoCube.h"
00007 #include "Iguana/Inventor/interface/IgSoG4Box.h"
00008 #include "Iguana/Inventor/interface/IgSoRotSolid.h"
00009 #include "Iguana/Inventor/interface/IgSoG4Trd.h"
00010 #include "Iguana/Inventor/interface/IgSoG4Trap.h"
00011 
00012 #include <Inventor/nodes/SoCoordinate4.h>
00013 #include <Inventor/nodes/SoSeparator.h>
00014 #include <Inventor/nodes/SoDrawStyle.h>
00015 #include <Inventor/nodes/SoMaterial.h>
00016 #include <Inventor/nodes/SoCube.h>
00017 #include <Inventor/nodes/SoLineSet.h>
00018 #include <Inventor/nodes/SoPointSet.h>
00019 #include <Inventor/nodes/SoMarkerSet.h>
00020 #include <Inventor/nodes/SoSphere.h>
00021 #include <Inventor/nodes/SoFont.h>
00022 #include <Inventor/nodes/SoText2.h>
00023 #include <Inventor/nodes/SoFaceSet.h>
00024 #include <Inventor/nodes/SoNormalBinding.h>
00025 #include <Inventor/nodes/SoComplexity.h>
00026 #include <Inventor/nodes/SoNurbsSurface.h>
00027 #include <Inventor/nodes/SoTranslation.h>
00028 #include <Inventor/nodes/SoMatrixTransform.h>
00029 #include <Inventor/nodes/SoTransform.h>
00030 
00031 #include <G4ThreeVector.hh>
00032 #include <G4Point3D.hh>
00033 #include <G4Normal3D.hh>
00034 #include <G4Transform3D.hh>
00035 #include <G4Polyline.hh>
00036 #include <G4Scale.hh>
00037 #include <G4Text.hh>
00038 #include <G4Circle.hh>
00039 #include <G4Square.hh>
00040 #include <G4Polyhedron.hh>
00041 #include <G4NURBS.hh>
00042 #include <G4Box.hh>
00043 #include <G4Tubs.hh>
00044 #include <G4Cons.hh>
00045 #include <G4Trap.hh>
00046 #include <G4Trd.hh>
00047 #include <G4Sphere.hh>
00048 #include <G4Para.hh>
00049 #include <G4Torus.hh>
00050 #include <G4Polycone.hh>
00051 #include <G4Polyhedra.hh>
00052 #include <G4VisAttributes.hh>
00053 #include <CLHEP/config/CLHEP.h>
00054 
00055 #include <classlib/utils/DebugAids.h>
00056 #include <classlib/utils/Log.h>
00057 
00058 //<<<<<< PRIVATE DEFINES                                                >>>>>>
00059 //<<<<<< PRIVATE CONSTANTS                                              >>>>>>
00060 //<<<<<< PRIVATE TYPES                                                  >>>>>>
00061 //<<<<<< PRIVATE VARIABLE DEFINITIONS                                   >>>>>>
00062 //<<<<<< PUBLIC VARIABLE DEFINITIONS                                    >>>>>>
00063 //<<<<<< CLASS STRUCTURE INITIALIZATION                                 >>>>>>
00064 //<<<<<< PRIVATE FUNCTION DEFINITIONS                                   >>>>>>
00065 
00066 static inline bool operator== (const G4Colour &x, const G4Colour &y)
00067 {
00068     float xrgba [4] = { x.GetRed (), x.GetGreen (), x.GetBlue (), x.GetAlpha () };
00069     float yrgba [4] = { y.GetRed (), y.GetGreen (), y.GetBlue (), y.GetAlpha () };
00070     for (unsigned i = 0; i < 4; ++i)
00071         if (xrgba [i] != yrgba [i])
00072             return false;
00073 
00074     return true;
00075 }
00076 
00077 static inline bool operator< (const G4Colour &x, const G4Colour &y)
00078 {
00079     float xrgba [4] = { x.GetRed (), x.GetGreen (), x.GetBlue (), x.GetAlpha () };
00080     float yrgba [4] = { y.GetRed (), y.GetGreen (), y.GetBlue (), y.GetAlpha () };
00081     for (unsigned i = 0; i < 4; ++i)
00082         if (xrgba [i] < yrgba [i])
00083             return true;
00084         else if (xrgba [i] > yrgba [i])
00085             return false;
00086 
00087     return false;
00088 }
00089 
00090 //<<<<<< PUBLIC FUNCTION DEFINITIONS                                    >>>>>>
00091 //<<<<<< MEMBER FUNCTION DEFINITIONS                                    >>>>>>
00092 
00093 VisG4VisSceneHandler *
00094 VisG4VisSceneHandler::instance (void)
00095 {
00096     static VisG4VisSceneHandler *instance = new VisG4VisSceneHandler;
00097     return instance;
00098 }
00099 
00100 
00101 VisG4VisSceneHandler::VisG4VisSceneHandler (void)
00102     : m_node (0),
00103       m_caching (false),
00104       m_cached (false),
00105       m_cacheNodes (0),
00106       m_cacheIndex (0),
00107       m_lines (new SoDrawStyle),
00108       m_solid (new SoDrawStyle),
00109       m_fallback (G4ViewParameters::polyhedron),
00110       m_bbox (0, .5),
00111       m_sides (24),
00112       m_fontSize (12)
00113 {
00114     // Initialise a shared scenegraph scaler node
00115     m_lines->ref ();
00116     m_solid->ref ();
00117     m_lines->style = SoDrawStyle::LINES;
00118     m_solid->style = SoDrawStyle::FILLED;
00119 
00120     // Determine if we can reuse OIV nodes for the volume.  We do not
00121     // reuse entire rep hierarchies, only solid shape lists, mainly
00122     // for the following reasons: 1) we do not yet have support for
00123     // shared reps, 2) each different volume path can have different
00124     // visualisation preferences, and 4) parametrised replicas might
00125     // vary solids (?).
00126     //
00127     // Note that we never clear our cache.  We assume the nodes
00128     // created for a particular solid are valid for forever (FIXME?).
00129     // Note that VisG4VolumeModel invokes this method exactly once.
00130     // Thus we can get away with single non-stacked caching state.
00131     //
00132     // We first check if we can share anything at all: in a replica we
00133     // can't.  Secondly, we only cache the solid shape nodes, the rest
00134     // is not cached (transformation matrices, material settings,
00135     // multiple broken down solid structures) (FIXME).  m_cacheIndex
00136     // tracks our progress in a complex solid structure; we assume
00137     // (and ASSERT) that the calls to solid description methods below
00138     // always appear in the same order for the same cached solid.
00139     //
00140     // Caching is on by default.  If $IGUANA_CACHING is defined, it
00141     // must be `1', `on' or `yes' for caching to be enabled.
00142     const char *cachingStr = getenv ("IGUANA_CACHING");
00143     m_caching = (! cachingStr
00144                  || !strcmp (cachingStr, "1")
00145                  || !strcmp (cachingStr, "on")
00146                  || !strcmp (cachingStr, "yes"));
00147 }
00148 
00149 void
00150 VisG4VisSceneHandler::defineFallback (RepStyle style)
00151 { m_fallback = style; }
00152 
00153 void
00154 VisG4VisSceneHandler::defineBounds (G4VisExtent bbox)
00155 { m_bbox = bbox; }
00156 
00157 void
00158 VisG4VisSceneHandler::defineNoOfSides (int sides)
00159 { m_sides = sides; }
00160 
00164 void
00165 VisG4VisSceneHandler::enableCache (bool enabled)
00166 {
00167     cacheEnd ();
00168     if (! (m_caching = enabled))
00169         clearCache ();
00170 }
00171 
00172 void
00173 VisG4VisSceneHandler::clearCache (void)
00174 {
00175     cacheEnd ();
00176     while (! m_shapeCache.empty ())
00177     {
00178         m_shapeCache.begin ()->second->unref ();
00179         m_shapeCache.erase (m_shapeCache.begin ());
00180     }
00181     while (! m_materialCache.empty ())
00182     {
00183         m_materialCache.begin ()->second->unref ();
00184         m_materialCache.erase (m_materialCache.begin ());
00185     }
00186 }
00187 
00188 void
00189 VisG4VisSceneHandler::cacheBegin (const void *object)
00190 {
00191     cacheEnd ();
00192     if (m_caching && object)
00193     {
00194         ASSERT (object);
00195         if (! m_shapeCache.count (object))
00196         {
00197             m_shapeCache [object] = m_cacheNodes = new SoGroup;
00198             m_cacheNodes->ref ();
00199         }
00200         else
00201         {
00202             m_cacheNodes = m_shapeCache [object];
00203             m_cached = true;
00204         }
00205     }
00206 }
00207 
00208 bool
00209 VisG4VisSceneHandler::cached (void)
00210 {
00211     if (m_cached)
00212     {
00213         ASSERT (m_node);
00214         ASSERT (m_cacheNodes);
00215         ASSERT (m_cacheIndex < m_cacheNodes->getNumChildren ());
00216         m_node->addChild (m_cacheNodes->getChild (m_cacheIndex));
00217         m_cacheIndex++;
00218         return true;
00219     }
00220     else
00221         return false;
00222 }
00223 
00224 void
00225 VisG4VisSceneHandler::cache (SoNode *node)
00226 {
00227     if (m_cacheNodes)
00228     {
00229         m_cacheNodes->addChild (node);
00230         m_cacheIndex++;
00231     }
00232 }
00233 
00234 void
00235 VisG4VisSceneHandler::cacheEnd (void)
00236 {
00237     m_cached = false;
00238     m_cacheNodes = 0;
00239     m_cacheIndex = 0;
00240 }
00241 
00245 void
00246 VisG4VisSceneHandler::beginObject (SoSeparator *node, const void *object)
00247 {
00248     // Set up output target.
00249     ASSERT (! m_node);
00250     ASSERT (node);
00251     m_node = node;
00252 
00253     // Setup caching.
00254     cacheBegin (object);
00255 }
00256 
00257 void
00258 VisG4VisSceneHandler::endObject (void)
00259 {
00260     ASSERT (m_node);
00261     cacheEnd ();
00262     m_node = 0;
00263 }
00264 
00268 void
00269 VisG4VisSceneHandler::addStyle (const G4VisAttributes *from)
00270 {
00271     // FIXME: To be removed when we get real vis prefs service
00272     ASSERT (from);
00273     addStyle (GetDrawingStyle (from));
00274     // Now using addMaterial(G4Material to set the material.
00275 }
00276 
00277 void
00278 VisG4VisSceneHandler::addStyle (DrawStyle style)
00279 {
00280     ASSERT (m_node);
00281 
00282     switch (style)
00283     {
00284     case G4ViewParameters::hlr:         // hidden lines removed
00285     case G4ViewParameters::wireframe:   // wireframe (no lines removed)
00286         m_node->addChild (m_lines);
00287         break;
00288 
00289     case G4ViewParameters::hlhsr:       // hidden lines and surfaces removed
00290     case G4ViewParameters::hsr:         // hidden surfaces removed
00291     default:
00292         m_node->addChild (m_solid);
00293         break;
00294     }
00295 }
00296 
00297 void
00298 VisG4VisSceneHandler::addMaterial (SoMaterial *mat)
00299 {
00300     ASSERT (mat);    
00301     ASSERT (m_node);
00302     
00303     m_node->addChild (mat);
00304 }
00305 
00306 void
00307 VisG4VisSceneHandler::addTransform (const G4Transform3D &by)
00308 {
00309     ASSERT (m_node);
00310 
00311     // Force uniform downscale to meters.
00312     SbMatrix scale;
00313     scale.setScale (1./m);
00314 
00315     SoMatrixTransform *xform = new SoMatrixTransform;
00316     xform->matrix.setValue (scale * VisG4VisTransform3D (by));
00317     m_node->addChild (xform);
00318 }
00319 
00323 void
00324 VisG4VisSceneHandler::addTranslation (SoSeparator *to, const G4Point3D &center)
00325 {
00326     ASSERT (to);
00327 
00328     SoTranslation *t = new SoTranslation;
00329     t->translation.setValue (center.x (), center.y (), center.z ());
00330     to->addChild (t);
00331 }
00332 
00333 void
00334 VisG4VisSceneHandler::addTranslation (SoSeparator *to, SbVec3f center)
00335 {
00336     ASSERT (to);
00337 
00338     SoTranslation *t = new SoTranslation;
00339     t->translation = center;
00340     to->addChild (t);
00341 }
00342 
00346 void
00347 VisG4VisSceneHandler::AddSolid (const G4Box &solid)
00348 {
00349     ASSERT (m_node);
00350     if (cached ()) return;
00351 
00352     // FIXME: Notice if the cube is "thin," in which case just use two
00353     // surfaces instead of the six, or use LOD.  This is to optimise
00354     // for large numbers of very thin boxes frequent in silicon wafers
00355     // etc.  It is useless to render all the sides always, you have to
00356     // be very close to see all the sides other than lines.
00357     IgSoCube *rep = new IgSoCube;
00358     rep->width     = 2 * solid.GetXHalfLength ();
00359     rep->length    = 2 * solid.GetYHalfLength ();
00360     rep->thickness = 2 * solid.GetZHalfLength (); 
00361 
00362     m_node->addChild (rep);
00363     cache (rep);
00364 }
00365 
00366 void
00367 VisG4VisSceneHandler::AddSolid (const G4Cons &solid)
00368 {
00369     ASSERT (m_node);
00370     if (cached ()) return;
00371 
00372     IgSoRotSolid *rep = new IgSoRotSolid;
00373     
00374     rep->makeCons (solid.GetRmin1 (),
00375                    solid.GetRmax1 (),
00376                    solid.GetRmin2 (),
00377                    solid.GetRmax2 (),
00378                    solid.GetDz (),
00379                    solid.GetSPhi (),
00380                    solid.GetDPhi ());
00381     
00382     m_node->addChild (rep);
00383     cache (rep);
00384 }
00385 
00386 void
00387 VisG4VisSceneHandler::AddSolid (const G4Tubs &solid)
00388 {
00389     ASSERT (m_node);
00390     if (cached ()) return;
00391 
00392     IgSoRotSolid *rep = new IgSoRotSolid;
00393     
00394     rep->makeTubs (solid.GetRMin (), 
00395                    solid.GetRMax (), 
00396                    solid.GetDz (),
00397                    solid.GetSPhi (), 
00398                    solid.GetDPhi ());
00399     m_node->addChild (rep);
00400     cache (rep);
00401 }
00402 
00403 void
00404 VisG4VisSceneHandler::AddSolid (const G4Trd &solid)
00405 {
00406     ASSERT (m_node);
00407     if (cached ()) return;
00408 
00409     IgSoG4Trd *rep = new IgSoG4Trd;
00410     rep->dx1 = solid.GetXHalfLength1 ();
00411     rep->dx2 = solid.GetXHalfLength2 ();
00412     rep->dy1 = solid.GetYHalfLength1 ();
00413     rep->dy2 = solid.GetYHalfLength2 ();
00414     rep->dz  = solid.GetZHalfLength ();
00415     m_node->addChild (rep);
00416     cache (rep);
00417 }
00418 
00419 void
00420 VisG4VisSceneHandler::AddSolid (const G4Trap &solid)
00421 {
00422     ASSERT (m_node);
00423     if (cached ()) return;
00424 
00425     G4ThreeVector       axis = solid.GetSymAxis ();
00426     IgSoG4Trap          *rep = new IgSoG4Trap;
00427     rep->phi   = atan2 (axis (kYAxis), axis (kXAxis));
00428     rep->theta = acos (axis (kZAxis));
00429     rep->dz    = solid.GetZHalfLength ();
00430     rep->dy1    = solid.GetYHalfLength1 ();
00431     rep->dx1    = solid.GetXHalfLength1 ();
00432     rep->dx2    = solid.GetXHalfLength2 ();
00433     rep->alp1   = solid.GetTanAlpha1 ();
00434     rep->dy2    = solid.GetYHalfLength2 ();
00435     rep->dx3    = solid.GetXHalfLength3 ();
00436     rep->dx4    = solid.GetXHalfLength4 ();
00437     rep->alp2   = solid.GetTanAlpha2 ();
00438     m_node->addChild (rep);
00439     cache (rep);
00440 }
00441 
00442 void
00443 VisG4VisSceneHandler::AddSolid (const G4Sphere &solid)
00444 { RequestPrimitives (solid); }
00445 
00446 void
00447 VisG4VisSceneHandler::AddSolid (const G4Para &solid)
00448 { RequestPrimitives (solid); }
00449 
00450 void
00451 VisG4VisSceneHandler::AddSolid (const G4Torus &solid)
00452 { RequestPrimitives (solid); }
00453 
00454 void
00455 VisG4VisSceneHandler::AddSolid (const G4Polycone &solid)
00456 { 
00457     ASSERT (m_node);
00458     if (cached ()) return;
00459 
00460     int                         nr = solid.GetNumRZCorner();   
00461     std::vector<SbVec2f>        polygon (nr);
00462     
00463     for (int i = 0; i < nr; ++i)
00464         polygon[i] = SbVec2f (solid.GetCorner (i).r, solid.GetCorner (i).z);    
00465 
00466     IgSoRotSolid *rep = new IgSoRotSolid;
00467     rep->phiStart       = solid.GetStartPhi ();
00468     rep->phiDelta       = solid.GetEndPhi () - solid.GetStartPhi ();
00469     rep->smooth         = true;
00470     rep->polygon.setValues (0, nr, &polygon[0]);
00471     
00472     m_node->addChild (rep);
00473     cache (rep);
00474 } 
00475 
00476 void
00477 VisG4VisSceneHandler::AddSolid (const G4Polyhedra &solid)
00478 {
00479     ASSERT (m_node);
00480     if (cached ()) return;
00481 
00482     int                         nr = solid.GetNumRZCorner();   
00483     std::vector<SbVec2f>        polygon (nr);
00484     
00485     for (int i = 0; i < nr; ++i)
00486         polygon[i] = SbVec2f (solid.GetCorner (i).r, solid.GetCorner (i).z); 
00487 
00488     IgSoRotSolid *rep = new IgSoRotSolid;
00489     rep->phiStart       = solid.GetStartPhi ();
00490     (solid.GetEndPhi () == solid.GetStartPhi ()) ? rep->phiDelta = 2 * M_PI :
00491     rep->phiDelta       = solid.GetEndPhi () - solid.GetStartPhi ();
00492     rep->divisions      = solid.GetNumSide ();    
00493     rep->smooth         = false;
00494     rep->polygon.setValues (0, nr, &polygon[0]);
00495     
00496     m_node->addChild (rep);
00497     cache (rep);
00498 }
00499 
00500 void
00501 VisG4VisSceneHandler::AddSolid (const G4VSolid &solid)
00502 {
00503     // Duh, some forms are declared as methods in base class, but
00504     // never called from the solids...  (FIXME: which else can we
00505     // handle -- G4VCSGfaceted?)
00506     if (const G4Polycone *pcon = dynamic_cast<const G4Polycone *> (&solid))
00507         AddSolid (*pcon);
00508     else if (const G4Polyhedra *pgon = dynamic_cast<const G4Polyhedra *> (&solid))
00509         AddSolid (*pgon);
00510     else
00511         RequestPrimitives (solid);
00512 }
00513 
00514 void
00515 VisG4VisSceneHandler::AddCompound (const G4VTrajectory & /*trajectory*/)
00516 { // FIXME 
00517 }
00518 
00519 void
00520 VisG4VisSceneHandler::AddCompound (const G4VHit & /*hit*/)
00521 { // FIXME
00522 }
00523 
00527 void
00528 VisG4VisSceneHandler::AddPrimitive (const G4Polyline &object)
00529 {
00530     ASSERT (m_node);
00531     if (cached ()) return;
00532 
00533     SoSeparator *me = new SoSeparator;
00534     m_node->addChild (me);
00535 
00536     // Force wireframe (FIXME: useless -- it's a line?).
00537     me->addChild (m_lines);
00538 
00539     // Add line with the points
00540     std::vector<SbVec3f> points (object.size (), SbVec3f ());
00541     for (unsigned i = 0; i < object.size (); ++i)
00542         points [i].setValue (object [i].x(), object [i].y(), object [i].z());
00543 
00544     SoLineSet           *lines = new SoLineSet;
00545     SoVertexProperty    *vtx = new SoVertexProperty;
00546     vtx->vertex.setValues (0, object.size (), &points[0]);
00547     lines->numVertices = object.size ();
00548     lines->vertexProperty = vtx;
00549     me->addChild (lines);
00550     cache (me);
00551 }
00552 
00553 void
00554 VisG4VisSceneHandler::AddPrimitive (const G4Scale &object)
00555 {
00556     // FIXME: This *really* should not be here.  Axes and scales are a
00557     // feature that should be done properly and only once in IGUANA,
00558     // not some crappy almost-good-for-something stuff like here!
00559 
00560     // Useful constants.
00561     double      length          = object.GetLength ();
00562     double      halfLength      = length / 2;
00563     double      tickLength      = length / 20;
00564     double      piBy2           = M_PI / 2;
00565 
00566     // Get size of the world.
00567     double       xmin           = m_bbox.GetXmin ();
00568     double       xmax           = m_bbox.GetXmax ();
00569     double       ymin           = m_bbox.GetYmin ();
00570     double       ymax           = m_bbox.GetYmax ();
00571     double       zmin           = m_bbox.GetZmin ();
00572     double       zmax           = m_bbox.GetZmax ();
00573 
00574     // Create (empty) polylines with present vis preferences.  Add
00575     // points to them to represent an scale parallel to the x-axis
00576     // centred on the origin.
00577     G4Polyline  scaleLine, tick11, tick12, tick21, tick22;
00578     G4Point3D   r1    (-halfLength, 0, 0);
00579     G4Point3D   r2    ( halfLength, 0, 0);
00580     G4Point3D   ticky (0, tickLength, 0);
00581     G4Point3D   tickz (0, 0, tickLength);
00582 
00583     scaleLine.push_back (r1);
00584     scaleLine.push_back (r2);
00585     tick11.push_back (r1 + ticky);
00586     tick11.push_back (r1 - ticky);
00587     tick12.push_back (r1 + tickz);
00588     tick12.push_back (r1 - tickz);
00589     tick21.push_back (r2 + ticky);
00590     tick21.push_back (r2 - ticky);
00591     tick22.push_back (r2 + tickz);
00592     tick22.push_back (r2 - tickz);
00593 
00594     // Annotation text.
00595     G4Text text (object.GetAnnotation(), G4Point3D (0., tickLength, 0.));
00596     text.SetScreenSize (24.);
00597 
00598     // Transformation.
00599     G4Transform3D rotation;
00600     switch (object.GetDirection ()) {
00601     case G4Scale::x: break;
00602     case G4Scale::y: rotation = G4RotateZ3D (piBy2); break;
00603     case G4Scale::z: rotation = G4RotateY3D (piBy2); break;
00604     }
00605 
00606     G4double    sxmid (object.GetXmid ());
00607     G4double    symid (object.GetYmid ());
00608     G4double    szmid (object.GetZmid ());
00609 
00610     if (object.GetAutoPlacing ()) {
00611         // Margins for comfortably scaled to be inside view volume.
00612         double  lomargin = 0.01;
00613         double  himargin = 1 - lomargin;
00614 
00615         sxmid = xmin + himargin * (xmax - xmin);
00616         symid = ymin + lomargin * (ymax - ymin);
00617         szmid = zmin + himargin * (zmax - zmin);
00618         switch (object.GetDirection ()) {
00619         case G4Scale::x: sxmid -= halfLength; break;
00620         case G4Scale::y: symid += halfLength; break;
00621         case G4Scale::z: szmid -= halfLength; break;
00622         }
00623     }
00624 
00625     // Add the transform and the primitives we've created
00626     SoSeparator *node = m_node;
00627     m_node = new SoSeparator;
00628     addTransform (G4Transform3D (G4Translate3D(sxmid,symid,szmid) * rotation));
00629     AddPrimitive (scaleLine);
00630     AddPrimitive (tick11);
00631     AddPrimitive (tick12);
00632     AddPrimitive (tick21);
00633     AddPrimitive (tick22);
00634     AddPrimitive (text);
00635     m_node = node;
00636 }
00637 
00638 void
00639 VisG4VisSceneHandler::AddPrimitive (const G4Text &object)
00640 {
00641     // FIXME: SoText2 supports only screen size.  It is not obvious
00642     // how useful the heroic attempts of G4 to compute screen size
00643     // from world size and current zoom settings are given that it all
00644     // varies very dynamically according to the current camera.  We
00645     // sure don't want to link the two by recomputing the text size on
00646     // the fly if we can avoid it.  OTOH, see the comment on the other
00647     // marker objects as well -- we do manage to do something sensible
00648     // there.  So perhaps we need to go into the trouble of getting it
00649     // right here with massive amount of GL magic?  If so, make it a
00650     // generic Inventor service and just use it here.
00651     ASSERT (m_node);
00652     if (cached ()) return;
00653 
00654     SoSeparator *me = new SoSeparator;
00655     m_node->addChild (me);
00656 
00657     // Translate to object position
00658     addTranslation (me, object.GetPosition ());
00659     // addMaterial (me, FIXME: is text colour special?)
00660 
00661     // FIXME: X/Y offset is in screen coordinates -- not supported;
00662     // needs raw GL support to be able to do that.
00663 
00664     // Font.  FIXME: fallback on global marker text size settings
00665     double size = object.GetScreenSize ();
00666     SoFont *font = new SoFont;
00667     font->size = size ? size : m_fontSize;
00668     me->addChild (font);
00669 
00670     // Text (FIXME: break string into separate values at newlines)
00671     SoText2 *text = new SoText2;
00672     text->string.setValue (object.GetText ());
00673     switch (object.GetLayout ()) {
00674     case G4Text::left:   text->justification = SoText2::LEFT;   break;
00675     case G4Text::centre: text->justification = SoText2::CENTER; break;
00676     case G4Text::right:  text->justification = SoText2::RIGHT;  break;
00677     }
00678     me->addChild (text);
00679     cache (me);
00680 }
00681 
00682 void
00683 VisG4VisSceneHandler::AddPrimitive (const G4Circle &object)
00684 {
00685     // FIXME: Steal more marker code into special GL shape from G4
00686     // OpenGL viewer and SoMarkerSet implementation.
00687     //
00688     // FIXME: Support an option to force markers on the top layer,
00689     // i.e. glDisable(GL_DEPTH_TEST). (IsMarkerNotHidden ()).
00690     ASSERT (m_node);
00691     if (cached ()) return;
00692 
00693     SoSeparator *me = new SoSeparator;
00694     m_node->addChild (me);
00695 
00696     MarkerSizeType       type;
00697     G4VMarker::FillStyle fill = object.GetFillStyle ();
00698     G4ThreeVector        pos (object.GetPosition ());
00699     double               size = GetMarkerSize (object, type);
00700     SoMarkerSet          *mset;
00701     SoVertexProperty     *vtx;
00702 
00703     switch (type)
00704     {
00705     case screen:
00706         // The marker has screen size.  Use SoMarkerSet with just one
00707         // point -- if you have many, use G4Polymarker or IgSoHitsKit,
00708         // this method to draw loads of circles will kill performance.
00709         mset = makeScreenMarker (G4Polymarker::circles, fill, size);
00710         vtx = new SoVertexProperty;
00711         vtx->vertex.setValue (SbVec3f (pos.x (), pos.y (), pos.z ()));
00712         mset->vertexProperty = vtx;
00713         mset->numPoints = 1;
00714         me->addChild (mset);
00715         break;
00716 
00717     case world:
00718         // The marker has world size: draw a sphere.  This is wrong,
00719         // the marker should be a circle always facing the viewer.
00720         // Filled ones the spheres will do, though inefficiently.
00721         // Anything else is a failure (actually "hashed" probably
00722         // looks about right due to the triangulation :-).  We should
00723         // use more powerful marker nodes that work at raw GL level.
00724         // Perhaps we can reuse code from the G4 OpenGL viewer.
00725         // (FIXME: Disable lighting?)
00726         if (fill != G4VMarker::filled)
00727             me->addChild (m_lines);
00728         addTranslation (me, pos);
00729         me->addChild (makeWorldMarker (G4Polymarker::circles, size));
00730         break;
00731     }
00732     cache (me);
00733 }
00734 
00735 void
00736 VisG4VisSceneHandler::AddPrimitive (const G4Square &object)
00737 {
00738     // FIXME: All this marker code should be replaced by a custom
00739     // marker node a la SoMarkerSet but with our own logic that we
00740     // could more or less steal from G4 OpenGL viewer.
00741     //
00742     // FIXME: Support an option to force markers on the top layer,
00743     // i.e. glDisable(GL_DEPTH_TEST). (IsMarkerNotHidden ()).
00744     ASSERT (m_node);
00745     if (cached ()) return;
00746 
00747     SoSeparator *me = new SoSeparator;
00748     m_node->addChild (me);
00749 
00750     MarkerSizeType       type;
00751     G4VMarker::FillStyle fill = object.GetFillStyle ();
00752     G4ThreeVector        pos (object.GetPosition ());
00753     double               size = GetMarkerSize (object, type);
00754     SoMarkerSet          *mset;
00755     SoVertexProperty     *vtx;
00756 
00757     switch (type)
00758     {
00759     case screen:
00760         // The marker has screen size.  Use SoMarkerSet with just one
00761         // point -- if you have many, use G4Polymarker or IgSoHitsKit,
00762         // this method to draw loads of circles will kill performance.
00763         mset = makeScreenMarker (G4Polymarker::squares, fill, size);
00764         vtx = new SoVertexProperty;
00765         vtx->vertex.setValue (SbVec3f (pos.x (), pos.y (), pos.z ()));
00766         mset->vertexProperty = vtx;
00767         mset->numPoints = 1;
00768         me->addChild (mset);
00769         break;
00770 
00771     case world:
00772         // The marker has world size: draw a cube.  This is wrong, the
00773         // marker should be a circle always facing the viewer.  Filled
00774         // ones the cubes will do, though inefficiently.  Anything
00775         // else is a failure (actually "hashed" probably looks about
00776         // right due to the triangulation :-).  We should use more
00777         // powerful marker nodes that work at raw GL level.  Perhaps
00778         // we can reuse code from the G4 OpenGL viewer.  (FIXME:
00779         // Disable lighting?)
00780         if (fill != G4VMarker::filled)
00781             me->addChild (m_lines);
00782         addTranslation (me, pos);
00783         me->addChild (makeWorldMarker (G4Polymarker::squares, size));
00784         break;
00785     }
00786     cache (me);
00787 }
00788 
00789 void
00790 VisG4VisSceneHandler::AddPrimitive (const G4Polyhedron &object)
00791 {
00792     ASSERT (m_node);
00793     if (! object.GetNoFacets () || cached ())
00794         return;
00795 
00796     // Collect the faces
00797     G4bool                      notLastFace;
00798     std::vector<SbVec3f>        vertices;
00799     std::vector<SbVec3f>        normals;
00800     std::vector<G4int>          nfaces;
00801     G4Normal3D                  normal;
00802     do {
00803         notLastFace = object.GetNextUnitNormal (normal);
00804         normals.push_back (SbVec3f (normal.x (), normal.y (), normal.z ()));
00805 
00806         G4int           faces = 0;
00807         G4bool          notLastEdge;
00808         G4Point3D       vertex;
00809         G4int           edgeFlag = 1;
00810 
00811         do {
00812             notLastEdge = object.GetNextVertex (vertex, edgeFlag);
00813             vertices.push_back (SbVec3f (vertex.x(), vertex.y(), vertex.z()));
00814             faces++;
00815         } while (notLastEdge);
00816 
00817         nfaces.push_back (faces);
00818     } while (notLastFace);
00819 
00820     // Add owner
00821     SoSeparator *me = new SoSeparator;
00822     m_node->addChild (me);
00823 
00824     // Store faces with normals and coordinates
00825     SoFaceSet        *faces = new SoFaceSet;
00826     SoVertexProperty *vtx = new SoVertexProperty;
00827 
00828     vtx->normalBinding = SoNormalBinding::PER_FACE;
00829     vtx->normal.setValues (0, normals.size (), &normals[0]);
00830     vtx->vertex.setValues (0, vertices.size (), &vertices[0]);
00831     faces->numVertices.setValues (0, nfaces.size (), &nfaces[0]);
00832     faces->vertexProperty = vtx;
00833     me->addChild (faces);
00834     cache (me);
00835 }
00836 
00837 void
00838 VisG4VisSceneHandler::AddPrimitive (const G4NURBS &nurb)
00839 {
00840     // FIXME: Does G4 support NURB trimming?
00841     ASSERT (m_node);
00842     ASSERT (G4NURBS::NofC == 4);
00843     if (cached ()) return;
00844 
00845     // Knots and control points must be G4floats.
00846     std::vector<G4float> uknots (nurb.GetnbrKnots(G4NURBS::U), 0.);
00847     std::vector<G4float> vknots (nurb.GetnbrKnots(G4NURBS::V), 0.);
00848     std::vector<G4float> ctrls (nurb.GettotalnbrCtrlPts () * G4NURBS::NofC,0.);
00849 
00850     G4NURBS::KnotsIterator u (nurb, G4NURBS::U);
00851     for (int i = 0; u.pick (&uknots [i]); i++)
00852         ;
00853 
00854     G4NURBS::KnotsIterator v (nurb, G4NURBS::V);
00855     for (int i = 0; v.pick (&vknots [i]); i++)
00856         ;
00857     
00858     G4NURBS::CtrlPtsCoordsIterator c (nurb);
00859     for (int i = 0; c.pick (&ctrls [i]); i++)
00860         ;
00861   
00862     // Add owner
00863     SoSeparator *me = new SoSeparator;
00864     m_node->addChild (me);
00865 
00866     // Set up NURBS
00867     G4int n = nurb.GettotalnbrCtrlPts ();
00868     std::vector<SbVec4f> points (n, SbVec4f ());
00869     for (G4int i = 0, j = 0; i < n ; ++i, j += 4)
00870         points [i].setValue (ctrls[j+0], ctrls[j+1], ctrls[j+2], ctrls[j+3]);
00871 
00872     SoComplexity *complexity = new SoComplexity;
00873     complexity->value = 0.6;
00874     me->addChild (complexity);
00875 
00876     SoCoordinate4 *controls = new SoCoordinate4;
00877     controls->point.setValues (0, n, &points[0]);
00878     me->addChild (controls);
00879 
00880     SoNurbsSurface *surface = new SoNurbsSurface;
00881     surface->numUControlPoints = uknots.size ();
00882     surface->numVControlPoints = vknots.size ();
00883     surface->uKnotVector.setValues (0,uknots.size (), &uknots [0]);
00884     surface->vKnotVector.setValues (0,vknots.size (), &vknots [0]);
00885     me->addChild (surface);
00886     cache (me);
00887 }
00888 
00889 void
00890 VisG4VisSceneHandler::AddPrimitive (const G4Polymarker &object)
00891 {
00892     ASSERT (m_node);
00893     if (cached ()) return;
00894 
00895     SoSeparator *me = new SoSeparator;
00896     m_node->addChild (me);
00897 
00898     // Translate to object position
00899     addTranslation (me, object.GetPosition ());
00900 
00901     // Compute points
00902     std::vector<SbVec3f> points (object.size (), SbVec3f ());
00903     for (unsigned i = 0; i < object.size (); ++i)
00904         points [i].setValue (object [i].x(),
00905                              object [i].y(),
00906                              object [i].z());
00907 
00908     // Determine marker type and for circles and squares, subtype too.
00909     MarkerSizeType       type;
00910     G4VMarker::FillStyle fill = object.GetFillStyle ();
00911     double               size = GetMarkerSize (object, type);
00912     SoPointSet           *pset;
00913     SoMarkerSet          *mset;
00914     SoVertexProperty     *vtx;
00915     SoShape              *shape;
00916     SbVec3f              last (0, 0, 0);
00917 
00918     // Render
00919     switch (object.GetMarkerType ())
00920     {
00921     default:
00922     case G4Polymarker::dots:
00923         // Point set
00924         vtx = new SoVertexProperty;
00925         vtx->vertex.setValues (0, object.size (), &points[0]);
00926         pset = new SoPointSet;
00927         pset->numPoints = object.size ();
00928         pset->vertexProperty = vtx;
00929         me->addChild (pset);
00930         break;
00931 
00932     case G4Polymarker::circles:
00933     case G4Polymarker::squares:
00934         // A circle or square at each marker position.
00935         switch (type)
00936         {
00937         case screen:
00938             vtx = new SoVertexProperty;
00939             vtx->vertex.setValues (0, object.size (), &points[0]);
00940             mset = makeScreenMarker (object.GetMarkerType (), fill, size);
00941             mset->numPoints = object.size ();
00942             mset->vertexProperty = vtx;
00943             me->addChild (mset);
00944             break;
00945 
00946         case world:
00947             if (fill != G4VMarker::filled)
00948                 me->addChild (m_lines);
00949             shape = makeWorldMarker (object.GetMarkerType (), size);
00950             for (unsigned i = 0; i < object.size (); last = points [i++])
00951             {
00952                 addTranslation (me, points [i] - last);
00953                 me->addChild (shape);
00954             }
00955             break;
00956         }
00957         break;
00958     }
00959     cache (me);
00960 }
00961 
00965 SoMarkerSet *
00966 VisG4VisSceneHandler::makeScreenMarker (G4Polymarker::MarkerType type,
00967                                        G4VMarker::FillStyle fill,
00968                                        double size)
00969 {
00970     // FIXME: If the marker size is not in range, create our own
00971     // custom bitmap of the required type, and then use that for the
00972     // markers.  (Cf. G4 OpenGL viewer for related code!)
00973     //
00974     // FIXME: If drawing screen-size filled markers and point size not
00975     // in range for SoMarkerSet, fall back on bare SoPointSet with
00976     // appropriate point size + glDisable(GL_POINT_SMOOTH)?
00977     SoMarkerSet *mset = new SoMarkerSet;
00978     switch (type)
00979     {
00980     case G4Polymarker::circles:
00981         switch (fill)
00982         {
00983         case G4VMarker::noFill:
00984             mset->markerIndex
00985                 = size <= 2.5 ? SoMarkerSet::CIRCLE_LINE_5_5
00986                 : size <= 3.5 ? SoMarkerSet::CIRCLE_LINE_7_7
00987                 : SoMarkerSet::CIRCLE_LINE_9_9;
00988             break;
00989 
00990         case G4VMarker::hashed:
00991             mset->markerIndex
00992                 = size <= 2.5 ? SoMarkerSet::STAR_5_5
00993                 : size <= 3.5 ? SoMarkerSet::STAR_7_7
00994                 : SoMarkerSet::STAR_9_9;
00995             break;
00996 
00997         case G4VMarker::filled:
00998             mset->markerIndex
00999                 = size <= 2.5 ? SoMarkerSet::CIRCLE_FILLED_5_5
01000                 : size <= 3.5 ? SoMarkerSet::CIRCLE_FILLED_7_7
01001                 : SoMarkerSet::CIRCLE_FILLED_9_9;
01002             break;
01003         }
01004         return mset;
01005 
01006     case G4Polymarker::squares:
01007         switch (fill)
01008         {
01009         case G4VMarker::noFill:
01010             mset->markerIndex
01011                 = size <= 2.5 ? SoMarkerSet::SQUARE_LINE_5_5
01012                 : size <= 3.5 ? SoMarkerSet::SQUARE_LINE_7_7
01013                 : SoMarkerSet::SQUARE_LINE_9_9;
01014             break;
01015 
01016         case G4VMarker::hashed:
01017             mset->markerIndex
01018                 = size <= 2.5 ? SoMarkerSet::CROSS_5_5
01019                 : size <= 3.5 ? SoMarkerSet::CROSS_7_7
01020                 : SoMarkerSet::CROSS_9_9;
01021             break;
01022 
01023         case G4VMarker::filled:
01024             mset->markerIndex
01025                 = size <= 2.5 ? SoMarkerSet::SQUARE_FILLED_5_5
01026                 : size <= 3.5 ? SoMarkerSet::SQUARE_FILLED_7_7
01027                 : SoMarkerSet::SQUARE_FILLED_9_9;
01028             break;
01029         }
01030         return mset;
01031 
01032     default:
01033         ASSERT (false);
01034         return 0;
01035     }
01036 }
01037 
01038 SoShape *
01039 VisG4VisSceneHandler::makeWorldMarker (G4Polymarker::MarkerType type, double size)
01040 {
01041     SoSphere *sphere;
01042     SoCube   *cube;
01043 
01044     switch (type)
01045     {
01046     case G4Polymarker::circles:
01047         sphere = new SoSphere;
01048         sphere->radius = size;
01049         return sphere;
01050 
01051     case G4Polymarker::squares:
01052         cube = new SoCube;
01053         cube->width = size * 2;
01054         cube->height = size * 2;
01055         cube->depth = size * 2;
01056         return cube;
01057 
01058     default:
01059         ASSERT (false);
01060         return 0;
01061     }
01062 }
01063 
01067 double
01068 VisG4VisSceneHandler::GetMarkerSize (const G4VMarker &marker,
01069                                     MarkerSizeType &type)
01070 {
01071     // FIXME: fall back on default marker
01072     double size = marker.GetWorldSize ();
01073 
01074     if (size)
01075         // Draw in world coordinates.
01076         type = world;
01077     else
01078     {
01079         // Draw in screen coordinates.
01080         size = marker.GetScreenSize ();
01081         type = screen;
01082     }
01083 
01084     return (size <= 0. ? 1. : size);
01085     // FIXME: * fpViewer -> GetViewParameters().GetGlobalMarkerScale();
01086 }
01087 
01091 void
01092 VisG4VisSceneHandler::RequestPrimitives (const G4VSolid &solid)
01093 {
01094     if (m_fallback == G4ViewParameters::nurbs)
01095         if (G4NURBS *nurb = solid.CreateNURBS ())
01096         {
01097             AddPrimitive (*nurb);
01098             delete nurb;
01099             return;
01100         }
01101 
01102     // Failed or want polyhedron, keep going (FIXME: barf if fails).
01103     G4Polyhedron::SetNumberOfRotationSteps (m_sides);
01104     if (G4Polyhedron *polyh = solid.CreatePolyhedron ())
01105     {
01106         AddPrimitive (*polyh);
01107         delete polyh;
01108     }
01109     G4Polyhedron::ResetNumberOfRotationSteps ();
01110 }
01111 
01112 G4ViewParameters::DrawingStyle
01113 VisG4VisSceneHandler::GetDrawingStyle (const G4VisAttributes *attrs)
01114 {
01115     G4ViewParameters::DrawingStyle style = G4ViewParameters::hlhsr;
01116     if (attrs->IsForceDrawingStyle ())
01117         // This is complicated because if hidden line removal has been
01118         // requested we wish to preserve this.
01119         switch (attrs->GetForcedDrawingStyle ())
01120         {
01121         case G4VisAttributes::solid:
01122             switch (style)
01123             {
01124             case G4ViewParameters::hlr:
01125                 style = G4ViewParameters::hlhsr;
01126                 break;
01127             case G4ViewParameters::wireframe:
01128                 style = G4ViewParameters::hsr;
01129                 break;
01130             default:
01131                 break;
01132             } 
01133             break;
01134 
01135         default:
01136         case G4VisAttributes::wireframe:
01137             switch (style)
01138             {
01139             case G4ViewParameters::hlhsr:
01140                 style = G4ViewParameters::hlr;
01141                 break;
01142             case G4ViewParameters::hsr:
01143                 style = G4ViewParameters::wireframe;
01144                 break;
01145             default:
01146                 break;
01147             } 
01148             break;
01149         }
01150 
01151     return style;
01152 }
01153 
01157 void
01158 VisG4VisSceneHandler::PreAddSolid (const G4Transform3D &,const G4VisAttributes &)
01159 { ASSERT (false); }
01160 
01161 void
01162 VisG4VisSceneHandler::PostAddSolid (void)
01163 { ASSERT (false); }
01164 
01165 void
01166 VisG4VisSceneHandler::BeginPrimitives (const G4Transform3D &)
01167 { ASSERT (false); }
01168 
01169 void
01170 VisG4VisSceneHandler::EndPrimitives (void)
01171 { ASSERT (false); }

Generated on Tue Jun 9 17:50:06 2009 for CMSSW by  doxygen 1.5.4