| File: | cvmfs/belle.cern.ch/el9/externals/v02-04-00/include/boost/algorithm/string/detail/classification.hpp |
| Warning: | line 141, column 17 Potential memory leak |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /************************************************************************** | |||
| 2 | * basf2 (Belle II Analysis Software Framework) * | |||
| 3 | * Author: The Belle II Collaboration * | |||
| 4 | * * | |||
| 5 | * See git log for contributors and copyright holders. * | |||
| 6 | * This file is licensed under LGPL-3.0, see LICENSE.md. * | |||
| 7 | **************************************************************************/ | |||
| 8 | ||||
| 9 | //For GFTrack visualisation: | |||
| 10 | /* Copyright 2011, Technische Universitaet Muenchen, | |||
| 11 | Author: Karl Bicker | |||
| 12 | ||||
| 13 | This file is part of GENFIT. | |||
| 14 | ||||
| 15 | GENFIT is free software: you can redistribute it and/or modify | |||
| 16 | it under the terms of the GNU Lesser General Public License as published | |||
| 17 | by the Free Software Foundation, either version 3 of the License, or | |||
| 18 | (at your option) any later version. | |||
| 19 | ||||
| 20 | GENFIT is distributed in the hope that it will be useful, | |||
| 21 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| 23 | GNU Lesser General Public License for more details. | |||
| 24 | ||||
| 25 | You should have received a copy of the GNU Lesser General Public License | |||
| 26 | along with GENFIT. If not, see <http://www.gnu.org/licenses/>. | |||
| 27 | */ | |||
| 28 | #include <display/EVEVisualization.h> | |||
| 29 | ||||
| 30 | #include <display/VisualRepMap.h> | |||
| 31 | #include <display/EveGeometry.h> | |||
| 32 | #include <display/EveVisBField.h> | |||
| 33 | #include <display/ObjectInfo.h> | |||
| 34 | ||||
| 35 | #include <vxd/geometry/GeoCache.h> | |||
| 36 | #include <klm/bklm/geometry/GeometryPar.h> | |||
| 37 | #include <cdc/geometry/CDCGeometryPar.h> | |||
| 38 | #include <cdc/dataobjects/CDCRecoHit.h> | |||
| 39 | #include <cdc/translators/RealisticTDCCountTranslator.h> | |||
| 40 | #include <arich/dbobjects/ARICHGeometryConfig.h> | |||
| 41 | #include <simulation/dataobjects/MCParticleTrajectory.h> | |||
| 42 | #include <svd/reconstruction/SVDRecoHit.h> | |||
| 43 | #include <top/geometry/TOPGeometryPar.h> | |||
| 44 | ||||
| 45 | #include <genfit/AbsMeasurement.h> | |||
| 46 | #include <genfit/PlanarMeasurement.h> | |||
| 47 | #include <genfit/SpacepointMeasurement.h> | |||
| 48 | #include <genfit/WireMeasurement.h> | |||
| 49 | #include <genfit/WireMeasurementNew.h> | |||
| 50 | #include <genfit/WirePointMeasurement.h> | |||
| 51 | #include <genfit/DetPlane.h> | |||
| 52 | #include <genfit/Exception.h> | |||
| 53 | #include <genfit/KalmanFitterInfo.h> | |||
| 54 | #include <genfit/GblFitterInfo.h> | |||
| 55 | ||||
| 56 | #include <framework/dataobjects/DisplayData.h> | |||
| 57 | #include <framework/logging/Logger.h> | |||
| 58 | #include <framework/utilities/ColorPalette.h> | |||
| 59 | #include <framework/geometry/VectorUtil.h> | |||
| 60 | ||||
| 61 | #include <Math/VectorUtil.h> | |||
| 62 | #include <TEveArrow.h> | |||
| 63 | #include <TEveBox.h> | |||
| 64 | #include <TEveCalo.h> | |||
| 65 | #include <TEveManager.h> | |||
| 66 | #include <TEveGeoShape.h> | |||
| 67 | #include <TEveLine.h> | |||
| 68 | #include <TEvePointSet.h> | |||
| 69 | #include <TEveSelection.h> | |||
| 70 | #include <TEveStraightLineSet.h> | |||
| 71 | #include <TEveTriangleSet.h> | |||
| 72 | #include <TEveText.h> | |||
| 73 | #include <TEveTrack.h> | |||
| 74 | #include <TEveTrackPropagator.h> | |||
| 75 | #include <TGeoEltu.h> | |||
| 76 | #include <TGeoMatrix.h> | |||
| 77 | #include <TGeoManager.h> | |||
| 78 | #include <TGeoSphere.h> | |||
| 79 | #include <TGeoTube.h> | |||
| 80 | #include <TGLLogicalShape.h> | |||
| 81 | #include <TParticle.h> | |||
| 82 | #include <TMath.h> | |||
| 83 | #include <TVectorD.h> | |||
| 84 | #include <TMatrixD.h> | |||
| 85 | #include <TMatrixDSymEigen.h> | |||
| 86 | ||||
| 87 | #include <boost/scoped_ptr.hpp> | |||
| 88 | #include <boost/algorithm/string/find.hpp> | |||
| 89 | #include <boost/algorithm/string/trim.hpp> | |||
| 90 | #include <boost/algorithm/string/classification.hpp> | |||
| 91 | ||||
| 92 | #include <cassert> | |||
| 93 | #include <cmath> | |||
| 94 | ||||
| 95 | using namespace Belle2; | |||
| 96 | using namespace Belle2::TangoPalette; | |||
| 97 | ||||
| 98 | namespace { | |||
| 99 | /** Destroys 'el', zeroes pointer. Supposed to also remove el from global lists, which 'delete el' would not. */ | |||
| 100 | template <class T> void destroyEveElement(T*& el) | |||
| 101 | { | |||
| 102 | if (!el) return; | |||
| 103 | if (el->GetDenyDestroy() > 1) | |||
| 104 | B2WARNING("destroyEveElement(): Element " << el->GetName() << " has unexpected refcount " << el->GetDenyDestroy())do { if (Belle2::LogSystem::Instance().isLevelEnabled(Belle2:: LogConfig::c_Warning, 0, "display")) { { LogVariableStream varStream ; varStream << "destroyEveElement(): Element " << el->GetName() << " has unexpected refcount " << el->GetDenyDestroy(); Belle2::LogSystem::Instance().sendMessage (Belle2::LogMessage(Belle2::LogConfig::c_Warning, std::move(varStream ), "display", __PRETTY_FUNCTION__, "display/src/EVEVisualization.cc" , 104, 0)); }; } } while(false); | |||
| 105 | ||||
| 106 | el->DecDenyDestroy(); //also deletes el when refcount <= 0 | |||
| 107 | el = nullptr; | |||
| 108 | } | |||
| 109 | ||||
| 110 | /** TEveGeoShape contains a TGeoShape and feels responsible for deletion; but TGeoShape is owned by global TGeoManager. | |||
| 111 | * | |||
| 112 | * What we want is deletion by TEve (after changing events), so we explicitly remove the object | |||
| 113 | * from TGeoManager's garbage collection list. (some objects might not be in the list because these | |||
| 114 | * things are horribly inconsistent. doesn't hurt to try though.) | |||
| 115 | */ | |||
| 116 | void fixGeoShapeRefCount(TEveGeoShape* eveshape) | |||
| 117 | { | |||
| 118 | TGeoShape* s = eveshape->GetShape(); | |||
| 119 | //Remove(obj) usually takes about 20us, but since usually s is at the end, we can shorten this | |||
| 120 | if (gGeoManager->GetListOfShapes()->Last() == s) | |||
| 121 | gGeoManager->GetListOfShapes()->RemoveAt(gGeoManager->GetListOfShapes()->GetLast()); | |||
| 122 | else | |||
| 123 | gGeoManager->GetListOfShapes()->Remove(s); | |||
| 124 | } | |||
| 125 | } | |||
| 126 | ||||
| 127 | const int EVEVisualization::c_recoHitColor = getTColorID("Orange", 1); | |||
| 128 | const int EVEVisualization::c_unassignedHitColor = getTColorID("Plum", 1); | |||
| 129 | const int EVEVisualization::c_trackColor = getTColorID("Sky Blue", 2); | |||
| 130 | const int EVEVisualization::c_recoTrackColor = getTColorID("Sky Blue", 1); | |||
| 131 | const int EVEVisualization::c_trackMarkerColor = getTColorID("Chameleon", 3); | |||
| 132 | const int EVEVisualization::c_klmClusterColor = getTColorID("Chameleon", 1); | |||
| 133 | ||||
| 134 | EVEVisualization::EVEVisualization(): | |||
| 135 | m_assignToPrimaries(false), | |||
| 136 | m_eclData(0), | |||
| 137 | m_bfield(new EveVisBField()) | |||
| 138 | { | |||
| 139 | setErrScale(); | |||
| 140 | ||||
| 141 | TGLLogicalShape::SetIgnoreSizeForCameraInterest(kTRUE); // Allows the visualization of the "small" error ellipsoid. | |||
| 142 | ||||
| 143 | //create new containers | |||
| 144 | m_trackpropagator = new TEveTrackPropagator(); | |||
| 145 | m_trackpropagator->IncDenyDestroy(); | |||
| 146 | m_trackpropagator->SetMagFieldObj(m_bfield, false); | |||
| 147 | m_trackpropagator->SetFitDaughters(false); //most secondaries are no longer immediate daughters since we might discard those! | |||
| 148 | m_trackpropagator->SetMaxR(EveGeometry::getMaxR()); //don't draw tracks outside detector | |||
| 149 | //TODO is this actually needed? | |||
| 150 | m_trackpropagator->SetMaxStep(1.0); //make sure to reeval magnetic field often enough | |||
| 151 | ||||
| 152 | m_tracklist = new TEveTrackList(m_trackpropagator); | |||
| 153 | m_tracklist->IncDenyDestroy(); | |||
| 154 | m_tracklist->SetName("MCParticles"); | |||
| 155 | m_tracklist->SelectByP(c_minPCut, FLT_MAX3.40282347e+38F); //don't show too many particles by default... | |||
| 156 | ||||
| 157 | m_gftrackpropagator = new TEveTrackPropagator(); | |||
| 158 | m_gftrackpropagator->IncDenyDestroy(); | |||
| 159 | m_gftrackpropagator->SetMagFieldObj(m_bfield, false); | |||
| 160 | m_gftrackpropagator->SetMaxOrbs(0.5); //stop after track markers | |||
| 161 | ||||
| 162 | m_consttrackpropagator = new TEveTrackPropagator(); | |||
| 163 | m_consttrackpropagator->IncDenyDestroy(); | |||
| 164 | m_consttrackpropagator->SetMagField(0, 0, -1.5); | |||
| 165 | m_consttrackpropagator->SetMaxR(EveGeometry::getMaxR()); | |||
| 166 | ||||
| 167 | m_calo3d = new TEveCalo3D(NULL__null, "ECLClusters"); | |||
| 168 | m_calo3d->SetBarrelRadius(125.80); //inner radius of ECL barrel | |||
| 169 | m_calo3d->SetForwardEndCapPos(196.5); //inner edge of forward endcap | |||
| 170 | m_calo3d->SetBackwardEndCapPos(-102.0); //inner edge of backward endcap | |||
| 171 | m_calo3d->SetMaxValAbs(2.1); | |||
| 172 | m_calo3d->SetRnrFrame(false, false); //don't show crystal grid | |||
| 173 | m_calo3d->IncDenyDestroy(); | |||
| 174 | ||||
| 175 | //Stop eve from deleting contents... (which might already be deleted) | |||
| 176 | gEve->GetSelection()->IncDenyDestroy(); | |||
| 177 | gEve->GetHighlight()->IncDenyDestroy(); | |||
| 178 | ||||
| 179 | clearEvent(); | |||
| 180 | } | |||
| 181 | ||||
| 182 | void EVEVisualization::setOptions(const std::string& opts) { m_options = opts; } | |||
| 183 | ||||
| 184 | void EVEVisualization::setErrScale(double errScale) { m_errorScale = errScale; } | |||
| 185 | ||||
| 186 | EVEVisualization::~EVEVisualization() | |||
| 187 | { | |||
| 188 | if (!gEve) | |||
| 189 | return; //objects are probably already freed by Eve | |||
| 190 | ||||
| 191 | //Eve objects | |||
| 192 | destroyEveElement(m_eclData); | |||
| 193 | destroyEveElement(m_unassignedRecoHits); | |||
| 194 | destroyEveElement(m_tracklist); | |||
| 195 | destroyEveElement(m_trackpropagator); | |||
| 196 | destroyEveElement(m_gftrackpropagator); | |||
| 197 | destroyEveElement(m_consttrackpropagator); | |||
| 198 | destroyEveElement(m_calo3d); | |||
| 199 | delete m_bfield; | |||
| 200 | } | |||
| 201 | ||||
| 202 | void EVEVisualization::addTrackCandidate(const std::string& collectionName, | |||
| 203 | const RecoTrack& recoTrack) | |||
| 204 | { | |||
| 205 | const TString label = ObjectInfo::getIdentifier(&recoTrack); | |||
| 206 | // parse the option string ------------------------------------------------------------------------ | |||
| 207 | bool drawHits = false; | |||
| 208 | ||||
| 209 | if (m_options != "") { | |||
| 210 | for (size_t i = 0; i < m_options.length(); i++) { | |||
| 211 | if (m_options.at(i) == 'H') drawHits = true; | |||
| 212 | } | |||
| 213 | } | |||
| 214 | // finished parsing the option string ------------------------------------------------------------- | |||
| 215 | ||||
| 216 | ||||
| 217 | //track seeds | |||
| 218 | const B2Vector3D& track_pos = recoTrack.getPositionSeed(); | |||
| 219 | const B2Vector3D& track_mom = recoTrack.getMomentumSeed(); | |||
| 220 | ||||
| 221 | TEveStraightLineSet* lines = new TEveStraightLineSet("RecoHits for " + label); | |||
| 222 | lines->SetMainColor(c_recoTrackColor); | |||
| 223 | lines->SetMarkerColor(c_recoTrackColor); | |||
| 224 | lines->SetMarkerStyle(6); | |||
| 225 | lines->SetMainTransparency(60); | |||
| 226 | ||||
| 227 | if (drawHits) { | |||
| 228 | // Loop over all hits in the track (three different types) | |||
| 229 | for (const RecoHitInformation::UsedPXDHit* pxdHit : recoTrack.getPXDHitList()) { | |||
| 230 | addRecoHit(pxdHit, lines); | |||
| 231 | } | |||
| 232 | ||||
| 233 | for (const RecoHitInformation::UsedSVDHit* svdHit : recoTrack.getSVDHitList()) { | |||
| 234 | addRecoHit(svdHit, lines); | |||
| 235 | } | |||
| 236 | ||||
| 237 | for (const RecoHitInformation::UsedCDCHit* cdcHit : recoTrack.getCDCHitList()) { | |||
| 238 | addRecoHit(cdcHit, lines); | |||
| 239 | } | |||
| 240 | } | |||
| 241 | ||||
| 242 | TEveRecTrack rectrack; | |||
| 243 | rectrack.fP.Set(track_mom); | |||
| 244 | rectrack.fV.Set(track_pos); | |||
| 245 | ||||
| 246 | TEveTrack* track_lines = new TEveTrack(&rectrack, m_gftrackpropagator); | |||
| 247 | track_lines->SetName(label); //popup label set at end of function | |||
| 248 | track_lines->SetPropagator(m_gftrackpropagator); | |||
| 249 | track_lines->SetLineColor(c_recoTrackColor); | |||
| 250 | track_lines->SetLineWidth(1); | |||
| 251 | track_lines->SetTitle(ObjectInfo::getTitle(&recoTrack)); | |||
| 252 | ||||
| 253 | track_lines->SetCharge((int)recoTrack.getChargeSeed()); | |||
| 254 | ||||
| 255 | ||||
| 256 | track_lines->AddElement(lines); | |||
| 257 | addToGroup(collectionName, track_lines); | |||
| 258 | addObject(&recoTrack, track_lines); | |||
| 259 | } | |||
| 260 | ||||
| 261 | void EVEVisualization::addTrackCandidateImproved(const std::string& collectionName, | |||
| 262 | const RecoTrack& recoTrack) | |||
| 263 | { | |||
| 264 | const TString label = ObjectInfo::getIdentifier(&recoTrack); | |||
| 265 | // parse the option string ------------------------------------------------------------------------ | |||
| 266 | bool drawHits = false; | |||
| 267 | ||||
| 268 | if (m_options != "") { | |||
| 269 | for (size_t i = 0; i < m_options.length(); i++) { | |||
| 270 | if (m_options.at(i) == 'H') drawHits = true; | |||
| 271 | } | |||
| 272 | } | |||
| 273 | // finished parsing the option string ------------------------------------------------------------- | |||
| 274 | ||||
| 275 | // Create a track as a polyline through reconstructed points | |||
| 276 | // FIXME this is snatched from PrimitivePlotter, need to add extrapolation out of CDC | |||
| 277 | TEveLine* track = new TEveLine(); // We are going to just add points with SetNextPoint | |||
| 278 | std::vector<ROOT::Math::XYZVector> posPoints; // But first we'll have to sort them as in RecoHits axial and stereo come in blocks | |||
| 279 | track->SetName(label); //popup label set at end of function | |||
| 280 | track->SetLineColor(c_recoTrackColor); | |||
| 281 | track->SetLineWidth(3); | |||
| 282 | track->SetTitle(ObjectInfo::getTitle(&recoTrack)); | |||
| 283 | track->SetSmooth(true); | |||
| 284 | ||||
| 285 | for (const auto recoHit : recoTrack.getRecoHitInformations()) { | |||
| 286 | // skip for reco hits which have not been used in the fit (and therefore have no fitted information on the plane | |||
| 287 | if (!recoHit->useInFit()) | |||
| 288 | continue; | |||
| 289 | ||||
| 290 | // Need TVector3 here for genfit interface below | |||
| 291 | TVector3 pos; | |||
| 292 | TVector3 mom; | |||
| 293 | TMatrixDSym cov; | |||
| 294 | ||||
| 295 | try { | |||
| 296 | const auto* trackPoint = recoTrack.getCreatedTrackPoint(recoHit); | |||
| 297 | const auto* fittedResult = trackPoint->getFitterInfo(); | |||
| 298 | if (not fittedResult) { | |||
| 299 | B2WARNING("Skipping unfitted track point")do { if (Belle2::LogSystem::Instance().isLevelEnabled(Belle2:: LogConfig::c_Warning, 0, "display")) { { LogVariableStream varStream ; varStream << "Skipping unfitted track point"; Belle2:: LogSystem::Instance().sendMessage(Belle2::LogMessage(Belle2:: LogConfig::c_Warning, std::move(varStream), "display", __PRETTY_FUNCTION__ , "display/src/EVEVisualization.cc", 299, 0)); }; } } while(false ); | |||
| 300 | continue; | |||
| 301 | } | |||
| 302 | const genfit::MeasuredStateOnPlane& state = fittedResult->getFittedState(); | |||
| 303 | state.getPosMomCov(pos, mom, cov); | |||
| 304 | } catch (const genfit::Exception&) { | |||
| 305 | B2WARNING("Skipping state with strange pos, mom or cov")do { if (Belle2::LogSystem::Instance().isLevelEnabled(Belle2:: LogConfig::c_Warning, 0, "display")) { { LogVariableStream varStream ; varStream << "Skipping state with strange pos, mom or cov" ; Belle2::LogSystem::Instance().sendMessage(Belle2::LogMessage (Belle2::LogConfig::c_Warning, std::move(varStream), "display" , __PRETTY_FUNCTION__, "display/src/EVEVisualization.cc", 305 , 0)); }; } } while(false); | |||
| 306 | continue; | |||
| 307 | } | |||
| 308 | ||||
| 309 | posPoints.push_back(ROOT::Math::XYZVector(pos.X(), pos.Y(), pos.Z())); | |||
| 310 | } | |||
| 311 | ||||
| 312 | sort(posPoints.begin(), posPoints.end(), | |||
| 313 | [](const ROOT::Math::XYZVector & a, const ROOT::Math::XYZVector & b) -> bool { | |||
| 314 | return a.X() * a.X() + a.Y() * a.Y() > b.X() * b.X() + b.Y() * b.Y(); | |||
| 315 | }); | |||
| 316 | for (auto vec : posPoints) { | |||
| 317 | track->SetNextPoint(vec.X(), vec.Y(), vec.Z()); | |||
| 318 | } | |||
| 319 | // add corresponding hits --------------------------------------------------------------------- | |||
| 320 | TEveStraightLineSet* lines = new TEveStraightLineSet("RecoHits for " + label); | |||
| 321 | lines->SetMainColor(c_recoTrackColor); | |||
| 322 | lines->SetMarkerColor(c_recoTrackColor); | |||
| 323 | lines->SetMarkerStyle(6); | |||
| 324 | lines->SetMainTransparency(60); | |||
| 325 | ||||
| 326 | if (drawHits) { | |||
| 327 | // Loop over all hits in the track (three different types) | |||
| 328 | for (const RecoHitInformation::UsedPXDHit* pxdHit : recoTrack.getPXDHitList()) { | |||
| 329 | addRecoHit(pxdHit, lines); | |||
| 330 | } | |||
| 331 | ||||
| 332 | for (const RecoHitInformation::UsedSVDHit* svdHit : recoTrack.getSVDHitList()) { | |||
| 333 | addRecoHit(svdHit, lines); | |||
| 334 | } | |||
| 335 | ||||
| 336 | for (const RecoHitInformation::UsedCDCHit* cdcHit : recoTrack.getCDCHitList()) { | |||
| 337 | addRecoHit(cdcHit, lines); | |||
| 338 | } | |||
| 339 | } | |||
| 340 | ||||
| 341 | track->AddElement(lines); | |||
| 342 | addToGroup(collectionName, track); | |||
| 343 | addObject(&recoTrack, track); | |||
| 344 | } | |||
| 345 | ||||
| 346 | ||||
| 347 | /** Add a CDCTriggerTrack or CDCTrigger3DHTrack. */ | |||
| 348 | template <typename TriggerTrack> | |||
| 349 | void EVEVisualization::addCDCTriggerTrack(const std::string& collectionName, | |||
| 350 | const TriggerTrack& trgTrack) | |||
| 351 | { | |||
| 352 | const TString label = ObjectInfo::getIdentifier(&trgTrack); | |||
| 353 | ||||
| 354 | B2Vector3D track_pos(0, 0, trgTrack.getZ0()); | |||
| 355 | B2Vector3D track_mom = (trgTrack.getChargeSign() == 0) ? | |||
| 356 | trgTrack.getDirection() * 1000 : | |||
| 357 | trgTrack.getMomentum(1.5); | |||
| 358 | ||||
| 359 | TEveRecTrack rectrack; | |||
| 360 | rectrack.fP.Set(track_mom); | |||
| 361 | rectrack.fV.Set(track_pos); | |||
| 362 | ||||
| 363 | TEveTrack* track_lines = new TEveTrack(&rectrack, m_consttrackpropagator); | |||
| 364 | track_lines->SetName(label); // popup label set at end of function | |||
| 365 | track_lines->SetPropagator(m_consttrackpropagator); | |||
| 366 | track_lines->SetLineColor(kOrange + 2); | |||
| 367 | track_lines->SetLineWidth(1); | |||
| 368 | ||||
| 369 | track_lines->SetTitle(ObjectInfo::getTitle(&trgTrack) + | |||
| 370 | TString::Format("\ncharge: %d, phi: %.2fdeg, pt: %.2fGeV, theta: %.2fdeg, z: %.2fcm", | |||
| 371 | trgTrack.getChargeSign(), | |||
| 372 | trgTrack.getPhi0() * 180 / M_PI3.14159265358979323846, | |||
| 373 | trgTrack.getTransverseMomentum(1.5), | |||
| 374 | trgTrack.getDirection().Theta() * 180 / M_PI3.14159265358979323846, | |||
| 375 | trgTrack.getZ0())); | |||
| 376 | ||||
| 377 | track_lines->SetCharge(trgTrack.getChargeSign()); | |||
| 378 | ||||
| 379 | // show 2D tracks with dashed lines | |||
| 380 | if (trgTrack.getZ0() == 0 && trgTrack.getCotTheta() == 0) | |||
| 381 | track_lines->SetLineStyle(2); | |||
| 382 | ||||
| 383 | addToGroup(collectionName, track_lines); | |||
| 384 | addObject(&trgTrack, track_lines); | |||
| 385 | } | |||
| 386 | ||||
| 387 | template void EVEVisualization::addCDCTriggerTrack<CDCTriggerTrack>( | |||
| 388 | const std::string&, const CDCTriggerTrack&); | |||
| 389 | ||||
| 390 | template void EVEVisualization::addCDCTriggerTrack<CDCTrigger3DHTrack>( | |||
| 391 | const std::string&, const CDCTrigger3DHTrack&); | |||
| 392 | ||||
| 393 | void EVEVisualization::addTrack(const Belle2::Track* belle2Track) | |||
| 394 | { | |||
| 395 | // load the pion fit hypothesis or the hypothesis which is the closest in mass to a pion | |||
| 396 | // the tracking will not always successfully fit with a pion hypothesis | |||
| 397 | const TrackFitResult* fitResult = belle2Track->getTrackFitResultWithClosestMass(Const::pion); | |||
| 398 | if (!fitResult) { | |||
| 399 | B2ERROR("Track without TrackFitResult skipped.")do { { LogVariableStream varStream; varStream << "Track without TrackFitResult skipped." ; Belle2::LogSystem::Instance().sendMessage(Belle2::LogMessage (Belle2::LogConfig::c_Error, std::move(varStream), "display", __PRETTY_FUNCTION__, "display/src/EVEVisualization.cc", 399, 0)); } } while(false); | |||
| 400 | return; | |||
| 401 | } | |||
| 402 | const RecoTrack* track = belle2Track->getRelated<RecoTrack>(); | |||
| 403 | ||||
| 404 | const TString label = ObjectInfo::getIdentifier(belle2Track) + " (" + ObjectInfo::getIdentifier(fitResult) + ")"; | |||
| 405 | ||||
| 406 | // parse the option string ------------------------------------------------------------------------ | |||
| 407 | bool drawDetectors = false; | |||
| 408 | bool drawHits = false; | |||
| 409 | bool drawPlanes = false; | |||
| 410 | ||||
| 411 | if (m_options != "") { | |||
| 412 | for (size_t i = 0; i < m_options.length(); i++) { | |||
| 413 | if (m_options.at(i) == 'D') drawDetectors = true; | |||
| 414 | if (m_options.at(i) == 'H') drawHits = true; | |||
| 415 | if (m_options.at(i) == 'P') drawPlanes = true; | |||
| 416 | } | |||
| 417 | } | |||
| 418 | // finished parsing the option string ------------------------------------------------------------- | |||
| 419 | ||||
| 420 | // We loop over all points (scattering non-measurement points for GBL) | |||
| 421 | // and for Kalman we skip those with no measurements, which should | |||
| 422 | // not be there | |||
| 423 | bool isPruned = (track == nullptr); | |||
| 424 | ||||
| 425 | ||||
| 426 | TEveRecTrackD recTrack; | |||
| 427 | const B2Vector3D& poca = fitResult->getPosition(); | |||
| 428 | recTrack.fV.Set(poca); | |||
| 429 | ||||
| 430 | const B2Vector3D& poca_momentum = fitResult->getMomentum(); | |||
| 431 | if (std::isfinite(poca_momentum.Mag())) | |||
| 432 | recTrack.fP.Set(poca_momentum); | |||
| 433 | else //use 1TeV momentum for tracks without curvature | |||
| 434 | recTrack.fP.Set(B2Vector3D(fitResult->getHelix().getDirection() * 1000)); | |||
| 435 | ||||
| 436 | recTrack.fSign = fitResult->getChargeSign(); | |||
| 437 | TEveTrack* eveTrack = new TEveTrack(&recTrack, m_gftrackpropagator); | |||
| 438 | eveTrack->SetName(label); | |||
| 439 | ||||
| 440 | ||||
| 441 | if (track) { | |||
| 442 | const genfit::AbsTrackRep* representation; | |||
| 443 | ||||
| 444 | if (m_drawCardinalRep) { | |||
| 445 | representation = track->getCardinalRepresentation(); | |||
| 446 | B2DEBUG(100, "Draw cardinal rep")do { if (Belle2::LogSystem::debugEnabled()) do { if (Belle2:: LogSystem::Instance().isLevelEnabled(Belle2::LogConfig::c_Debug , 100, "display")) { { LogVariableStream varStream; varStream << "Draw cardinal rep"; Belle2::LogSystem::Instance(). sendMessage(Belle2::LogMessage(Belle2::LogConfig::c_Debug, std ::move(varStream), "display", __PRETTY_FUNCTION__, "display/src/EVEVisualization.cc" , 446, 100)); }; } } while(false); } while(false); | |||
| 447 | } else { | |||
| 448 | const auto& representations = track->getRepresentations(); | |||
| 449 | if (representations.empty()) { | |||
| 450 | B2ERROR("No representations found in the reco track!")do { { LogVariableStream varStream; varStream << "No representations found in the reco track!" ; Belle2::LogSystem::Instance().sendMessage(Belle2::LogMessage (Belle2::LogConfig::c_Error, std::move(varStream), "display", __PRETTY_FUNCTION__, "display/src/EVEVisualization.cc", 450, 0)); } } while(false); | |||
| 451 | return; | |||
| 452 | } | |||
| 453 | B2DEBUG(100, "Draw representation number 0.")do { if (Belle2::LogSystem::debugEnabled()) do { if (Belle2:: LogSystem::Instance().isLevelEnabled(Belle2::LogConfig::c_Debug , 100, "display")) { { LogVariableStream varStream; varStream << "Draw representation number 0."; Belle2::LogSystem:: Instance().sendMessage(Belle2::LogMessage(Belle2::LogConfig:: c_Debug, std::move(varStream), "display", __PRETTY_FUNCTION__ , "display/src/EVEVisualization.cc", 453, 100)); }; } } while (false); } while(false); | |||
| 454 | representation = representations.front(); | |||
| 455 | } | |||
| 456 | ||||
| 457 | if (!track->hasTrackFitStatus(representation)) { | |||
| 458 | B2ERROR("RecoTrack without FitStatus: will be skipped!")do { { LogVariableStream varStream; varStream << "RecoTrack without FitStatus: will be skipped!" ; Belle2::LogSystem::Instance().sendMessage(Belle2::LogMessage (Belle2::LogConfig::c_Error, std::move(varStream), "display", __PRETTY_FUNCTION__, "display/src/EVEVisualization.cc", 458, 0)); } } while(false); | |||
| 459 | return; | |||
| 460 | } | |||
| 461 | ||||
| 462 | const genfit::FitStatus* fitStatus = track->getTrackFitStatus(representation); | |||
| 463 | ||||
| 464 | isPruned = fitStatus->isTrackPruned(); | |||
| 465 | ||||
| 466 | // GBL and Kalman cannot mix in a track. | |||
| 467 | // What is 0 after first loop will stay 0: | |||
| 468 | genfit::KalmanFitterInfo* fi = 0; | |||
| 469 | genfit::KalmanFitterInfo* prevFi = 0; | |||
| 470 | genfit::GblFitterInfo* gfi = 0; | |||
| 471 | genfit::GblFitterInfo* prevGFi = 0; | |||
| 472 | const genfit::MeasuredStateOnPlane* fittedState(NULL__null); | |||
| 473 | const genfit::MeasuredStateOnPlane* prevFittedState(NULL__null); | |||
| 474 | ||||
| 475 | ||||
| 476 | const auto& hitPoints = track->getHitPointsWithMeasurement(); | |||
| 477 | const unsigned int numpoints = hitPoints.size(); | |||
| 478 | ||||
| 479 | int hitCounter = -1; | |||
| 480 | for (const genfit::TrackPoint* tp : hitPoints) { // loop over all points in the track | |||
| 481 | hitCounter++; | |||
| 482 | ||||
| 483 | // get the fitter infos ------------------------------------------------------------------ | |||
| 484 | if (! tp->hasFitterInfo(representation)) { | |||
| 485 | B2ERROR("trackPoint has no fitterInfo for rep")do { { LogVariableStream varStream; varStream << "trackPoint has no fitterInfo for rep" ; Belle2::LogSystem::Instance().sendMessage(Belle2::LogMessage (Belle2::LogConfig::c_Error, std::move(varStream), "display", __PRETTY_FUNCTION__, "display/src/EVEVisualization.cc", 485, 0)); } } while(false); | |||
| 486 | continue; | |||
| 487 | } | |||
| 488 | ||||
| 489 | genfit::AbsFitterInfo* fitterInfo = tp->getFitterInfo(representation); | |||
| 490 | ||||
| 491 | fi = dynamic_cast<genfit::KalmanFitterInfo*>(fitterInfo); | |||
| 492 | gfi = dynamic_cast<genfit::GblFitterInfo*>(fitterInfo); | |||
| 493 | ||||
| 494 | if (!gfi && !fi) { | |||
| 495 | B2ERROR("Can only display KalmanFitterInfo or GblFitterInfo")do { { LogVariableStream varStream; varStream << "Can only display KalmanFitterInfo or GblFitterInfo" ; Belle2::LogSystem::Instance().sendMessage(Belle2::LogMessage (Belle2::LogConfig::c_Error, std::move(varStream), "display", __PRETTY_FUNCTION__, "display/src/EVEVisualization.cc", 495, 0)); } } while(false); | |||
| 496 | continue; | |||
| 497 | } | |||
| 498 | ||||
| 499 | if (gfi && fi) | |||
| 500 | B2FATAL("AbsFitterInfo dynamic-casted to both KalmanFitterInfo and GblFitterInfo!")do { { LogVariableStream varStream; varStream << "AbsFitterInfo dynamic-casted to both KalmanFitterInfo and GblFitterInfo!" ; Belle2::LogSystem::Instance().sendMessage(Belle2::LogMessage (Belle2::LogConfig::c_Fatal, std::move(varStream), "display", __PRETTY_FUNCTION__, "display/src/EVEVisualization.cc", 500, 0)); }; exit(1); } while(false); | |||
| 501 | ||||
| 502 | ||||
| 503 | if (fi && ! tp->hasRawMeasurements()) { | |||
| 504 | B2ERROR("trackPoint has no raw measurements")do { { LogVariableStream varStream; varStream << "trackPoint has no raw measurements" ; Belle2::LogSystem::Instance().sendMessage(Belle2::LogMessage (Belle2::LogConfig::c_Error, std::move(varStream), "display", __PRETTY_FUNCTION__, "display/src/EVEVisualization.cc", 504, 0)); } } while(false); | |||
| 505 | continue; | |||
| 506 | } | |||
| 507 | ||||
| 508 | if (fi && ! fi->hasPredictionsAndUpdates()) { | |||
| 509 | B2ERROR("KalmanFitterInfo does not have all predictions and updates")do { { LogVariableStream varStream; varStream << "KalmanFitterInfo does not have all predictions and updates" ; Belle2::LogSystem::Instance().sendMessage(Belle2::LogMessage (Belle2::LogConfig::c_Error, std::move(varStream), "display", __PRETTY_FUNCTION__, "display/src/EVEVisualization.cc", 509, 0)); } } while(false); | |||
| 510 | continue; | |||
| 511 | } | |||
| 512 | ||||
| 513 | try { | |||
| 514 | if (gfi) | |||
| 515 | fittedState = &(gfi->getFittedState(true)); | |||
| 516 | if (fi) | |||
| 517 | fittedState = &(fi->getFittedState(true)); | |||
| 518 | } catch (genfit::Exception& e) { | |||
| 519 | B2ERROR(e.what() << " - can not get fitted state")do { { LogVariableStream varStream; varStream << e.what () << " - can not get fitted state"; Belle2::LogSystem:: Instance().sendMessage(Belle2::LogMessage(Belle2::LogConfig:: c_Error, std::move(varStream), "display", __PRETTY_FUNCTION__ , "display/src/EVEVisualization.cc", 519, 0)); } } while(false ); | |||
| 520 | continue; | |||
| 521 | } | |||
| 522 | ||||
| 523 | ROOT::Math::XYZVector track_pos = ROOT::Math::XYZVector(representation->getPos(*fittedState)); | |||
| 524 | ||||
| 525 | // draw track if corresponding option is set ------------------------------------------ | |||
| 526 | if (prevFittedState != NULL__null) { | |||
| 527 | ||||
| 528 | TEvePathMark::EType_e markType = TEvePathMark::kReference; | |||
| 529 | if (hitCounter + 1 == static_cast<int>(numpoints)) //track should stop here. | |||
| 530 | markType = TEvePathMark::kDecay; | |||
| 531 | ||||
| 532 | // Kalman: non-null prevFi ensures that the previous fitter info was also KalmanFitterInfo | |||
| 533 | if (fi && prevFi) { | |||
| 534 | makeLines(eveTrack, prevFittedState, fittedState, representation, markType, m_drawErrors); | |||
| 535 | if (m_drawErrors) { // make sure to draw errors in both directions | |||
| 536 | makeLines(eveTrack, prevFittedState, fittedState, representation, markType, m_drawErrors, 0); | |||
| 537 | } | |||
| 538 | //these are currently disabled. | |||
| 539 | //TODO: if activated, I want to have a separate TEveStraightLineSet instead of eveTrack (different colors/options) | |||
| 540 | if (m_drawForward) | |||
| 541 | makeLines(eveTrack, prevFi->getForwardUpdate(), fi->getForwardPrediction(), representation, markType, m_drawErrors, 0); | |||
| 542 | if (m_drawBackward) | |||
| 543 | makeLines(eveTrack, prevFi->getBackwardPrediction(), fi->getBackwardUpdate(), representation, markType, m_drawErrors); | |||
| 544 | // draw reference track if corresponding option is set ------------------------------------------ | |||
| 545 | if (m_drawRefTrack && fi->hasReferenceState() && prevFi->hasReferenceState()) | |||
| 546 | makeLines(eveTrack, prevFi->getReferenceState(), fi->getReferenceState(), representation, markType, false); | |||
| 547 | } | |||
| 548 | ||||
| 549 | // GBL: non-null prevGFi ensures that the previous fitter info was also GblFitterInfo | |||
| 550 | if (gfi && prevGFi) { | |||
| 551 | makeLines(eveTrack, prevFittedState, fittedState, representation, markType, m_drawErrors); | |||
| 552 | if (m_drawErrors) { | |||
| 553 | makeLines(eveTrack, prevFittedState, fittedState, representation, markType, m_drawErrors, 0); | |||
| 554 | } | |||
| 555 | ||||
| 556 | if (m_drawRefTrack && gfi->hasReferenceState() && prevGFi->hasReferenceState()) { | |||
| 557 | genfit::StateOnPlane prevSop = prevGFi->getReferenceState(); | |||
| 558 | genfit::StateOnPlane sop = gfi->getReferenceState(); | |||
| 559 | makeLines(eveTrack, &prevSop, &sop, representation, markType, false); | |||
| 560 | } | |||
| 561 | } | |||
| 562 | ||||
| 563 | } | |||
| 564 | prevFi = fi; // Kalman | |||
| 565 | prevGFi = gfi; // GBL | |||
| 566 | prevFittedState = fittedState; | |||
| 567 | ||||
| 568 | ||||
| 569 | //loop over all measurements for this point (e.g. u and v-type strips) | |||
| 570 | const int numMeasurements = tp->getNumRawMeasurements(); | |||
| 571 | for (int iMeasurement = 0; iMeasurement < numMeasurements; iMeasurement++) { | |||
| 572 | const genfit::AbsMeasurement* m = tp->getRawMeasurement(iMeasurement); | |||
| 573 | ||||
| 574 | TVectorT<double> hit_coords; | |||
| 575 | TMatrixTSym<double> hit_cov; | |||
| 576 | ||||
| 577 | if (fi) { | |||
| 578 | // Kalman | |||
| 579 | genfit::MeasurementOnPlane* mop = fi->getMeasurementOnPlane(iMeasurement); | |||
| 580 | hit_coords.ResizeTo(mop->getState()); | |||
| 581 | hit_cov.ResizeTo(mop->getCov()); | |||
| 582 | hit_coords = mop->getState(); | |||
| 583 | hit_cov = mop->getCov(); | |||
| 584 | } | |||
| 585 | if (gfi) { | |||
| 586 | // GBL - has only one measurement (other should be already merged before the track is constructed) | |||
| 587 | // That means tp->getNumRawMeasurements() returns 1 for tracks fitted by GBL, because GBLfit Module | |||
| 588 | // merges all corresponding SVD strips to 2D combined clusters. | |||
| 589 | genfit::MeasurementOnPlane gblMeas = gfi->getMeasurement(); | |||
| 590 | hit_coords.ResizeTo(gblMeas.getState()); | |||
| 591 | hit_cov.ResizeTo(gblMeas.getCov()); | |||
| 592 | hit_coords = gblMeas.getState(); | |||
| 593 | hit_cov = gblMeas.getCov(); | |||
| 594 | } | |||
| 595 | ||||
| 596 | // finished getting the hit infos ----------------------------------------------------- | |||
| 597 | ||||
| 598 | // sort hit infos into variables ------------------------------------------------------ | |||
| 599 | ROOT::Math::XYZVector o = ROOT::Math::XYZVector(fittedState->getPlane()->getO()); | |||
| 600 | ROOT::Math::XYZVector u = ROOT::Math::XYZVector(fittedState->getPlane()->getU()); | |||
| 601 | ROOT::Math::XYZVector v = ROOT::Math::XYZVector(fittedState->getPlane()->getV()); | |||
| 602 | ||||
| 603 | bool planar_hit = false; | |||
| 604 | bool planar_pixel_hit = false; | |||
| 605 | bool space_hit = false; | |||
| 606 | bool wire_hit = false; | |||
| 607 | bool wirepoint_hit = false; | |||
| 608 | double_t hit_u = 0; | |||
| 609 | double_t hit_v = 0; | |||
| 610 | double_t plane_size = 4; | |||
| 611 | ||||
| 612 | if (dynamic_cast<const genfit::PlanarMeasurement*>(m) != NULL__null) { | |||
| 613 | int hit_coords_dim = m->getDim(); | |||
| 614 | planar_hit = true; | |||
| 615 | if (hit_coords_dim == 1) { | |||
| 616 | hit_u = hit_coords(0); | |||
| 617 | } else if (hit_coords_dim == 2) { | |||
| 618 | planar_pixel_hit = true; | |||
| 619 | hit_u = hit_coords(0); | |||
| 620 | hit_v = hit_coords(1); | |||
| 621 | } | |||
| 622 | } else if (dynamic_cast<const genfit::SpacepointMeasurement*>(m) != NULL__null) { | |||
| 623 | space_hit = true; | |||
| 624 | } else if (dynamic_cast<const CDCRecoHit*>(m) | |||
| 625 | || dynamic_cast<const genfit::WireMeasurement*>(m) | |||
| 626 | || dynamic_cast<const genfit::WireMeasurementNew*>(m)) { | |||
| 627 | wire_hit = true; | |||
| 628 | hit_u = fabs(hit_coords(0)); | |||
| 629 | hit_v = v.Dot(track_pos - o); // move the covariance tube so that the track goes through it | |||
| 630 | if (dynamic_cast<const genfit::WirePointMeasurement*>(m) != NULL__null) { | |||
| 631 | wirepoint_hit = true; | |||
| 632 | hit_v = hit_coords(1); | |||
| 633 | } | |||
| 634 | } else { | |||
| 635 | B2ERROR("Hit " << hitCounter << ", Measurement " << iMeasurement << ": Unknown measurement type: skipping hit!")do { { LogVariableStream varStream; varStream << "Hit " << hitCounter << ", Measurement " << iMeasurement << ": Unknown measurement type: skipping hit!"; Belle2 ::LogSystem::Instance().sendMessage(Belle2::LogMessage(Belle2 ::LogConfig::c_Error, std::move(varStream), "display", __PRETTY_FUNCTION__ , "display/src/EVEVisualization.cc", 635, 0)); } } while(false ); | |||
| 636 | break; | |||
| 637 | } | |||
| 638 | ||||
| 639 | // finished setting variables --------------------------------------------------------- | |||
| 640 | ||||
| 641 | // draw planes if corresponding option is set ----------------------------------------- | |||
| 642 | if (drawPlanes || (drawDetectors && planar_hit)) { | |||
| 643 | ROOT::Math::XYZVector move(0, 0, 0); | |||
| 644 | if (wire_hit) move = v * (v.Dot(track_pos - o)); // move the plane along the wire until the track goes through it | |||
| 645 | TEveBox* box = boxCreator(o + move, u, v, plane_size, plane_size, 0.01); | |||
| 646 | if (drawDetectors && planar_hit) { | |||
| 647 | box->SetMainColor(kCyan); | |||
| 648 | } else { | |||
| 649 | box->SetMainColor(kGray); | |||
| 650 | } | |||
| 651 | box->SetMainTransparency(50); | |||
| 652 | eveTrack->AddElement(box); | |||
| 653 | } | |||
| 654 | // finished drawing planes ------------------------------------------------------------ | |||
| 655 | ||||
| 656 | // draw detectors if option is set, only important for wire hits ---------------------- | |||
| 657 | if (drawDetectors) { | |||
| 658 | ||||
| 659 | if (wire_hit) { | |||
| 660 | TEveGeoShape* det_shape = new TEveGeoShape("det_shape"); | |||
| 661 | det_shape->SetShape(new TGeoTube(std::max(0., (double)(hit_u - 0.0105 / 2.)), hit_u + 0.0105 / 2., plane_size)); | |||
| 662 | fixGeoShapeRefCount(det_shape); | |||
| 663 | ||||
| 664 | ROOT::Math::XYZVector norm = u.Cross(v); | |||
| 665 | TGeoRotation det_rot("det_rot", (u.Theta() * 180) / TMath::Pi(), (u.Phi() * 180) / TMath::Pi(), | |||
| 666 | (norm.Theta() * 180) / TMath::Pi(), (norm.Phi() * 180) / TMath::Pi(), | |||
| 667 | (v.Theta() * 180) / TMath::Pi(), (v.Phi() * 180) / TMath::Pi()); // move the tube to the right place and rotate it correctly | |||
| 668 | ROOT::Math::XYZVector move = v * (v.Dot(track_pos - o)); // move the tube along the wire until the track goes through it | |||
| 669 | TGeoCombiTrans det_trans(o.X() + move.X(), | |||
| 670 | o.Y() + move.Y(), | |||
| 671 | o.Z() + move.Z(), | |||
| 672 | &det_rot); | |||
| 673 | det_shape->SetTransMatrix(det_trans); | |||
| 674 | det_shape->SetMainColor(kCyan); | |||
| 675 | det_shape->SetMainTransparency(25); | |||
| 676 | if ((drawHits && (hit_u + 0.0105 / 2 > 0)) || !drawHits) { | |||
| 677 | eveTrack->AddElement(det_shape); | |||
| 678 | } | |||
| 679 | } | |||
| 680 | ||||
| 681 | } | |||
| 682 | // finished drawing detectors --------------------------------------------------------- | |||
| 683 | ||||
| 684 | if (drawHits) { | |||
| 685 | ||||
| 686 | // draw planar hits, with distinction between strip and pixel hits ---------------- | |||
| 687 | if (planar_hit) { | |||
| 688 | if (!planar_pixel_hit) { | |||
| 689 | //strip hit | |||
| 690 | static VXD::GeoCache& geo = VXD::GeoCache::getInstance(); | |||
| 691 | const SVDRecoHit* recoHit = dynamic_cast<const SVDRecoHit*>(m); | |||
| 692 | if (!recoHit) { | |||
| 693 | B2WARNING("SVD recohit couldn't be converted... ")do { if (Belle2::LogSystem::Instance().isLevelEnabled(Belle2:: LogConfig::c_Warning, 0, "display")) { { LogVariableStream varStream ; varStream << "SVD recohit couldn't be converted... "; Belle2::LogSystem::Instance().sendMessage(Belle2::LogMessage (Belle2::LogConfig::c_Warning, std::move(varStream), "display" , __PRETTY_FUNCTION__, "display/src/EVEVisualization.cc", 693 , 0)); }; } } while(false); | |||
| 694 | continue; | |||
| 695 | } | |||
| 696 | ||||
| 697 | const VXD::SensorInfoBase& sensor = geo.getSensorInfo(recoHit->getSensorID()); | |||
| 698 | double du, dv; | |||
| 699 | ROOT::Math::XYZVector a = o; //defines position of sensor plane | |||
| 700 | double hit_res_u = hit_cov(0, 0); | |||
| 701 | if (recoHit->isU()) { | |||
| 702 | du = std::sqrt(hit_res_u); | |||
| 703 | dv = sensor.getLength(); | |||
| 704 | a += hit_u * u; | |||
| 705 | } else { | |||
| 706 | du = sensor.getWidth(); | |||
| 707 | dv = std::sqrt(hit_res_u); | |||
| 708 | a += hit_u * v; | |||
| 709 | } | |||
| 710 | double depth = sensor.getThickness(); | |||
| 711 | TEveBox* hit_box = boxCreator(a, u, v, du, dv, depth); | |||
| 712 | hit_box->SetName("SVDRecoHit"); | |||
| 713 | hit_box->SetMainColor(c_recoHitColor); | |||
| 714 | hit_box->SetMainTransparency(0); | |||
| 715 | eveTrack->AddElement(hit_box); | |||
| 716 | } else { | |||
| 717 | //pixel hit | |||
| 718 | // calculate eigenvalues to draw error-ellipse ---------------------------- | |||
| 719 | TMatrixDSymEigen eigen_values(hit_cov); | |||
| 720 | TEveGeoShape* cov_shape = new TEveGeoShape("PXDRecoHit"); | |||
| 721 | const TVectorD& ev = eigen_values.GetEigenValues(); | |||
| 722 | const TMatrixD& eVec = eigen_values.GetEigenVectors(); | |||
| 723 | double pseudo_res_0 = m_errorScale * std::sqrt(ev(0)); | |||
| 724 | double pseudo_res_1 = m_errorScale * std::sqrt(ev(1)); | |||
| 725 | // finished calculating, got the values ----------------------------------- | |||
| 726 | ||||
| 727 | // calculate the semiaxis of the error ellipse ---------------------------- | |||
| 728 | cov_shape->SetShape(new TGeoEltu(pseudo_res_0, pseudo_res_1, 0.0105)); | |||
| 729 | fixGeoShapeRefCount(cov_shape); | |||
| 730 | ROOT::Math::XYZVector pix_pos = o + hit_u * u + hit_v * v; | |||
| 731 | ROOT::Math::XYZVector u_semiaxis = (pix_pos + eVec(0, 0) * u + eVec(1, 0) * v) - pix_pos; | |||
| 732 | ROOT::Math::XYZVector v_semiaxis = (pix_pos + eVec(0, 1) * u + eVec(1, 1) * v) - pix_pos; | |||
| 733 | ROOT::Math::XYZVector norm = u.Cross(v); | |||
| 734 | // finished calculating --------------------------------------------------- | |||
| 735 | ||||
| 736 | // rotate and translate everything correctly ------------------------------ | |||
| 737 | TGeoRotation det_rot("det_rot", (u_semiaxis.Theta() * 180) / TMath::Pi(), (u_semiaxis.Phi() * 180) / TMath::Pi(), | |||
| 738 | (v_semiaxis.Theta() * 180) / TMath::Pi(), (v_semiaxis.Phi() * 180) / TMath::Pi(), | |||
| 739 | (norm.Theta() * 180) / TMath::Pi(), (norm.Phi() * 180) / TMath::Pi()); | |||
| 740 | TGeoCombiTrans det_trans(pix_pos.X(), pix_pos.Y(), pix_pos.Z(), &det_rot); | |||
| 741 | cov_shape->SetTransMatrix(det_trans); | |||
| 742 | // finished rotating and translating -------------------------------------- | |||
| 743 | ||||
| 744 | cov_shape->SetMainColor(c_recoHitColor); | |||
| 745 | cov_shape->SetMainTransparency(0); | |||
| 746 | eveTrack->AddElement(cov_shape); | |||
| 747 | } | |||
| 748 | } | |||
| 749 | // finished drawing planar hits --------------------------------------------------- | |||
| 750 | ||||
| 751 | // draw spacepoint hits ----------------------------------------------------------- | |||
| 752 | if (space_hit) { | |||
| 753 | ||||
| 754 | // get eigenvalues of covariance to know how to draw the ellipsoid ------------ | |||
| 755 | TMatrixDSymEigen eigen_values(m->getRawHitCov()); | |||
| 756 | TEveGeoShape* cov_shape = new TEveGeoShape("SpacePoint Hit"); | |||
| 757 | cov_shape->SetShape(new TGeoSphere(0., 1.)); | |||
| 758 | fixGeoShapeRefCount(cov_shape); | |||
| 759 | const TVectorD& ev = eigen_values.GetEigenValues(); | |||
| 760 | const TMatrixD& eVec = eigen_values.GetEigenVectors(); | |||
| 761 | ROOT::Math::XYZVector eVec1(eVec(0, 0), eVec(1, 0), eVec(2, 0)); | |||
| 762 | ROOT::Math::XYZVector eVec2(eVec(0, 1), eVec(1, 1), eVec(2, 1)); | |||
| 763 | ROOT::Math::XYZVector eVec3(eVec(0, 2), eVec(1, 2), eVec(2, 2)); | |||
| 764 | // got everything we need ----------------------------------------------------- | |||
| 765 | ||||
| 766 | ||||
| 767 | TGeoRotation det_rot("det_rot", (eVec1.Theta() * 180) / TMath::Pi(), (eVec1.Phi() * 180) / TMath::Pi(), | |||
| 768 | (eVec2.Theta() * 180) / TMath::Pi(), (eVec2.Phi() * 180) / TMath::Pi(), | |||
| 769 | (eVec3.Theta() * 180) / TMath::Pi(), (eVec3.Phi() * 180) / TMath::Pi()); // the rotation is already clear | |||
| 770 | ||||
| 771 | // set the scaled eigenvalues ------------------------------------------------- | |||
| 772 | double pseudo_res_0 = m_errorScale * std::sqrt(ev(0)); | |||
| 773 | double pseudo_res_1 = m_errorScale * std::sqrt(ev(1)); | |||
| 774 | double pseudo_res_2 = m_errorScale * std::sqrt(ev(2)); | |||
| 775 | // finished scaling ----------------------------------------------------------- | |||
| 776 | ||||
| 777 | // rotate and translate ------------------------------------------------------- | |||
| 778 | TGeoGenTrans det_trans(o.X(), o.Y(), o.Z(), | |||
| 779 | //std::sqrt(pseudo_res_0/pseudo_res_1/pseudo_res_2), std::sqrt(pseudo_res_1/pseudo_res_0/pseudo_res_2), std::sqrt(pseudo_res_2/pseudo_res_0/pseudo_res_1), // this workaround is necessary due to the "normalization" performed in TGeoGenTrans::SetScale | |||
| 780 | //1/(pseudo_res_0),1/(pseudo_res_1),1/(pseudo_res_2), | |||
| 781 | pseudo_res_0, pseudo_res_1, pseudo_res_2, | |||
| 782 | &det_rot); | |||
| 783 | cov_shape->SetTransMatrix(det_trans); | |||
| 784 | // finished rotating and translating ------------------------------------------ | |||
| 785 | ||||
| 786 | cov_shape->SetMainColor(c_recoHitColor); | |||
| 787 | cov_shape->SetMainTransparency(10); | |||
| 788 | eveTrack->AddElement(cov_shape); | |||
| 789 | } | |||
| 790 | // finished drawing spacepoint hits ----------------------------------------------- | |||
| 791 | ||||
| 792 | // draw wire hits ----------------------------------------------------------------- | |||
| 793 | if (wire_hit) { | |||
| 794 | const double cdcErrorScale = 1.0; | |||
| 795 | TEveGeoShape* cov_shape = new TEveGeoShape("CDCRecoHit"); | |||
| 796 | double pseudo_res_0 = cdcErrorScale * std::sqrt(hit_cov(0, 0)); | |||
| 797 | double pseudo_res_1 = plane_size; | |||
| 798 | if (wirepoint_hit) pseudo_res_1 = cdcErrorScale * std::sqrt(hit_cov(1, 1)); | |||
| 799 | ||||
| 800 | cov_shape->SetShape(new TGeoTube(std::max(0., (double)(hit_u - pseudo_res_0)), hit_u + pseudo_res_0, pseudo_res_1)); | |||
| 801 | fixGeoShapeRefCount(cov_shape); | |||
| 802 | ROOT::Math::XYZVector norm = u.Cross(v); | |||
| 803 | ||||
| 804 | // rotate and translate ------------------------------------------------------- | |||
| 805 | TGeoRotation det_rot("det_rot", (u.Theta() * 180) / TMath::Pi(), (u.Phi() * 180) / TMath::Pi(), | |||
| 806 | (norm.Theta() * 180) / TMath::Pi(), (norm.Phi() * 180) / TMath::Pi(), | |||
| 807 | (v.Theta() * 180) / TMath::Pi(), (v.Phi() * 180) / TMath::Pi()); | |||
| 808 | TGeoCombiTrans det_trans(o.X() + hit_v * v.X(), | |||
| 809 | o.Y() + hit_v * v.Y(), | |||
| 810 | o.Z() + hit_v * v.Z(), | |||
| 811 | &det_rot); | |||
| 812 | cov_shape->SetTransMatrix(det_trans); | |||
| 813 | // finished rotating and translating ------------------------------------------ | |||
| 814 | ||||
| 815 | cov_shape->SetMainColor(c_recoHitColor); | |||
| 816 | cov_shape->SetMainTransparency(50); | |||
| 817 | eveTrack->AddElement(cov_shape); | |||
| 818 | } | |||
| 819 | // finished drawing wire hits ----------------------------------------------------- | |||
| 820 | } | |||
| 821 | ||||
| 822 | } | |||
| 823 | } | |||
| 824 | ||||
| 825 | auto& firstref = eveTrack->RefPathMarks().front(); | |||
| 826 | auto& lastref = eveTrack->RefPathMarks().back(); | |||
| 827 | double f = firstref.fV.Distance(recTrack.fV); | |||
| 828 | double b = lastref.fV.Distance(recTrack.fV); | |||
| 829 | if (f > 100 and f > b) { | |||
| 830 | B2WARNING("Decay vertex is much closer to POCA than first vertex, reversing order of track points... (this is intended for cosmic tracks, if you see this message in other context it might indicate a problem)")do { if (Belle2::LogSystem::Instance().isLevelEnabled(Belle2:: LogConfig::c_Warning, 0, "display")) { { LogVariableStream varStream ; varStream << "Decay vertex is much closer to POCA than first vertex, reversing order of track points... (this is intended for cosmic tracks, if you see this message in other context it might indicate a problem)" ; Belle2::LogSystem::Instance().sendMessage(Belle2::LogMessage (Belle2::LogConfig::c_Warning, std::move(varStream), "display" , __PRETTY_FUNCTION__, "display/src/EVEVisualization.cc", 830 , 0)); }; } } while(false); | |||
| 831 | //last ref is better than first... | |||
| 832 | lastref.fType = TEvePathMarkD::kReference; | |||
| 833 | firstref.fType = TEvePathMarkD::kDecay; | |||
| 834 | std::reverse(eveTrack->RefPathMarks().begin(), eveTrack->RefPathMarks().end()); | |||
| 835 | } | |||
| 836 | } | |||
| 837 | eveTrack->SetTitle(TString::Format("%s\n" | |||
| 838 | "pruned: %s\n" | |||
| 839 | "pT=%.3f, pZ=%.3f\n" | |||
| 840 | "pVal: %e", | |||
| 841 | label.Data(), | |||
| 842 | isPruned ? " yes" : "no", | |||
| 843 | poca_momentum.Pt(), poca_momentum.Pz(), | |||
| 844 | fitResult->getPValue() | |||
| 845 | )); | |||
| 846 | eveTrack->SetLineColor(c_trackColor); | |||
| 847 | eveTrack->SetLineStyle(1); | |||
| 848 | eveTrack->SetLineWidth(3.0); | |||
| 849 | ||||
| 850 | ||||
| 851 | addToGroup("Fitted Tracks", eveTrack); | |||
| 852 | if (track) | |||
| 853 | addObject(track, eveTrack); | |||
| 854 | addObject(belle2Track, eveTrack); | |||
| 855 | } | |||
| 856 | ||||
| 857 | TEveBox* EVEVisualization::boxCreator(const ROOT::Math::XYZVector& o, ROOT::Math::XYZVector u, ROOT::Math::XYZVector v, | |||
| 858 | float ud, | |||
| 859 | float vd, float depth) | |||
| 860 | { | |||
| 861 | //force minimum width of polygon to deal with Eve limits | |||
| 862 | float min = 0.04; | |||
| 863 | if (vd < min) | |||
| 864 | vd = min; | |||
| 865 | if (ud < min) | |||
| 866 | ud = min; | |||
| 867 | if (depth < min) | |||
| 868 | depth = min; | |||
| 869 | ||||
| 870 | TEveBox* box = new TEveBox; | |||
| 871 | box->SetPickable(true); | |||
| 872 | ||||
| 873 | ROOT::Math::XYZVector norm = u.Cross(v); | |||
| 874 | u *= (0.5 * ud); | |||
| 875 | v *= (0.5 * vd); | |||
| 876 | norm *= (0.5 * depth); | |||
| 877 | ||||
| 878 | ||||
| 879 | for (int k = 0; k < 8; ++k) { | |||
| 880 | // Coordinates for all eight corners of the box | |||
| 881 | // as two parallel rectangles, with vertices specified in clockwise direction | |||
| 882 | int signU = ((k + 1) & 2) ? -1 : 1; | |||
| 883 | int signV = (k & 4) ? -1 : 1; | |||
| 884 | int signN = (k & 2) ? -1 : 1; | |||
| 885 | float vertex[3]; | |||
| 886 | // for (int i = 0; i < 3; ++i) { | |||
| 887 | // vertex[i] = o(i) + signU * u(i) + signV * v(i) + signN * norm(i); | |||
| 888 | // } | |||
| 889 | vertex[0] = o.X() + signU * u.X() + signV * v.X() + signN * norm.X(); | |||
| 890 | vertex[1] = o.Y() + signU * u.Y() + signV * v.Y() + signN * norm.Y(); | |||
| 891 | vertex[2] = o.Z() + signU * u.Z() + signV * v.Z() + signN * norm.Z(); | |||
| 892 | box->SetVertex(k, vertex); | |||
| 893 | } | |||
| 894 | ||||
| 895 | return box; | |||
| 896 | } | |||
| 897 | ||||
| 898 | void EVEVisualization::makeLines(TEveTrack* eveTrack, const genfit::StateOnPlane* prevState, | |||
| 899 | const genfit::StateOnPlane* state, | |||
| 900 | const genfit::AbsTrackRep* rep, | |||
| 901 | TEvePathMark::EType_e markType, bool drawErrors, int markerPos) | |||
| 902 | { | |||
| 903 | using namespace genfit; | |||
| 904 | ||||
| 905 | // Need TVector3 for genfit interface | |||
| 906 | TVector3 pos, dir, oldPos, oldDir; | |||
| 907 | rep->getPosDir(*state, pos, dir); | |||
| 908 | rep->getPosDir(*prevState, oldPos, oldDir); | |||
| 909 | ||||
| 910 | double distA = (pos - oldPos).Mag(); | |||
| 911 | double distB = distA; | |||
| 912 | if ((pos - oldPos)*oldDir < 0) | |||
| 913 | distA *= -1.; | |||
| 914 | if ((pos - oldPos)*dir < 0) | |||
| 915 | distB *= -1.; | |||
| 916 | ||||
| 917 | TEvePathMark mark( | |||
| 918 | markType, | |||
| 919 | TEveVector(pos.X(), pos.Y(), pos.Z()), | |||
| 920 | TEveVector(dir.X(), dir.Y(), dir.Z()) | |||
| 921 | ); | |||
| 922 | eveTrack->AddPathMark(mark); | |||
| 923 | ||||
| 924 | ||||
| 925 | if (drawErrors) { | |||
| 926 | const MeasuredStateOnPlane* measuredState; | |||
| 927 | if (markerPos == 0) | |||
| 928 | measuredState = dynamic_cast<const MeasuredStateOnPlane*>(prevState); | |||
| 929 | else | |||
| 930 | measuredState = dynamic_cast<const MeasuredStateOnPlane*>(state); | |||
| 931 | ||||
| 932 | if (measuredState != NULL__null) { | |||
| 933 | ||||
| 934 | // step for evaluate at a distance from the original plane | |||
| 935 | ROOT::Math::XYZVector eval; | |||
| 936 | if (markerPos == 0) | |||
| 937 | eval = 0.2 * distA * oldDir; | |||
| 938 | else | |||
| 939 | eval = -0.2 * distB * dir; | |||
| 940 | ||||
| 941 | ||||
| 942 | // get cov at first plane | |||
| 943 | TMatrixDSym cov; | |||
| 944 | // Need TVector3 for genfit interface | |||
| 945 | TVector3 position, direction; | |||
| 946 | rep->getPosMomCov(*measuredState, position, direction, cov); | |||
| 947 | ||||
| 948 | // get eigenvalues & -vectors | |||
| 949 | TMatrixDSymEigen eigen_values(cov.GetSub(0, 2, 0, 2)); | |||
| 950 | const TVectorD& ev = eigen_values.GetEigenValues(); | |||
| 951 | const TMatrixD& eVec = eigen_values.GetEigenVectors(); | |||
| 952 | ROOT::Math::XYZVector eVec1, eVec2; | |||
| 953 | // limit | |||
| 954 | static const double maxErr = 1000.; | |||
| 955 | double ev0 = std::min(ev(0), maxErr); | |||
| 956 | double ev1 = std::min(ev(1), maxErr); | |||
| 957 | double ev2 = std::min(ev(2), maxErr); | |||
| 958 | ||||
| 959 | // get two largest eigenvalues/-vectors | |||
| 960 | if (ev0 < ev1 && ev0 < ev2) { | |||
| 961 | eVec1.SetXYZ(eVec(0, 1), eVec(1, 1), eVec(2, 1)); | |||
| 962 | eVec1 *= sqrt(ev1); | |||
| 963 | eVec2.SetXYZ(eVec(0, 2), eVec(1, 2), eVec(2, 2)); | |||
| 964 | eVec2 *= sqrt(ev2); | |||
| 965 | } else if (ev1 < ev0 && ev1 < ev2) { | |||
| 966 | eVec1.SetXYZ(eVec(0, 0), eVec(1, 0), eVec(2, 0)); | |||
| 967 | eVec1 *= sqrt(ev0); | |||
| 968 | eVec2.SetXYZ(eVec(0, 2), eVec(1, 2), eVec(2, 2)); | |||
| 969 | eVec2 *= sqrt(ev2); | |||
| 970 | } else { | |||
| 971 | eVec1.SetXYZ(eVec(0, 0), eVec(1, 0), eVec(2, 0)); | |||
| 972 | eVec1 *= sqrt(ev0); | |||
| 973 | eVec2.SetXYZ(eVec(0, 1), eVec(1, 1), eVec(2, 1)); | |||
| 974 | eVec2 *= sqrt(ev1); | |||
| 975 | } | |||
| 976 | ||||
| 977 | if (eVec1.Cross(eVec2).Dot(eval) < 0) | |||
| 978 | eVec2 *= -1; | |||
| 979 | //assert(eVec1.Cross(eVec2)*eval > 0); | |||
| 980 | ||||
| 981 | ROOT::Math::XYZVector oldEVec1(eVec1); | |||
| 982 | ||||
| 983 | const int nEdges = 24; | |||
| 984 | std::vector<ROOT::Math::XYZVector> vertices; | |||
| 985 | ||||
| 986 | vertices.push_back(ROOT::Math::XYZVector(position)); | |||
| 987 | ||||
| 988 | // vertices at plane | |||
| 989 | for (int i = 0; i < nEdges; ++i) { | |||
| 990 | const double angle = 2 * TMath::Pi() / nEdges * i; | |||
| 991 | vertices.push_back(ROOT::Math::XYZVector(position) + cos(angle)*eVec1 + sin(angle)*eVec2); | |||
| 992 | } | |||
| 993 | ||||
| 994 | ||||
| 995 | ||||
| 996 | SharedPlanePtr newPlane(new DetPlane(*(measuredState->getPlane()))); | |||
| 997 | newPlane->setO(position + XYZToTVector(eval)); | |||
| 998 | ||||
| 999 | MeasuredStateOnPlane stateCopy(*measuredState); | |||
| 1000 | try { | |||
| 1001 | rep->extrapolateToPlane(stateCopy, newPlane); | |||
| 1002 | } catch (Exception& e) { | |||
| 1003 | B2ERROR(e.what())do { { LogVariableStream varStream; varStream << e.what (); Belle2::LogSystem::Instance().sendMessage(Belle2::LogMessage (Belle2::LogConfig::c_Error, std::move(varStream), "display", __PRETTY_FUNCTION__, "display/src/EVEVisualization.cc", 1003 , 0)); } } while(false); | |||
| 1004 | return; | |||
| 1005 | } | |||
| 1006 | ||||
| 1007 | // get cov at 2nd plane | |||
| 1008 | rep->getPosMomCov(stateCopy, position, direction, cov); | |||
| 1009 | ||||
| 1010 | // get eigenvalues & -vectors | |||
| 1011 | { | |||
| 1012 | TMatrixDSymEigen eigen_values2(cov.GetSub(0, 2, 0, 2)); | |||
| 1013 | const TVectorD& eVal = eigen_values2.GetEigenValues(); | |||
| 1014 | const TMatrixD& eVect = eigen_values2.GetEigenVectors(); | |||
| 1015 | // limit | |||
| 1016 | ev0 = std::min(eVal(0), maxErr); | |||
| 1017 | ev1 = std::min(eVal(1), maxErr); | |||
| 1018 | ev2 = std::min(eVal(2), maxErr); | |||
| 1019 | ||||
| 1020 | // get two largest eigenvalues/-vectors | |||
| 1021 | if (ev0 < ev1 && ev0 < ev2) { | |||
| 1022 | eVec1.SetXYZ(eVect(0, 1), eVect(1, 1), eVect(2, 1)); | |||
| 1023 | eVec1 *= sqrt(ev1); | |||
| 1024 | eVec2.SetXYZ(eVect(0, 2), eVect(1, 2), eVect(2, 2)); | |||
| 1025 | eVec2 *= sqrt(ev2); | |||
| 1026 | } else if (ev1 < ev0 && ev1 < ev2) { | |||
| 1027 | eVec1.SetXYZ(eVect(0, 0), eVect(1, 0), eVect(2, 0)); | |||
| 1028 | eVec1 *= sqrt(ev0); | |||
| 1029 | eVec2.SetXYZ(eVect(0, 2), eVect(1, 2), eVect(2, 2)); | |||
| 1030 | eVec2 *= sqrt(ev2); | |||
| 1031 | } else { | |||
| 1032 | eVec1.SetXYZ(eVect(0, 0), eVect(1, 0), eVect(2, 0)); | |||
| 1033 | eVec1 *= sqrt(ev0); | |||
| 1034 | eVec2.SetXYZ(eVect(0, 1), eVect(1, 1), eVect(2, 1)); | |||
| 1035 | } eVec2 *= sqrt(ev1); | |||
| 1036 | } | |||
| 1037 | ||||
| 1038 | if (eVec1.Cross(eVec2).Dot(eval) < 0) | |||
| 1039 | eVec2 *= -1; | |||
| 1040 | //assert(eVec1.Cross(eVec2)*eval > 0); | |||
| 1041 | ||||
| 1042 | if (oldEVec1.Dot(eVec1) < 0) { | |||
| 1043 | eVec1 *= -1; | |||
| 1044 | eVec2 *= -1; | |||
| 1045 | } | |||
| 1046 | ||||
| 1047 | // vertices at 2nd plane | |||
| 1048 | double angle0 = ROOT::Math::VectorUtil::Angle(eVec1, oldEVec1); | |||
| 1049 | if (eVec1.Dot(eval.Cross(oldEVec1)) < 0) | |||
| 1050 | angle0 *= -1; | |||
| 1051 | for (int i = 0; i < nEdges; ++i) { | |||
| 1052 | const double angle = 2 * TMath::Pi() / nEdges * i - angle0; | |||
| 1053 | vertices.push_back(ROOT::Math::XYZVector(position) + cos(angle)*eVec1 + sin(angle)*eVec2); | |||
| 1054 | } | |||
| 1055 | ||||
| 1056 | vertices.push_back(ROOT::Math::XYZVector(position)); | |||
| 1057 | ||||
| 1058 | ||||
| 1059 | TEveTriangleSet* error_shape = new TEveTriangleSet(vertices.size(), nEdges * 2); | |||
| 1060 | for (unsigned int k = 0; k < vertices.size(); ++k) { | |||
| 1061 | error_shape->SetVertex(k, vertices[k].X(), vertices[k].Y(), vertices[k].Z()); | |||
| 1062 | } | |||
| 1063 | ||||
| 1064 | assert(vertices.size() == 2 * nEdges + 2)(static_cast <bool> (vertices.size() == 2 * nEdges + 2) ? void (0) : __assert_fail ("vertices.size() == 2 * nEdges + 2" , "display/src/EVEVisualization.cc", 1064, __extension__ __PRETTY_FUNCTION__ )); | |||
| 1065 | ||||
| 1066 | int iTri(0); | |||
| 1067 | for (int i = 0; i < nEdges; ++i) { | |||
| 1068 | //error_shape->SetTriangle(iTri++, 0, i+1, (i+1)%nEdges+1); | |||
| 1069 | error_shape->SetTriangle(iTri++, i + 1, i + 1 + nEdges, (i + 1) % nEdges + 1); | |||
| 1070 | error_shape->SetTriangle(iTri++, (i + 1) % nEdges + 1, i + 1 + nEdges, (i + 1) % nEdges + 1 + nEdges); | |||
| 1071 | //error_shape->SetTriangle(iTri++, 2*nEdges+1, i+1+nEdges, (i+1)%nEdges+1+nEdges); | |||
| 1072 | } | |||
| 1073 | ||||
| 1074 | //assert(iTri == nEdges*4); | |||
| 1075 | ||||
| 1076 | error_shape->SetMainColor(c_trackColor); | |||
| 1077 | error_shape->SetMainTransparency(25); | |||
| 1078 | eveTrack->AddElement(error_shape); | |||
| 1079 | } | |||
| 1080 | } | |||
| 1081 | } | |||
| 1082 | ||||
| 1083 | void EVEVisualization::addSimHit(const CDCSimHit* hit, const MCParticle* particle) | |||
| 1084 | { | |||
| 1085 | addSimHit(ROOT::Math::XYZVector(hit->getPosWire()), particle); | |||
| 1086 | } | |||
| 1087 | void EVEVisualization::addSimHit(const PXDSimHit* hit, const MCParticle* particle) | |||
| 1088 | { | |||
| 1089 | static VXD::GeoCache& geo = VXD::GeoCache::getInstance(); | |||
| 1090 | const ROOT::Math::XYZVector& global_pos = geo.getSensorInfo(hit->getSensorID()).pointToGlobal(hit->getPosIn()); | |||
| 1091 | addSimHit(global_pos, particle); | |||
| 1092 | } | |||
| 1093 | void EVEVisualization::addSimHit(const SVDSimHit* hit, const MCParticle* particle) | |||
| 1094 | { | |||
| 1095 | static VXD::GeoCache& geo = VXD::GeoCache::getInstance(); | |||
| 1096 | const ROOT::Math::XYZVector& global_pos = geo.getSensorInfo(hit->getSensorID()).pointToGlobal(hit->getPosIn()); | |||
| 1097 | addSimHit(global_pos, particle); | |||
| 1098 | } | |||
| 1099 | void EVEVisualization::addSimHit(const KLMSimHit* hit, const MCParticle* particle) | |||
| 1100 | { | |||
| 1101 | const ROOT::Math::XYZVector& global_pos = hit->getPosition(); | |||
| 1102 | addSimHit(global_pos, particle); | |||
| 1103 | } | |||
| 1104 | void EVEVisualization::addSimHit(const ROOT::Math::XYZVector& v, const MCParticle* particle) | |||
| 1105 | { | |||
| 1106 | MCTrack* track = addMCParticle(particle); | |||
| 1107 | if (!track) | |||
| 1108 | return; //hide hits from this particle | |||
| 1109 | track->simhits->SetNextPoint(v.X(), v.Y(), v.Z()); | |||
| 1110 | } | |||
| 1111 | ||||
| 1112 | EVEVisualization::MCTrack* EVEVisualization::addMCParticle(const MCParticle* particle) | |||
| 1113 | { | |||
| 1114 | if (!particle) { | |||
| 1115 | if (!m_mcparticleTracks[nullptr].simhits) { | |||
| 1116 | const TString pointsTitle("Unassigned SimHits"); | |||
| 1117 | m_mcparticleTracks[nullptr].simhits = new TEvePointSet(pointsTitle); | |||
| 1118 | m_mcparticleTracks[nullptr].simhits->SetTitle(pointsTitle); | |||
| 1119 | m_mcparticleTracks[nullptr].simhits->SetMarkerStyle(6); | |||
| 1120 | m_mcparticleTracks[nullptr].simhits->SetMainColor(c_unassignedHitColor); | |||
| 1121 | //m_mcparticleTracks[nullptr].simhits->SetMainTransparency(50); | |||
| 1122 | m_mcparticleTracks[nullptr].track = NULL__null; | |||
| 1123 | } | |||
| 1124 | return &m_mcparticleTracks[nullptr]; | |||
| 1125 | } | |||
| 1126 | ||||
| 1127 | if (m_hideSecondaries and !particle->hasStatus(MCParticle::c_PrimaryParticle)) { | |||
| 1128 | return NULL__null; | |||
| 1129 | } | |||
| 1130 | if (m_assignToPrimaries) { | |||
| 1131 | while (!particle->hasStatus(MCParticle::c_PrimaryParticle) and particle->getMother()) | |||
| 1132 | particle = particle->getMother(); | |||
| 1133 | } | |||
| 1134 | ||||
| 1135 | if (!m_mcparticleTracks[particle].track) { | |||
| 1136 | const ROOT::Math::XYZVector& p = particle->getMomentum(); | |||
| 1137 | const ROOT::Math::XYZVector& vertex = particle->getProductionVertex(); | |||
| 1138 | const int pdg = particle->getPDG(); | |||
| 1139 | TParticle tparticle(pdg, particle->getStatus(), | |||
| 1140 | (particle->getMother() ? particle->getMother()->getIndex() : 0), 0, particle->getFirstDaughter(), particle->getLastDaughter(), | |||
| 1141 | p.X(), p.Y(), p.Z(), particle->getEnergy(), | |||
| 1142 | vertex.X(), vertex.Y(), vertex.Z(), particle->getProductionTime()); | |||
| 1143 | TEveMCTrack mctrack; | |||
| 1144 | mctrack = tparticle; | |||
| 1145 | mctrack.fTDecay = particle->getDecayTime(); | |||
| 1146 | mctrack.fVDecay.Set(B2Vector3D(particle->getDecayVertex())); | |||
| 1147 | mctrack.fDecayed = !std::isinf(mctrack.fTDecay); | |||
| 1148 | mctrack.fIndex = particle->getIndex(); | |||
| 1149 | m_mcparticleTracks[particle].track = new TEveTrack(&mctrack, m_trackpropagator); | |||
| 1150 | ||||
| 1151 | //Check if there is a trajectory stored for this particle | |||
| 1152 | const auto mcTrajectories = particle->getRelationsTo<MCParticleTrajectory>(); | |||
| 1153 | bool hasTrajectory(false); | |||
| 1154 | for (auto rel : mcTrajectories.relations()) { | |||
| 1155 | //Trajectories with negative weight are from secondary daughters which | |||
| 1156 | //were ignored so we don't use them. | |||
| 1157 | if (rel.weight <= 0) continue; | |||
| 1158 | //Found one, let's add tose point as reference points to the TEveTrack. | |||
| 1159 | //This will force the track propagation to visit all points in order but | |||
| 1160 | //provide smooth helix interpolation between the points | |||
| 1161 | const MCParticleTrajectory& trajectory = dynamic_cast<const MCParticleTrajectory&>(*rel.object); | |||
| 1162 | for (const MCTrajectoryPoint& pt : trajectory) { | |||
| 1163 | m_mcparticleTracks[particle].track->AddPathMark( | |||
| 1164 | TEvePathMark( | |||
| 1165 | //Add the last trajectory point as decay point to prevent TEve to | |||
| 1166 | //propagate beyond the end of the track. So lets compare the address | |||
| 1167 | //to the address of last point and choose the pathmark accordingly | |||
| 1168 | (&pt == &trajectory.back()) ? TEvePathMark::kDecay : TEvePathMark::kReference, | |||
| 1169 | TEveVector(pt.x, pt.y, pt.z), | |||
| 1170 | TEveVector(pt.px, pt.py, pt.pz) | |||
| 1171 | )); | |||
| 1172 | } | |||
| 1173 | //"There can only be One" -> found a trajectory, stop the loop | |||
| 1174 | hasTrajectory = true; | |||
| 1175 | break; | |||
| 1176 | } | |||
| 1177 | ||||
| 1178 | //If we have the full trajectory there is no need to add additional path marks | |||
| 1179 | if (!hasTrajectory) { | |||
| 1180 | //add daughter vertices - improves track rendering as lost momentum is taken into account | |||
| 1181 | for (int iDaughter = particle->getFirstDaughter(); iDaughter <= particle->getLastDaughter(); iDaughter++) { | |||
| 1182 | if (iDaughter == 0) | |||
| 1183 | continue; //no actual daughter | |||
| 1184 | ||||
| 1185 | const MCParticle* daughter = StoreArray<MCParticle>()[iDaughter - 1]; | |||
| 1186 | ||||
| 1187 | TEvePathMarkD refMark(TEvePathMarkD::kDaughter); | |||
| 1188 | refMark.fV.Set(B2Vector3D(daughter->getProductionVertex())); | |||
| 1189 | refMark.fP.Set(B2Vector3D(daughter->getMomentum())); | |||
| 1190 | refMark.fTime = daughter->getProductionTime(); | |||
| 1191 | m_mcparticleTracks[particle].track->AddPathMark(refMark); | |||
| 1192 | } | |||
| 1193 | ||||
| 1194 | //neutrals and very short-lived particles should stop somewhere | |||
| 1195 | //(can result in wrong shapes for particles stopped in the detector, so not used there) | |||
| 1196 | if ((TMath::Nint(particle->getCharge()) == 0 or !particle->hasStatus(MCParticle::c_StoppedInDetector)) | |||
| 1197 | and mctrack.fDecayed) { | |||
| 1198 | TEvePathMarkD decayMark(TEvePathMarkD::kDecay); | |||
| 1199 | decayMark.fV.Set(B2Vector3D(particle->getDecayVertex())); | |||
| 1200 | m_mcparticleTracks[particle].track->AddPathMark(decayMark); | |||
| 1201 | } | |||
| 1202 | } | |||
| 1203 | TString particle_name(mctrack.GetName()); | |||
| 1204 | ||||
| 1205 | //set track title (for popup) | |||
| 1206 | const MCParticle* mom = particle->getMother(); | |||
| 1207 | if (mom) { | |||
| 1208 | m_mcparticleTracks[particle].parentParticle = mom; | |||
| 1209 | addMCParticle(mom); | |||
| 1210 | } | |||
| 1211 | ||||
| 1212 | TString title = ObjectInfo::getTitle(particle); | |||
| 1213 | if (!hasTrajectory) { | |||
| 1214 | //Hijack the mother label to show that the track position is only | |||
| 1215 | //extrapolated, not known from simulation | |||
| 1216 | title += "\n(track estimated from initial momentum)"; | |||
| 1217 | //Also, show those tracks with dashed lines | |||
| 1218 | m_mcparticleTracks[particle].track->SetLineStyle(2); | |||
| 1219 | } | |||
| 1220 | ||||
| 1221 | m_mcparticleTracks[particle].track->SetTitle(title); | |||
| 1222 | ||||
| 1223 | //add some color (avoid black & white) | |||
| 1224 | switch (abs(pdg)) { | |||
| 1225 | case 11: | |||
| 1226 | m_mcparticleTracks[particle].track->SetLineColor(kAzure); | |||
| 1227 | break; | |||
| 1228 | case 13: | |||
| 1229 | m_mcparticleTracks[particle].track->SetLineColor(kCyan + 1); | |||
| 1230 | break; | |||
| 1231 | case 22: | |||
| 1232 | m_mcparticleTracks[particle].track->SetLineColor(kSpring); | |||
| 1233 | break; | |||
| 1234 | case 211: | |||
| 1235 | m_mcparticleTracks[particle].track->SetLineColor(kGray + 1); | |||
| 1236 | break; | |||
| 1237 | case 321: | |||
| 1238 | m_mcparticleTracks[particle].track->SetLineColor(kRed + 1); | |||
| 1239 | break; | |||
| 1240 | case 2212: | |||
| 1241 | m_mcparticleTracks[particle].track->SetLineColor(kOrange - 2); | |||
| 1242 | break; | |||
| 1243 | default: | |||
| 1244 | m_mcparticleTracks[particle].track->SetLineColor(kMagenta); | |||
| 1245 | } | |||
| 1246 | ||||
| 1247 | //create point set for hits | |||
| 1248 | const TString pointsTitle = "SimHits for " + ObjectInfo::getIdentifier(particle) + " - " + particle_name; | |||
| 1249 | m_mcparticleTracks[particle].simhits = new TEvePointSet(pointsTitle); | |||
| 1250 | m_mcparticleTracks[particle].simhits->SetTitle(pointsTitle); | |||
| 1251 | m_mcparticleTracks[particle].simhits->SetMarkerStyle(6); | |||
| 1252 | m_mcparticleTracks[particle].simhits->SetMainColor(m_mcparticleTracks[particle].track->GetLineColor()); | |||
| 1253 | //m_mcparticleTracks[particle].simhits->SetMainTransparency(50); | |||
| 1254 | addObject(particle, m_mcparticleTracks[particle].track); | |||
| 1255 | } | |||
| 1256 | return &m_mcparticleTracks[particle]; | |||
| 1257 | } | |||
| 1258 | ||||
| 1259 | void EVEVisualization::makeTracks() | |||
| 1260 | { | |||
| 1261 | for (auto& mcTrackPair : m_mcparticleTracks) { | |||
| 1262 | MCTrack& mcTrack = mcTrackPair.second; | |||
| 1263 | if (mcTrack.track) { | |||
| 1264 | if (mcTrack.simhits->Size() > 0) { | |||
| 1265 | mcTrack.track->AddElement(mcTrack.simhits); | |||
| 1266 | } else { | |||
| 1267 | //if we don't add it, remove empty collection | |||
| 1268 | destroyEveElement(mcTrack.simhits); | |||
| 1269 | } | |||
| 1270 | ||||
| 1271 | TEveElement* parent = m_tracklist; | |||
| 1272 | if (mcTrack.parentParticle) { | |||
| 1273 | const auto& parentIt = m_mcparticleTracks.find(mcTrack.parentParticle); | |||
| 1274 | if (parentIt != m_mcparticleTracks.end()) { | |||
| 1275 | parent = parentIt->second.track; | |||
| 1276 | } | |||
| 1277 | } | |||
| 1278 | parent->AddElement(mcTrack.track); | |||
| 1279 | } else { //add simhits directly | |||
| 1280 | gEve->AddElement(mcTrack.simhits); | |||
| 1281 | } | |||
| 1282 | } | |||
| 1283 | gEve->AddElement(m_tracklist); | |||
| 1284 | m_tracklist->MakeTracks(); | |||
| 1285 | m_tracklist->SelectByP(c_minPCut, FLT_MAX3.40282347e+38F); //don't show too many particles by default... | |||
| 1286 | ||||
| 1287 | for (size_t i = 0; i < m_options.length(); i++) { | |||
| 1288 | if (m_options.at(i) == 'M') { | |||
| 1289 | m_gftrackpropagator->SetRnrDaughters(true); | |||
| 1290 | m_gftrackpropagator->SetRnrReferences(true); | |||
| 1291 | //m_gftrackpropagator->SetRnrFV(true); //TODO: this crashes? | |||
| 1292 | TMarker m; | |||
| 1293 | m.SetMarkerColor(c_trackMarkerColor); | |||
| 1294 | m.SetMarkerStyle(1); //a single pixel | |||
| 1295 | m.SetMarkerSize(1); //ignored. | |||
| 1296 | m_gftrackpropagator->RefPMAtt() = m; | |||
| 1297 | m_gftrackpropagator->RefFVAtt() = m; | |||
| 1298 | } | |||
| 1299 | } | |||
| 1300 | ||||
| 1301 | m_consttrackpropagator->SetMagField(0, 0, -1.5); | |||
| 1302 | ||||
| 1303 | m_eclData->DataChanged(); //update limits (Empty() won't work otherwise) | |||
| 1304 | if (!m_eclData->Empty()) { | |||
| 1305 | m_eclData->SetAxisFromBins(0.0, | |||
| 1306 | 0.0); //epsilon_x/y = 0 so we don't merge neighboring bins. This avoids some rendering issues with projections of small clusters. | |||
| 1307 | m_calo3d->SetData(m_eclData); | |||
| 1308 | } | |||
| 1309 | gEve->AddElement(m_calo3d); | |||
| 1310 | ||||
| 1311 | if (m_unassignedRecoHits) { | |||
| 1312 | m_unassignedRecoHits->SetRnrState(m_unassignedRecoHitsVisibility); | |||
| 1313 | gEve->AddElement(m_unassignedRecoHits); | |||
| 1314 | } | |||
| 1315 | ||||
| 1316 | } | |||
| 1317 | ||||
| 1318 | void EVEVisualization::clearEvent() | |||
| 1319 | { | |||
| 1320 | if (!gEve) | |||
| 1321 | return; | |||
| 1322 | ||||
| 1323 | VisualRepMap::getInstance()->clear(); | |||
| 1324 | for (auto& groupPair : m_groups) { | |||
| 1325 | //store visibility, invalidate pointers | |||
| 1326 | if (groupPair.second.group) | |||
| 1327 | groupPair.second.visible = groupPair.second.group->GetRnrState(); | |||
| 1328 | groupPair.second.group = nullptr; | |||
| 1329 | } | |||
| 1330 | ||||
| 1331 | m_mcparticleTracks.clear(); | |||
| 1332 | m_shownRecohits.clear(); | |||
| 1333 | m_tracklist->DestroyElements(); | |||
| 1334 | ||||
| 1335 | //remove ECL data from event | |||
| 1336 | m_calo3d->SetData(NULL__null); | |||
| 1337 | m_calo3d->DestroyElements(); | |||
| 1338 | ||||
| 1339 | //lower energy threshold for ECL | |||
| 1340 | float ecl_threshold = 0.01; | |||
| 1341 | if (m_eclData) | |||
| 1342 | ecl_threshold = m_eclData->GetSliceThreshold(0); | |||
| 1343 | ||||
| 1344 | destroyEveElement(m_eclData); | |||
| 1345 | m_eclData = new TEveCaloDataVec(1); //#slices | |||
| 1346 | m_eclData->IncDenyDestroy(); | |||
| 1347 | m_eclData->RefSliceInfo(0).Setup("ECL", ecl_threshold, kRed); | |||
| 1348 | ||||
| 1349 | if (m_unassignedRecoHits) | |||
| 1350 | m_unassignedRecoHitsVisibility = m_unassignedRecoHits->GetRnrState(); | |||
| 1351 | destroyEveElement(m_unassignedRecoHits); | |||
| 1352 | ||||
| 1353 | gEve->GetSelection()->RemoveElements(); | |||
| 1354 | gEve->GetHighlight()->RemoveElements(); | |||
| 1355 | //other things are cleaned up by TEve... | |||
| 1356 | } | |||
| 1357 | ||||
| 1358 | ||||
| 1359 | ||||
| 1360 | ||||
| 1361 | void EVEVisualization::addVertex(const genfit::GFRaveVertex* vertex) | |||
| 1362 | { | |||
| 1363 | ROOT::Math::XYZVector v = ROOT::Math::XYZVector(vertex->getPos()); | |||
| 1364 | TEvePointSet* vertexPoint = new TEvePointSet(ObjectInfo::getInfo(vertex)); | |||
| 1365 | //sadly, setting a title for a TEveGeoShape doesn't result in a popup... | |||
| 1366 | vertexPoint->SetTitle(ObjectInfo::getTitle(vertex)); | |||
| 1367 | vertexPoint->SetMainColor(c_recoHitColor); | |||
| 1368 | vertexPoint->SetNextPoint(v.X(), v.Y(), v.Z()); | |||
| 1369 | ||||
| 1370 | TMatrixDSymEigen eigen_values(vertex->getCov()); | |||
| 1371 | TEveGeoShape* det_shape = new TEveGeoShape(ObjectInfo::getInfo(vertex) + " Error"); | |||
| 1372 | det_shape->SetShape(new TGeoSphere(0., 1.)); //Initially created as a sphere, then "scaled" into an ellipsoid. | |||
| 1373 | fixGeoShapeRefCount(det_shape); | |||
| 1374 | const TVectorD& ev = eigen_values.GetEigenValues(); //Assigns the eigenvalues into the "ev" matrix. | |||
| 1375 | const TMatrixD& eVec = eigen_values.GetEigenVectors(); //Assigns the eigenvalues into the "eVec" matrix. | |||
| 1376 | //Define the 3 eigenvectors of the covariance matrix as objects of the ROOT::Math::XYZVector class using constructor. | |||
| 1377 | ROOT::Math::XYZVector eVec1(eVec(0, 0), eVec(1, 0), eVec(2, 0)); | |||
| 1378 | //eVec(i,j) uses the method/overloaded operator ( . ) of the TMatrixT class to return the matrix entry. | |||
| 1379 | ROOT::Math::XYZVector eVec2(eVec(0, 1), eVec(1, 1), eVec(2, 1)); | |||
| 1380 | ROOT::Math::XYZVector eVec3(eVec(0, 2), eVec(1, 2), eVec(2, 2)); | |||
| 1381 | // got everything we need ----------------------------------------------------- //Eigenvalues(semi axis) of the covariance matrix acquired! | |||
| 1382 | ||||
| 1383 | ||||
| 1384 | TGeoRotation det_rot("det_rot", (eVec1.Theta() * 180) / TMath::Pi(), (eVec1.Phi() * 180) / TMath::Pi(), | |||
| 1385 | (eVec2.Theta() * 180) / TMath::Pi(), (eVec2.Phi() * 180) / TMath::Pi(), | |||
| 1386 | (eVec3.Theta() * 180) / TMath::Pi(), (eVec3.Phi() * 180) / TMath::Pi()); // the rotation is already clear | |||
| 1387 | ||||
| 1388 | // set the scaled eigenvalues ------------------------------------------------- | |||
| 1389 | //"Scaled" eigenvalues pseudo_res (lengths of the semi axis) are the sqrt of the eigenvalues. | |||
| 1390 | double pseudo_res_0 = std::sqrt(ev(0)); | |||
| 1391 | double pseudo_res_1 = std::sqrt(ev(1)); | |||
| 1392 | double pseudo_res_2 = std::sqrt(ev(2)); | |||
| 1393 | ||||
| 1394 | //B2INFO("The pseudo_res_0/1/2 are " << pseudo_res_0 << "," << pseudo_res_1 << "," << pseudo_res_2); //shows the scaled eigenvalues | |||
| 1395 | ||||
| 1396 | ||||
| 1397 | ||||
| 1398 | // rotate and translate ------------------------------------------------------- | |||
| 1399 | TGeoGenTrans det_trans(v.X(), v.Y(), v.Z(), pseudo_res_0, pseudo_res_1, pseudo_res_2, | |||
| 1400 | &det_rot); //Puts the ellipsoid at the position of the vertex, v(0)=v.X(), operator () overloaded. | |||
| 1401 | det_shape->SetTransMatrix(det_trans); | |||
| 1402 | // finished rotating and translating ------------------------------------------ | |||
| 1403 | ||||
| 1404 | det_shape->SetMainColor(kOrange); //The color of the error ellipsoid. | |||
| 1405 | det_shape->SetMainTransparency(0); | |||
| 1406 | ||||
| 1407 | vertexPoint->AddElement(det_shape); | |||
| 1408 | addToGroup("Vertices", vertexPoint); | |||
| 1409 | addObject(vertex, vertexPoint); | |||
| 1410 | } | |||
| 1411 | ||||
| 1412 | ||||
| 1413 | void EVEVisualization::addECLCluster(const ECLCluster* cluster) | |||
| 1414 | { | |||
| 1415 | ||||
| 1416 | // only display c_nPhotons hypothesis clusters | |||
| 1417 | if (cluster->hasHypothesis(ECLCluster::EHypothesisBit::c_nPhotons)) { | |||
| 1418 | ||||
| 1419 | const float phi = cluster->getPhi(); | |||
| 1420 | float dPhi = cluster->getUncertaintyPhi(); | |||
| 1421 | float dTheta = cluster->getUncertaintyTheta(); | |||
| 1422 | if (dPhi >= M_PI3.14159265358979323846 / 4 or dTheta >= M_PI3.14159265358979323846 / 4 or cluster->getUncertaintyEnergy() == 1.0) { | |||
| 1423 | B2WARNING("Found ECL cluster with broken errors (unit matrix or too large). Using 0.05 as error in phi/theta. The 3x3 error matrix previously was:")do { if (Belle2::LogSystem::Instance().isLevelEnabled(Belle2:: LogConfig::c_Warning, 0, "display")) { { LogVariableStream varStream ; varStream << "Found ECL cluster with broken errors (unit matrix or too large). Using 0.05 as error in phi/theta. The 3x3 error matrix previously was:" ; Belle2::LogSystem::Instance().sendMessage(Belle2::LogMessage (Belle2::LogConfig::c_Warning, std::move(varStream), "display" , __PRETTY_FUNCTION__, "display/src/EVEVisualization.cc", 1423 , 0)); }; } } while(false); | |||
| 1424 | cluster->getCovarianceMatrix3x3().Print(); | |||
| 1425 | dPhi = dTheta = 0.05; | |||
| 1426 | } | |||
| 1427 | ||||
| 1428 | if (!std::isfinite(dPhi) or !std::isfinite(dTheta)) { | |||
| 1429 | B2ERROR("ECLCluster phi or theta error is NaN or infinite, skipping cluster!")do { { LogVariableStream varStream; varStream << "ECLCluster phi or theta error is NaN or infinite, skipping cluster!" ; Belle2::LogSystem::Instance().sendMessage(Belle2::LogMessage (Belle2::LogConfig::c_Error, std::move(varStream), "display", __PRETTY_FUNCTION__, "display/src/EVEVisualization.cc", 1429 , 0)); } } while(false); | |||
| 1430 | return; | |||
| 1431 | } | |||
| 1432 | ||||
| 1433 | //convert theta +- dTheta into eta +- dEta | |||
| 1434 | ROOT::Math::XYZVector thetaLow; | |||
| 1435 | VectorUtil::setPtThetaPhi(thetaLow, 1.0, cluster->getTheta() - dTheta, phi); | |||
| 1436 | ROOT::Math::XYZVector thetaHigh; | |||
| 1437 | VectorUtil::setPtThetaPhi(thetaHigh, 1.0, cluster->getTheta() + dTheta, phi); | |||
| 1438 | float etaLow = thetaLow.Eta(); | |||
| 1439 | float etaHigh = thetaHigh.Eta(); | |||
| 1440 | if (etaLow > etaHigh) { | |||
| 1441 | std::swap(etaLow, etaHigh); | |||
| 1442 | } | |||
| 1443 | ||||
| 1444 | int id = m_eclData->AddTower(etaLow, etaHigh, phi - dPhi, phi + dPhi); | |||
| 1445 | m_eclData->FillSlice(0, cluster->getEnergy(ECLCluster::EHypothesisBit::c_nPhotons)); | |||
| 1446 | VisualRepMap::getInstance()->addCluster(cluster, m_eclData, id); | |||
| 1447 | } | |||
| 1448 | } | |||
| 1449 | ||||
| 1450 | void EVEVisualization::addKLMCluster(const KLMCluster* cluster) | |||
| 1451 | { | |||
| 1452 | const double layerThicknessCm = 3.16; //TDR, Fig 10.2 | |||
| 1453 | const double layerDistanceCm = 9.1 - layerThicknessCm; | |||
| 1454 | ||||
| 1455 | // Pposition of first RPC plane. | |||
| 1456 | ROOT::Math::XYZVector position = cluster->getClusterPosition(); | |||
| 1457 | ROOT::Math::XYZVector startPos(position.X(), position.Y(), position.Z()); | |||
| 1458 | ROOT::Math::XYZVector dir; //direction of cluster stack, Mag() == distance between planes | |||
| 1459 | ROOT::Math::XYZVector a, b; //defines RPC plane | |||
| 1460 | bool isBarrel = (startPos.Z() > -175.0 and startPos.Z() < 270.0); | |||
| 1461 | if (isBarrel) { | |||
| 1462 | //barrel | |||
| 1463 | b = ROOT::Math::XYZVector(0, 0, 1); | |||
| 1464 | a = startPos.Cross(b).Unit(); | |||
| 1465 | double c = M_PI3.14159265358979323846 / 4.0; | |||
| 1466 | double offset = c / 2.0 + M_PI3.14159265358979323846; | |||
| 1467 | VectorUtil::setPhi(a, int((a.Phi() + offset) / (c))*c - M_PI3.14159265358979323846); | |||
| 1468 | ROOT::Math::XYZVector perp = b.Cross(a); | |||
| 1469 | ||||
| 1470 | const double barrelRadiusCm = 204.0; | |||
| 1471 | VectorUtil::setMag(startPos, barrelRadiusCm / perp.Dot(startPos.Unit())); | |||
| 1472 | ||||
| 1473 | dir = startPos.Unit(); | |||
| 1474 | VectorUtil::setMag(dir, (layerDistanceCm + layerThicknessCm) / perp.Dot(dir)); | |||
| 1475 | } else { | |||
| 1476 | //endcap | |||
| 1477 | b = ROOT::Math::XYZVector(startPos.X(), startPos.Y(), 0).Unit(); | |||
| 1478 | a = startPos.Cross(b).Unit(); | |||
| 1479 | double endcapStartZ = 284; | |||
| 1480 | if (startPos.Z() < 0) | |||
| 1481 | endcapStartZ = -189.5; | |||
| 1482 | ||||
| 1483 | double scaleFac = endcapStartZ / startPos.Z(); | |||
| 1484 | VectorUtil::setMag(startPos, startPos.R() * scaleFac); | |||
| 1485 | ||||
| 1486 | dir = startPos.Unit(); | |||
| 1487 | VectorUtil::setMag(dir, (layerDistanceCm + layerThicknessCm) / fabs(dir.Z())); | |||
| 1488 | } | |||
| 1489 | ||||
| 1490 | for (int i = 0; i < cluster->getLayers(); i++) { | |||
| 1491 | ROOT::Math::XYZVector layerPos = startPos; | |||
| 1492 | layerPos += (cluster->getInnermostLayer() + i) * dir; | |||
| 1493 | auto* layer = boxCreator(layerPos, a, b, 20.0, 20.0, layerThicknessCm / 2); | |||
| 1494 | layer->SetMainColor(c_klmClusterColor); | |||
| 1495 | layer->SetMainTransparency(70); | |||
| 1496 | layer->SetName(ObjectInfo::getIdentifier(cluster)); | |||
| 1497 | layer->SetTitle(ObjectInfo::getTitle(cluster)); | |||
| 1498 | ||||
| 1499 | addToGroup(std::string("KLMClusters/") + ObjectInfo::getIdentifier(cluster).Data(), layer); | |||
| 1500 | addObject(cluster, layer); | |||
| 1501 | } | |||
| 1502 | } | |||
| 1503 | ||||
| 1504 | void EVEVisualization::addBKLMHit2d(const KLMHit2d* bklm2dhit) | |||
| 1505 | { | |||
| 1506 | const bklm::GeometryPar* m_GeoPar = Belle2::bklm::GeometryPar::instance(); | |||
| 1507 | const bklm::Module* module = m_GeoPar->findModule(bklm2dhit->getSection(), bklm2dhit->getSector(), bklm2dhit->getLayer()); | |||
| 1508 | ||||
| 1509 | CLHEP::Hep3Vector global; | |||
| 1510 | //+++ global coordinates of the hit | |||
| 1511 | global[0] = bklm2dhit->getPositionX(); | |||
| 1512 | global[1] = bklm2dhit->getPositionY(); | |||
| 1513 | global[2] = bklm2dhit->getPositionZ(); | |||
| 1514 | ||||
| 1515 | //+++ local coordinates of the hit | |||
| 1516 | CLHEP::Hep3Vector local = module->globalToLocal(global); | |||
| 1517 | //double localU = local[1]; //phi | |||
| 1518 | //double localV = local[2]; //z | |||
| 1519 | int Nphistrip = bklm2dhit->getPhiStripMax() - bklm2dhit->getPhiStripMin() + 1; | |||
| 1520 | int Nztrip = bklm2dhit->getZStripMax() - bklm2dhit->getZStripMin() + 1; | |||
| 1521 | double du = module->getPhiStripWidth() * Nphistrip; | |||
| 1522 | double dv = module->getZStripWidth() * Nztrip; | |||
| 1523 | ||||
| 1524 | //Let's do some simple thing | |||
| 1525 | CLHEP::Hep3Vector localU(local[0], local[1] + 1.0, local[2]); | |||
| 1526 | CLHEP::Hep3Vector localV(local[0], local[1], local[2] + 1.0); | |||
| 1527 | ||||
| 1528 | CLHEP::Hep3Vector globalU = module->localToGlobal(localU); | |||
| 1529 | CLHEP::Hep3Vector globalV = module->localToGlobal(localV); | |||
| 1530 | ||||
| 1531 | ROOT::Math::XYZVector o(global[0], global[1], global[2]); | |||
| 1532 | ROOT::Math::XYZVector u(globalU[0], globalU[1], globalU[2]); | |||
| 1533 | ROOT::Math::XYZVector v(globalV[0], globalV[1], globalV[2]); | |||
| 1534 | ||||
| 1535 | //Lest's just assign the depth is 1.0 cm (thickness of a layer), better to update | |||
| 1536 | TEveBox* bklmbox = boxCreator(o, u - o, v - o, du, dv, 1.0); | |||
| 1537 | ||||
| 1538 | bklmbox->SetMainColor(kGreen); | |||
| 1539 | //bklmbox->SetName((std::to_string(hitModule)).c_str()); | |||
| 1540 | bklmbox->SetName("BKLMHit2d"); | |||
| 1541 | ||||
| 1542 | addToGroup("BKLM2dHits", bklmbox); | |||
| 1543 | addObject(bklm2dhit, bklmbox); | |||
| 1544 | } | |||
| 1545 | ||||
| 1546 | void EVEVisualization::addEKLMHit2d(const KLMHit2d* eklm2dhit) | |||
| 1547 | { | |||
| 1548 | const double du = 2.0; | |||
| 1549 | const double dv = 2.0; | |||
| 1550 | ROOT::Math::XYZVector hitPosition = eklm2dhit->getPosition(); | |||
| 1551 | ROOT::Math::XYZVector o(hitPosition.X(), hitPosition.Y(), hitPosition.Z()); | |||
| 1552 | ROOT::Math::XYZVector u(1.0, 0.0, 0.0); | |||
| 1553 | ROOT::Math::XYZVector v(0.0, 1.0, 0.0); | |||
| 1554 | TEveBox* eklmbox = boxCreator(o, u, v, du, dv, 4.0); | |||
| 1555 | eklmbox->SetMainColor(kGreen); | |||
| 1556 | eklmbox->SetName("EKLMHit2d"); | |||
| 1557 | addToGroup("EKLM2dHits", eklmbox); | |||
| 1558 | addObject(eklm2dhit, eklmbox); | |||
| 1559 | } | |||
| 1560 | ||||
| 1561 | void EVEVisualization::addROI(const ROIid* roi) | |||
| 1562 | { | |||
| 1563 | const VXD::GeoCache& aGeometry = VXD::GeoCache::getInstance(); | |||
| 1564 | ||||
| 1565 | VxdID sensorID = roi->getSensorID(); | |||
| 1566 | const VXD::SensorInfoBase& aSensorInfo = aGeometry.getSensorInfo(sensorID); | |||
| 1567 | ||||
| 1568 | double minU = aSensorInfo.getUCellPosition(roi->getMinUid(), roi->getMinVid()); | |||
| 1569 | double minV = aSensorInfo.getVCellPosition(roi->getMinVid()); | |||
| 1570 | double maxU = aSensorInfo.getUCellPosition(roi->getMaxUid(), roi->getMaxVid()); | |||
| 1571 | double maxV = aSensorInfo.getVCellPosition(roi->getMaxVid()); | |||
| 1572 | ||||
| 1573 | ||||
| 1574 | ROOT::Math::XYZVector localA(minU, minV, 0); | |||
| 1575 | ROOT::Math::XYZVector localB(minU, maxV, 0); | |||
| 1576 | ROOT::Math::XYZVector localC(maxU, minV, 0); | |||
| 1577 | ||||
| 1578 | ROOT::Math::XYZVector globalA = aSensorInfo.pointToGlobal(localA); | |||
| 1579 | ROOT::Math::XYZVector globalB = aSensorInfo.pointToGlobal(localB); | |||
| 1580 | ROOT::Math::XYZVector globalC = aSensorInfo.pointToGlobal(localC); | |||
| 1581 | ||||
| 1582 | TEveBox* ROIbox = boxCreator(globalB + globalC * 0.5, globalB - globalA, globalC - globalA, 1, 1, 0.01); | |||
| 1583 | ||||
| 1584 | ROIbox->SetName(ObjectInfo::getIdentifier(roi)); | |||
| 1585 | ROIbox->SetMainColor(kSpring - 9); | |||
| 1586 | ROIbox->SetMainTransparency(50); | |||
| 1587 | ||||
| 1588 | addToGroup("ROIs", ROIbox); | |||
| ||||
| 1589 | addObject(roi, ROIbox); | |||
| 1590 | } | |||
| 1591 | ||||
| 1592 | void EVEVisualization::addRecoHit(const SVDCluster* hit, TEveStraightLineSet* lines) | |||
| 1593 | { | |||
| 1594 | static VXD::GeoCache& geo = VXD::GeoCache::getInstance(); | |||
| 1595 | const VXD::SensorInfoBase& sensor = geo.getSensorInfo(hit->getSensorID()); | |||
| 1596 | ||||
| 1597 | ROOT::Math::XYZVector a, b; | |||
| 1598 | if (hit->isUCluster()) { | |||
| 1599 | const float u = hit->getPosition(); | |||
| 1600 | a = sensor.pointToGlobal(ROOT::Math::XYZVector(sensor.getBackwardWidth() / sensor.getWidth(0) * u, -0.5 * sensor.getLength(), 0.0)); | |||
| 1601 | b = sensor.pointToGlobal(ROOT::Math::XYZVector(sensor.getForwardWidth() / sensor.getWidth(0) * u, +0.5 * sensor.getLength(), 0.0)); | |||
| 1602 | } else { | |||
| 1603 | const float v = hit->getPosition(); | |||
| 1604 | a = sensor.pointToGlobal(ROOT::Math::XYZVector(-0.5 * sensor.getWidth(v), v, 0.0)); | |||
| 1605 | b = sensor.pointToGlobal(ROOT::Math::XYZVector(+0.5 * sensor.getWidth(v), v, 0.0)); | |||
| 1606 | } | |||
| 1607 | ||||
| 1608 | lines->AddLine(a.X(), a.Y(), a.Z(), b.X(), b.Y(), b.Z()); | |||
| 1609 | m_shownRecohits.insert(hit); | |||
| 1610 | } | |||
| 1611 | ||||
| 1612 | void EVEVisualization::addRecoHit(const CDCHit* hit, TEveStraightLineSet* lines) | |||
| 1613 | { | |||
| 1614 | static CDC::CDCGeometryPar& cdcgeo = CDC::CDCGeometryPar::Instance(); | |||
| 1615 | const ROOT::Math::XYZVector& wire_pos_f = cdcgeo.wireForwardPosition(WireID(hit->getID())); | |||
| 1616 | const ROOT::Math::XYZVector& wire_pos_b = cdcgeo.wireBackwardPosition(WireID(hit->getID())); | |||
| 1617 | ||||
| 1618 | lines->AddLine(wire_pos_f.X(), wire_pos_f.Y(), wire_pos_f.Z(), wire_pos_b.X(), wire_pos_b.Y(), wire_pos_b.Z()); | |||
| 1619 | m_shownRecohits.insert(hit); | |||
| 1620 | ||||
| 1621 | } | |||
| 1622 | ||||
| 1623 | void EVEVisualization::addCDCHit(const CDCHit* hit, bool showTriggerHits) | |||
| 1624 | { | |||
| 1625 | static CDC::CDCGeometryPar& cdcgeo = CDC::CDCGeometryPar::Instance(); | |||
| 1626 | const B2Vector3D& wire_pos_f = cdcgeo.wireForwardPosition(WireID(hit->getID())); | |||
| 1627 | const B2Vector3D& wire_pos_b = cdcgeo.wireBackwardPosition(WireID(hit->getID())); | |||
| 1628 | static CDC::RealisticTDCCountTranslator tdcTranslator; | |||
| 1629 | TEveGeoShape* cov_shape = new TEveGeoShape("cov_shape"); | |||
| 1630 | //TODO: leftrightflag not set! (same for other parameters, unsure which ones should be set) | |||
| 1631 | double driftLength = tdcTranslator.getDriftLength(hit->getTDCCount(), WireID(hit->getID())); | |||
| 1632 | double driftLengthRes = tdcTranslator.getDriftLengthResolution(driftLength, WireID(hit->getID())); | |||
| 1633 | driftLengthRes = std::max(driftLengthRes, 0.005); | |||
| 1634 | const double lengthOfWireSection = 3.0; | |||
| 1635 | ||||
| 1636 | //z in wire direction, x,y orthogonal | |||
| 1637 | const B2Vector3D zaxis = wire_pos_b - wire_pos_f; | |||
| 1638 | const B2Vector3D xaxis = zaxis.Orthogonal(); | |||
| 1639 | const B2Vector3D yaxis = xaxis.Cross(zaxis); | |||
| 1640 | ||||
| 1641 | // move to z=0 | |||
| 1642 | const B2Vector3D midPoint = wire_pos_f - zaxis * (wire_pos_f.Z() / zaxis.Z()); | |||
| 1643 | ||||
| 1644 | cov_shape->SetShape(new TGeoTube(std::max(0., (double)(driftLength - driftLengthRes)), driftLength + driftLengthRes, | |||
| 1645 | lengthOfWireSection)); | |||
| 1646 | fixGeoShapeRefCount(cov_shape); | |||
| 1647 | ||||
| 1648 | TGeoRotation det_rot("det_rot", | |||
| 1649 | xaxis.Theta() * 180 / TMath::Pi(), xaxis.Phi() * 180 / TMath::Pi(), | |||
| 1650 | yaxis.Theta() * 180 / TMath::Pi(), yaxis.Phi() * 180 / TMath::Pi(), | |||
| 1651 | zaxis.Theta() * 180 / TMath::Pi(), zaxis.Phi() * 180 / TMath::Pi() | |||
| 1652 | ); | |||
| 1653 | ||||
| 1654 | TGeoCombiTrans det_trans(midPoint.X(), midPoint.Y(), midPoint.Z(), &det_rot); | |||
| 1655 | cov_shape->SetTransMatrix(det_trans); | |||
| 1656 | ||||
| 1657 | // get relation to trigger track segments | |||
| 1658 | bool isPartOfTS = false; | |||
| 1659 | const auto segments = hit->getRelationsFrom<CDCTriggerSegmentHit>(); | |||
| 1660 | if (showTriggerHits && segments.size() > 0) { | |||
| 1661 | isPartOfTS = true; | |||
| 1662 | } | |||
| 1663 | ||||
| 1664 | if (hit->getISuperLayer() % 2 == 0) { | |||
| 1665 | if (isPartOfTS) | |||
| 1666 | cov_shape->SetMainColor(kCyan + 3); | |||
| 1667 | else | |||
| 1668 | cov_shape->SetMainColor(kCyan); | |||
| 1669 | } else { | |||
| 1670 | if (isPartOfTS) | |||
| 1671 | cov_shape->SetMainColor(kPink + 6); | |||
| 1672 | else | |||
| 1673 | cov_shape->SetMainColor(kPink + 7); | |||
| 1674 | } | |||
| 1675 | ||||
| 1676 | cov_shape->SetMainTransparency(50); | |||
| 1677 | cov_shape->SetName(ObjectInfo::getIdentifier(hit)); | |||
| 1678 | cov_shape->SetTitle(ObjectInfo::getInfo(hit) + TString::Format("\nWire ID: %d\nADC: %d\nTDC: %d", | |||
| 1679 | hit->getID(), hit->getADCCount(), hit->getTDCCount())); | |||
| 1680 | ||||
| 1681 | addToGroup("CDCHits", cov_shape); | |||
| 1682 | addObject(hit, cov_shape); | |||
| 1683 | if (isPartOfTS) { | |||
| 1684 | addToGroup("CDCTriggerSegmentHits", cov_shape); | |||
| 1685 | for (auto rel : segments.relations()) { | |||
| 1686 | addObject(rel.object, cov_shape); | |||
| 1687 | } | |||
| 1688 | } | |||
| 1689 | } | |||
| 1690 | ||||
| 1691 | void EVEVisualization::addCDCTriggerSegmentHit(const std::string& collectionName, const CDCTriggerSegmentHit* hit) | |||
| 1692 | { | |||
| 1693 | static CDC::CDCGeometryPar& cdcgeo = CDC::CDCGeometryPar::Instance(); | |||
| 1694 | TEveStraightLineSet* shape = new TEveStraightLineSet(); | |||
| 1695 | ||||
| 1696 | // get center wire | |||
| 1697 | unsigned iL = WireID(hit->getID()).getICLayer(); | |||
| 1698 | if (hit->getPriorityPosition() < 3) iL -= 1; | |||
| 1699 | unsigned nWires = cdcgeo.nWiresInLayer(iL); | |||
| 1700 | unsigned iCenter = hit->getIWire(); | |||
| 1701 | if (hit->getPriorityPosition() == 1) iCenter += 1; | |||
| 1702 | ||||
| 1703 | // a track segment consists of 11 wires (15 in SL0) in a special configuration | |||
| 1704 | // -> get the shift with respect to the center wire (*) for all wires | |||
| 1705 | // SL 1-8: | |||
| 1706 | // _ _ _ | |||
| 1707 | // |_|_|_| | |||
| 1708 | // |_|_| | |||
| 1709 | // |*| | |||
| 1710 | // |_|_| | |||
| 1711 | // |_|_|_| | |||
| 1712 | std::vector<int> layershift = { -2, -1, 0, 1, 2}; | |||
| 1713 | std::vector<std::vector<float>> cellshift = { | |||
| 1714 | { -1, 0, 1}, | |||
| 1715 | { -0.5, 0.5}, | |||
| 1716 | { 0}, | |||
| 1717 | { -0.5, 0.5}, | |||
| 1718 | { -1, 0, 1} | |||
| 1719 | }; | |||
| 1720 | // SL 0: | |||
| 1721 | // _ _ _ _ _ | |||
| 1722 | // |_|_|_|_|_| | |||
| 1723 | // |_|_|_|_| | |||
| 1724 | // |_|_|_| | |||
| 1725 | // |_|_| | |||
| 1726 | // |*| | |||
| 1727 | if (hit->getISuperLayer() == 0) { | |||
| 1728 | layershift = { 0, 1, 2, 3, 4}; | |||
| 1729 | cellshift = { | |||
| 1730 | { 0}, | |||
| 1731 | { -0.5, 0.5}, | |||
| 1732 | { -1, 0, 1}, | |||
| 1733 | { -1.5, -0.5, 0.5, 1.5}, | |||
| 1734 | { -2, -1, 0, 1, 2} | |||
| 1735 | }; | |||
| 1736 | } | |||
| 1737 | ||||
| 1738 | // draw all cells in segment | |||
| 1739 | for (unsigned il = 0; il < layershift.size(); ++il) { | |||
| 1740 | for (unsigned ic = 0; ic < cellshift[il].size(); ++ic) { | |||
| 1741 | ROOT::Math::XYZVector corners[2][2]; | |||
| 1742 | for (unsigned ir = 0; ir < 2; ++ir) { | |||
| 1743 | double r = cdcgeo.fieldWireR(iL + layershift[il] - ir); | |||
| 1744 | double fz = cdcgeo.fieldWireFZ(iL + layershift[il] - ir); | |||
| 1745 | double bz = cdcgeo.fieldWireBZ(iL + layershift[il] - ir); | |||
| 1746 | for (unsigned iphi = 0; iphi < 2; ++iphi) { | |||
| 1747 | double phib = (iCenter + cellshift[il][ic] + iphi - 0.5) * 2 * M_PI3.14159265358979323846 / nWires; | |||
| 1748 | double phif = phib + cdcgeo.nShifts(iL + layershift[il]) * M_PI3.14159265358979323846 / nWires; | |||
| 1749 | ||||
| 1750 | ROOT::Math::XYZVector pos_f = ROOT::Math::XYZVector(cos(phif) * r, sin(phif) * r, fz); | |||
| 1751 | ROOT::Math::XYZVector pos_b = ROOT::Math::XYZVector(cos(phib) * r, sin(phib) * r, bz); | |||
| 1752 | ROOT::Math::XYZVector zaxis = pos_b - pos_f; | |||
| 1753 | corners[ir][iphi] = pos_f - zaxis * (pos_f.Z() / zaxis.Z()); | |||
| 1754 | } | |||
| 1755 | } | |||
| 1756 | ||||
| 1757 | shape->AddLine(corners[0][0].X(), corners[0][0].Y(), 0, | |||
| 1758 | corners[0][1].X(), corners[0][1].Y(), 0); | |||
| 1759 | shape->AddLine(corners[0][1].X(), corners[0][1].Y(), 0, | |||
| 1760 | corners[1][1].X(), corners[1][1].Y(), 0); | |||
| 1761 | shape->AddLine(corners[1][1].X(), corners[1][1].Y(), 0, | |||
| 1762 | corners[1][0].X(), corners[1][0].Y(), 0); | |||
| 1763 | shape->AddLine(corners[1][0].X(), corners[1][0].Y(), 0, | |||
| 1764 | corners[0][0].X(), corners[0][0].Y(), 0); | |||
| 1765 | } | |||
| 1766 | } | |||
| 1767 | ||||
| 1768 | if (hit->getISuperLayer() % 2 == 0) { | |||
| 1769 | shape->SetMainColor(kCyan + 3); | |||
| 1770 | } else { | |||
| 1771 | shape->SetMainColor(kPink + 6); | |||
| 1772 | } | |||
| 1773 | ||||
| 1774 | shape->SetName(ObjectInfo::getIdentifier(hit)); | |||
| 1775 | shape->SetTitle(ObjectInfo::getTitle(hit) + | |||
| 1776 | TString::Format("\nPriority: %d\nLeft/Right: %d", | |||
| 1777 | hit->getPriorityPosition(), hit->getLeftRight())); | |||
| 1778 | addToGroup(collectionName, shape); | |||
| 1779 | addObject(hit, shape); | |||
| 1780 | } | |||
| 1781 | ||||
| 1782 | void EVEVisualization::addARICHHit(const ARICHHit* hit) | |||
| 1783 | { | |||
| 1784 | DBObjPtr<ARICHGeometryConfig> arichGeo; | |||
| 1785 | ||||
| 1786 | int hitModule = hit->getModule(); | |||
| 1787 | float fi = arichGeo->getDetectorPlane().getSlotPhi(hitModule); | |||
| 1788 | ||||
| 1789 | ROOT::Math::XYZVector centerPos3D = hit->getPosition(); | |||
| 1790 | ||||
| 1791 | ROOT::Math::RotationZ rotZ(fi); | |||
| 1792 | ROOT::Math::XYZVector channelX(1, 0, 0); | |||
| 1793 | ROOT::Math::XYZVector channelY(0, 1, 0); | |||
| 1794 | channelX = rotZ * channelX; | |||
| 1795 | channelY = rotZ * channelY; | |||
| 1796 | ||||
| 1797 | auto* arichbox = boxCreator(centerPos3D, | |||
| 1798 | arichGeo->getMasterVolume().momentumToGlobal(channelX), | |||
| 1799 | arichGeo->getMasterVolume().momentumToGlobal(channelY), | |||
| 1800 | 0.49, 0.49, 0.05); | |||
| 1801 | arichbox->SetMainColor(kOrange + 10); | |||
| 1802 | arichbox->SetName((std::to_string(hitModule)).c_str()); | |||
| 1803 | ||||
| 1804 | addToGroup("ARICHHits", arichbox); | |||
| 1805 | addObject(hit, arichbox); | |||
| 1806 | } | |||
| 1807 | ||||
| 1808 | void EVEVisualization::addTOPDigits(const StoreArray<TOPDigit>& digits) | |||
| 1809 | { | |||
| 1810 | /* TOP module ID -> #digits */ | |||
| 1811 | std::map<int, int> m_topSummary; | |||
| 1812 | for (const TOPDigit& hit : digits) { | |||
| 1813 | int mod = hit.getModuleID(); | |||
| 1814 | ++m_topSummary[mod]; | |||
| 1815 | } | |||
| 1816 | int maxcount = 0; | |||
| 1817 | for (auto modCountPair : m_topSummary) { | |||
| 1818 | if (modCountPair.second > maxcount) | |||
| 1819 | maxcount = modCountPair.second; | |||
| 1820 | } | |||
| 1821 | for (auto modCountPair : m_topSummary) { | |||
| 1822 | const auto& topmod = TOP::TOPGeometryPar::Instance()->getGeometry()->getModule(modCountPair.first); | |||
| 1823 | double phi = topmod.getPhi(); | |||
| 1824 | double r_center = topmod.getRadius(); | |||
| 1825 | double z = topmod.getZc(); | |||
| 1826 | ||||
| 1827 | ROOT::Math::XYZVector centerPos3D; | |||
| 1828 | VectorUtil::setMagThetaPhi(centerPos3D, r_center, M_PI3.14159265358979323846 / 2, phi); | |||
| 1829 | centerPos3D.SetZ(z); | |||
| 1830 | ||||
| 1831 | B2Vector3D channelX(1, 0, 0); channelX.RotateZ(phi); | |||
| 1832 | B2Vector3D channelY(0, 1, 0); channelY.RotateZ(phi); | |||
| 1833 | ||||
| 1834 | //bar is a bit thicker so we can mouse over without getting the geometry | |||
| 1835 | auto* moduleBox = boxCreator(centerPos3D, channelX, channelY, | |||
| 1836 | 3.0 * topmod.getBarThickness(), topmod.getBarWidth(), topmod.getBarLength()); | |||
| 1837 | moduleBox->SetMainColor(kAzure + 10); | |||
| 1838 | double weight = double(modCountPair.second) / maxcount; | |||
| 1839 | moduleBox->SetMainTransparency(90 - weight * 50); | |||
| 1840 | moduleBox->SetName(("TOP module " + std::to_string(modCountPair.first)).c_str()); | |||
| 1841 | moduleBox->SetTitle(TString::Format("#TOPDigits: %d ", modCountPair.second)); | |||
| 1842 | ||||
| 1843 | addToGroup("TOP Modules", moduleBox); | |||
| 1844 | //associate all TOPDigits with this module. | |||
| 1845 | for (const TOPDigit& hit : digits) { | |||
| 1846 | if (modCountPair.first == hit.getModuleID()) | |||
| 1847 | addObject(&hit, moduleBox); | |||
| 1848 | } | |||
| 1849 | } | |||
| 1850 | } | |||
| 1851 | ||||
| 1852 | ||||
| 1853 | void EVEVisualization::showUserData(const DisplayData& displayData) | |||
| 1854 | { | |||
| 1855 | for (const auto& labelPair : displayData.m_labels) { | |||
| 1856 | TEveText* text = new TEveText(labelPair.first.c_str()); | |||
| 1857 | text->SetName(labelPair.first.c_str()); | |||
| 1858 | text->SetTitle(labelPair.first.c_str()); | |||
| 1859 | text->SetMainColor(kGray + 1); | |||
| 1860 | const ROOT::Math::XYZVector& p = labelPair.second; | |||
| 1861 | text->PtrMainTrans()->SetPos(p.X(), p.Y(), p.Z()); | |||
| 1862 | addToGroup("DisplayData", text); | |||
| 1863 | } | |||
| 1864 | ||||
| 1865 | for (const auto& pointPair : displayData.m_pointSets) { | |||
| 1866 | TEvePointSet* points = new TEvePointSet(pointPair.first.c_str()); | |||
| 1867 | points->SetTitle(pointPair.first.c_str()); | |||
| 1868 | points->SetMarkerStyle(7); | |||
| 1869 | points->SetMainColor(kGreen); | |||
| 1870 | for (const auto& p : pointPair.second) { | |||
| 1871 | points->SetNextPoint(p.X(), p.Y(), p.Z()); | |||
| 1872 | } | |||
| 1873 | addToGroup("DisplayData", points); | |||
| 1874 | } | |||
| 1875 | ||||
| 1876 | int randomColor = 2; //primary colours, changing rapidly with index | |||
| 1877 | for (const auto& arrow : displayData.m_arrows) { | |||
| 1878 | const ROOT::Math::XYZVector pos = arrow.start; | |||
| 1879 | const ROOT::Math::XYZVector dir = arrow.end - pos; | |||
| 1880 | TEveArrow* eveArrow = new TEveArrow(dir.X(), dir.Y(), dir.Z(), pos.X(), pos.Y(), pos.Z()); | |||
| 1881 | eveArrow->SetName(arrow.name.c_str()); | |||
| 1882 | eveArrow->SetTitle(arrow.name.c_str()); | |||
| 1883 | int arrowColor = arrow.color; | |||
| 1884 | if (arrowColor == -1) { | |||
| 1885 | arrowColor = randomColor; | |||
| 1886 | randomColor++; | |||
| 1887 | } | |||
| 1888 | eveArrow->SetMainColor(arrowColor); | |||
| 1889 | ||||
| 1890 | //add label | |||
| 1891 | TEveText* text = new TEveText(arrow.name.c_str()); | |||
| 1892 | text->SetMainColor(arrowColor); | |||
| 1893 | //place label in middle of arrow, with some slight offset | |||
| 1894 | // orthogonal direction is arbitrary, set smallest component zero | |||
| 1895 | ROOT::Math::XYZVector orthogonalDir; | |||
| 1896 | if (std::abs(dir.X()) < std::abs(dir.Y())) { | |||
| 1897 | if (std::abs(dir.X()) < std::abs(dir.Z())) { | |||
| 1898 | orthogonalDir.SetCoordinates(0, dir.Z(), -dir.Y()); | |||
| 1899 | } else { | |||
| 1900 | orthogonalDir.SetCoordinates(dir.Y(), -dir.X(), 0); | |||
| 1901 | } | |||
| 1902 | } else { | |||
| 1903 | if (std::abs(dir.Y()) < std::abs(dir.Z())) { | |||
| 1904 | orthogonalDir.SetCoordinates(-dir.Z(), 0, dir.X()); | |||
| 1905 | } else { | |||
| 1906 | orthogonalDir.SetCoordinates(dir.Y(), -dir.X(), 0); | |||
| 1907 | } | |||
| 1908 | } | |||
| 1909 | const ROOT::Math::XYZVector& labelPos = pos + 0.5 * dir + 0.1 * orthogonalDir; | |||
| 1910 | text->PtrMainTrans()->SetPos(labelPos.X(), labelPos.Y(), labelPos.Z()); | |||
| 1911 | eveArrow->AddElement(text); | |||
| 1912 | addToGroup("DisplayData", eveArrow); | |||
| 1913 | } | |||
| 1914 | ||||
| 1915 | } | |||
| 1916 | ||||
| 1917 | void EVEVisualization::addObject(const TObject* dataStoreObject, TEveElement* visualRepresentation) | |||
| 1918 | { | |||
| 1919 | VisualRepMap::getInstance()->add(dataStoreObject, visualRepresentation); | |||
| 1920 | } | |||
| 1921 | ||||
| 1922 | void EVEVisualization::addToGroup(const std::string& name, TEveElement* elem) | |||
| 1923 | { | |||
| 1924 | //slashes at beginning and end are ignored | |||
| 1925 | const std::string& groupName = boost::algorithm::trim_copy_if(name, boost::algorithm::is_any_of("/")); | |||
| 1926 | ||||
| 1927 | TEveElementList* group = m_groups[groupName].group; | |||
| 1928 | if (!group) { | |||
| 1929 | group = new TEveElementList(groupName.c_str(), groupName.c_str()); | |||
| 1930 | group->SetRnrState(m_groups[groupName].visible); | |||
| 1931 | m_groups[groupName].group = group; | |||
| 1932 | ||||
| 1933 | //if groupName contains '/', remove last bit and add to parent group | |||
| 1934 | //e.g. if groupName=A/B/C, call addToGroup("A/B", groupC) | |||
| 1935 | auto lastSlash = boost::algorithm::find_last(groupName, "/"); | |||
| 1936 | if (lastSlash) { | |||
| 1937 | const std::string parentGroup(groupName.begin(), lastSlash.begin()); | |||
| 1938 | const std::string thisGroup(lastSlash.end(), groupName.end()); | |||
| 1939 | group->SetElementName(thisGroup.c_str()); | |||
| 1940 | addToGroup(parentGroup, group); | |||
| 1941 | } else { | |||
| 1942 | gEve->AddElement(group); | |||
| 1943 | } | |||
| 1944 | } | |||
| 1945 | group->AddElement(elem); | |||
| 1946 | } | |||
| 1947 |
| 1 | // Boost string_algo library trim.hpp header file ---------------------------// |
| 2 | |
| 3 | // Copyright Pavol Droba 2002-2003. |
| 4 | // |
| 5 | // Distributed under the Boost Software License, Version 1.0. |
| 6 | // (See accompanying file LICENSE_1_0.txt or copy at |
| 7 | // http://www.boost.org/LICENSE_1_0.txt) |
| 8 | |
| 9 | // See http://www.boost.org/ for updates, documentation, and revision history. |
| 10 | |
| 11 | #ifndef BOOST_STRING_TRIM_HPP |
| 12 | #define BOOST_STRING_TRIM_HPP |
| 13 | |
| 14 | #include <boost/algorithm/string/config.hpp> |
| 15 | |
| 16 | #include <boost/range/begin.hpp> |
| 17 | #include <boost/range/end.hpp> |
| 18 | #include <boost/range/const_iterator.hpp> |
| 19 | #include <boost/range/as_literal.hpp> |
| 20 | #include <boost/range/iterator_range_core.hpp> |
| 21 | |
| 22 | #include <boost/algorithm/string/detail/trim.hpp> |
| 23 | #include <boost/algorithm/string/classification.hpp> |
| 24 | #include <locale> |
| 25 | |
| 26 | /*! \file |
| 27 | Defines trim algorithms. |
| 28 | Trim algorithms are used to remove trailing and leading spaces from a |
| 29 | sequence (string). Space is recognized using given locales. |
| 30 | |
| 31 | Parametric (\c _if) variants use a predicate (functor) to select which characters |
| 32 | are to be trimmed.. |
| 33 | Functions take a selection predicate as a parameter, which is used to determine |
| 34 | whether a character is a space. Common predicates are provided in classification.hpp header. |
| 35 | |
| 36 | */ |
| 37 | |
| 38 | namespace boost { |
| 39 | namespace algorithm { |
| 40 | |
| 41 | // left trim -----------------------------------------------// |
| 42 | |
| 43 | |
| 44 | //! Left trim - parametric |
| 45 | /*! |
| 46 | Remove all leading spaces from the input. |
| 47 | The supplied predicate is used to determine which characters are considered spaces. |
| 48 | The result is a trimmed copy of the input. It is returned as a sequence |
| 49 | or copied to the output iterator |
| 50 | |
| 51 | \param Output An output iterator to which the result will be copied |
| 52 | \param Input An input range |
| 53 | \param IsSpace A unary predicate identifying spaces |
| 54 | \return |
| 55 | An output iterator pointing just after the last inserted character or |
| 56 | a copy of the input |
| 57 | |
| 58 | \note The second variant of this function provides the strong exception-safety guarantee |
| 59 | */ |
| 60 | template<typename OutputIteratorT, typename RangeT, typename PredicateT> |
| 61 | inline OutputIteratorT trim_left_copy_if( |
| 62 | OutputIteratorT Output, |
| 63 | const RangeT& Input, |
| 64 | PredicateT IsSpace) |
| 65 | { |
| 66 | iterator_range<BOOST_STRING_TYPENAMEtypename range_const_iterator<RangeT>::type> lit_range(::boost::as_literal(Input)); |
| 67 | |
| 68 | std::copy( |
| 69 | ::boost::algorithm::detail::trim_begin( |
| 70 | ::boost::begin(lit_range), |
| 71 | ::boost::end(lit_range), |
| 72 | IsSpace ), |
| 73 | ::boost::end(lit_range), |
| 74 | Output); |
| 75 | |
| 76 | return Output; |
| 77 | } |
| 78 | |
| 79 | //! Left trim - parametric |
| 80 | /*! |
| 81 | \overload |
| 82 | */ |
| 83 | template<typename SequenceT, typename PredicateT> |
| 84 | inline SequenceT trim_left_copy_if(const SequenceT& Input, PredicateT IsSpace) |
| 85 | { |
| 86 | return SequenceT( |
| 87 | ::boost::algorithm::detail::trim_begin( |
| 88 | ::boost::begin(Input), |
| 89 | ::boost::end(Input), |
| 90 | IsSpace ), |
| 91 | ::boost::end(Input)); |
| 92 | } |
| 93 | |
| 94 | //! Left trim - parametric |
| 95 | /*! |
| 96 | Remove all leading spaces from the input. |
| 97 | The result is a trimmed copy of the input. |
| 98 | |
| 99 | \param Input An input sequence |
| 100 | \param Loc a locale used for 'space' classification |
| 101 | \return A trimmed copy of the input |
| 102 | |
| 103 | \note This function provides the strong exception-safety guarantee |
| 104 | */ |
| 105 | template<typename SequenceT> |
| 106 | inline SequenceT trim_left_copy(const SequenceT& Input, const std::locale& Loc=std::locale()) |
| 107 | { |
| 108 | return |
| 109 | ::boost::algorithm::trim_left_copy_if( |
| 110 | Input, |
| 111 | is_space(Loc)); |
| 112 | } |
| 113 | |
| 114 | //! Left trim |
| 115 | /*! |
| 116 | Remove all leading spaces from the input. The supplied predicate is |
| 117 | used to determine which characters are considered spaces. |
| 118 | The input sequence is modified in-place. |
| 119 | |
| 120 | \param Input An input sequence |
| 121 | \param IsSpace A unary predicate identifying spaces |
| 122 | */ |
| 123 | template<typename SequenceT, typename PredicateT> |
| 124 | inline void trim_left_if(SequenceT& Input, PredicateT IsSpace) |
| 125 | { |
| 126 | Input.erase( |
| 127 | ::boost::begin(Input), |
| 128 | ::boost::algorithm::detail::trim_begin( |
| 129 | ::boost::begin(Input), |
| 130 | ::boost::end(Input), |
| 131 | IsSpace)); |
| 132 | } |
| 133 | |
| 134 | //! Left trim |
| 135 | /*! |
| 136 | Remove all leading spaces from the input. |
| 137 | The Input sequence is modified in-place. |
| 138 | |
| 139 | \param Input An input sequence |
| 140 | \param Loc A locale used for 'space' classification |
| 141 | */ |
| 142 | template<typename SequenceT> |
| 143 | inline void trim_left(SequenceT& Input, const std::locale& Loc=std::locale()) |
| 144 | { |
| 145 | ::boost::algorithm::trim_left_if( |
| 146 | Input, |
| 147 | is_space(Loc)); |
| 148 | } |
| 149 | |
| 150 | // right trim -----------------------------------------------// |
| 151 | |
| 152 | //! Right trim - parametric |
| 153 | /*! |
| 154 | Remove all trailing spaces from the input. |
| 155 | The supplied predicate is used to determine which characters are considered spaces. |
| 156 | The result is a trimmed copy of the input. It is returned as a sequence |
| 157 | or copied to the output iterator |
| 158 | |
| 159 | \param Output An output iterator to which the result will be copied |
| 160 | \param Input An input range |
| 161 | \param IsSpace A unary predicate identifying spaces |
| 162 | \return |
| 163 | An output iterator pointing just after the last inserted character or |
| 164 | a copy of the input |
| 165 | |
| 166 | \note The second variant of this function provides the strong exception-safety guarantee |
| 167 | */ |
| 168 | template<typename OutputIteratorT, typename RangeT, typename PredicateT> |
| 169 | inline OutputIteratorT trim_right_copy_if( |
| 170 | OutputIteratorT Output, |
| 171 | const RangeT& Input, |
| 172 | PredicateT IsSpace ) |
| 173 | { |
| 174 | iterator_range<BOOST_STRING_TYPENAMEtypename range_const_iterator<RangeT>::type> lit_range(::boost::as_literal(Input)); |
| 175 | |
| 176 | std::copy( |
| 177 | ::boost::begin(lit_range), |
| 178 | ::boost::algorithm::detail::trim_end( |
| 179 | ::boost::begin(lit_range), |
| 180 | ::boost::end(lit_range), |
| 181 | IsSpace ), |
| 182 | Output ); |
| 183 | |
| 184 | return Output; |
| 185 | } |
| 186 | |
| 187 | //! Right trim - parametric |
| 188 | /*! |
| 189 | \overload |
| 190 | */ |
| 191 | template<typename SequenceT, typename PredicateT> |
| 192 | inline SequenceT trim_right_copy_if(const SequenceT& Input, PredicateT IsSpace) |
| 193 | { |
| 194 | return SequenceT( |
| 195 | ::boost::begin(Input), |
| 196 | ::boost::algorithm::detail::trim_end( |
| 197 | ::boost::begin(Input), |
| 198 | ::boost::end(Input), |
| 199 | IsSpace) |
| 200 | ); |
| 201 | } |
| 202 | |
| 203 | //! Right trim |
| 204 | /*! |
| 205 | Remove all trailing spaces from the input. |
| 206 | The result is a trimmed copy of the input |
| 207 | |
| 208 | \param Input An input sequence |
| 209 | \param Loc A locale used for 'space' classification |
| 210 | \return A trimmed copy of the input |
| 211 | |
| 212 | \note This function provides the strong exception-safety guarantee |
| 213 | */ |
| 214 | template<typename SequenceT> |
| 215 | inline SequenceT trim_right_copy(const SequenceT& Input, const std::locale& Loc=std::locale()) |
| 216 | { |
| 217 | return |
| 218 | ::boost::algorithm::trim_right_copy_if( |
| 219 | Input, |
| 220 | is_space(Loc)); |
| 221 | } |
| 222 | |
| 223 | |
| 224 | //! Right trim - parametric |
| 225 | /*! |
| 226 | Remove all trailing spaces from the input. |
| 227 | The supplied predicate is used to determine which characters are considered spaces. |
| 228 | The input sequence is modified in-place. |
| 229 | |
| 230 | \param Input An input sequence |
| 231 | \param IsSpace A unary predicate identifying spaces |
| 232 | */ |
| 233 | template<typename SequenceT, typename PredicateT> |
| 234 | inline void trim_right_if(SequenceT& Input, PredicateT IsSpace) |
| 235 | { |
| 236 | Input.erase( |
| 237 | ::boost::algorithm::detail::trim_end( |
| 238 | ::boost::begin(Input), |
| 239 | ::boost::end(Input), |
| 240 | IsSpace ), |
| 241 | ::boost::end(Input) |
| 242 | ); |
| 243 | } |
| 244 | |
| 245 | |
| 246 | //! Right trim |
| 247 | /*! |
| 248 | Remove all trailing spaces from the input. |
| 249 | The input sequence is modified in-place. |
| 250 | |
| 251 | \param Input An input sequence |
| 252 | \param Loc A locale used for 'space' classification |
| 253 | */ |
| 254 | template<typename SequenceT> |
| 255 | inline void trim_right(SequenceT& Input, const std::locale& Loc=std::locale()) |
| 256 | { |
| 257 | ::boost::algorithm::trim_right_if( |
| 258 | Input, |
| 259 | is_space(Loc) ); |
| 260 | } |
| 261 | |
| 262 | // both side trim -----------------------------------------------// |
| 263 | |
| 264 | //! Trim - parametric |
| 265 | /*! |
| 266 | Remove all trailing and leading spaces from the input. |
| 267 | The supplied predicate is used to determine which characters are considered spaces. |
| 268 | The result is a trimmed copy of the input. It is returned as a sequence |
| 269 | or copied to the output iterator |
| 270 | |
| 271 | \param Output An output iterator to which the result will be copied |
| 272 | \param Input An input range |
| 273 | \param IsSpace A unary predicate identifying spaces |
| 274 | \return |
| 275 | An output iterator pointing just after the last inserted character or |
| 276 | a copy of the input |
| 277 | |
| 278 | \note The second variant of this function provides the strong exception-safety guarantee |
| 279 | */ |
| 280 | template<typename OutputIteratorT, typename RangeT, typename PredicateT> |
| 281 | inline OutputIteratorT trim_copy_if( |
| 282 | OutputIteratorT Output, |
| 283 | const RangeT& Input, |
| 284 | PredicateT IsSpace) |
| 285 | { |
| 286 | iterator_range<BOOST_STRING_TYPENAMEtypename range_const_iterator<RangeT>::type> lit_range(::boost::as_literal(Input)); |
| 287 | |
| 288 | BOOST_STRING_TYPENAMEtypename |
| 289 | range_const_iterator<RangeT>::type TrimEnd= |
| 290 | ::boost::algorithm::detail::trim_end( |
| 291 | ::boost::begin(lit_range), |
| 292 | ::boost::end(lit_range), |
| 293 | IsSpace); |
| 294 | |
| 295 | std::copy( |
| 296 | detail::trim_begin( |
| 297 | ::boost::begin(lit_range), TrimEnd, IsSpace), |
| 298 | TrimEnd, |
| 299 | Output |
| 300 | ); |
| 301 | |
| 302 | return Output; |
| 303 | } |
| 304 | |
| 305 | //! Trim - parametric |
| 306 | /*! |
| 307 | \overload |
| 308 | */ |
| 309 | template<typename SequenceT, typename PredicateT> |
| 310 | inline SequenceT trim_copy_if(const SequenceT& Input, PredicateT IsSpace) |
| 311 | { |
| 312 | BOOST_STRING_TYPENAMEtypename |
| 313 | range_const_iterator<SequenceT>::type TrimEnd= |
| 314 | ::boost::algorithm::detail::trim_end( |
| 315 | ::boost::begin(Input), |
| 316 | ::boost::end(Input), |
| 317 | IsSpace); |
| 318 | |
| 319 | return SequenceT( |
| 320 | detail::trim_begin( |
| 321 | ::boost::begin(Input), |
| 322 | TrimEnd, |
| 323 | IsSpace), |
| 324 | TrimEnd |
| 325 | ); |
| 326 | } |
| 327 | |
| 328 | //! Trim |
| 329 | /*! |
| 330 | Remove all leading and trailing spaces from the input. |
| 331 | The result is a trimmed copy of the input |
| 332 | |
| 333 | \param Input An input sequence |
| 334 | \param Loc A locale used for 'space' classification |
| 335 | \return A trimmed copy of the input |
| 336 | |
| 337 | \note This function provides the strong exception-safety guarantee |
| 338 | */ |
| 339 | template<typename SequenceT> |
| 340 | inline SequenceT trim_copy( const SequenceT& Input, const std::locale& Loc=std::locale() ) |
| 341 | { |
| 342 | return |
| 343 | ::boost::algorithm::trim_copy_if( |
| 344 | Input, |
| 345 | is_space(Loc) ); |
| 346 | } |
| 347 | |
| 348 | //! Trim |
| 349 | /*! |
| 350 | Remove all leading and trailing spaces from the input. |
| 351 | The supplied predicate is used to determine which characters are considered spaces. |
| 352 | The input sequence is modified in-place. |
| 353 | |
| 354 | \param Input An input sequence |
| 355 | \param IsSpace A unary predicate identifying spaces |
| 356 | */ |
| 357 | template<typename SequenceT, typename PredicateT> |
| 358 | inline void trim_if(SequenceT& Input, PredicateT IsSpace) |
| 359 | { |
| 360 | ::boost::algorithm::trim_right_if( Input, IsSpace ); |
| 361 | ::boost::algorithm::trim_left_if( Input, IsSpace ); |
| 362 | } |
| 363 | |
| 364 | //! Trim |
| 365 | /*! |
| 366 | Remove all leading and trailing spaces from the input. |
| 367 | The input sequence is modified in-place. |
| 368 | |
| 369 | \param Input An input sequence |
| 370 | \param Loc A locale used for 'space' classification |
| 371 | */ |
| 372 | template<typename SequenceT> |
| 373 | inline void trim(SequenceT& Input, const std::locale& Loc=std::locale()) |
| 374 | { |
| 375 | ::boost::algorithm::trim_if( |
| 376 | Input, |
| 377 | is_space( Loc ) ); |
| 378 | } |
| 379 | |
| 380 | } // namespace algorithm |
| 381 | |
| 382 | // pull names to the boost namespace |
| 383 | using algorithm::trim_left; |
| 384 | using algorithm::trim_left_if; |
| 385 | using algorithm::trim_left_copy; |
| 386 | using algorithm::trim_left_copy_if; |
| 387 | using algorithm::trim_right; |
| 388 | using algorithm::trim_right_if; |
| 389 | using algorithm::trim_right_copy; |
| 390 | using algorithm::trim_right_copy_if; |
| 391 | using algorithm::trim; |
| 392 | using algorithm::trim_if; |
| 393 | using algorithm::trim_copy; |
| 394 | using algorithm::trim_copy_if; |
| 395 | |
| 396 | } // namespace boost |
| 397 | |
| 398 | #endif // BOOST_STRING_TRIM_HPP |
| 1 | // Boost string_algo library classification.hpp header file ---------------------------// | |||
| 2 | ||||
| 3 | // Copyright Pavol Droba 2002-2003. | |||
| 4 | // | |||
| 5 | // Distributed under the Boost Software License, Version 1.0. | |||
| 6 | // (See accompanying file LICENSE_1_0.txt or copy at | |||
| 7 | // http://www.boost.org/LICENSE_1_0.txt) | |||
| 8 | ||||
| 9 | // See http://www.boost.org/ for updates, documentation, and revision history. | |||
| 10 | ||||
| 11 | #ifndef BOOST_STRING_CLASSIFICATION_DETAIL_HPP | |||
| 12 | #define BOOST_STRING_CLASSIFICATION_DETAIL_HPP | |||
| 13 | ||||
| 14 | #include <boost/algorithm/string/config.hpp> | |||
| 15 | #include <algorithm> | |||
| 16 | #include <cstring> | |||
| 17 | #include <functional> | |||
| 18 | #include <locale> | |||
| 19 | ||||
| 20 | #include <boost/range/begin.hpp> | |||
| 21 | #include <boost/range/distance.hpp> | |||
| 22 | #include <boost/range/end.hpp> | |||
| 23 | ||||
| 24 | #include <boost/algorithm/string/predicate_facade.hpp> | |||
| 25 | #include <boost/type_traits/remove_const.hpp> | |||
| 26 | ||||
| 27 | namespace boost { | |||
| 28 | namespace algorithm { | |||
| 29 | namespace detail { | |||
| 30 | ||||
| 31 | // classification functors -----------------------------------------------// | |||
| 32 | ||||
| 33 | // is_classified functor | |||
| 34 | struct is_classifiedF : | |||
| 35 | public predicate_facade<is_classifiedF> | |||
| 36 | { | |||
| 37 | // Boost.ResultOf support | |||
| 38 | typedef bool result_type; | |||
| 39 | ||||
| 40 | // Constructor from a locale | |||
| 41 | is_classifiedF(std::ctype_base::mask Type, std::locale const & Loc = std::locale()) : | |||
| 42 | m_Type(Type), m_Locale(Loc) {} | |||
| 43 | // Operation | |||
| 44 | template<typename CharT> | |||
| 45 | bool operator()( CharT Ch ) const | |||
| 46 | { | |||
| 47 | return std::use_facet< std::ctype<CharT> >(m_Locale).is( m_Type, Ch ); | |||
| 48 | } | |||
| 49 | ||||
| 50 | #if defined(BOOST_BORLANDC) && (BOOST_BORLANDC >= 0x560) && (BOOST_BORLANDC <= 0x582) && !defined(_USE_OLD_RW_STL) | |||
| 51 | template<> | |||
| 52 | bool operator()( char const Ch ) const | |||
| 53 | { | |||
| 54 | return std::use_facet< std::ctype<char> >(m_Locale).is( m_Type, Ch ); | |||
| 55 | } | |||
| 56 | #endif | |||
| 57 | ||||
| 58 | private: | |||
| 59 | std::ctype_base::mask m_Type; | |||
| 60 | std::locale m_Locale; | |||
| 61 | }; | |||
| 62 | ||||
| 63 | ||||
| 64 | // is_any_of functor | |||
| 65 | /* | |||
| 66 | returns true if the value is from the specified set | |||
| 67 | */ | |||
| 68 | template<typename CharT> | |||
| 69 | struct is_any_ofF : | |||
| 70 | public predicate_facade<is_any_ofF<CharT> > | |||
| 71 | { | |||
| 72 | private: | |||
| 73 | // set cannot operate on const value-type | |||
| 74 | typedef typename ::boost::remove_const<CharT>::type set_value_type; | |||
| 75 | ||||
| 76 | public: | |||
| 77 | // Boost.ResultOf support | |||
| 78 | typedef bool result_type; | |||
| 79 | ||||
| 80 | // Constructor | |||
| 81 | template<typename RangeT> | |||
| 82 | is_any_ofF( const RangeT& Range ) : m_Size(0) | |||
| 83 | { | |||
| 84 | // Prepare storage | |||
| 85 | m_Storage.m_dynSet=0; | |||
| 86 | ||||
| 87 | std::size_t Size=::boost::distance(Range); | |||
| 88 | m_Size=Size; | |||
| 89 | set_value_type* Storage=0; | |||
| 90 | ||||
| 91 | if(use_fixed_storage(m_Size)) | |||
| 92 | { | |||
| 93 | // Use fixed storage | |||
| 94 | Storage=&m_Storage.m_fixSet[0]; | |||
| 95 | } | |||
| 96 | else | |||
| 97 | { | |||
| 98 | // Use dynamic storage | |||
| 99 | m_Storage.m_dynSet=new set_value_type[m_Size]; | |||
| 100 | Storage=m_Storage.m_dynSet; | |||
| 101 | } | |||
| 102 | ||||
| 103 | // Use fixed storage | |||
| 104 | ::std::copy(::boost::begin(Range), ::boost::end(Range), Storage); | |||
| 105 | ::std::sort(Storage, Storage+m_Size); | |||
| 106 | } | |||
| 107 | ||||
| 108 | // Copy constructor | |||
| 109 | is_any_ofF(const is_any_ofF& Other) : m_Size(Other.m_Size) | |||
| 110 | { | |||
| 111 | // Prepare storage | |||
| 112 | m_Storage.m_dynSet=0; | |||
| 113 | const set_value_type* SrcStorage=0; | |||
| 114 | set_value_type* DestStorage=0; | |||
| 115 | ||||
| 116 | if(use_fixed_storage(m_Size)) | |||
| 117 | { | |||
| 118 | // Use fixed storage | |||
| 119 | DestStorage=&m_Storage.m_fixSet[0]; | |||
| 120 | SrcStorage=&Other.m_Storage.m_fixSet[0]; | |||
| 121 | } | |||
| 122 | else | |||
| 123 | { | |||
| 124 | // Use dynamic storage | |||
| 125 | m_Storage.m_dynSet=new set_value_type[m_Size]; | |||
| 126 | DestStorage=m_Storage.m_dynSet; | |||
| 127 | SrcStorage=Other.m_Storage.m_dynSet; | |||
| 128 | } | |||
| 129 | ||||
| 130 | // Use fixed storage | |||
| 131 | ::std::memcpy(DestStorage, SrcStorage, sizeof(set_value_type)*m_Size); | |||
| 132 | } | |||
| 133 | ||||
| 134 | // Destructor | |||
| 135 | ~is_any_ofF() | |||
| 136 | { | |||
| 137 | if(!use_fixed_storage(m_Size) && m_Storage.m_dynSet!=0) | |||
| 138 | { | |||
| 139 | delete [] m_Storage.m_dynSet; | |||
| 140 | } | |||
| 141 | } | |||
| ||||
| 142 | ||||
| 143 | // Assignment | |||
| 144 | is_any_ofF& operator=(const is_any_ofF& Other) | |||
| 145 | { | |||
| 146 | // Handle self assignment | |||
| 147 | if(this==&Other) return *this; | |||
| 148 | ||||
| 149 | // Prepare storage | |||
| 150 | const set_value_type* SrcStorage; | |||
| 151 | set_value_type* DestStorage; | |||
| 152 | ||||
| 153 | if(use_fixed_storage(Other.m_Size)) | |||
| 154 | { | |||
| 155 | // Use fixed storage | |||
| 156 | DestStorage=&m_Storage.m_fixSet[0]; | |||
| 157 | SrcStorage=&Other.m_Storage.m_fixSet[0]; | |||
| 158 | ||||
| 159 | // Delete old storage if was present | |||
| 160 | if(!use_fixed_storage(m_Size) && m_Storage.m_dynSet!=0) | |||
| 161 | { | |||
| 162 | delete [] m_Storage.m_dynSet; | |||
| 163 | } | |||
| 164 | ||||
| 165 | // Set new size | |||
| 166 | m_Size=Other.m_Size; | |||
| 167 | } | |||
| 168 | else | |||
| 169 | { | |||
| 170 | // Other uses dynamic storage | |||
| 171 | SrcStorage=Other.m_Storage.m_dynSet; | |||
| 172 | ||||
| 173 | // Check what kind of storage are we using right now | |||
| 174 | if(use_fixed_storage(m_Size)) | |||
| 175 | { | |||
| 176 | // Using fixed storage, allocate new | |||
| 177 | set_value_type* pTemp=new set_value_type[Other.m_Size]; | |||
| 178 | DestStorage=pTemp; | |||
| 179 | m_Storage.m_dynSet=pTemp; | |||
| 180 | m_Size=Other.m_Size; | |||
| 181 | } | |||
| 182 | else | |||
| 183 | { | |||
| 184 | // Using dynamic storage, check if can reuse | |||
| 185 | if(m_Storage.m_dynSet!=0 && m_Size>=Other.m_Size && m_Size<Other.m_Size*2) | |||
| 186 | { | |||
| 187 | // Reuse the current storage | |||
| 188 | DestStorage=m_Storage.m_dynSet; | |||
| 189 | m_Size=Other.m_Size; | |||
| 190 | } | |||
| 191 | else | |||
| 192 | { | |||
| 193 | // Allocate the new one | |||
| 194 | set_value_type* pTemp=new set_value_type[Other.m_Size]; | |||
| 195 | DestStorage=pTemp; | |||
| 196 | ||||
| 197 | // Delete old storage if necessary | |||
| 198 | if(m_Storage.m_dynSet!=0) | |||
| 199 | { | |||
| 200 | delete [] m_Storage.m_dynSet; | |||
| 201 | } | |||
| 202 | // Store the new storage | |||
| 203 | m_Storage.m_dynSet=pTemp; | |||
| 204 | // Set new size | |||
| 205 | m_Size=Other.m_Size; | |||
| 206 | } | |||
| 207 | } | |||
| 208 | } | |||
| 209 | ||||
| 210 | // Copy the data | |||
| 211 | ::std::memcpy(DestStorage, SrcStorage, sizeof(set_value_type)*m_Size); | |||
| 212 | ||||
| 213 | return *this; | |||
| 214 | } | |||
| 215 | ||||
| 216 | // Operation | |||
| 217 | template<typename Char2T> | |||
| 218 | bool operator()( Char2T Ch ) const | |||
| 219 | { | |||
| 220 | const set_value_type* Storage= | |||
| 221 | (use_fixed_storage(m_Size)) | |||
| 222 | ? &m_Storage.m_fixSet[0] | |||
| 223 | : m_Storage.m_dynSet; | |||
| 224 | ||||
| 225 | return ::std::binary_search(Storage, Storage+m_Size, Ch); | |||
| 226 | } | |||
| 227 | private: | |||
| 228 | // check if the size is eligible for fixed storage | |||
| 229 | static bool use_fixed_storage(std::size_t size) | |||
| 230 | { | |||
| 231 | return size<=sizeof(set_value_type*)*2; | |||
| 232 | } | |||
| 233 | ||||
| 234 | ||||
| 235 | private: | |||
| 236 | // storage | |||
| 237 | // The actual used storage is selected on the type | |||
| 238 | union | |||
| 239 | { | |||
| 240 | set_value_type* m_dynSet; | |||
| 241 | set_value_type m_fixSet[sizeof(set_value_type*)*2]; | |||
| 242 | } | |||
| 243 | m_Storage; | |||
| 244 | ||||
| 245 | // storage size | |||
| 246 | ::std::size_t m_Size; | |||
| 247 | }; | |||
| 248 | ||||
| 249 | // is_from_range functor | |||
| 250 | /* | |||
| 251 | returns true if the value is from the specified range. | |||
| 252 | (i.e. x>=From && x>=To) | |||
| 253 | */ | |||
| 254 | template<typename CharT> | |||
| 255 | struct is_from_rangeF : | |||
| 256 | public predicate_facade< is_from_rangeF<CharT> > | |||
| 257 | { | |||
| 258 | // Boost.ResultOf support | |||
| 259 | typedef bool result_type; | |||
| 260 | ||||
| 261 | // Constructor | |||
| 262 | is_from_rangeF( CharT From, CharT To ) : m_From(From), m_To(To) {} | |||
| 263 | ||||
| 264 | // Operation | |||
| 265 | template<typename Char2T> | |||
| 266 | bool operator()( Char2T Ch ) const | |||
| 267 | { | |||
| 268 | return ( m_From <= Ch ) && ( Ch <= m_To ); | |||
| 269 | } | |||
| 270 | ||||
| 271 | private: | |||
| 272 | CharT m_From; | |||
| 273 | CharT m_To; | |||
| 274 | }; | |||
| 275 | ||||
| 276 | // class_and composition predicate | |||
| 277 | template<typename Pred1T, typename Pred2T> | |||
| 278 | struct pred_andF : | |||
| 279 | public predicate_facade< pred_andF<Pred1T,Pred2T> > | |||
| 280 | { | |||
| 281 | public: | |||
| 282 | ||||
| 283 | // Boost.ResultOf support | |||
| 284 | typedef bool result_type; | |||
| 285 | ||||
| 286 | // Constructor | |||
| 287 | pred_andF( Pred1T Pred1, Pred2T Pred2 ) : | |||
| 288 | m_Pred1(Pred1), m_Pred2(Pred2) {} | |||
| 289 | ||||
| 290 | // Operation | |||
| 291 | template<typename CharT> | |||
| 292 | bool operator()( CharT Ch ) const | |||
| 293 | { | |||
| 294 | return m_Pred1(Ch) && m_Pred2(Ch); | |||
| 295 | } | |||
| 296 | ||||
| 297 | private: | |||
| 298 | Pred1T m_Pred1; | |||
| 299 | Pred2T m_Pred2; | |||
| 300 | }; | |||
| 301 | ||||
| 302 | // class_or composition predicate | |||
| 303 | template<typename Pred1T, typename Pred2T> | |||
| 304 | struct pred_orF : | |||
| 305 | public predicate_facade< pred_orF<Pred1T,Pred2T> > | |||
| 306 | { | |||
| 307 | public: | |||
| 308 | // Boost.ResultOf support | |||
| 309 | typedef bool result_type; | |||
| 310 | ||||
| 311 | // Constructor | |||
| 312 | pred_orF( Pred1T Pred1, Pred2T Pred2 ) : | |||
| 313 | m_Pred1(Pred1), m_Pred2(Pred2) {} | |||
| 314 | ||||
| 315 | // Operation | |||
| 316 | template<typename CharT> | |||
| 317 | bool operator()( CharT Ch ) const | |||
| 318 | { | |||
| 319 | return m_Pred1(Ch) || m_Pred2(Ch); | |||
| 320 | } | |||
| 321 | ||||
| 322 | private: | |||
| 323 | Pred1T m_Pred1; | |||
| 324 | Pred2T m_Pred2; | |||
| 325 | }; | |||
| 326 | ||||
| 327 | // class_not composition predicate | |||
| 328 | template< typename PredT > | |||
| 329 | struct pred_notF : | |||
| 330 | public predicate_facade< pred_notF<PredT> > | |||
| 331 | { | |||
| 332 | public: | |||
| 333 | // Boost.ResultOf support | |||
| 334 | typedef bool result_type; | |||
| 335 | ||||
| 336 | // Constructor | |||
| 337 | pred_notF( PredT Pred ) : m_Pred(Pred) {} | |||
| 338 | ||||
| 339 | // Operation | |||
| 340 | template<typename CharT> | |||
| 341 | bool operator()( CharT Ch ) const | |||
| 342 | { | |||
| 343 | return !m_Pred(Ch); | |||
| 344 | } | |||
| 345 | ||||
| 346 | private: | |||
| 347 | PredT m_Pred; | |||
| 348 | }; | |||
| 349 | ||||
| 350 | } // namespace detail | |||
| 351 | } // namespace algorithm | |||
| 352 | } // namespace boost | |||
| 353 | ||||
| 354 | ||||
| 355 | #endif // BOOST_STRING_CLASSIFICATION_DETAIL_HPP |