00001 #ifndef VIS_G4_CORE_VIS_G4_VIS_SCENE_HANDLER_H 00002 # define VIS_G4_CORE_VIS_G4_VIS_SCENE_HANDLER_H 00003 00004 //<<<<<< INCLUDES >>>>>> 00005 00006 # include "VisGeant4/VisG4Core/interface/config.h" 00007 # include <G4VGraphicsScene.hh> 00008 # include <G4ViewParameters.hh> 00009 # include <G4VisExtent.hh> 00010 # include <G4Polymarker.hh> 00011 # include <G4VMarker.hh> 00012 # include <G4Material.hh> 00013 # include <stack> 00014 # include <map> 00015 00016 //<<<<<< PUBLIC DEFINES >>>>>> 00017 //<<<<<< PUBLIC CONSTANTS >>>>>> 00018 //<<<<<< PUBLIC TYPES >>>>>> 00019 00020 class VisG4VisSystem; 00021 class VisG4Path; 00022 class G4Visible; 00023 class G4VisAttributes; 00024 class SoSeparator; 00025 class SoNode; 00026 class SoGroup; 00027 class SoDrawStyle; 00028 class SoResetTransform; 00029 class SoMarkerSet; 00030 class SoMaterial; 00031 class SoShape; 00032 class SbVec3f; 00033 00034 //<<<<<< PUBLIC VARIABLES >>>>>> 00035 //<<<<<< PUBLIC FUNCTIONS >>>>>> 00036 //<<<<<< CLASS DECLARATIONS >>>>>> 00037 00038 /* A quick introduction to Geant 4 volumes 00039 00040 A LOGICAL VOLUME has a SOLID (which could be a complex object, such 00041 as a boolean solid). The logical volume also has a number of 00042 PHYSICAL daughter VOLUMEs, each of which has positions relative to 00043 the mother a logical volume. A single logical volume can be placed 00044 several times via several physical volumes (see pictures below). 00045 Normally all daughters of a logical volume are replicated in all 00046 copies of that logical volume, but as an exception a physical 00047 daughter may also have a PHYSICAL MOTHER, meaning that the daughter 00048 is a daughter of its logical mother only when the logical mother is 00049 being positioned by the given physical mother. (In other words, a 00050 daughter may appear in only one of the copies of its mother.) 00051 Finally, a physical daughter volume may be REPLICATED, resulting in 00052 multiple copies of its logical volume in several positions, or 00053 PARAMETRISED, resulting in a number of copies of the logical volume 00054 in arbitrary transforms and with arbitrary solids. */ 00055 00056 /* This is essentially a rewrite of the G4 visualisation framework. 00057 The principal reason for this is that as of G4 version 4.3.2, the 00058 G4 visualisation framework is unsuitable for interactive use, for 00059 two major reasons. 00060 00061 Firstly, the framework does not provide enough information about 00062 the processing of the volumes to allow the scene handler to map the 00063 representations it is creating to the original volume tree (it does 00064 provide information about the volumes it is processing, but not in 00065 a manner that allows the scene graph tree to be constructed). As a 00066 consequence, picking is not possible. It also makes it painful to 00067 try to reuse the representations like G4 does with logical volumes 00068 (but see below why we don't want to do this anyway). This same 00069 issue applies also to the event content (hits and trajectories). 00070 00071 Secondly, the G4 framework has not been designed for incremental 00072 rendering. We need to allow users to choose which parts of the 00073 detector and event are to be visualised, and with what parameters; 00074 each change of settings ought to allow for immediate change of the 00075 representation. With the existing support in G4 it is not easy to 00076 (re)process only a particular volume without disturbing the rest of 00077 the existing scene graph. 00078 00079 Therefore we have rewritten parts of the G4 visualisation framework 00080 in a way that matches our needs. */ 00081 00082 // FIXME: can't use G4 visualisation because the stuff below is far 00083 // too complicated to get to work reliably, and even then we can't do 00084 // things incrementally/interactively... 00085 00086 /* Try to determine what is going on: reuse nodes for a logical volume 00087 if possible, and build a scene graph for the nodes. For reuse, 00088 reposition the same solid representation several times (just as G4 00089 does with logical volumes). It is safe to not get the replication 00090 completely right, we'll just end up doing more work. However, the 00091 scene graph we do want to get right -- it is our primary output! 00092 00093 We need to distinguish between two situations: 1) we are still 00094 building the solid representation for the logical volume and 00095 `AddThis' should append to the current definition, and 2) the 00096 logical volume solid is complete and we should remember the new 00097 positioning for it (new path, replica, ...) but ignore calls to 00098 `AddThis'. For the latter case we need to be careful with 00099 boundaries so that we know when we should come out of the sharing 00100 mode (FIXME: just set CurtailDescent() to avoid processing the 00101 children!). 00102 00103 This is not simple to achieve -- G4 visualisation architecture only 00104 gives us limited information of what is going on. What we have is 00105 this: fpCurrentPV points to the current physical volume, 00106 fpCurrentLV to its logical volume, and PreAddThis, AddThis and 00107 PostAddThis are called for each solid in the logical volume. 00108 [FIXME: This ignores primitives drawn without solids, as 00109 G4VisManager::Draw via Begin/Add/EndPrimitives to draw event 00110 content (tracks and hits, with fReadyForTransients == true?), and 00111 stuff such as axes and text annotations. Do we prefer to do these 00112 independent of G4 -- do we want to support full visualisation or 00113 only ``useful'' parts of it?] 00114 00115 This method may be called several times in order to build the solid 00116 representation (without wrapping the calls in any way), 00117 unfortunately we cannot rely on recognising the last call to 00118 PostAddThis; this can happen for example with boolean solids. 00119 Replication has a similar issue: we are not being told when the 00120 logical volume of one replica ends and the next one begins; all we 00121 know is that we are still within the same physical/logical volume 00122 pair. On the other hand, a logical volume may be repeated several 00123 times (via several physical volume paths). 00124 00125 To deal with the above, we keep track of changes to the current 00126 physical volume. We know a physical volume's relationship to its 00127 mother is unique: it is a child of any logical mother only once (it 00128 may appear several times during the processing as the logical 00129 mother volume may be repeated several times). We also know that 00130 the solid of the logical mother is described fully before any of 00131 its daughters are described. Therefore, we compare the previous 00132 fpCurrentPV with the current one. If they are different, the 00133 previous solid has become complete and we've gone somewhere else in 00134 the tree; if we then re-encounter the logical volume, we should 00135 just reuse the old definition with a different transformation (and 00136 tell the processing to ignore the rest of the tree). If they are 00137 the same, we are encountering one of the following cases: 1) we are 00138 being fed the solids of a composite solid and get first the 00139 constituents and then whole complex solid, and `AddThis' should 00140 append to the current representation; 2) we are being fed a 00141 replicated physical volume whose logical volume has no daughters, 00142 and we should reuse the existing solid representation for the 00143 logical volume (the solid may follow the previous case!); 3) we are 00144 being fed a parametrised physical volume whose logical volume has 00145 no daughters, but the solid changes from one replica to another 00146 (and may follow the first case!). (NB: Not all combinations of 00147 parametrised volumes, solids and daughters are currently allowed, 00148 however the last case above already presents us one of the more 00149 difficult situations.) 00150 00151 Note that a replicated and/or parametrised physical volume can 00152 point to a logical volume with daughters. In that case the logical 00153 volume will be described in full for each replica, so we will see 00154 the current physical volume change; that is ok, we will 00155 automatically know to reuse the representations with new 00156 transformations. (FIXME: For a parametrised physical volume we 00157 assume that the solids are not changing if the logical volume has 00158 daughters. G4 does not seem to support parametrisations with 00159 daughters and varying solids anyway.) 00160 00161 The primary problem we tackle is the building of scene graph once 00162 we've detected which physical volume owns the nodes. Here we rely 00163 on the knowledge that the mother is always processed before its 00164 daughters. There is however a twist: the mother may be invisible 00165 and the daughters (perhaps several levels down) visible -- and we 00166 will not get invoked for the intermediate visible mothers. 00167 00168 If `fpCurrentPV' has changed, we discover exactly where it should 00169 be in the scene graph; we assume the client wants results organised 00170 by the volume tree. We also know that {FIXME]. 00171 00172 For now, we do nothing about replicated/parametrised physical 00173 volumes -- we do not have enough information to reuse the solid 00174 representations. We simply lump all the replicas together as the 00175 representation of the physical volume. 00176 00177 00178 [FIXME: this breaks with voxelisation?] [FIXME: what about 00179 end-of-event models (hits, trajectories) and axes? 00180 00181 [FIXME: currently (G4.3.2) visualises physical daughters that have 00182 physical mothers wrong: it always renders them. If corrected, 00183 would it change the logic here?] 00184 00185 (FIXME: do we detect the stacking order correctly? I.e. when to 00186 start and *stop* ignoring AddThis, once we've decided that we are 00187 ignoring a replica/already represented volume?) 00188 00189 00190 ------------------------------------------------------------ 00191 ASCII art diagram for a scenario that matters (sharing): 00192 00193 | LV 1 | -> / S 1 / 00194 | 00195 +- ( PV 1.1 ) --+> | LV 2 | -> / S 2 / 00196 +- ( PV 1.2 ) -' | 00197 +- ( PV 2.1 ) -> | LV 3 | -> / S 3 / 00198 00199 Processing order (note the indentantation is not explicit in 00200 the calls we get in any way!): 00201 < PV 0.1 / LV 1 / S1 > 00202 < PV 1.1 / LV 2 / S2 > 00203 < PV 2.1 / LV 3 / S3 > 00204 < PV 1.2 / LV 2 / S2 > 00205 < PV 2.1 / LV 3 / S3 > 00206 00207 DIAGNOSIS: *detectable*; note the change of PV and close the 00208 current representation when that happens. 00209 00210 00211 ------------------------------------------------------------ 00212 ASCII art diagram for a scenario that matters (csg replication): 00213 00214 | LV 1 | -> / S 1 / 00215 | 00216 +- ( PV 1.1 ) -(2x)-> | LV 2 | -> / S 2 / +-> / S 2.1 / 00217 +-> / S 2.2 / 00218 Processing order: 00219 < PV 0.1 / LV 1 / S1 > 00220 < PV 1.1 / LV 2 / S2.1 > 00221 < PV 1.1 / LV 2 / S2.2 > 00222 < PV 1.1 / LV 2 / S2 > 00223 < PV 1.1 / LV 2 / S2.1 > 00224 < PV 1.1 / LV 2 / S2.2 > 00225 < PV 1.1 / LV 2 / S2 > 00226 00227 DIAGNOSIS: *detectable*; note the call with the same solid as 00228 pointed to by LV (S2) to close the current replica rep. 00229 (FIXME: fragile -- what if the code changes!?) 00230 00231 00232 ------------------------------------------------------------ 00233 ASCII art diagram for a scenario that matters (parametrisation): 00234 00235 | LV 1 | -> / S 1 / 00236 | 00237 +- ( PV 1.1 ) -(2x)-> | LV 2 | -> / S 2 / 00238 00239 Processing order (Sn, Sm CSG solids generated by parametrisation): 00240 < PV 0.1 / LV 1 / S1 > 00241 < PV 1.1 / LV 2 / Sn.1 > 00242 < PV 1.1 / LV 2 / Sn.2 > 00243 < PV 1.1 / LV 2 / Sn > 00244 < PV 1.1 / LV 2 / Sm.1 > 00245 < PV 1.1 / LV 2 / Sm.2 > 00246 < PV 1.1 / LV 2 / Sm > 00247 00248 DIAGNOSIS: *undetectable*; merge all replicas together as the 00249 representation of the PV (if Sn == Sm == S2, this reduces to 00250 the previous case and is detectable). 00251 00252 ------------------------------------------------------------ 00253 FIXME: Can we prevent (or not support) the use of 00254 G4LogicalVolumeModel that causes the solid split? */ 00255 00256 // G4VPhysicalVolumeModel and G4VSceneHandler maintain two useful pointers: 00257 // `fpCurrentPV' and `fpCurrentLV' (and `fpCurrentDepth'): the current 00258 // physical and logical volume, respectively. We use these to map the 00259 // drawn primitives to the original volumes, and from there, the twig 00260 // representables. Once the view has been drawn, clients can query 00261 // the map we've built. (FIXME: Also use reuse replicated solids.) 00262 00263 // FIXME: Abuse G4VSceneHandler to grab solid representations. 00264 00265 // Note on the appearance and placement handling of primitives: 00266 // 00267 // Primitives may both be created from shape simplification and added 00268 // on their own right. We ignore primitive appearance and assume the 00269 // caller will invoke AddMaterial() and AddStyle() as appropriate -- 00270 // if the primitive is a result of shape simplification, this will 00271 // have happened; if the primitive is an object of its own, then the 00272 // caller must arrange for the suitable calls. On the contrary, we do 00273 // translate to the primitive position: we assume the caller has made 00274 // a compatible invocation to AddTransform() (= no call for globally 00275 // positioned primitives, and when one has already been added for a 00276 // shape, then its primitives don't get an extra one). 00277 00278 class VIS_G4_CORE_API VisG4VisSceneHandler : public G4VGraphicsScene 00279 { 00280 public: 00281 typedef G4ViewParameters::RepStyle RepStyle; 00282 typedef G4ViewParameters::DrawingStyle DrawStyle; 00283 00284 // implicit copy constructor 00285 // implicit destructor 00286 // implicit assignment operator 00287 00288 static VisG4VisSceneHandler *instance (void); 00289 00290 // Various settings 00291 virtual void defineFallback (RepStyle style); 00292 virtual void defineBounds (G4VisExtent bbox); 00293 virtual void defineNoOfSides (int sides); 00294 00295 // Cache management 00296 virtual void enableCache (bool enabled); 00297 virtual void clearCache (void); 00298 00299 // Delimiting objects. Wrap various add*() and Add*() calls inside these 00300 virtual void beginObject (SoSeparator *node,const void *object); 00301 virtual void endObject (void); 00302 00303 // Drawing attributes handling 00304 virtual void addStyle (const G4VisAttributes *from); 00305 virtual void addStyle (DrawStyle style); 00306 virtual void addMaterial (SoMaterial *mat); 00307 virtual void addTransform (const G4Transform3D &by); 00308 00309 // Solid handling 00310 virtual void AddSolid (const G4Box &solid); 00311 virtual void AddSolid (const G4Cons &solid); 00312 virtual void AddSolid (const G4Tubs &solid); 00313 virtual void AddSolid (const G4Trd &solid); 00314 virtual void AddSolid (const G4Trap &solid); 00315 virtual void AddSolid (const G4Sphere &solid); 00316 virtual void AddSolid (const G4Para &solid); 00317 virtual void AddSolid (const G4Torus &solid); 00318 virtual void AddSolid (const G4Polycone &solid); 00319 virtual void AddSolid (const G4Polyhedra &solid); 00320 virtual void AddSolid (const G4VSolid &solid); 00321 virtual void AddCompound (const G4VTrajectory &trajectory); 00322 virtual void AddCompound (const G4VHit &hit); 00323 00324 // Solid expansion and primitives 00325 virtual void AddPrimitive (const G4Polyline &object); 00326 virtual void AddPrimitive (const G4Scale &object); 00327 virtual void AddPrimitive (const G4Text &object); 00328 virtual void AddPrimitive (const G4Circle &object); 00329 virtual void AddPrimitive (const G4Square &object); 00330 virtual void AddPrimitive (const G4Polymarker &object); 00331 virtual void AddPrimitive (const G4Polyhedron &object); 00332 virtual void AddPrimitive (const G4NURBS &object); 00333 00334 private: 00335 typedef std::map<const void *, SoGroup *> NodeCache; 00336 typedef std::map<const G4Material *, SoMaterial *> MaterialCache; 00337 enum MarkerSizeType { world, screen }; 00338 00339 VisG4VisSceneHandler (void); 00340 virtual ~VisG4VisSceneHandler (void) {}; 00341 00342 void addTranslation (SoSeparator *to, const G4Point3D ¢er); 00343 void addTranslation (SoSeparator *to, SbVec3f center); 00344 00345 void RequestPrimitives (const G4VSolid &solid); 00346 double GetMarkerSize (const G4VMarker &mark); 00347 double GetMarkerSize (const G4VMarker &mark, 00348 MarkerSizeType &type); 00349 SoMarkerSet * makeScreenMarker (G4Polymarker::MarkerType type, 00350 G4VMarker::FillStyle fill, 00351 double size); 00352 SoShape * makeWorldMarker (G4Polymarker::MarkerType type, 00353 double size); 00354 00355 DrawStyle GetDrawingStyle (const G4Visible &); 00356 DrawStyle GetDrawingStyle (const G4VisAttributes *); 00357 // G4double GetMarkerDiameter (== Size), ...Radius (== Size/2) 00358 00359 // G4Colour GetColour (const G4Visible &); 00360 // G4Colour GetTextColour (const G4Text &); 00361 00362 void cacheBegin (const void *object); 00363 bool cached (void); 00364 void cache (SoNode *node); 00365 void cacheEnd (void); 00366 00367 SoSeparator *m_node; 00368 00369 NodeCache m_shapeCache; 00370 bool m_caching; 00371 bool m_cached; 00372 SoGroup *m_cacheNodes; 00373 int m_cacheIndex; 00374 00375 SoResetTransform *m_reset; 00376 SoDrawStyle *m_lines; 00377 SoDrawStyle *m_solid; 00378 MaterialCache m_materialCache; 00379 00380 RepStyle m_fallback; 00381 G4VisExtent m_bbox; 00382 int m_sides; 00383 double m_fontSize; 00384 00385 // Unsupported but required to be implemented to keep G4 happy. 00386 // Never use these, use BeginObject() end EndObject() instead. 00387 // Calling these will cause immediate termination. 00388 virtual void BeginPrimitives (const G4Transform3D &transform); 00389 virtual void PreAddSolid (const G4Transform3D &transform, 00390 const G4VisAttributes &attributes); 00391 virtual void PostAddSolid (void); 00392 virtual void EndPrimitives (void); 00393 virtual void BeginPrimitives2D () {} 00394 virtual void EndPrimitives2D (){} 00395 }; 00396 00397 //<<<<<< INLINE PUBLIC FUNCTIONS >>>>>> 00398 //<<<<<< INLINE MEMBER FUNCTIONS >>>>>> 00399 00400 #endif // VIS_G4_CORE_VIS_G4_VIS_SCENE_HANDLER_H