From b79e82d24e9bf7b11273f3671415815a3e2bea95 Mon Sep 17 00:00:00 2001 From: yuxiao Date: Thu, 29 Jan 2026 16:43:42 +0100 Subject: [PATCH 1/5] added REveCamera class to make list REveCamera implement added REveCamera class implement isEveCameraPerspective set REveCamera free as an independent class implement camera on the client side. Also, the hardcoded test matrix is here hardcoded matrix test change the paths & env variables myslef as the author Remove commented lines with V1, V2 fCamera declaration does not need a comment. Restore align. include the REveCamera.hxx header in REveManager.cxx GetCameraId() replaced with REveCamera* GetCamera() {return fCamera; } SetCamBaseMtx override with string input SetCameraByElementId function implement; Set default camera to kCameraPerspXOZ save camera matrix implemented --- graf3d/eve7/CMakeLists.txt | 2 + graf3d/eve7/inc/LinkDef.h | 4 + graf3d/eve7/inc/ROOT/REveCamera.hxx | 85 +++++++++++++ graf3d/eve7/inc/ROOT/REveManager.hxx | 3 +- graf3d/eve7/inc/ROOT/REveViewer.hxx | 31 ++--- graf3d/eve7/src/REveCamera.cxx | 123 ++++++++++++++++++ graf3d/eve7/src/REveManager.cxx | 54 ++++++++ graf3d/eve7/src/REveViewer.cxx | 80 +++++++----- tutorials/visualisation/eve7/jets.C | 16 ++- ui5/eve7/controller/GL.controller.js | 17 ++- ui5/eve7/controller/Ged.controller.js | 172 +++++++++++++++++++++++++- ui5/eve7/lib/GlViewerRCore.js | 85 ++++++++++++- ui5/eve7/lib/RenderCore.js | 12 +- 13 files changed, 616 insertions(+), 68 deletions(-) create mode 100644 graf3d/eve7/inc/ROOT/REveCamera.hxx create mode 100644 graf3d/eve7/src/REveCamera.cxx diff --git a/graf3d/eve7/CMakeLists.txt b/graf3d/eve7/CMakeLists.txt index f6152ee616c14..71179175651b7 100644 --- a/graf3d/eve7/CMakeLists.txt +++ b/graf3d/eve7/CMakeLists.txt @@ -63,6 +63,7 @@ ROOT_STANDARD_LIBRARY_PACKAGE(ROOTEve ROOT/REveUtil.hxx ROOT/REveVector.hxx ROOT/REveViewer.hxx + ROOT/REveCamera.hxx ROOT/REveViewContext.hxx ROOT/REveVSD.hxx ROOT/REveVSDStructs.hxx @@ -126,6 +127,7 @@ ROOT_STANDARD_LIBRARY_PACKAGE(ROOTEve src/REveUtil.cxx src/REveVector.cxx src/REveViewer.cxx + src/REveCamera.cxx src/REveVSD.cxx src/REveVSDStructs.cxx DEPENDENCIES diff --git a/graf3d/eve7/inc/LinkDef.h b/graf3d/eve7/inc/LinkDef.h index b8e4754f53e5e..d35f4d9c21b2e 100644 --- a/graf3d/eve7/inc/LinkDef.h +++ b/graf3d/eve7/inc/LinkDef.h @@ -250,4 +250,8 @@ // Tables #pragma link C++ class ROOT::Experimental::REveTableViewInfo; +// Camera +#pragma link C++ class ROOT::Experimental::REveCamera+; +#pragma link C++ enum ROOT::Experimental::REveCamera::ECameraType; + #endif diff --git a/graf3d/eve7/inc/ROOT/REveCamera.hxx b/graf3d/eve7/inc/ROOT/REveCamera.hxx new file mode 100644 index 0000000000000..aa499d8ac6aec --- /dev/null +++ b/graf3d/eve7/inc/ROOT/REveCamera.hxx @@ -0,0 +1,85 @@ +// @(#)root/eve7:$Id$ +// Authors: Yuxiao Wang, 2025 + +/************************************************************************* + * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#ifndef ROOT7_REveCamera +#define ROOT7_REveCamera + +#include +#include +#include + +#include + +namespace ROOT { +namespace Experimental { + +class REveCamera : public REveElement +{ +public: + enum ECameraType { + // Perspective + kCameraPerspXOZ, // XOZ floor + kCameraPerspYOZ, // YOZ floor + kCameraPerspXOY, // XOY floor + // Orthographic + kCameraOrthoXOY, // Looking down Z axis, X horz, Y vert + kCameraOrthoXOZ, // Looking along Y axis, X horz, Z vert + kCameraOrthoZOY, // Looking along X axis, Z horz, Y vert + kCameraOrthoZOX, // Looking along Y axis, Z horz, X vert + // Orthographic negative + kCameraOrthoXnOY, // Looking along Z axis, -X horz, Y vert + kCameraOrthoXnOZ, // Looking down Y axis, -X horz, Z vert + kCameraOrthoZnOY, // Looking down X axis, -Z horz, Y vert + kCameraOrthoZnOX // Looking down Y axis, -Z horz, X vert + }; + +private: + ECameraType fType; + std::string fName; + + // Camera transformation matrices + REveTrans fCamBase; // Base camera matrix (main positioning) + REveTrans fCamTrans; + +public: + REveCamera(); + REveCamera(const std::string &name); + virtual ~REveCamera() {} + + void Setup(ECameraType type, const std::string &name, const REveVector &v1, const REveVector &v2); + + ECameraType GetType() const { return fType; } + const std::string &GetCameraName() const { return fName; } + + // Camera matrix accessors + REveTrans &RefCamBase() { return fCamBase; } + const REveTrans &GetCamBase() const { return fCamBase; } + + REveTrans &RefCamTrans() { return fCamTrans; } + const REveTrans &GetCamTrans() const { return fCamTrans; } + + void SetCamBase(const REveTrans &base) { fCamBase = base; StampObjProps(); } + + // receive mtx from client + void SetCamBaseMtx(const std::vector &arr); + void SetCamBaseMtx(const std::string &json_str); + + void BuildRenderData() override{}; + + Int_t WriteCoreJson(nlohmann::json &j, Int_t rnr_offset) override; + + ClassDef(REveCamera, 0); +}; + +} // namespace Experimental +} // namespace ROOT + +#endif \ No newline at end of file diff --git a/graf3d/eve7/inc/ROOT/REveManager.hxx b/graf3d/eve7/inc/ROOT/REveManager.hxx index 1913661f649ca..896fae7237213 100644 --- a/graf3d/eve7/inc/ROOT/REveManager.hxx +++ b/graf3d/eve7/inc/ROOT/REveManager.hxx @@ -15,7 +15,6 @@ #include #include #include - #include #include "TSysEvtHandler.h" @@ -127,6 +126,7 @@ protected: REveViewerList *fViewers{nullptr}; REveSceneList *fScenes{nullptr}; + REveElement *fCameras{nullptr}; REveScene *fGlobalScene{nullptr}; REveScene *fEventScene{nullptr}; @@ -182,6 +182,7 @@ public: REveSceneList *GetScenes() const { return fScenes; } REveViewerList *GetViewers() const { return fViewers; } + REveElement *GetCameras() const { return fCameras; } //yuxiao REveScene *GetGlobalScene() const { return fGlobalScene; } REveScene *GetEventScene() const { return fEventScene; } diff --git a/graf3d/eve7/inc/ROOT/REveViewer.hxx b/graf3d/eve7/inc/ROOT/REveViewer.hxx index d26a3836dd359..adbe829d42acb 100644 --- a/graf3d/eve7/inc/ROOT/REveViewer.hxx +++ b/graf3d/eve7/inc/ROOT/REveViewer.hxx @@ -18,6 +18,7 @@ namespace ROOT { namespace Experimental { class REveScene; +class REveCamera; // yuxiao //////////////////////////////////////////////////////////////////////////////// /// REveViewer @@ -51,30 +52,12 @@ public: kAxesEdge }; - // For the moment REveCamera is internal class - class REveCamera - { - ECameraType fType; - std::string fName; - REveVector fV2; - REveVector fV1; - - public: - REveCamera() { Setup(kCameraPerspXOZ, "PerspXOZ", REveVector(-1.0, 0.0, 0.0), REveVector(0.0, 1.0, 0.0));} - ~REveCamera() {} - - void Setup(ECameraType type, const std::string& name, REveVector v1, REveVector v2); - - ECameraType GetType() const { return fType; } - - int WriteCoreJson(nlohmann::json &j, Int_t /*rnr_offset*/); - }; - private: REveViewer(const REveViewer&) = delete; REveViewer& operator=(const REveViewer&) = delete; - REveCamera fCamera; + REveCamera* fCamera{0}; + EAxesType fAxesType{kAxesNone}; bool fBlackBackground{false}; @@ -90,8 +73,12 @@ public: virtual void AddScene(REveScene* scene); // XXX Missing RemoveScene() ???? - void SetCameraType(ECameraType t); - ECameraType GetCameraType() const { return fCamera.GetType(); } + // void SetCameraType(ECameraType t); + // ECameraType GetCameraType() const { return fCamera->GetType(); } + void SetCamera(::ROOT::Experimental::REveCamera *cam); + REveCamera* GetCamera() const { return fCamera;} + + void SetCameraByElementId(ElementId_t cameraId); // set camera via ElementID void SetAxesType(int); void SetBlackBackground(bool); diff --git a/graf3d/eve7/src/REveCamera.cxx b/graf3d/eve7/src/REveCamera.cxx new file mode 100644 index 0000000000000..4a8a902722a42 --- /dev/null +++ b/graf3d/eve7/src/REveCamera.cxx @@ -0,0 +1,123 @@ +// @(#)root/eve7:$Id$ +// Authors: Matevz Tadel & Alja Mrak-Tadel: 2006, 2007, 2018 + +/************************************************************************* + * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#include +#include + +#include + +using namespace ROOT::Experimental; + +//////////////////////////////////////////////////////////////////////////////// +/// Default constructor + +REveCamera::REveCamera() : REveElement("REveCamera") +{ + Setup(kCameraPerspXOZ, "PerspXOZ", REveVector(-1.0, 0.0, 0.0), REveVector(0.0, 1.0, 0.0)); + fCamBase.UnitTrans(); + fCamTrans.UnitTrans(); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Constructor with name + +REveCamera::REveCamera(const std::string &name) : REveElement(name) +{ + Setup(kCameraPerspXOZ, name, REveVector(-1.0, 0.0, 0.0), REveVector(0.0, 1.0, 0.0)); + fCamBase.UnitTrans(); + fCamTrans.UnitTrans(); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Setup camera with type, name, direction and up vectors + +void REveCamera::Setup(ECameraType type, const std::string &name, const REveVector &v1, const REveVector &v2) +{ + fType = type; + fName = name; + // fV1 = v1; + // fV2 = v2; + + // Set up base camera matrix from direction and up vectors + fCamBase.UnitTrans(); + fCamTrans.UnitTrans(); + + // Create a coordinate system from v1 (direction) and v2 (up) + REveVector dir = v1; + dir.Normalize(); + + REveVector up = v2; + up.Normalize(); + + // Right vector = dir × up + REveVector right; + right.fX = dir.fY * up.fZ - dir.fZ * up.fY; + right.fY = dir.fZ * up.fX - dir.fX * up.fZ; + right.fZ = dir.fX * up.fY - dir.fY * up.fX; + right.Normalize(); + + // Recalculate up = right × dir for orthogonality + REveVector newUp; + newUp.fX = right.fY * dir.fZ - right.fZ * dir.fY; + newUp.fY = right.fZ * dir.fX - right.fX * dir.fZ; + newUp.fZ = right.fX * dir.fY - right.fY * dir.fX; + + // Set rotation part of matrix (as row vectors) + Double_t *M = fCamBase.Array(); + M[0] = right.fX; M[4] = right.fY; M[8] = right.fZ; + M[1] = newUp.fX; M[5] = newUp.fY; M[9] = newUp.fZ; + M[2] = dir.fX; M[6] = dir.fY; M[10] = dir.fZ; + + StampObjProps(); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Set camera base matrix from array (called from client via MIR) + +void REveCamera::SetCamBaseMtx(const std::vector &arr) +{ + if (arr.size() == 16) { + fCamBase.SetFromArray(arr.data()); + StampObjProps(); + } +} + +void REveCamera::SetCamBaseMtx(const std::string &json_str) +{ + auto j = nlohmann::json::parse(json_str); + std::vector arr = j.get>(); + SetCamBaseMtx(arr); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Write core JSON for camera + +Int_t REveCamera::WriteCoreJson(nlohmann::json &j, Int_t rnr_offset) +{ + Int_t ret = REveElement::WriteCoreJson(j, rnr_offset); + + j["fType"] = fType; + j["fName"] = fName; + // j["fV1"] = {fV1.fX, fV1.fY, fV1.fZ}; + // j["fV2"] = {fV2.fX, fV2.fY, fV2.fZ}; + + // Stream both matrices + // Client will read these as fMatrix arrays (16 elements each) + const Double_t *camBaseArr = fCamBase.Array(); + j["camBase"] = std::vector(camBaseArr, camBaseArr + 16); + + const Double_t *camTransArr = fCamTrans.Array(); + j["camTrans"] = std::vector(camTransArr, camTransArr + 16); + + return ret; +} + +ClassImp(REveCamera); \ No newline at end of file diff --git a/graf3d/eve7/src/REveManager.cxx b/graf3d/eve7/src/REveManager.cxx index e57faf0904099..57dda5bd87842 100644 --- a/graf3d/eve7/src/REveManager.cxx +++ b/graf3d/eve7/src/REveManager.cxx @@ -11,6 +11,7 @@ #include +#include #include #include #include @@ -142,6 +143,59 @@ REveManager::REveManager() fScenes->IncDenyDestroy(); fWorld->AddElement(fScenes); + // -------------------------------- + // Create camera list + // -------------------------------- + fCameras = new REveElement("Cameras", "Camera list"); + fCameras->IncDenyDestroy(); + fWorld->AddElement(fCameras); + + // Create predefined cameras with their view vectors, yuxiao + struct CameraDef { + REveCamera::ECameraType type; + const char* name; + REveVector v1; + REveVector v2; + }; + + CameraDef predefinedCameras[] = { + // Perspective cameras + {REveCamera::kCameraPerspXOZ, "PerspXOZ", + REveVector(-1.0, 0.0, 0.0), REveVector(0.0, 1.0, 0.0)}, + {REveCamera::kCameraPerspYOZ, "PerspYOZ", + REveVector(0.0, -1.0, 0.0), REveVector(1.0, 0.0, 0.0)}, + {REveCamera::kCameraPerspXOY, "PerspXOY", + REveVector(-1.0, 0.0, 0.0), REveVector(0.0, 0.0, 1.0)}, + + // Orthographic cameras + {REveCamera::kCameraOrthoXOY, "OrthoXOY", + REveVector(0.0, 0.0, 1.0), REveVector(0.0, 1.0, 0.0)}, + {REveCamera::kCameraOrthoXOZ, "OrthoXOZ", + REveVector(0.0, -1.0, 0.0), REveVector(0.0, 0.0, 1.0)}, + {REveCamera::kCameraOrthoZOY, "OrthoZOY", + REveVector(-1.0, 0.0, 0.0), REveVector(0.0, 1.0, 0.0)}, + {REveCamera::kCameraOrthoZOX, "OrthoZOX", + REveVector(0.0, -1.0, 0.0), REveVector(1.0, 0.0, 0.0)}, + + // Orthographic negative cameras + {REveCamera::kCameraOrthoXnOY, "OrthoXnOY", + REveVector(0.0, 0.0, -1.0), REveVector(0.0, 1.0, 0.0)}, + {REveCamera::kCameraOrthoXnOZ, "OrthoXnOZ", + REveVector(0.0, 1.0, 0.0), REveVector(0.0, 0.0, 1.0)}, + {REveCamera::kCameraOrthoZnOY, "OrthoZnOY", + REveVector(1.0, 0.0, 0.0), REveVector(0.0, 1.0, 0.0)}, + {REveCamera::kCameraOrthoZnOX, "OrthoZnOX", + REveVector(0.0, 1.0, 0.0), REveVector(1.0, 0.0, 0.0)} + }; + + // Create and add all predefined cameras + for (const auto &camDef : predefinedCameras) { + auto cam = new REveCamera(camDef.name); + cam->Setup(camDef.type, camDef.name, camDef.v1, camDef.v2); + fCameras->AddElement(cam); + std::cout << "camera ID: " << cam->GetElementId() << std::endl; + } + fGlobalScene = new REveScene("Geometry scene"); fGlobalScene->IncDenyDestroy(); fScenes->AddElement(fGlobalScene); diff --git a/graf3d/eve7/src/REveViewer.cxx b/graf3d/eve7/src/REveViewer.cxx index 334d9806bc046..a24c93c3e82b1 100644 --- a/graf3d/eve7/src/REveViewer.cxx +++ b/graf3d/eve7/src/REveViewer.cxx @@ -10,7 +10,7 @@ *************************************************************************/ #include - +#include #include #include #include @@ -34,9 +34,34 @@ Eve representation of a GL view. In a gist, it's a camera + a list of scenes. /// Constructor. REveViewer::REveViewer(const std::string& n, const std::string& t) : - REveElement(n, t) + REveElement(n, t), + fCamera(nullptr) { - // SetChildClass(TClass::GetClass()); + // Set default camera to kCameraPerspXOZ + if (gEve) + { + auto cameras = gEve->GetCameras(); + if (cameras && cameras->HasChildren()) + { + // Search for kCameraPerspXOZ camera + for (auto child : cameras->RefChildren()) + { + auto cam = dynamic_cast(child); + if (cam && cam->GetType() == REveCamera::kCameraPerspXOZ) + { + fCamera = cam; + break; + } + } + + // Fallback: use first camera if kCameraPerspXOZ not found. + // But usually, kCameraPerspXOZ is always the first camera.. + if (!fCamera) + { + fCamera = dynamic_cast(cameras->FirstChild()); + } + } + } } //////////////////////////////////////////////////////////////////////////////// @@ -129,11 +154,12 @@ void REveViewer::SetBlackBackground(bool x) /// Virtual from REveElement. int REveViewer::WriteCoreJson(nlohmann::json &j, Int_t rnr_offset) { - fCamera.WriteCoreJson(j, rnr_offset); + // fCamera.WriteCoreJson(j, rnr_offset); j["Mandatory"] = fMandatory; j["AxesType"] = fAxesType; j["BlackBg"] = fBlackBackground; + j["fCameraId"] = fCamera ? fCamera->GetElementId() : 0; j["UT_PostStream"] = "UT_EveViewerUpdate"; @@ -171,6 +197,7 @@ void REveViewer::SetMandatory(bool x) /// // Set base vectors of camera base matrix // +/* void REveViewer::SetCameraType(ECameraType cameraType) { switch(cameraType) { @@ -212,33 +239,14 @@ void REveViewer::SetCameraType(ECameraType cameraType) return; } } - +*/ //////////////////////////////////////////////////////////////////////////////// -// -// Set camera base matrix -// -void REveViewer::REveCamera::Setup( ECameraType type, const std::string& name, REveVector v1, REveVector v2) -{ - fType = type; - fName = name; - fV1 = v1; - fV2 = v2; -} +/// Set camera reference by ID, yuxiao -//////////////////////////////////////////////////////////////////////////////// -/// -// Stream camera info -// -int REveViewer::REveCamera::WriteCoreJson(nlohmann::json &j, Int_t /*rnr_offset*/) +void REveViewer::SetCamera(::ROOT::Experimental::REveCamera *cam) { - nlohmann::json out; - out["type"] = fName; - out["V1"] = {fV1.fX, fV1.fY, fV1.fZ}; - out["V2"] = {fV2.fX, fV2.fY, fV2.fZ}; - - j["camera"] = out; - - return 0; + fCamera = cam; + StampObjProps(); } //////////////////////////////////////////////////////////////////////////////// @@ -435,3 +443,19 @@ void REveViewerList::SwitchColorSet() // } // EndChanges on EveWorld; } + +//////////////////////////////////////////////////////////////////////////////// +/// Set camera by element ID (called from MIR) + +void REveViewer::SetCameraByElementId(ElementId_t cameraId) +{ + if (gEve) { + auto element = gEve->FindElementById(cameraId); + auto cam = dynamic_cast(element); + + if (cam) { + fCamera = cam; + StampObjProps(); + } + } +} \ No newline at end of file diff --git a/tutorials/visualisation/eve7/jets.C b/tutorials/visualisation/eve7/jets.C index 445acf99eb0e6..357a600d8167a 100644 --- a/tutorials/visualisation/eve7/jets.C +++ b/tutorials/visualisation/eve7/jets.C @@ -10,6 +10,8 @@ #include #include #include +#include +#include namespace REX = ROOT::Experimental; @@ -35,7 +37,19 @@ void makeJets(int N_Jets, REX::REveElement *jetHolder) void jets() { auto eveMng = REX::REveManager::Create(); - + eveMng->AllowMultipleRemoteConnections(false, false); + + auto cam = (REX::REveCamera*)eveMng->FindElementById(8); + // auto camTrans = cam->RefCamTrans(); + REX::REveTrans& camTrans = cam->RefCamTrans(); + + Double_t arr[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1000, -300, 0, 1}; + camTrans.SetFrom(arr); + // auto camTrans1 = cam->RefCamTrans(); + // camTrans1.Print(); + + //eveMng->GetDefaultViewer()->SetCamera(cam); + REX::REveElement *jetHolder = new REX::REveElement("Jets"); eveMng->GetEventScene()->AddElement(jetHolder); makeJets(7, jetHolder); diff --git a/ui5/eve7/controller/GL.controller.js b/ui5/eve7/controller/GL.controller.js index a96086405f497..bca36a3ac05ca 100644 --- a/ui5/eve7/controller/GL.controller.js +++ b/ui5/eve7/controller/GL.controller.js @@ -252,7 +252,22 @@ sap.ui.define([ isEveCameraPerspective: function() { let vo = this.mgr.GetElement(this.eveViewerId); - return vo.camera.type.startsWith("Persp"); + + // try to get camera type from standalone REveCamera element + let camera = this.mgr.GetElement(vo.fCameraId); + if (camera && camera.fType !== undefined) { + // REveCamera::ECameraType: 0-2 are Perspective, 3-8 are Orthographic + return camera.fType < 3; + } + + // Fallback: use nested camera type (backward compatibility) + // return vo.camera.type.startsWith("Persp"); + if (vo.camera && vo.camera.type) { + return vo.camera.type.startsWith("Persp"); + } + + console.warn("GL.controller.isEveCameraPerspective: no camera info found, defaulting to perspective"); + return true; }, switchSingle: function() diff --git a/ui5/eve7/controller/Ged.controller.js b/ui5/eve7/controller/Ged.controller.js index 51071b701468c..57dc40df62a2a 100644 --- a/ui5/eve7/controller/Ged.controller.js +++ b/ui5/eve7/controller/Ged.controller.js @@ -325,6 +325,11 @@ sap.ui.define([ { this.makeBoolSetter(Boolean(el.AxesType), "ShowAxes", "SetAxesType"); this.makeBoolSetter(el.BlackBg, "BlackBackground"); + + // camera type selector + this.makeCameraTypeSelector(el); + // save camera button + this.makeSaveCameraButton(el); }, buildREveDataCollectionSetter : function(el) @@ -748,8 +753,7 @@ sap.ui.define([ let selected = this.secSelectList.getSelectedItems(); for (let s = 0; s < selected.length; s++) this.secSelectList.setSelectedItem(selected[s], false); - - + for (let i =0; i < sec_idcs.length; ++i) { let sid = "item_"+sec_idcs[i]; this.secSelectList.setSelectedItemById(sid, true); @@ -758,9 +762,170 @@ sap.ui.define([ else this.secSelectList.removeSelections(); } - } + }, + + makeCameraTypeSelector: function(viewer) { + let gedFrame = this.getView().byId("GED"); + let gcm = this; + + let cameraTypes = [ + { key: 0, text: "Perspective XOZ" }, + { key: 1, text: "Perspective YOZ" }, + { key: 2, text: "Perspective XOY" }, + { key: 3, text: "Orthographic XOY" }, + { key: 4, text: "Orthographic XOZ" }, + { key: 5, text: "Orthographic ZOY" }, + { key: 6, text: "Orthographic ZOX" }, + { key: 7, text: "Orthographic XnOY" }, + { key: 8, text: "Orthographic XnOZ" }, + { key: 9, text: "Orthographic ZnOY" }, + { key: 10, text: "Orthographic ZnOX" } + ]; + + let currentCamera = null; + let currentType = 0; + + if (viewer.fCameraId) { + currentCamera = this.mgr.GetElement(viewer.fCameraId); + if (currentCamera && currentCamera.fType !== undefined) { + currentType = currentCamera.fType; + } + } + + let cameraModel = new sap.ui.model.json.JSONModel({ + types: cameraTypes + }); + + let comboBox = new sap.m.ComboBox({ + width: "100%", + selectedKey: currentType.toString(), + items: { + path: "/types", + template: new sap.ui.core.ListItem({ + key: "{key}", + text: "{text}" + }) + }, + selectionChange: function(oEvent) { + let selectedItem = oEvent.getParameter("selectedItem"); + if (selectedItem) { + let selectedType = parseInt(selectedItem.getKey()); + gcm.onCameraTypeChange(viewer, selectedType); + } + } + }); + + comboBox.setModel(cameraModel); + + let labelWidget = new mText({ text: "Camera Type" }); + labelWidget.addStyleClass("sapUiTinyMargin"); + + let frame = new HorizontalLayout({ + content: [labelWidget, comboBox] + }); + + gedFrame.addContent(frame); + }, + + onCameraTypeChange: function(viewer, newCameraType) { + let cameras = this.getCameraList(); + + for (let cam of cameras) { + if (cam.fType === newCameraType) { + let mir = "SetCameraByElementId(" + cam.fElementId + ")"; + this.mgr.SendMIR(mir, viewer.fElementId, viewer._typename); + console.log("Camera switched to:", cam.fName, "(Type:", newCameraType, ")"); + break; + } + } + }, + + getCameraList: function() { + let cameras = []; + + if (this.mgr && this.mgr.childs && this.mgr.childs.length > 0) { + let world = this.mgr.childs[0]; + + if (world.childs) { + for (let child of world.childs) { + if (child.fName === "Cameras" && child.childs) { + cameras = child.childs; + break; + } + } + } + } + + return cameras; + }, + + makeSaveCameraButton: function(viewer) { + let gedFrame = this.getView().byId("GED"); + let gcm = this; + + let button = new Button({ + text: "Save Camera Matrix", + width: "50%", + press: function() { + gcm.onSaveCameraMatrix(viewer); + } + }); + + gedFrame.addContent(button); + }, + + onSaveCameraMatrix: function(viewer) { + let view = this.getView(); + + if (!view || !view.oController) { + sap.m.MessageToast.show("Controller not found"); + console.error("view.oController not available"); + return; + } + + let glViewer = view.oController.editorElement.ca.oController.viewer; + + if (!glViewer || !glViewer.controls) { + sap.m.MessageToast.show("Camera controls not found"); + console.error("viewer.controls not available"); + return; + } + + let controls = glViewer.controls; + + if (!controls) { + sap.m.MessageToast.show("Camera matrix not available"); + console.error("camBaseMtx not available"); + return; + } + + let matrixObj = controls.getCamBase(); + + if (!matrixObj) { + sap.m.MessageToast.show("CamBase not available!"); + return; + } + let matrix = Array.from(matrixObj.elements); + + if (matrix.length !== 16) { + sap.m.MessageToast.show("Matrix must have 16 elements!"); + return; + } + + let jsonStr = JSON.stringify(matrix); + let mir = 'SetCamBaseMtx("' + jsonStr + '")'; + + console.log("Sending MIR:", mir); + + this.mgr.SendMIR(mir, viewer.fCameraId, "ROOT::Experimental::REveCamera"); + + sap.m.MessageToast.show("Camera matrix saved!"); + console.log("Saved camera matrix:", matrix); + + } }); + GedController.canEditClass = function(typename) { return true; }; @@ -776,7 +941,6 @@ sap.ui.define([ return "SetRnrSelf"; } - return GedController; }); diff --git a/ui5/eve7/lib/GlViewerRCore.js b/ui5/eve7/lib/GlViewerRCore.js index e9abf2ac505e3..260782c351941 100644 --- a/ui5/eve7/lib/GlViewerRCore.js +++ b/ui5/eve7/lib/GlViewerRCore.js @@ -31,7 +31,7 @@ sap.ui.define([ this.top_path = jsrp.substring(0, jsrp.length - 10); this.eve_path = this.top_path + 'rootui5sys/eve7/'; - this._logLevel = 1; // 0 - error, 1 - warning, 2 - info, 3 - debug + this._logLevel = 3; // 0 - error, 1 - warning, 2 - info, 3 - debug if (this._logLevel > 2) { console.log("GlViewerRCore RQ_Mode:", this.RQ_Mode, "RQ_SSAA:", this.RQ_SSAA, @@ -447,9 +447,24 @@ sap.ui.define([ } }); + // implement the camera control to client side (and look into how to locate the camera) this.controls = new RC.REveCameraControls(this.camera, this.canvas.canvasDOM); this.controls.addEventListener('change', this.render.bind(this)); + // send to server when the client finishes camera setting + this.controls.addEventListener('end', () => { + let eveView = this.controller.mgr.GetElement(this.controller.eveViewerId); + if (eveView && eveView.fCameraId && this.controls.camBaseMtx) { + let arr = Array.from(this.controls.camBaseMtx.elements); + this.controller.mgr.SendMIR("SetCamBaseMtx", eveView.fCameraId, + "ROOT::Experimental::REveCamera", + JSON.stringify(arr)); + if (this._logLevel >= 2) { + console.log("Camera matrix sent to server, ID:", eveView.fCameraId); + } + } + }); + // camera center marker let col = new RC.Color(0.5, 0, 0); const msize = this.RQ_SSAA * 8; // marker size @@ -492,7 +507,7 @@ sap.ui.define([ let sbbox = this.scene_bbox; let posV = new RC.Vector3; posV.subVectors(sbbox.max, this.rot_center); let negV = new RC.Vector3; negV.subVectors(sbbox.min, this.rot_center); - + let extV = new RC.Vector3; extV = negV; extV.negate(); extV.max(posV); let extR = extV.length(); @@ -500,9 +515,53 @@ sap.ui.define([ console.log("GlViewerRenderCore.resetRenderer", sbbox, posV, negV, extV, extR); let eveView = this.controller.mgr.GetElement(this.controller.eveViewerId); - let v1 = eveView.camera.V1; - let v2 = eveView.camera.V2; + // Try to use standalone REveCamera if available + // let cameraId = eveView.fCameraId; + let cameraId = 8; + let camera = null; + let v1, v2; + + if (cameraId) { + camera = this.controller.mgr.GetElement(cameraId); + if (this._logLevel >= 2) { + console.log("GlViewerRCore.resetRenderer: Using standalone camera ID", cameraId); + if (camera) { + console.log(" Camera name:", camera.fName); + // console.log(" Camera fV1:", camera.fV1); + // console.log(" Camera fV2:", camera.fV2); + console.log(" Camera camBase:", camera.camBase); + } + } + } + + // In resetRenderer() + // if (camera && camera.fV1 && camera.fV2) { + // v1 = camera.fV1; + // v2 = camera.fV2; + if (camera && camera.camBase && camera.camBase.length === 16) { + v1 = [camera.camBase[8], camera.camBase[9], camera.camBase[10]]; // forward/direction + v2 = [camera.camBase[4], camera.camBase[5], camera.camBase[6]]; // up + + // Apply camTrans if available + if (camera.camTrans && camera.camTrans.length === 16) { + this.controls.setCamTrans(camera.camTrans); + if (this._logLevel >= 2) { + console.log("GlViewerRCore.resetRenderer: Applied camTrans from REveCamera"); + } + } + + if (this._logLevel >= 2) { + console.log("GlViewerRCore.resetRenderer: Using standalone REveCamera"); + } + } else { + // Fallback to nested camera for backward compatibility + v1 = eveView.camera.V1; + v2 = eveView.camera.V2; + if (this._logLevel >= 1) { + console.log("GlViewerRCore.resetRenderer: Using nested camera (fallback)"); + } + } if (this.camera.isPerspectiveCamera) { @@ -543,7 +602,23 @@ sap.ui.define([ // console.log("resetRenderer 2D scene bbox ex ey", sbbox, ex, ey, ", camera_pos ", posC, ", look_at ", this.rot_center); } - this.controls.setFromBBox(sbbox); + // this.controls.setFromBBox(sbbox); + /* + if (this.camera.isPerspectiveCamera) { + let camTransTest = [1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 1000, -300, 0, 1]; + this.controls.setCamTrans(camTransTest); + console.log("Applied hardcoded camTrans:", camTransTest); + } + */ + if (camera.camTrans && camera.camTrans.length === 16) { + this.controls.setCamTrans(camera.camTrans); + if (this._logLevel >= 2) { + console.log("GlViewerRCore.resetRenderer: Applied camTrans from REveCamera"); + } + } this.controls.update(); } diff --git a/ui5/eve7/lib/RenderCore.js b/ui5/eve7/lib/RenderCore.js index 3ddf59241a5ac..36b45492c3b5d 100644 --- a/ui5/eve7/lib/RenderCore.js +++ b/ui5/eve7/lib/RenderCore.js @@ -1,9 +1,9 @@ // Standard import from ROOT build -export * from '../rcore/REveRenderCore-min.mjs'; -export const REveShaderPath = "rcore/shaders/"; -export const REveDevelMode = false; +// export * from '../rcore/REveRenderCore-min.mjs'; +// export const REveShaderPath = "rcore/shaders/"; +// export const REveDevelMode = false; // Development import from a RenderCore checkout in RC directory -// export * from '../RC/src/contrib/REveRenderCore.js'; -// export const REveShaderPath = "RC/src/shaders/"; -// export const REveDevelMode = true; \ No newline at end of file +export * from '../RC/src/contrib/REveRenderCore.js'; +export const REveShaderPath = "RC/src/shaders/"; +export const REveDevelMode = true; From 48329b0bc3b13663a8aede8af8a4510e5564aa05 Mon Sep 17 00:00:00 2001 From: yuxiao Date: Wed, 8 Apr 2026 19:18:35 +0200 Subject: [PATCH 2/5] change back to standard mode --- tutorials/visualisation/eve7/jets.C | 16 +--------------- ui5/eve7/lib/RenderCore.js | 12 ++++++------ 2 files changed, 7 insertions(+), 21 deletions(-) diff --git a/tutorials/visualisation/eve7/jets.C b/tutorials/visualisation/eve7/jets.C index 357a600d8167a..445acf99eb0e6 100644 --- a/tutorials/visualisation/eve7/jets.C +++ b/tutorials/visualisation/eve7/jets.C @@ -10,8 +10,6 @@ #include #include #include -#include -#include namespace REX = ROOT::Experimental; @@ -37,19 +35,7 @@ void makeJets(int N_Jets, REX::REveElement *jetHolder) void jets() { auto eveMng = REX::REveManager::Create(); - eveMng->AllowMultipleRemoteConnections(false, false); - - auto cam = (REX::REveCamera*)eveMng->FindElementById(8); - // auto camTrans = cam->RefCamTrans(); - REX::REveTrans& camTrans = cam->RefCamTrans(); - - Double_t arr[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1000, -300, 0, 1}; - camTrans.SetFrom(arr); - // auto camTrans1 = cam->RefCamTrans(); - // camTrans1.Print(); - - //eveMng->GetDefaultViewer()->SetCamera(cam); - + REX::REveElement *jetHolder = new REX::REveElement("Jets"); eveMng->GetEventScene()->AddElement(jetHolder); makeJets(7, jetHolder); diff --git a/ui5/eve7/lib/RenderCore.js b/ui5/eve7/lib/RenderCore.js index 36b45492c3b5d..3ddf59241a5ac 100644 --- a/ui5/eve7/lib/RenderCore.js +++ b/ui5/eve7/lib/RenderCore.js @@ -1,9 +1,9 @@ // Standard import from ROOT build -// export * from '../rcore/REveRenderCore-min.mjs'; -// export const REveShaderPath = "rcore/shaders/"; -// export const REveDevelMode = false; +export * from '../rcore/REveRenderCore-min.mjs'; +export const REveShaderPath = "rcore/shaders/"; +export const REveDevelMode = false; // Development import from a RenderCore checkout in RC directory -export * from '../RC/src/contrib/REveRenderCore.js'; -export const REveShaderPath = "RC/src/shaders/"; -export const REveDevelMode = true; +// export * from '../RC/src/contrib/REveRenderCore.js'; +// export const REveShaderPath = "RC/src/shaders/"; +// export const REveDevelMode = true; \ No newline at end of file From da6364fbd51b50ba3276b7f8d129936a8e751905 Mon Sep 17 00:00:00 2001 From: yuxiao Date: Wed, 8 Apr 2026 19:33:07 +0200 Subject: [PATCH 3/5] SetCamTransMtx implemented on server side --- graf3d/eve7/inc/ROOT/REveCamera.hxx | 3 +++ graf3d/eve7/src/REveCamera.cxx | 15 +++++++++++++++ ui5/eve7/controller/Ged.controller.js | 25 +++++++++---------------- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/graf3d/eve7/inc/ROOT/REveCamera.hxx b/graf3d/eve7/inc/ROOT/REveCamera.hxx index aa499d8ac6aec..069d873da1709 100644 --- a/graf3d/eve7/inc/ROOT/REveCamera.hxx +++ b/graf3d/eve7/inc/ROOT/REveCamera.hxx @@ -72,6 +72,9 @@ public: void SetCamBaseMtx(const std::vector &arr); void SetCamBaseMtx(const std::string &json_str); + void SetCamTransMtx(const std::vector &arr); + void SetCamTransMtx(const char* json_str); + void BuildRenderData() override{}; Int_t WriteCoreJson(nlohmann::json &j, Int_t rnr_offset) override; diff --git a/graf3d/eve7/src/REveCamera.cxx b/graf3d/eve7/src/REveCamera.cxx index 4a8a902722a42..6b94f7691f2bd 100644 --- a/graf3d/eve7/src/REveCamera.cxx +++ b/graf3d/eve7/src/REveCamera.cxx @@ -97,6 +97,21 @@ void REveCamera::SetCamBaseMtx(const std::string &json_str) SetCamBaseMtx(arr); } +void REveCamera::SetCamTransMtx(const std::vector &arr) +{ + if (arr.size() == 16) { + fCamTrans.SetFromArray(arr.data()); + StampObjProps(); + } +} + +void REveCamera::SetCamTransMtx(const char* json_str) +{ + auto j = nlohmann::json::parse(json_str); + std::vector arr = j.get>(); + SetCamTransMtx(arr); +} + //////////////////////////////////////////////////////////////////////////////// /// Write core JSON for camera diff --git a/ui5/eve7/controller/Ged.controller.js b/ui5/eve7/controller/Ged.controller.js index 57dc40df62a2a..3056a970d2c66 100644 --- a/ui5/eve7/controller/Ged.controller.js +++ b/ui5/eve7/controller/Ged.controller.js @@ -894,34 +894,27 @@ sap.ui.define([ let controls = glViewer.controls; if (!controls) { - sap.m.MessageToast.show("Camera matrix not available"); - console.error("camBaseMtx not available"); + sap.m.MessageToast.show("Camera control not available"); + console.error("controls not available"); return; } - - let matrixObj = controls.getCamBase(); - - if (!matrixObj) { - sap.m.MessageToast.show("CamBase not available!"); - return; - } - - let matrix = Array.from(matrixObj.elements); - if (matrix.length !== 16) { - sap.m.MessageToast.show("Matrix must have 16 elements!"); + let camTransMtx = controls.getCamTransMtx(); + + if (!camTransMtx || camTransMtx.length !== 16) { + sap.m.MessageToast.show("Camera transform not available!"); return; } - let jsonStr = JSON.stringify(matrix); - let mir = 'SetCamBaseMtx("' + jsonStr + '")'; + let jsonStr = JSON.stringify(camTransMtx); + let mir = 'SetCamTransMtx("' + jsonStr + '")'; console.log("Sending MIR:", mir); this.mgr.SendMIR(mir, viewer.fCameraId, "ROOT::Experimental::REveCamera"); sap.m.MessageToast.show("Camera matrix saved!"); - console.log("Saved camera matrix:", matrix); + console.log("Saved camera matrix:", camTransMtx); } }); From 46ce0a091e904d38357da5528b05525a082614e1 Mon Sep 17 00:00:00 2001 From: yuxiao Date: Wed, 29 Apr 2026 17:15:32 +0200 Subject: [PATCH 4/5] added fInitialized member --- graf3d/eve7/inc/ROOT/REveCamera.hxx | 4 ++++ graf3d/eve7/src/REveCamera.cxx | 4 ++-- ui5/eve7/lib/GlViewerRCore.js | 14 ++++++++++++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/graf3d/eve7/inc/ROOT/REveCamera.hxx b/graf3d/eve7/inc/ROOT/REveCamera.hxx index 069d873da1709..0ff7e3e85c9f0 100644 --- a/graf3d/eve7/inc/ROOT/REveCamera.hxx +++ b/graf3d/eve7/inc/ROOT/REveCamera.hxx @@ -48,6 +48,7 @@ private: // Camera transformation matrices REveTrans fCamBase; // Base camera matrix (main positioning) REveTrans fCamTrans; + Bool_t fInitialized{kFALSE}; public: REveCamera(); @@ -75,6 +76,9 @@ public: void SetCamTransMtx(const std::vector &arr); void SetCamTransMtx(const char* json_str); + Bool_t IsInitialized() const { return fInitialized; } + void SetInitialized(Bool_t val) { fInitialized = val; } + void BuildRenderData() override{}; Int_t WriteCoreJson(nlohmann::json &j, Int_t rnr_offset) override; diff --git a/graf3d/eve7/src/REveCamera.cxx b/graf3d/eve7/src/REveCamera.cxx index 6b94f7691f2bd..89d86e5d7b14e 100644 --- a/graf3d/eve7/src/REveCamera.cxx +++ b/graf3d/eve7/src/REveCamera.cxx @@ -101,6 +101,7 @@ void REveCamera::SetCamTransMtx(const std::vector &arr) { if (arr.size() == 16) { fCamTrans.SetFromArray(arr.data()); + fInitialized = kTRUE; // Mark as initialized when user saves StampObjProps(); } } @@ -121,8 +122,7 @@ Int_t REveCamera::WriteCoreJson(nlohmann::json &j, Int_t rnr_offset) j["fType"] = fType; j["fName"] = fName; - // j["fV1"] = {fV1.fX, fV1.fY, fV1.fZ}; - // j["fV2"] = {fV2.fX, fV2.fY, fV2.fZ}; + j["fInitialized"] = fInitialized; // Stream to client // Stream both matrices // Client will read these as fMatrix arrays (16 elements each) diff --git a/ui5/eve7/lib/GlViewerRCore.js b/ui5/eve7/lib/GlViewerRCore.js index 260782c351941..ec89cc72f2b3a 100644 --- a/ui5/eve7/lib/GlViewerRCore.js +++ b/ui5/eve7/lib/GlViewerRCore.js @@ -602,7 +602,15 @@ sap.ui.define([ // console.log("resetRenderer 2D scene bbox ex ey", sbbox, ex, ey, ", camera_pos ", posC, ", look_at ", this.rot_center); } - // this.controls.setFromBBox(sbbox); + // Only call setFromBBox if camera not initialized + if (!camera || !camera.fInitialized) { + // First time: auto-position from scene bounds + this.controls.setFromBBox(sbbox); + if (this._logLevel >= 2) { + console.log("Camera not initialized, using setFromBBox"); + } + } + /* if (this.camera.isPerspectiveCamera) { let camTransTest = [1, 0, 0, 0, @@ -613,7 +621,9 @@ sap.ui.define([ console.log("Applied hardcoded camTrans:", camTransTest); } */ - if (camera.camTrans && camera.camTrans.length === 16) { + + // Apply saved camTrans (if initialized) + if (camera && camera.fInitialized && camera.camTrans && camera.camTrans.length === 16) { this.controls.setCamTrans(camera.camTrans); if (this._logLevel >= 2) { console.log("GlViewerRCore.resetRenderer: Applied camTrans from REveCamera"); From 6d23a1dc184468bc7dded0bcb918d793e351d672 Mon Sep 17 00:00:00 2001 From: yuxiao Date: Wed, 29 Apr 2026 17:16:40 +0200 Subject: [PATCH 5/5] alias for backward compatibility --- graf3d/eve7/inc/ROOT/REveViewer.hxx | 37 +++++++++++++++-------------- graf3d/eve7/src/REveViewer.cxx | 26 ++++++++++++++++++++ 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/graf3d/eve7/inc/ROOT/REveViewer.hxx b/graf3d/eve7/inc/ROOT/REveViewer.hxx index adbe829d42acb..0d29802c8b979 100644 --- a/graf3d/eve7/inc/ROOT/REveViewer.hxx +++ b/graf3d/eve7/inc/ROOT/REveViewer.hxx @@ -13,12 +13,13 @@ #define ROOT7_REveViewer #include +#include namespace ROOT { namespace Experimental { class REveScene; -class REveCamera; // yuxiao +// class REveCamera; // yuxiao //////////////////////////////////////////////////////////////////////////////// /// REveViewer @@ -28,23 +29,21 @@ class REveCamera; // yuxiao class REveViewer : public REveElement { public: - enum ECameraType - { - // Perspective - kCameraPerspXOZ, // XOZ floor - kCameraPerspYOZ, // YOZ floor - kCameraPerspXOY, // XOY floor - // Orthographic - kCameraOrthoXOY, // Looking down Z axis, X horz, Y vert - kCameraOrthoXOZ, // Looking along Y axis, X horz, Z vert - kCameraOrthoZOY, // Looking along X axis, Z horz, Y vert - kCameraOrthoZOX, // Looking along Y axis, Z horz, X vert - // nOrthographic - kCameraOrthoXnOY, // Looking along Z axis, -X horz, Y vert - kCameraOrthoXnOZ, // Looking down Y axis, -X horz, Z vert - kCameraOrthoZnOY, // Looking down X axis, -Z horz, Y vert - kCameraOrthoZnOX // Looking down Y axis, -Z horz, X vert - }; + // set alias instead + using ECameraType = REveCamera::ECameraType; + + // backward compatibility + static constexpr ECameraType kCameraPerspXOZ = REveCamera::kCameraPerspXOZ; + static constexpr ECameraType kCameraPerspYOZ = REveCamera::kCameraPerspYOZ; + static constexpr ECameraType kCameraPerspXOY = REveCamera::kCameraPerspXOY; + static constexpr ECameraType kCameraOrthoXOY = REveCamera::kCameraOrthoXOY; + static constexpr ECameraType kCameraOrthoXOZ = REveCamera::kCameraOrthoXOZ; + static constexpr ECameraType kCameraOrthoZOY = REveCamera::kCameraOrthoZOY; + static constexpr ECameraType kCameraOrthoZOX = REveCamera::kCameraOrthoZOX; + static constexpr ECameraType kCameraOrthoXnOY = REveCamera::kCameraOrthoXnOY; + static constexpr ECameraType kCameraOrthoXnOZ = REveCamera::kCameraOrthoXnOZ; + static constexpr ECameraType kCameraOrthoZnOY = REveCamera::kCameraOrthoZnOY; + static constexpr ECameraType kCameraOrthoZnOX = REveCamera::kCameraOrthoZnOX; enum EAxesType { kAxesNone, @@ -80,6 +79,8 @@ public: void SetCameraByElementId(ElementId_t cameraId); // set camera via ElementID + void SetCameraType(REveCamera::ECameraType type); + void SetAxesType(int); void SetBlackBackground(bool); diff --git a/graf3d/eve7/src/REveViewer.cxx b/graf3d/eve7/src/REveViewer.cxx index a24c93c3e82b1..904a66990f907 100644 --- a/graf3d/eve7/src/REveViewer.cxx +++ b/graf3d/eve7/src/REveViewer.cxx @@ -458,4 +458,30 @@ void REveViewer::SetCameraByElementId(ElementId_t cameraId) StampObjProps(); } } +} + +//////////////////////////////////////////////////////////////////////////////// +/// Set camera by type (backward compatibility with old API) + +void REveViewer::SetCameraType(REveCamera::ECameraType type) +{ + if (gEve) { + auto cameras = gEve->GetCameras(); + if (cameras) { + for (auto child : cameras->RefChildren()) { + auto cam = dynamic_cast(child); + if (cam && cam->GetType() == type) { + fCamera = cam; + StampObjProps(); + + if (gDebug > 0) { + ::Info("REveViewer::SetCameraType", "Camera set to type %d (%s)", + type, cam->GetCameraName().c_str()); + } + return; + } + } + ::Warning("REveViewer::SetCameraType", "Camera with type %d not found", type); + } + } } \ No newline at end of file