From 04a2d46aa8adae5886e00729a3935b61d087510f Mon Sep 17 00:00:00 2001 From: AbbasReads Date: Mon, 15 Sep 2025 11:40:34 +0530 Subject: [PATCH 01/27] feat: Add yaw, azimuth, and elevation methods to camera implementation --- library/private/camera_impl.h | 5 ++- library/public/camera.h | 5 ++- library/src/camera_impl.cxx | 73 ++++++++++++++++++++++++++++++- library/testing/TestSDKCamera.cxx | 52 +++++++++++++++++++++- 4 files changed, 131 insertions(+), 4 deletions(-) diff --git a/library/private/camera_impl.h b/library/private/camera_impl.h index 17173d74ca..4a39ed51ee 100644 --- a/library/private/camera_impl.h +++ b/library/private/camera_impl.h @@ -50,6 +50,9 @@ class camera_impl : public camera camera& setState(const camera_state_t& state) override; camera_state_t getState() override; void getState(camera_state_t& state) override; + angle_deg_t getYaw() override; + angle_deg_t getAzimuth() override; + angle_deg_t getElevation() override; camera& dolly(double val) override; camera& pan(double right, double up, double forward) override; @@ -85,4 +88,4 @@ class camera_impl : public camera }; } -#endif +#endif \ No newline at end of file diff --git a/library/public/camera.h b/library/public/camera.h index 670afec571..636d2f7d3e 100644 --- a/library/public/camera.h +++ b/library/public/camera.h @@ -49,6 +49,9 @@ class F3D_EXPORT camera virtual camera& setState(const camera_state_t& state) = 0; [[nodiscard]] virtual camera_state_t getState() = 0; virtual void getState(camera_state_t& state) = 0; + [[nodiscard]] virtual angle_deg_t getYaw() = 0; + [[nodiscard]] virtual angle_deg_t getAzimuth() = 0; + [[nodiscard]] virtual angle_deg_t getElevation() = 0; ///@} ///@{ @name Manipulation @@ -103,4 +106,4 @@ class F3D_EXPORT camera }; } -#endif +#endif \ No newline at end of file diff --git a/library/src/camera_impl.cxx b/library/src/camera_impl.cxx index ab4b7ef46d..70d383a7f8 100644 --- a/library/src/camera_impl.cxx +++ b/library/src/camera_impl.cxx @@ -183,6 +183,77 @@ void camera_impl::getState(camera_state_t& state) state.viewAngle = cam->GetViewAngle(); } //---------------------------------------------------------------------------- +angle_deg_t camera_impl::getYaw() +{ + point3_t pos, foc; + vector3_t dir; + double *up, *right; + this->getPosition(pos); + this->getFocalPoint(foc); + up = this->Internals->VTKRenderer->GetEnvironmentUp(); + right = this->Internals->VTKRenderer->GetEnvironmentRight(); + // Forward vector (focal - position) + vtkMath::Subtract(foc, pos, dir); + vtkMath::Normalize(dir.data()); + vtkMath::Normalize(up); + + // Project forward onto plane perpendicular to up + double dot = vtkMath::Dot(dir.data(), up); + vector3_t projected; + for (int i = 0; i < 3; ++i) + { + projected[i] = dir[i] - dot * up[i]; + } + vtkMath::Normalize(projected.data()); + vector3_t cross; + vtkMath::Cross(right, projected.data(), cross.data()); + double sign = (vtkMath::Dot(cross, up) >= 0) ? 1 : -1; + double angleRad = vtkMath::AngleBetweenVectors(right, projected.data()); + return sign * vtkMath::DegreesFromRadians(angleRad); +} +//---------------------------------------------------------------------------- +angle_deg_t camera_impl::getElevation() +{ + double* up; + up = this->Internals->VTKRenderer->GetEnvironmentUp(); + vtkCamera* cam = this->GetVTKCamera(); + return vtkMath::DegreesFromRadians( + vtkMath::AngleBetweenVectors(up, cam->GetDirectionOfProjection()) - vtkMath::Pi() / 2); +} +//---------------------------------------------------------------------------- +angle_deg_t camera_impl::getAzimuth() +{ + point3_t pos, foc; + vector3_t dir; + double* up = this->Internals->VTKRenderer->GetEnvironmentUp(); + double* right = this->Internals->VTKRenderer->GetEnvironmentRight(); + this->getPosition(pos); + this->getFocalPoint(foc); + + // Forward vector (focal - position) + vtkMath::Subtract(foc, pos, dir); + vtkMath::Normalize(dir.data()); + vtkMath::Normalize(up); + + // Project forward onto plane perpendicular to up + double dot = vtkMath::Dot(dir.data(), up); + vector3_t projected; + for (int i = 0; i < 3; ++i) + { + projected[i] = dir[i] - dot * up[i]; + } + vtkMath::Normalize(projected.data()); + + // Azimuth is the signed angle between right and projected forward, using up as the normal + double angleRad = vtkMath::AngleBetweenVectors(right, projected.data()); + // Determine sign using cross product + vector3_t cross; + vtkMath::Cross(right, projected.data(), cross.data()); + double sign = vtkMath::Dot(cross.data(), up) >= 0 ? 1.0 : -1.0; + + return sign * vtkMath::DegreesFromRadians(angleRad); +} +//---------------------------------------------------------------------------- camera& camera_impl::dolly(double val) { vtkCamera* cam = this->GetVTKCamera(); @@ -323,4 +394,4 @@ vtkCamera* camera_impl::GetVTKCamera() { return this->Internals->VTKRenderer->GetActiveCamera(); } -}; +}; \ No newline at end of file diff --git a/library/testing/TestSDKCamera.cxx b/library/testing/TestSDKCamera.cxx index 7aeff88ebd..5d0cb651d5 100644 --- a/library/testing/TestSDKCamera.cxx +++ b/library/testing/TestSDKCamera.cxx @@ -81,6 +81,56 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) return EXIT_FAILURE; } + // Test getYaw + cam.setPosition({ 0, 0, 1 }); + cam.setFocalPoint({ 0, 0, 0 }); + cam.setViewUp({ 0, 1, 0 }); + f3d::angle_deg_t testYaw = 90.0; + f3d::angle_deg_t yaw = cam.getYaw(); + if (!compareDouble(yaw, testYaw)) + { + std::cerr << "get yaw is not behaving as expected: " << yaw << " " << "\n"; + return EXIT_FAILURE; + } + cam.yaw(90); + testYaw = 180.0; + yaw = cam.getYaw(); + if (!compareDouble(yaw, testYaw)) + { + std::cerr << "Yaw after +90° yaw() is incorrect: " << yaw << "\n"; + return EXIT_FAILURE; + } + cam.yaw(180); + testYaw = 0; + yaw = cam.getYaw(); + if (!compareDouble(yaw, testYaw)) + { + std::cerr << "Yaw after +90° yaw() is incorrect: " << yaw << "\n"; + return EXIT_FAILURE; + } + + // Test getElevation + cam.setPosition({ 0, 0, -1 }); + cam.setFocalPoint({ 0, 0, 0 }); + cam.setViewUp({ 0, 1, 0 }); + f3d::angle_deg_t testElevation = 0.0; + f3d::angle_deg_t elevation = cam.getElevation(); + if (!compareDouble(elevation, testElevation)) + { + std::cerr << "get elevation is not behaving as expected: " << elevation + << " != " << testElevation << "\n"; + return EXIT_FAILURE; + } + cam.elevation(45); + testElevation = 45.0; + elevation = cam.getElevation(); + if (!compareDouble(elevation, testElevation)) + { + std::cerr << "get elevation after elevation +45 is not behaving as expected: " << elevation + << " != " << testElevation << "\n"; + return EXIT_FAILURE; + } + // Test position f3d::point3_t testPos = { 0., 0., 10. }; f3d::point3_t pos = cam.setPosition(testPos).getPosition(); @@ -313,4 +363,4 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) } return EXIT_SUCCESS; -} +} \ No newline at end of file From 6789df350ee85ec9c46123222a39408cea84e5e4 Mon Sep 17 00:00:00 2001 From: AbbasReads Date: Mon, 15 Sep 2025 20:04:34 +0530 Subject: [PATCH 02/27] Update camera tests for yaw, elevation, and add getAzimuth method and test --- library/src/camera_impl.cxx | 3 --- library/testing/TestSDKCamera.cxx | 38 ++++++++++++++++++++----------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/library/src/camera_impl.cxx b/library/src/camera_impl.cxx index 70d383a7f8..6dbd268be5 100644 --- a/library/src/camera_impl.cxx +++ b/library/src/camera_impl.cxx @@ -244,13 +244,10 @@ angle_deg_t camera_impl::getAzimuth() } vtkMath::Normalize(projected.data()); - // Azimuth is the signed angle between right and projected forward, using up as the normal double angleRad = vtkMath::AngleBetweenVectors(right, projected.data()); - // Determine sign using cross product vector3_t cross; vtkMath::Cross(right, projected.data(), cross.data()); double sign = vtkMath::Dot(cross.data(), up) >= 0 ? 1.0 : -1.0; - return sign * vtkMath::DegreesFromRadians(angleRad); } //---------------------------------------------------------------------------- diff --git a/library/testing/TestSDKCamera.cxx b/library/testing/TestSDKCamera.cxx index 5d0cb651d5..cc5cf79a0e 100644 --- a/library/testing/TestSDKCamera.cxx +++ b/library/testing/TestSDKCamera.cxx @@ -82,10 +82,10 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) } // Test getYaw - cam.setPosition({ 0, 0, 1 }); + cam.setPosition({ -1, 0, 0 }); cam.setFocalPoint({ 0, 0, 0 }); cam.setViewUp({ 0, 1, 0 }); - f3d::angle_deg_t testYaw = 90.0; + f3d::angle_deg_t testYaw = 0.0; f3d::angle_deg_t yaw = cam.getYaw(); if (!compareDouble(yaw, testYaw)) { @@ -93,15 +93,7 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) return EXIT_FAILURE; } cam.yaw(90); - testYaw = 180.0; - yaw = cam.getYaw(); - if (!compareDouble(yaw, testYaw)) - { - std::cerr << "Yaw after +90° yaw() is incorrect: " << yaw << "\n"; - return EXIT_FAILURE; - } - cam.yaw(180); - testYaw = 0; + testYaw = 90.0; yaw = cam.getYaw(); if (!compareDouble(yaw, testYaw)) { @@ -121,8 +113,8 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) << " != " << testElevation << "\n"; return EXIT_FAILURE; } - cam.elevation(45); - testElevation = 45.0; + cam.elevation(-45); + testElevation = -45.0; elevation = cam.getElevation(); if (!compareDouble(elevation, testElevation)) { @@ -131,6 +123,26 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) return EXIT_FAILURE; } + // Test getAzimuth + cam.setPosition({ -1, 0, 0 }); + cam.setFocalPoint({ 0, 0, 0 }); + cam.setViewUp({ 0, 1, 0 }); + f3d::angle_deg_t testAzimuth = 0.0; + f3d::angle_deg_t azimuth = cam.getAzimuth(); + if (!compareDouble(azimuth, testAzimuth)) + { + std::cerr << "get azimuth is not behaving as expected: " << azimuth << " != " << testAzimuth << "\n"; + return EXIT_FAILURE; + } + cam.azimuth(90); + testAzimuth = 90.0; + azimuth = cam.getAzimuth(); + if (!compareDouble(azimuth, testAzimuth)) + { + std::cerr << "get azimuth after azimuth +90 is not behaving as expected: " << azimuth << " != " << testAzimuth << "\n"; + return EXIT_FAILURE; + } + // Test position f3d::point3_t testPos = { 0., 0., 10. }; f3d::point3_t pos = cam.setPosition(testPos).getPosition(); From c13cf2edd0be1da17a7aa28f7dcda29a8837ac39 Mon Sep 17 00:00:00 2001 From: Abbas Mehdi <24je0656@iitism.ac.in> Date: Mon, 15 Sep 2025 22:56:47 +0530 Subject: [PATCH 03/27] Update library/testing/TestSDKCamera.cxx Co-authored-by: Mathieu Westphal --- library/testing/TestSDKCamera.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/testing/TestSDKCamera.cxx b/library/testing/TestSDKCamera.cxx index cc5cf79a0e..3a325f1fb6 100644 --- a/library/testing/TestSDKCamera.cxx +++ b/library/testing/TestSDKCamera.cxx @@ -134,8 +134,8 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) std::cerr << "get azimuth is not behaving as expected: " << azimuth << " != " << testAzimuth << "\n"; return EXIT_FAILURE; } - cam.azimuth(90); - testAzimuth = 90.0; + testAzimuth = 90.0; + cam.azimuth(testAzimuth); azimuth = cam.getAzimuth(); if (!compareDouble(azimuth, testAzimuth)) { From e4f037c8a651d9ded50dac80d36a9116418e21ec Mon Sep 17 00:00:00 2001 From: Abbas Mehdi <24je0656@iitism.ac.in> Date: Mon, 15 Sep 2025 22:57:32 +0530 Subject: [PATCH 04/27] Update library/testing/TestSDKCamera.cxx Co-authored-by: Mathieu Westphal --- library/testing/TestSDKCamera.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/testing/TestSDKCamera.cxx b/library/testing/TestSDKCamera.cxx index 3a325f1fb6..976217d41c 100644 --- a/library/testing/TestSDKCamera.cxx +++ b/library/testing/TestSDKCamera.cxx @@ -113,8 +113,8 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) << " != " << testElevation << "\n"; return EXIT_FAILURE; } - cam.elevation(-45); testElevation = -45.0; + cam.elevation(testElevation); elevation = cam.getElevation(); if (!compareDouble(elevation, testElevation)) { From d0bdf55607213b23d49ac0ab9bdbdc43101fb6d7 Mon Sep 17 00:00:00 2001 From: Abbas Mehdi <24je0656@iitism.ac.in> Date: Mon, 15 Sep 2025 22:57:46 +0530 Subject: [PATCH 05/27] Update library/testing/TestSDKCamera.cxx Co-authored-by: Mathieu Westphal --- library/testing/TestSDKCamera.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/testing/TestSDKCamera.cxx b/library/testing/TestSDKCamera.cxx index 976217d41c..224af909f7 100644 --- a/library/testing/TestSDKCamera.cxx +++ b/library/testing/TestSDKCamera.cxx @@ -92,8 +92,8 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) std::cerr << "get yaw is not behaving as expected: " << yaw << " " << "\n"; return EXIT_FAILURE; } - cam.yaw(90); - testYaw = 90.0; + testYaw = 90.0; + cam.yaw(testYaw); yaw = cam.getYaw(); if (!compareDouble(yaw, testYaw)) { From 2e0a6e5d08fb78035fe2f6bb1deb2be3756443c7 Mon Sep 17 00:00:00 2001 From: Abbas Mehdi <24je0656@iitism.ac.in> Date: Mon, 15 Sep 2025 22:59:00 +0530 Subject: [PATCH 06/27] Update library/testing/TestSDKCamera.cxx Co-authored-by: Mathieu Westphal --- library/testing/TestSDKCamera.cxx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/testing/TestSDKCamera.cxx b/library/testing/TestSDKCamera.cxx index 224af909f7..df69602a48 100644 --- a/library/testing/TestSDKCamera.cxx +++ b/library/testing/TestSDKCamera.cxx @@ -85,9 +85,8 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) cam.setPosition({ -1, 0, 0 }); cam.setFocalPoint({ 0, 0, 0 }); cam.setViewUp({ 0, 1, 0 }); - f3d::angle_deg_t testYaw = 0.0; f3d::angle_deg_t yaw = cam.getYaw(); - if (!compareDouble(yaw, testYaw)) + if (!compareDouble(yaw, 0.)) { std::cerr << "get yaw is not behaving as expected: " << yaw << " " << "\n"; return EXIT_FAILURE; From d111df79f2c9851e86d65441d2bc124c3d2cacc0 Mon Sep 17 00:00:00 2001 From: Abbas Mehdi <24je0656@iitism.ac.in> Date: Mon, 15 Sep 2025 22:59:35 +0530 Subject: [PATCH 07/27] Update library/src/camera_impl.cxx Co-authored-by: Mathieu Westphal --- library/src/camera_impl.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/src/camera_impl.cxx b/library/src/camera_impl.cxx index 6dbd268be5..d794a85f96 100644 --- a/library/src/camera_impl.cxx +++ b/library/src/camera_impl.cxx @@ -190,8 +190,8 @@ angle_deg_t camera_impl::getYaw() double *up, *right; this->getPosition(pos); this->getFocalPoint(foc); - up = this->Internals->VTKRenderer->GetEnvironmentUp(); - right = this->Internals->VTKRenderer->GetEnvironmentRight(); + double* up = this->Internals->VTKRenderer->GetEnvironmentUp(); + double* right = this->Internals->VTKRenderer->GetEnvironmentRight(); // Forward vector (focal - position) vtkMath::Subtract(foc, pos, dir); vtkMath::Normalize(dir.data()); From 689642ee5de77e23fd0d8f6da24105974c330930 Mon Sep 17 00:00:00 2001 From: Abbas Mehdi <24je0656@iitism.ac.in> Date: Mon, 15 Sep 2025 22:59:58 +0530 Subject: [PATCH 08/27] Update library/src/camera_impl.cxx Co-authored-by: Mathieu Westphal --- library/src/camera_impl.cxx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/src/camera_impl.cxx b/library/src/camera_impl.cxx index d794a85f96..15eee72223 100644 --- a/library/src/camera_impl.cxx +++ b/library/src/camera_impl.cxx @@ -214,8 +214,7 @@ angle_deg_t camera_impl::getYaw() //---------------------------------------------------------------------------- angle_deg_t camera_impl::getElevation() { - double* up; - up = this->Internals->VTKRenderer->GetEnvironmentUp(); + double* up = this->Internals->VTKRenderer->GetEnvironmentUp(); vtkCamera* cam = this->GetVTKCamera(); return vtkMath::DegreesFromRadians( vtkMath::AngleBetweenVectors(up, cam->GetDirectionOfProjection()) - vtkMath::Pi() / 2); From 6ea92d755b7cbdcaa8847129621e9723e5b63ebb Mon Sep 17 00:00:00 2001 From: AbbasReads Date: Tue, 16 Sep 2025 01:13:28 +0530 Subject: [PATCH 09/27] Refactor camera angle methods for improved clarity --- library/private/camera_impl.h | 9 +- library/public/camera.h | 14 ++-- library/src/camera_impl.cxx | 135 +++++++++++++++--------------- library/testing/TestSDKCamera.cxx | 16 ++-- 4 files changed, 91 insertions(+), 83 deletions(-) diff --git a/library/private/camera_impl.h b/library/private/camera_impl.h index 4a39ed51ee..c758a624f6 100644 --- a/library/private/camera_impl.h +++ b/library/private/camera_impl.h @@ -50,9 +50,6 @@ class camera_impl : public camera camera& setState(const camera_state_t& state) override; camera_state_t getState() override; void getState(camera_state_t& state) override; - angle_deg_t getYaw() override; - angle_deg_t getAzimuth() override; - angle_deg_t getElevation() override; camera& dolly(double val) override; camera& pan(double right, double up, double forward) override; @@ -63,6 +60,10 @@ class camera_impl : public camera camera& elevation(angle_deg_t angle) override; camera& pitch(angle_deg_t angle) override; + angle_deg_t getYaw() override; + angle_deg_t getAzimuth() override; + angle_deg_t getElevation() override; + camera& setCurrentAsDefault() override; camera& resetToDefault() override; camera& resetToBounds(double zoomFactor = 0.9) override; @@ -88,4 +89,4 @@ class camera_impl : public camera }; } -#endif \ No newline at end of file +#endif diff --git a/library/public/camera.h b/library/public/camera.h index 636d2f7d3e..795d858e70 100644 --- a/library/public/camera.h +++ b/library/public/camera.h @@ -49,9 +49,6 @@ class F3D_EXPORT camera virtual camera& setState(const camera_state_t& state) = 0; [[nodiscard]] virtual camera_state_t getState() = 0; virtual void getState(camera_state_t& state) = 0; - [[nodiscard]] virtual angle_deg_t getYaw() = 0; - [[nodiscard]] virtual angle_deg_t getAzimuth() = 0; - [[nodiscard]] virtual angle_deg_t getElevation() = 0; ///@} ///@{ @name Manipulation @@ -73,9 +70,16 @@ class F3D_EXPORT camera virtual camera& elevation(angle_deg_t angle) = 0; /** Rotate the camera about its horizontal axis, centered the camera's position. */ virtual camera& pitch(angle_deg_t angle) = 0; - ///@} + ///@{ @name Getters + /// Yaw, azimuth and elevation getter methods(calculated on call). Angles are in degrees. + + [[nodiscard]] virtual angle_deg_t getYaw() = 0; + [[nodiscard]] virtual angle_deg_t getAzimuth() = 0; + [[nodiscard]] virtual angle_deg_t getElevation() = 0; + ///@} + /** * Store the current camera configuration as default. */ @@ -106,4 +110,4 @@ class F3D_EXPORT camera }; } -#endif \ No newline at end of file +#endif diff --git a/library/src/camera_impl.cxx b/library/src/camera_impl.cxx index 15eee72223..e77e48e8c7 100644 --- a/library/src/camera_impl.cxx +++ b/library/src/camera_impl.cxx @@ -182,73 +182,7 @@ void camera_impl::getState(camera_state_t& state) cam->GetViewUp(state.viewUp.data()); state.viewAngle = cam->GetViewAngle(); } -//---------------------------------------------------------------------------- -angle_deg_t camera_impl::getYaw() -{ - point3_t pos, foc; - vector3_t dir; - double *up, *right; - this->getPosition(pos); - this->getFocalPoint(foc); - double* up = this->Internals->VTKRenderer->GetEnvironmentUp(); - double* right = this->Internals->VTKRenderer->GetEnvironmentRight(); - // Forward vector (focal - position) - vtkMath::Subtract(foc, pos, dir); - vtkMath::Normalize(dir.data()); - vtkMath::Normalize(up); - // Project forward onto plane perpendicular to up - double dot = vtkMath::Dot(dir.data(), up); - vector3_t projected; - for (int i = 0; i < 3; ++i) - { - projected[i] = dir[i] - dot * up[i]; - } - vtkMath::Normalize(projected.data()); - vector3_t cross; - vtkMath::Cross(right, projected.data(), cross.data()); - double sign = (vtkMath::Dot(cross, up) >= 0) ? 1 : -1; - double angleRad = vtkMath::AngleBetweenVectors(right, projected.data()); - return sign * vtkMath::DegreesFromRadians(angleRad); -} -//---------------------------------------------------------------------------- -angle_deg_t camera_impl::getElevation() -{ - double* up = this->Internals->VTKRenderer->GetEnvironmentUp(); - vtkCamera* cam = this->GetVTKCamera(); - return vtkMath::DegreesFromRadians( - vtkMath::AngleBetweenVectors(up, cam->GetDirectionOfProjection()) - vtkMath::Pi() / 2); -} -//---------------------------------------------------------------------------- -angle_deg_t camera_impl::getAzimuth() -{ - point3_t pos, foc; - vector3_t dir; - double* up = this->Internals->VTKRenderer->GetEnvironmentUp(); - double* right = this->Internals->VTKRenderer->GetEnvironmentRight(); - this->getPosition(pos); - this->getFocalPoint(foc); - - // Forward vector (focal - position) - vtkMath::Subtract(foc, pos, dir); - vtkMath::Normalize(dir.data()); - vtkMath::Normalize(up); - - // Project forward onto plane perpendicular to up - double dot = vtkMath::Dot(dir.data(), up); - vector3_t projected; - for (int i = 0; i < 3; ++i) - { - projected[i] = dir[i] - dot * up[i]; - } - vtkMath::Normalize(projected.data()); - - double angleRad = vtkMath::AngleBetweenVectors(right, projected.data()); - vector3_t cross; - vtkMath::Cross(right, projected.data(), cross.data()); - double sign = vtkMath::Dot(cross.data(), up) >= 0 ? 1.0 : -1.0; - return sign * vtkMath::DegreesFromRadians(angleRad); -} //---------------------------------------------------------------------------- camera& camera_impl::dolly(double val) { @@ -349,6 +283,73 @@ camera& camera_impl::pitch(angle_deg_t angle) return *this; } +//---------------------------------------------------------------------------- +angle_deg_t camera_impl::getYaw() +{ + point3_t pos, foc; + vector3_t dir, projectedAlongUp, projected; + double* up = this->Internals->VTKRenderer->GetEnvironmentUp(); + double* right = this->Internals->VTKRenderer->GetEnvironmentRight(); + this->getPosition(pos); + this->getFocalPoint(foc); + + // Forward vector (focal - position) + vtkMath::Subtract(foc, pos, dir); + vtkMath::Normalize(dir.data()); + vtkMath::Normalize(up); + + // Project forward vector onto up vector + vtkMath::ProjectVector(dir.data(), up, projectedAlongUp.data()); + vtkMath::Normalize(projectedAlongUp.data()); + + // Projection of forward vector along the plane perpendicular to up vector + vtkMath::Subtract(dir,projectedAlongUp,projected); + + vector3_t cross; + vtkMath::Cross(right, projected.data(), cross.data()); + double sign = (vtkMath::Dot(cross.data(), up) >= 0) ? 1.0 : -1.0; + double angleRad = vtkMath::AngleBetweenVectors(right, projected.data()); + return sign * vtkMath::DegreesFromRadians(angleRad); +} + +//---------------------------------------------------------------------------- +angle_deg_t camera_impl::getAzimuth() +{ + point3_t pos, foc; + vector3_t dir, projectedAlongUp, projected; + double* up = this->Internals->VTKRenderer->GetEnvironmentUp(); + double* right = this->Internals->VTKRenderer->GetEnvironmentRight(); + this->getPosition(pos); + this->getFocalPoint(foc); + + // Forward vector (focal - position) + vtkMath::Subtract(foc, pos, dir); + vtkMath::Normalize(dir.data()); + vtkMath::Normalize(up); + + // Project forward vector onto up vector + vtkMath::ProjectVector(dir.data(), up, projectedAlongUp.data()); + vtkMath::Normalize(projectedAlongUp.data()); + + //Projection of forward vector along the plane perpendicular to up vector + vtkMath::Subtract(dir,projectedAlongUp,projected); + + double angleRad = vtkMath::AngleBetweenVectors(right, projected.data()); + vector3_t cross; + vtkMath::Cross(right, projected.data(), cross.data()); + double sign = vtkMath::Dot(cross.data(), up) >= 0 ? 1.0 : -1.0; + return sign * vtkMath::DegreesFromRadians(angleRad); +} + +//---------------------------------------------------------------------------- +angle_deg_t camera_impl::getElevation() +{ + double* up = this->Internals->VTKRenderer->GetEnvironmentUp(); + vtkCamera* cam = this->GetVTKCamera(); + return vtkMath::DegreesFromRadians( + vtkMath::AngleBetweenVectors(up, cam->GetDirectionOfProjection()) - vtkMath::Pi() / 2); +} + //---------------------------------------------------------------------------- camera& camera_impl::setCurrentAsDefault() { @@ -390,4 +391,4 @@ vtkCamera* camera_impl::GetVTKCamera() { return this->Internals->VTKRenderer->GetActiveCamera(); } -}; \ No newline at end of file +}; diff --git a/library/testing/TestSDKCamera.cxx b/library/testing/TestSDKCamera.cxx index df69602a48..dad4b1f4d3 100644 --- a/library/testing/TestSDKCamera.cxx +++ b/library/testing/TestSDKCamera.cxx @@ -91,8 +91,8 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) std::cerr << "get yaw is not behaving as expected: " << yaw << " " << "\n"; return EXIT_FAILURE; } - testYaw = 90.0; - cam.yaw(testYaw); + f3d::angle_deg_t testYaw = 90.0; + cam.yaw(testYaw); yaw = cam.getYaw(); if (!compareDouble(yaw, testYaw)) { @@ -130,15 +130,17 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) f3d::angle_deg_t azimuth = cam.getAzimuth(); if (!compareDouble(azimuth, testAzimuth)) { - std::cerr << "get azimuth is not behaving as expected: " << azimuth << " != " << testAzimuth << "\n"; + std::cerr << "get azimuth is not behaving as expected: " << azimuth << " != " << testAzimuth + << "\n"; return EXIT_FAILURE; } - testAzimuth = 90.0; - cam.azimuth(testAzimuth); + testAzimuth = 90.0; + cam.azimuth(testAzimuth); azimuth = cam.getAzimuth(); if (!compareDouble(azimuth, testAzimuth)) { - std::cerr << "get azimuth after azimuth +90 is not behaving as expected: " << azimuth << " != " << testAzimuth << "\n"; + std::cerr << "get azimuth after azimuth +90 is not behaving as expected: " << azimuth + << " != " << testAzimuth << "\n"; return EXIT_FAILURE; } @@ -374,4 +376,4 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) } return EXIT_SUCCESS; -} \ No newline at end of file +} From b36aff694d50248b93dc8286c0cbdca30251d554 Mon Sep 17 00:00:00 2001 From: Abbas Mehdi <24je0656@iitism.ac.in> Date: Tue, 16 Sep 2025 01:16:31 +0530 Subject: [PATCH 10/27] Update library/testing/TestSDKCamera.cxx Co-authored-by: Mathieu Westphal --- library/testing/TestSDKCamera.cxx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/testing/TestSDKCamera.cxx b/library/testing/TestSDKCamera.cxx index dad4b1f4d3..ad261017ea 100644 --- a/library/testing/TestSDKCamera.cxx +++ b/library/testing/TestSDKCamera.cxx @@ -104,9 +104,8 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) cam.setPosition({ 0, 0, -1 }); cam.setFocalPoint({ 0, 0, 0 }); cam.setViewUp({ 0, 1, 0 }); - f3d::angle_deg_t testElevation = 0.0; f3d::angle_deg_t elevation = cam.getElevation(); - if (!compareDouble(elevation, testElevation)) + if (!compareDouble(elevation, 0.)) { std::cerr << "get elevation is not behaving as expected: " << elevation << " != " << testElevation << "\n"; From 78e40189100ad1a2ed77797770067ec609a57e23 Mon Sep 17 00:00:00 2001 From: Abbas Mehdi <24je0656@iitism.ac.in> Date: Tue, 16 Sep 2025 01:17:11 +0530 Subject: [PATCH 11/27] Update library/testing/TestSDKCamera.cxx Co-authored-by: Mathieu Westphal --- library/testing/TestSDKCamera.cxx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/testing/TestSDKCamera.cxx b/library/testing/TestSDKCamera.cxx index ad261017ea..320d128c4c 100644 --- a/library/testing/TestSDKCamera.cxx +++ b/library/testing/TestSDKCamera.cxx @@ -125,9 +125,8 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) cam.setPosition({ -1, 0, 0 }); cam.setFocalPoint({ 0, 0, 0 }); cam.setViewUp({ 0, 1, 0 }); - f3d::angle_deg_t testAzimuth = 0.0; f3d::angle_deg_t azimuth = cam.getAzimuth(); - if (!compareDouble(azimuth, testAzimuth)) + if (!compareDouble(azimuth, 0.)) { std::cerr << "get azimuth is not behaving as expected: " << azimuth << " != " << testAzimuth << "\n"; From a0bd210a7064dbe754f8d752a879b7eb8f92791a Mon Sep 17 00:00:00 2001 From: AbbasReads Date: Mon, 22 Sep 2025 11:28:58 +0530 Subject: [PATCH 12/27] Enhance camera angle method documentation and fix test variable initialization --- library/public/camera.h | 14 ++++++++++++-- library/testing/TestSDKCamera.cxx | 11 +++++------ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/library/public/camera.h b/library/public/camera.h index 795d858e70..5ce39eafbc 100644 --- a/library/public/camera.h +++ b/library/public/camera.h @@ -75,8 +75,18 @@ class F3D_EXPORT camera ///@{ @name Getters /// Yaw, azimuth and elevation getter methods(calculated on call). Angles are in degrees. - [[nodiscard]] virtual angle_deg_t getYaw() = 0; - [[nodiscard]] virtual angle_deg_t getAzimuth() = 0; + /** Calculates angle between the projection of the forward vector (on + * the plane perpendicular to the up vector) and the right vector (-180 to 180 degrees) + */ + [[nodiscard]] virtual angle_deg_t getYaw() = 0; + + /** Calculates the horizontal rotation angle of the forward vector + * around the up vector, measured from the right vector. (-180 to 180 degrees) + */ +[[nodiscard]] virtual angle_deg_t getAzimuth() = 0; + + + /** Calculates the angle between the forward vector and the up vector (-90 to +90 degrees) */ [[nodiscard]] virtual angle_deg_t getElevation() = 0; ///@} diff --git a/library/testing/TestSDKCamera.cxx b/library/testing/TestSDKCamera.cxx index 320d128c4c..4e2fbc122d 100644 --- a/library/testing/TestSDKCamera.cxx +++ b/library/testing/TestSDKCamera.cxx @@ -107,11 +107,11 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) f3d::angle_deg_t elevation = cam.getElevation(); if (!compareDouble(elevation, 0.)) { - std::cerr << "get elevation is not behaving as expected: " << elevation - << " != " << testElevation << "\n"; + std::cerr << "get elevation is not behaving as expected: " << elevation << " != " << 0.0 + << "\n"; return EXIT_FAILURE; } - testElevation = -45.0; + f3d::angle_deg_t testElevation = -45.0; cam.elevation(testElevation); elevation = cam.getElevation(); if (!compareDouble(elevation, testElevation)) @@ -128,11 +128,10 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) f3d::angle_deg_t azimuth = cam.getAzimuth(); if (!compareDouble(azimuth, 0.)) { - std::cerr << "get azimuth is not behaving as expected: " << azimuth << " != " << testAzimuth - << "\n"; + std::cerr << "get azimuth is not behaving as expected: " << azimuth << " != " << 0.0 << "\n"; return EXIT_FAILURE; } - testAzimuth = 90.0; + f3d::angle_deg_t testAzimuth = 90.0; cam.azimuth(testAzimuth); azimuth = cam.getAzimuth(); if (!compareDouble(azimuth, testAzimuth)) From 46a814052a23e653f721d78cc9cac2baf19f2cc0 Mon Sep 17 00:00:00 2001 From: AbbasReads Date: Mon, 22 Sep 2025 11:35:48 +0530 Subject: [PATCH 13/27] Add camera getter methods to Python bindings --- python/F3DPythonBindings.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/F3DPythonBindings.cxx b/python/F3DPythonBindings.cxx index fc69c54e9d..ab1d6a558f 100644 --- a/python/F3DPythonBindings.cxx +++ b/python/F3DPythonBindings.cxx @@ -465,6 +465,9 @@ PYBIND11_MODULE(pyf3d, module) .def("yaw", &f3d::camera::yaw) .def("elevation", &f3d::camera::elevation) .def("pitch", &f3d::camera::pitch) + .def("get_yaw", &f3d::camera::getYaw) + .def("get_azimuth", &f3d::camera::getAzimuth) + .def("get_elevation", &f3d::camera::getElevation) .def("set_current_as_default", &f3d::camera::setCurrentAsDefault) .def("reset_to_default", &f3d::camera::resetToDefault) .def("reset_to_bounds", &f3d::camera::resetToBounds, py::arg("zoom_factor") = 0.9); From 6700db9a449be08bf8949303cf91c5d5cea24709 Mon Sep 17 00:00:00 2001 From: Abbas Mehdi <24je0656@iitism.ac.in> Date: Mon, 22 Sep 2025 13:06:53 +0530 Subject: [PATCH 14/27] Update library/public/camera.h Co-authored-by: Mathieu Westphal --- library/public/camera.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/public/camera.h b/library/public/camera.h index 5ce39eafbc..34207e08cf 100644 --- a/library/public/camera.h +++ b/library/public/camera.h @@ -80,9 +80,10 @@ class F3D_EXPORT camera */ [[nodiscard]] virtual angle_deg_t getYaw() = 0; - /** Calculates the horizontal rotation angle of the forward vector - * around the up vector, measured from the right vector. (-180 to 180 degrees) - */ + /** + * Calculates the horizontal rotation angle of the forward vector + * around the up vector, measured from the right vector. (-180 to 180 degrees) + */ [[nodiscard]] virtual angle_deg_t getAzimuth() = 0; From 0558b695d0374067c779b69e4cee20e7c43b41c5 Mon Sep 17 00:00:00 2001 From: Abbas Mehdi <24je0656@iitism.ac.in> Date: Mon, 22 Sep 2025 13:07:28 +0530 Subject: [PATCH 15/27] Update library/public/camera.h Co-authored-by: Mathieu Westphal --- library/public/camera.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/public/camera.h b/library/public/camera.h index 34207e08cf..cb5ecb1e99 100644 --- a/library/public/camera.h +++ b/library/public/camera.h @@ -87,7 +87,9 @@ class F3D_EXPORT camera [[nodiscard]] virtual angle_deg_t getAzimuth() = 0; - /** Calculates the angle between the forward vector and the up vector (-90 to +90 degrees) */ + /** + * Calculates the angle between the forward vector and the up vector (-90 to +90 degrees) + */ [[nodiscard]] virtual angle_deg_t getElevation() = 0; ///@} From fb348816a6668ff441ab7f6e9800fe2dccdf36c6 Mon Sep 17 00:00:00 2001 From: AbbasReads Date: Tue, 23 Sep 2025 01:11:06 +0530 Subject: [PATCH 16/27] Add combined camera movement tests for yaw, elevation, and azimuth and python bindings tests --- library/testing/TestSDKCamera.cxx | 42 +++++++++++++++++++++++++++++++ python/testing/test_camera.py | 20 ++++++++++++--- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/library/testing/TestSDKCamera.cxx b/library/testing/TestSDKCamera.cxx index 4e2fbc122d..97c2694780 100644 --- a/library/testing/TestSDKCamera.cxx +++ b/library/testing/TestSDKCamera.cxx @@ -141,6 +141,48 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) return EXIT_FAILURE; } + // Combined test for yaw, elevation, and azimuth + { + cam.setPosition({ -1, 0, 0 }); + cam.setFocalPoint({ 0, 0, 0 }); + cam.setViewUp({ 0, 1, 0 }); + + // Initial orientation + if (!compareDouble(cam.getYaw(), 0.0) || !compareDouble(cam.getElevation(), 0.0) || + !compareDouble(cam.getAzimuth(), 0.0)) + { + std::cerr << "Initial orientation not as expected\n"; + return EXIT_FAILURE; + } + + // Apply yaw(90) + cam.yaw(90.0); + if (!compareDouble(cam.getYaw(), 90.0) || !compareDouble(cam.getElevation(), 0.0) || + !compareDouble(cam.getAzimuth(), 90.0)) + { + std::cerr << "After yaw(90): unexpected orientation\n"; + return EXIT_FAILURE; + } + + // Apply elevation(45) + cam.elevation(45.0); + if (!compareDouble(cam.getYaw(), 90.0) || !compareDouble(cam.getElevation(), 45.0) || + !compareDouble(cam.getAzimuth(), 90.0)) + { + std::cerr << "After elevation(45): unexpected orientation\n"; + return EXIT_FAILURE; + } + + // Apply azimuth(90) + cam.azimuth(90.0); + if (!compareDouble(cam.getYaw(), 180.0) || !compareDouble(cam.getElevation(), 0.0) || + !compareDouble(cam.getAzimuth(), 180.0)) + { + std::cerr << "After azimuth(90): unexpected orientation\n"; + return EXIT_FAILURE; + } + } + // Test position f3d::point3_t testPos = { 0., 0., 10. }; f3d::point3_t pos = cam.setPosition(testPos).getPosition(); diff --git a/python/testing/test_camera.py b/python/testing/test_camera.py index 94a98bcda2..d8dad8bb1a 100644 --- a/python/testing/test_camera.py +++ b/python/testing/test_camera.py @@ -1,5 +1,5 @@ import pytest - +import math import f3d @@ -104,15 +104,27 @@ def test_state_compare(): def test_moves(): engine = f3d.Engine.create(True) camera = engine.window.camera + pos = -1, 0, 0 + foc = 0, 0, 0 + up = 0, 1, 0 - camera.dolly(10) + camera.position = pos + camera.focal_point = foc + camera.view_up = up angle = 30 - camera.roll(angle) + camera.azimuth(angle) + az_value = camera.get_azimuth() + assert math.isclose(az_value, angle, abs_tol=1e-3), f"Expected azimuth ~{angle}, got {az_value}" camera.yaw(angle) + yaw_value = camera.get_yaw() + assert math.isclose(yaw_value, 2*angle, abs_tol=1e-3), f"Expected azimuth ~{2*angle}, got {yaw_value}" camera.elevation(angle) + elev_value = camera.get_elevation() + assert math.isclose(elev_value, angle, abs_tol=1e-3), f"Expected azimuth ~{angle}, got {elev_value}" camera.pitch(angle) - + camera.roll(angle) + camera.dolly(10) def test_pan(): engine = f3d.Engine.create(True) From 7c687aa1a9214f1f5dd2964951d469e3885427d6 Mon Sep 17 00:00:00 2001 From: AbbasReads Date: Tue, 23 Sep 2025 02:39:39 +0530 Subject: [PATCH 17/27] Refactor getAzimuth method to call getYaw directly = --- library/src/camera_impl.cxx | 25 +------------------------ library/testing/TestSDKCamera.cxx | 4 ---- 2 files changed, 1 insertion(+), 28 deletions(-) diff --git a/library/src/camera_impl.cxx b/library/src/camera_impl.cxx index e77e48e8c7..0cf559173f 100644 --- a/library/src/camera_impl.cxx +++ b/library/src/camera_impl.cxx @@ -315,30 +315,7 @@ angle_deg_t camera_impl::getYaw() //---------------------------------------------------------------------------- angle_deg_t camera_impl::getAzimuth() { - point3_t pos, foc; - vector3_t dir, projectedAlongUp, projected; - double* up = this->Internals->VTKRenderer->GetEnvironmentUp(); - double* right = this->Internals->VTKRenderer->GetEnvironmentRight(); - this->getPosition(pos); - this->getFocalPoint(foc); - - // Forward vector (focal - position) - vtkMath::Subtract(foc, pos, dir); - vtkMath::Normalize(dir.data()); - vtkMath::Normalize(up); - - // Project forward vector onto up vector - vtkMath::ProjectVector(dir.data(), up, projectedAlongUp.data()); - vtkMath::Normalize(projectedAlongUp.data()); - - //Projection of forward vector along the plane perpendicular to up vector - vtkMath::Subtract(dir,projectedAlongUp,projected); - - double angleRad = vtkMath::AngleBetweenVectors(right, projected.data()); - vector3_t cross; - vtkMath::Cross(right, projected.data(), cross.data()); - double sign = vtkMath::Dot(cross.data(), up) >= 0 ? 1.0 : -1.0; - return sign * vtkMath::DegreesFromRadians(angleRad); + return camera_impl::getYaw(); } //---------------------------------------------------------------------------- diff --git a/library/testing/TestSDKCamera.cxx b/library/testing/TestSDKCamera.cxx index 97c2694780..8f2a9921ad 100644 --- a/library/testing/TestSDKCamera.cxx +++ b/library/testing/TestSDKCamera.cxx @@ -147,7 +147,6 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) cam.setFocalPoint({ 0, 0, 0 }); cam.setViewUp({ 0, 1, 0 }); - // Initial orientation if (!compareDouble(cam.getYaw(), 0.0) || !compareDouble(cam.getElevation(), 0.0) || !compareDouble(cam.getAzimuth(), 0.0)) { @@ -155,7 +154,6 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) return EXIT_FAILURE; } - // Apply yaw(90) cam.yaw(90.0); if (!compareDouble(cam.getYaw(), 90.0) || !compareDouble(cam.getElevation(), 0.0) || !compareDouble(cam.getAzimuth(), 90.0)) @@ -164,7 +162,6 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) return EXIT_FAILURE; } - // Apply elevation(45) cam.elevation(45.0); if (!compareDouble(cam.getYaw(), 90.0) || !compareDouble(cam.getElevation(), 45.0) || !compareDouble(cam.getAzimuth(), 90.0)) @@ -173,7 +170,6 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) return EXIT_FAILURE; } - // Apply azimuth(90) cam.azimuth(90.0); if (!compareDouble(cam.getYaw(), 180.0) || !compareDouble(cam.getElevation(), 0.0) || !compareDouble(cam.getAzimuth(), 180.0)) From 2eae0ee9650276a41050fcd5f76001c3c0900ef6 Mon Sep 17 00:00:00 2001 From: Abbas Mehdi <24je0656@iitism.ac.in> Date: Wed, 24 Sep 2025 01:49:21 +0530 Subject: [PATCH 18/27] Update library/public/camera.h Co-authored-by: Mathieu Westphal --- library/public/camera.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/public/camera.h b/library/public/camera.h index cb5ecb1e99..e0e9188846 100644 --- a/library/public/camera.h +++ b/library/public/camera.h @@ -75,7 +75,8 @@ class F3D_EXPORT camera ///@{ @name Getters /// Yaw, azimuth and elevation getter methods(calculated on call). Angles are in degrees. - /** Calculates angle between the projection of the forward vector (on + /** + * Calculates angle between the projection of the forward vector (on * the plane perpendicular to the up vector) and the right vector (-180 to 180 degrees) */ [[nodiscard]] virtual angle_deg_t getYaw() = 0; From 952d074df8deb1cc831c1ade11d5bd564c4f2602 Mon Sep 17 00:00:00 2001 From: AbbasReads Date: Wed, 24 Sep 2025 08:49:25 +0530 Subject: [PATCH 19/27] Edited getAzimuth documentation --- library/public/camera.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/public/camera.h b/library/public/camera.h index e0e9188846..471e3044e5 100644 --- a/library/public/camera.h +++ b/library/public/camera.h @@ -75,25 +75,25 @@ class F3D_EXPORT camera ///@{ @name Getters /// Yaw, azimuth and elevation getter methods(calculated on call). Angles are in degrees. - /** + /** * Calculates angle between the projection of the forward vector (on * the plane perpendicular to the up vector) and the right vector (-180 to 180 degrees) */ - [[nodiscard]] virtual angle_deg_t getYaw() = 0; + [[nodiscard]] virtual angle_deg_t getYaw() = 0; /** * Calculates the horizontal rotation angle of the forward vector * around the up vector, measured from the right vector. (-180 to 180 degrees) + * Mathematically the same as getYaw() */ -[[nodiscard]] virtual angle_deg_t getAzimuth() = 0; - + [[nodiscard]] virtual angle_deg_t getAzimuth() = 0; - /** - * Calculates the angle between the forward vector and the up vector (-90 to +90 degrees) - */ + /** + * Calculates the angle between the forward vector and the up vector (-90 to +90 degrees) + */ [[nodiscard]] virtual angle_deg_t getElevation() = 0; ///@} - + /** * Store the current camera configuration as default. */ From fde0219dbaa5162767a71fbf4418d85741bb9f3b Mon Sep 17 00:00:00 2001 From: AbbasReads Date: Wed, 24 Sep 2025 08:50:31 +0530 Subject: [PATCH 20/27] Fix formatting in getYaw documentation comment --- library/public/camera.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/public/camera.h b/library/public/camera.h index 471e3044e5..1e73bf2e82 100644 --- a/library/public/camera.h +++ b/library/public/camera.h @@ -77,7 +77,7 @@ class F3D_EXPORT camera /** * Calculates angle between the projection of the forward vector (on - * the plane perpendicular to the up vector) and the right vector (-180 to 180 degrees) + * the plane perpendicular to the up vector) and the right vector (-180 to 180 degrees) */ [[nodiscard]] virtual angle_deg_t getYaw() = 0; From 4ab9bad80cf4c71a4a22fe1ae2a252f2aacea8e9 Mon Sep 17 00:00:00 2001 From: AbbasReads Date: Wed, 24 Sep 2025 13:55:26 +0530 Subject: [PATCH 21/27] Fix formatting in camera_impl.cxx and test_camera.py --- library/src/camera_impl.cxx | 2 +- python/testing/test_camera.py | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/library/src/camera_impl.cxx b/library/src/camera_impl.cxx index 0cf559173f..0d69a0e094 100644 --- a/library/src/camera_impl.cxx +++ b/library/src/camera_impl.cxx @@ -303,7 +303,7 @@ angle_deg_t camera_impl::getYaw() vtkMath::Normalize(projectedAlongUp.data()); // Projection of forward vector along the plane perpendicular to up vector - vtkMath::Subtract(dir,projectedAlongUp,projected); + vtkMath::Subtract(dir, projectedAlongUp, projected); vector3_t cross; vtkMath::Cross(right, projected.data(), cross.data()); diff --git a/python/testing/test_camera.py b/python/testing/test_camera.py index d8dad8bb1a..147c2275f0 100644 --- a/python/testing/test_camera.py +++ b/python/testing/test_camera.py @@ -112,19 +112,26 @@ def test_moves(): camera.focal_point = foc camera.view_up = up angle = 30 - + camera.azimuth(angle) az_value = camera.get_azimuth() - assert math.isclose(az_value, angle, abs_tol=1e-3), f"Expected azimuth ~{angle}, got {az_value}" + assert math.isclose( + az_value, angle, abs_tol=1e-3 + ), f"Expected azimuth ~{angle}, got {az_value}" camera.yaw(angle) yaw_value = camera.get_yaw() - assert math.isclose(yaw_value, 2*angle, abs_tol=1e-3), f"Expected azimuth ~{2*angle}, got {yaw_value}" + assert math.isclose( + yaw_value, 2 * angle, abs_tol=1e-3 + ), f"Expected azimuth ~{2*angle}, got {yaw_value}" camera.elevation(angle) elev_value = camera.get_elevation() - assert math.isclose(elev_value, angle, abs_tol=1e-3), f"Expected azimuth ~{angle}, got {elev_value}" + assert math.isclose( + elev_value, angle, abs_tol=1e-3 + ), f"Expected azimuth ~{angle}, got {elev_value}" camera.pitch(angle) camera.roll(angle) - camera.dolly(10) + camera.dolly(10) + def test_pan(): engine = f3d.Engine.create(True) From e6303f4380cadd698f3978187d6efe9551599461 Mon Sep 17 00:00:00 2001 From: AbbasReads Date: Thu, 25 Sep 2025 12:51:17 +0530 Subject: [PATCH 22/27] Printing test values for debugging --- library/testing/TestSDKCamera.cxx | 76 +++++++++++++++++-------------- 1 file changed, 43 insertions(+), 33 deletions(-) diff --git a/library/testing/TestSDKCamera.cxx b/library/testing/TestSDKCamera.cxx index 8f2a9921ad..b83ba14031 100644 --- a/library/testing/TestSDKCamera.cxx +++ b/library/testing/TestSDKCamera.cxx @@ -142,41 +142,51 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) } // Combined test for yaw, elevation, and azimuth + cam.setPosition({ -1, 0, 0 }); + cam.setFocalPoint({ 0, 0, 0 }); + cam.setViewUp({ 0, 1, 0 }); + + if (!compareDouble(cam.getYaw(), 0.0) || !compareDouble(cam.getElevation(), 0.0) || + !compareDouble(cam.getAzimuth(), 0.0)) { - cam.setPosition({ -1, 0, 0 }); - cam.setFocalPoint({ 0, 0, 0 }); - cam.setViewUp({ 0, 1, 0 }); + std::cerr << "Initial orientation not as expected\n" + << "Yaw: expected 0, got " << cam.getYaw() << "\n" + << "Elevation: expected 0, got " << cam.getElevation() << "\n" + << "Azimuth: expected 0, got " << cam.getAzimuth() << "\n"; + return EXIT_FAILURE; + } + + cam.yaw(90.0); + if (!compareDouble(cam.getYaw(), 90.0) || !compareDouble(cam.getElevation(), 0.0) || + !compareDouble(cam.getAzimuth(), 90.0)) + { + std::cerr << "After yaw(90): unexpected orientation\n" + << "Yaw: expected 90, got " << cam.getYaw() << "\n" + << "Elevation: expected 0, got " << cam.getElevation() << "\n" + << "Azimuth: expected 90, got " << cam.getAzimuth() << "\n"; + return EXIT_FAILURE; + } - if (!compareDouble(cam.getYaw(), 0.0) || !compareDouble(cam.getElevation(), 0.0) || - !compareDouble(cam.getAzimuth(), 0.0)) - { - std::cerr << "Initial orientation not as expected\n"; - return EXIT_FAILURE; - } - - cam.yaw(90.0); - if (!compareDouble(cam.getYaw(), 90.0) || !compareDouble(cam.getElevation(), 0.0) || - !compareDouble(cam.getAzimuth(), 90.0)) - { - std::cerr << "After yaw(90): unexpected orientation\n"; - return EXIT_FAILURE; - } - - cam.elevation(45.0); - if (!compareDouble(cam.getYaw(), 90.0) || !compareDouble(cam.getElevation(), 45.0) || - !compareDouble(cam.getAzimuth(), 90.0)) - { - std::cerr << "After elevation(45): unexpected orientation\n"; - return EXIT_FAILURE; - } - - cam.azimuth(90.0); - if (!compareDouble(cam.getYaw(), 180.0) || !compareDouble(cam.getElevation(), 0.0) || - !compareDouble(cam.getAzimuth(), 180.0)) - { - std::cerr << "After azimuth(90): unexpected orientation\n"; - return EXIT_FAILURE; - } + cam.elevation(45.0); + if (!compareDouble(cam.getYaw(), 90.0) || !compareDouble(cam.getElevation(), 45.0) || + !compareDouble(cam.getAzimuth(), 90.0)) + { + std::cerr << "After elevation(45): unexpected orientation\n" + << "Yaw: expected 90, got " << cam.getYaw() << "\n" + << "Elevation: expected 45, got " << cam.getElevation() << "\n" + << "Azimuth: expected 90, got " << cam.getAzimuth() << "\n"; + return EXIT_FAILURE; + } + + cam.azimuth(90.0); + if (!compareDouble(cam.getYaw(), 180.0) || !compareDouble(cam.getElevation(), 0.0) || + !compareDouble(cam.getAzimuth(), 180.0)) + { + std::cerr << "After azimuth(90): unexpected orientation\n" + << "Yaw: expected 180, got " << cam.getYaw() << "\n" + << "Elevation: expected 0, got " << cam.getElevation() << "\n" + << "Azimuth: expected 180, got " << cam.getAzimuth() << "\n"; + return EXIT_FAILURE; } // Test position From edec2e664b562122f0084d8c16553d88d6bebf72 Mon Sep 17 00:00:00 2001 From: AbbasReads Date: Mon, 29 Sep 2025 23:01:02 +0530 Subject: [PATCH 23/27] Refactor compareDouble for better tolerance handling and update test assertions to use pytest.approx for floating-point comparisons --- library/testing/TestSDKCamera.cxx | 4 ++-- python/testing/test_camera.py | 13 +++---------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/library/testing/TestSDKCamera.cxx b/library/testing/TestSDKCamera.cxx index b83ba14031..c70d0cf359 100644 --- a/library/testing/TestSDKCamera.cxx +++ b/library/testing/TestSDKCamera.cxx @@ -11,9 +11,9 @@ // TODO these methods should be put in types.h at some point. // https://github.com/f3d-app/f3d/issues/361 -bool compareDouble(double a, double b) +bool compareDouble(double a, double b, double tol = 128 * std::numeric_limits::epsilon()) { - return std::fabs(a - b) < 128 * std::numeric_limits::epsilon(); + return std::fabs(a - b) < tol; } bool compareVec(const f3d::vector3_t& vec1, const f3d::vector3_t& vec2) diff --git a/python/testing/test_camera.py b/python/testing/test_camera.py index 147c2275f0..89597b5618 100644 --- a/python/testing/test_camera.py +++ b/python/testing/test_camera.py @@ -1,5 +1,4 @@ import pytest -import math import f3d @@ -115,19 +114,13 @@ def test_moves(): camera.azimuth(angle) az_value = camera.get_azimuth() - assert math.isclose( - az_value, angle, abs_tol=1e-3 - ), f"Expected azimuth ~{angle}, got {az_value}" + assert az_value == pytest.approx(angle) camera.yaw(angle) yaw_value = camera.get_yaw() - assert math.isclose( - yaw_value, 2 * angle, abs_tol=1e-3 - ), f"Expected azimuth ~{2*angle}, got {yaw_value}" + assert yaw_value == pytest.approx(2 * angle) camera.elevation(angle) elev_value = camera.get_elevation() - assert math.isclose( - elev_value, angle, abs_tol=1e-3 - ), f"Expected azimuth ~{angle}, got {elev_value}" + assert elev_value == pytest.approx(angle) camera.pitch(angle) camera.roll(angle) camera.dolly(10) From e740b130b06c06a860ad9972bbca6acef929d912 Mon Sep 17 00:00:00 2001 From: AbbasReads Date: Tue, 30 Sep 2025 23:27:15 +0530 Subject: [PATCH 24/27] Update compareDouble tolerance in TestSDKCamera in yaw, elevation, and azimuth checks --- library/testing/TestSDKCamera.cxx | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/library/testing/TestSDKCamera.cxx b/library/testing/TestSDKCamera.cxx index c70d0cf359..5acc7c79ee 100644 --- a/library/testing/TestSDKCamera.cxx +++ b/library/testing/TestSDKCamera.cxx @@ -86,7 +86,7 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) cam.setFocalPoint({ 0, 0, 0 }); cam.setViewUp({ 0, 1, 0 }); f3d::angle_deg_t yaw = cam.getYaw(); - if (!compareDouble(yaw, 0.)) + if (!compareDouble(yaw, 0., 1e-6)) { std::cerr << "get yaw is not behaving as expected: " << yaw << " " << "\n"; return EXIT_FAILURE; @@ -94,7 +94,7 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) f3d::angle_deg_t testYaw = 90.0; cam.yaw(testYaw); yaw = cam.getYaw(); - if (!compareDouble(yaw, testYaw)) + if (!compareDouble(yaw, testYaw, 1e-6)) { std::cerr << "Yaw after +90° yaw() is incorrect: " << yaw << "\n"; return EXIT_FAILURE; @@ -105,7 +105,7 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) cam.setFocalPoint({ 0, 0, 0 }); cam.setViewUp({ 0, 1, 0 }); f3d::angle_deg_t elevation = cam.getElevation(); - if (!compareDouble(elevation, 0.)) + if (!compareDouble(elevation, 0., 1e-6)) { std::cerr << "get elevation is not behaving as expected: " << elevation << " != " << 0.0 << "\n"; @@ -114,7 +114,7 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) f3d::angle_deg_t testElevation = -45.0; cam.elevation(testElevation); elevation = cam.getElevation(); - if (!compareDouble(elevation, testElevation)) + if (!compareDouble(elevation, testElevation, 1e-6)) { std::cerr << "get elevation after elevation +45 is not behaving as expected: " << elevation << " != " << testElevation << "\n"; @@ -126,7 +126,7 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) cam.setFocalPoint({ 0, 0, 0 }); cam.setViewUp({ 0, 1, 0 }); f3d::angle_deg_t azimuth = cam.getAzimuth(); - if (!compareDouble(azimuth, 0.)) + if (!compareDouble(azimuth, 0., 1e-6)) { std::cerr << "get azimuth is not behaving as expected: " << azimuth << " != " << 0.0 << "\n"; return EXIT_FAILURE; @@ -134,7 +134,7 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) f3d::angle_deg_t testAzimuth = 90.0; cam.azimuth(testAzimuth); azimuth = cam.getAzimuth(); - if (!compareDouble(azimuth, testAzimuth)) + if (!compareDouble(azimuth, testAzimuth, 1e-6)) { std::cerr << "get azimuth after azimuth +90 is not behaving as expected: " << azimuth << " != " << testAzimuth << "\n"; @@ -146,8 +146,8 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) cam.setFocalPoint({ 0, 0, 0 }); cam.setViewUp({ 0, 1, 0 }); - if (!compareDouble(cam.getYaw(), 0.0) || !compareDouble(cam.getElevation(), 0.0) || - !compareDouble(cam.getAzimuth(), 0.0)) + if (!compareDouble(cam.getYaw(), 0.0, 1e-6) || !compareDouble(cam.getElevation(), 0.0, 1e-6) || + !compareDouble(cam.getAzimuth(), 0.0, 1e-6)) { std::cerr << "Initial orientation not as expected\n" << "Yaw: expected 0, got " << cam.getYaw() << "\n" @@ -157,8 +157,8 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) } cam.yaw(90.0); - if (!compareDouble(cam.getYaw(), 90.0) || !compareDouble(cam.getElevation(), 0.0) || - !compareDouble(cam.getAzimuth(), 90.0)) + if (!compareDouble(cam.getYaw(), 90.0, 1e-6) || !compareDouble(cam.getElevation(), 0.0, 1e-6) || + !compareDouble(cam.getAzimuth(), 90.0, 1e-6)) { std::cerr << "After yaw(90): unexpected orientation\n" << "Yaw: expected 90, got " << cam.getYaw() << "\n" @@ -168,8 +168,8 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) } cam.elevation(45.0); - if (!compareDouble(cam.getYaw(), 90.0) || !compareDouble(cam.getElevation(), 45.0) || - !compareDouble(cam.getAzimuth(), 90.0)) + if (!compareDouble(cam.getYaw(), 90.0, 1e-6) || !compareDouble(cam.getElevation(), 45.0, 1e-6) || + !compareDouble(cam.getAzimuth(), 90.0, 1e-6)) { std::cerr << "After elevation(45): unexpected orientation\n" << "Yaw: expected 90, got " << cam.getYaw() << "\n" @@ -179,8 +179,8 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) } cam.azimuth(90.0); - if (!compareDouble(cam.getYaw(), 180.0) || !compareDouble(cam.getElevation(), 0.0) || - !compareDouble(cam.getAzimuth(), 180.0)) + if (!compareDouble(cam.getYaw(), 180.0, 1e-6) || !compareDouble(cam.getElevation(), 0.0, 1e-6) || + !compareDouble(cam.getAzimuth(), 180.0, 1e-6)) { std::cerr << "After azimuth(90): unexpected orientation\n" << "Yaw: expected 180, got " << cam.getYaw() << "\n" From 6974af78be024b12e8d5b79569ae4b4e619ae4e4 Mon Sep 17 00:00:00 2001 From: AbbasReads Date: Wed, 1 Oct 2025 00:24:36 +0530 Subject: [PATCH 25/27] Update elevation test in TestSDKCamera to check for correct values --- library/testing/TestSDKCamera.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/testing/TestSDKCamera.cxx b/library/testing/TestSDKCamera.cxx index 5acc7c79ee..bb0350a35e 100644 --- a/library/testing/TestSDKCamera.cxx +++ b/library/testing/TestSDKCamera.cxx @@ -167,13 +167,13 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) return EXIT_FAILURE; } - cam.elevation(45.0); - if (!compareDouble(cam.getYaw(), 90.0, 1e-6) || !compareDouble(cam.getElevation(), 45.0, 1e-6) || + cam.elevation(90.0); + if (!compareDouble(cam.getYaw(), 90.0, 1e-6) || !compareDouble(cam.getElevation(), 90.0, 1e-6) || !compareDouble(cam.getAzimuth(), 90.0, 1e-6)) { std::cerr << "After elevation(45): unexpected orientation\n" << "Yaw: expected 90, got " << cam.getYaw() << "\n" - << "Elevation: expected 45, got " << cam.getElevation() << "\n" + << "Elevation: expected 90, got " << cam.getElevation() << "\n" << "Azimuth: expected 90, got " << cam.getAzimuth() << "\n"; return EXIT_FAILURE; } From 2024de6f43f00ad867a541986c5c39802c57e620 Mon Sep 17 00:00:00 2001 From: AbbasReads Date: Fri, 3 Oct 2025 12:58:47 +0530 Subject: [PATCH 26/27] testing --- library/testing/TestSDKCamera.cxx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/testing/TestSDKCamera.cxx b/library/testing/TestSDKCamera.cxx index bb0350a35e..108332493c 100644 --- a/library/testing/TestSDKCamera.cxx +++ b/library/testing/TestSDKCamera.cxx @@ -171,7 +171,7 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) if (!compareDouble(cam.getYaw(), 90.0, 1e-6) || !compareDouble(cam.getElevation(), 90.0, 1e-6) || !compareDouble(cam.getAzimuth(), 90.0, 1e-6)) { - std::cerr << "After elevation(45): unexpected orientation\n" + std::cerr << "After elevation(90): unexpected orientation\n" << "Yaw: expected 90, got " << cam.getYaw() << "\n" << "Elevation: expected 90, got " << cam.getElevation() << "\n" << "Azimuth: expected 90, got " << cam.getAzimuth() << "\n"; @@ -179,13 +179,13 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) } cam.azimuth(90.0); - if (!compareDouble(cam.getYaw(), 180.0, 1e-6) || !compareDouble(cam.getElevation(), 0.0, 1e-6) || - !compareDouble(cam.getAzimuth(), 180.0, 1e-6)) + if (!compareDouble(cam.getYaw(), 135.0, 1e-6) || !compareDouble(cam.getElevation(), 0.0, 1e-6) || + !compareDouble(cam.getAzimuth(), 135.0, 1e-6)) { std::cerr << "After azimuth(90): unexpected orientation\n" - << "Yaw: expected 180, got " << cam.getYaw() << "\n" + << "Yaw: expected 135, got " << cam.getYaw() << "\n" << "Elevation: expected 0, got " << cam.getElevation() << "\n" - << "Azimuth: expected 180, got " << cam.getAzimuth() << "\n"; + << "Azimuth: expected 135, got " << cam.getAzimuth() << "\n"; return EXIT_FAILURE; } From 95fa7f9fa33bfc66012e32a37e85dec06586ee6c Mon Sep 17 00:00:00 2001 From: AbbasReads Date: Fri, 3 Oct 2025 13:37:29 +0530 Subject: [PATCH 27/27] debugging --- library/testing/TestSDKCamera.cxx | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/library/testing/TestSDKCamera.cxx b/library/testing/TestSDKCamera.cxx index 108332493c..265a97abc9 100644 --- a/library/testing/TestSDKCamera.cxx +++ b/library/testing/TestSDKCamera.cxx @@ -178,17 +178,6 @@ int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) return EXIT_FAILURE; } - cam.azimuth(90.0); - if (!compareDouble(cam.getYaw(), 135.0, 1e-6) || !compareDouble(cam.getElevation(), 0.0, 1e-6) || - !compareDouble(cam.getAzimuth(), 135.0, 1e-6)) - { - std::cerr << "After azimuth(90): unexpected orientation\n" - << "Yaw: expected 135, got " << cam.getYaw() << "\n" - << "Elevation: expected 0, got " << cam.getElevation() << "\n" - << "Azimuth: expected 135, got " << cam.getAzimuth() << "\n"; - return EXIT_FAILURE; - } - // Test position f3d::point3_t testPos = { 0., 0., 10. }; f3d::point3_t pos = cam.setPosition(testPos).getPosition();