From b79e82d24e9bf7b11273f3671415815a3e2bea95 Mon Sep 17 00:00:00 2001 From: yuxiao Date: Thu, 29 Jan 2026 16:43:42 +0100 Subject: [PATCH 1/3] 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/3] 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/3] 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); } });