Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix 0º and 180º singularity cases in _rotation_matrix_from_vectors #4206

Merged

Conversation

SergioRAgostinho
Copy link
Contributor

@SergioRAgostinho SergioRAgostinho commented Mar 27, 2024

What changes are proposed in this pull request?

Fixes #4203.

The method _rotation_matrix_from_vectors is ill-defined and returnes NaN when the angle between vec1 and vec2 was 0º or 180º.

From a geometrical standpoint the issue is being cause by the fact that there is no longer a single "shortest" rotation that transforms vec1 to vec2 There are now infinite perpendicular axes to vec1 and vec2 that can be used to rotate vec1 onto vec2.

This PR addresses that.

How is this patch tested? If it is not, please explain why.

With unit tests validating exactly the cases described above, as well as the original cases.

Release Notes

Is this a user-facing change that should be mentioned in the release notes?

  • No. You can skip the rest of this section.
  • Yes. Give a description of this change to be included in the release
    notes for FiftyOne users.

(Details in 1-2 sentences. You can just refer to another PR with a description
if this PR is part of a larger change.)

What areas of FiftyOne does this PR affect?

  • App: FiftyOne application changes
  • Build: Build and test infrastructure changes
  • Core: Core fiftyone Python library changes
  • Documentation: FiftyOne documentation changes
  • Other

Summary by CodeRabbit

  • New Features
    • Enhanced 3D vector handling with improved rotation logic for vector alignment using sp.transform.Rotation.align_vectors.
  • Tests
    • Added a comprehensive test suite for validating the functionality of rotation matrix calculations in 3D vector transformations.

Copy link
Contributor

coderabbitai bot commented Mar 27, 2024

Walkthrough

The update introduces a method to handle the calculation of skew-symmetric matrices for 3D vectors and refines the rotation matrix computation to address a specific edge case. This edge case arises when the angle between two vectors is exactly 180º, which previously led to a NaN issue. By selecting a random perpendicular vector for alignment, the solution elegantly circumvents the infinite possibilities problem, ensuring robust orthographic projection capabilities.

Changes

File Path Change Summary
fiftyone/utils/utils3d.py Added _skew_symmetric_matrix function; Updated _rotation_matrix_from_vectors for 180º rotation case
tests/unittests/utils3d_tests.py Added test suite for rotation matrix calculation method validation

Assessment against linked issues

Objective Addressed Explanation
Fix NaN issue in _rotation_matrix_from_vectors when angle between vec1 and vec2 is 180º (#4203)
Allow specifying a full rotation matrix for camera orientation in orthographic projection (#4203) The changes focus on fixing the NaN issue but do not address the flexibility in specifying a full rotation matrix.

Poem

In the realm of vectors and space,
A rabbit hopped at a steady pace.
Faced with a twist, a turn so wide,
It found a path where none did bide.
🌟 With math as its guide, through NaN it leaped,
Ensuring projections were perfectly steeped.
In code, it danced, with a fix so bright,
A bug squashed, in the moon's soft light.

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share

Tips

Chat

There are 3 ways to chat with CodeRabbit:

Note: Auto-reply has been disabled for this repository by the repository owner. The CodeRabbit bot will not respond to your replies unless it is explicitly tagged.

  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit tests for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit tests.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

CodeRabbit Discord Community

Join our Discord Community to get help, request features, and share feedback.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 0

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 7bea0c2 and 9908116.
Files selected for processing (2)
  • fiftyone/utils/utils3d.py (2 hunks)
  • tests/unittests/utils/utils3d_tests.py (1 hunks)
Additional comments: 3
tests/unittests/utils/utils3d_tests.py (1)
  • 13-34: The test function test_rotation_matrix_from_vectors is well-structured and covers a comprehensive range of scenarios, including the critical singular cases of 0º and 180º rotations. It's good practice to add a brief comment explaining the choice of atol=1e-15 in the np.testing.assert_allclose calls, as this helps maintainers understand the tolerance level for floating-point comparisons.
fiftyone/utils/utils3d.py (2)
  • 778-782: The implementation of _skew_symmetric_matrix is correct and follows the mathematical definition of a skew-symmetric matrix for a 3D vector. Well done.
  • 785-809: The modifications to _rotation_matrix_from_vectors to handle the 180º rotation singular case by selecting a random perpendicular vector are logically sound. However, consider enhancing the comment on line 800 to explain why this approach is necessary and how it resolves the issue with singular cases. Additionally, ensure that the function always returns a valid rotation matrix, especially in edge cases where vec1 and vec2 might be nearly parallel or antiparallel.

@SergioRAgostinho
Copy link
Contributor Author

Regarding this.

Objective Addressed Explanation
Allow specifying a full rotation matrix for camera orientation in orthographic projection (#4203) The changes focus on fixing the NaN issue but do not address the flexibility in specifying a full rotation matrix.

It's better to handle it an a separate PR because it requires touching a public facing API and it needs discussion on what to do with current way of specifying the camera orientation.

@swheaton
Copy link
Contributor

Regarding this.

Objective
Addressed
Explanation

Allow specifying a full rotation matrix for camera orientation in orthographic projection (#4203)

The changes focus on fixing the NaN issue but do not address the flexibility in specifying a full rotation matrix.

It's better to handle it an a separate PR because it requires touching a public facing API and it needs discussion on what to do with current way of specifying the camera orientation.

Def agree! Code Rabbit keeping us honest


if abs(c + 1) > np.finfo(c.dtype).eps:
K = _skew_symmetric_matrix(v)
return np.eye(3) + K + K.dot(K) / (1 + c)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, I had seen this simplification also

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If scipy is a valid dependency for this project (didn't even consider) than there's no point in having _rotation_matrix_from_vectors at all. We should just use Rotation.align_vectors. Less code to maintain and this PR can be reduced to a 1-2 LoC diff.

Edit: A bit more. scipy rightfully complains, so this needs to be suppressed.

UserWarning: Optimal rotation is not uniquely or poorly defined for the given sets of vectors.

Kabsch / Wabba are usually used to find the optimal rotation between point clouds. For a fully defined rotation one needs at least 3 non-collinear points.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scipy was added as a dependency very very recently, and is not in any release yet. But it's already been implicitly required for a while, as we require scikit-learn and likely others that require scipy.

I would definitely be a big fan of using a module of its stature rather than rolling our own.
Please make this change, and if there are any other functions/operations that would more appropriately be replaced by scipy, let us know or add to this PR!

"""Validates the returned rotation matrix transforms rotates vec1 to vec2."""
R = fou3d._rotation_matrix_from_vectors(vec1, vec2)

vec1_rot = R @ vec1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whoa I never knew this operator existed ... (named as def __matmul__)

Copy link

codecov bot commented Mar 27, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 28.87%. Comparing base (6f28ab0) to head (0febe76).
Report is 7 commits behind head on develop.

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #4206      +/-   ##
===========================================
+ Coverage    28.85%   28.87%   +0.01%     
===========================================
  Files          768      769       +1     
  Lines        97048    97151     +103     
  Branches      1120     1128       +8     
===========================================
+ Hits         28004    28050      +46     
- Misses       69044    69101      +57     
Flag Coverage Δ
app 16.03% <ø> (+0.02%) ⬆️
python 99.23% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

fiftyone/utils/utils3d.py Outdated Show resolved Hide resolved
tests/unittests/utils/utils3d_tests.py Outdated Show resolved Hide resolved
Copy link
Contributor

@swheaton swheaton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hold for resolution of comments

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 0

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 9908116 and 2df5582.
Files selected for processing (2)
  • fiftyone/utils/utils3d.py (1 hunks)
  • tests/unittests/utils3d_tests.py (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • fiftyone/utils/utils3d.py
Additional comments: 1
tests/unittests/utils3d_tests.py (1)
  • 284-307: The test method test_rotation_matrix_from_vectors is well-structured and covers essential cases, including the critical singular cases of 0º and 180º rotation. It's important to ensure direct testing of the _rotation_matrix_from_vectors method to accurately assess its behavior in these edge cases. Consider adding a comment to clarify that this method is being directly tested, which is crucial for understanding the context of these tests.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 1

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 2df5582 and 787c63d.
Files selected for processing (2)
  • fiftyone/utils/utils3d.py (2 hunks)
  • tests/unittests/utils3d_tests.py (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • tests/unittests/utils3d_tests.py

fiftyone/utils/utils3d.py Outdated Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 0

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 787c63d and 0febe76.
Files selected for processing (1)
  • fiftyone/utils/utils3d.py (2 hunks)
Files skipped from review as they are similar to previous changes (1)
  • fiftyone/utils/utils3d.py

Copy link
Contributor

@swheaton swheaton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @SergioRAgostinho I forgot to circle back on this. LGTM, thanks for added tests 👍🏼

Congrats on your first contribution, welcome to the FiftyOne family!! Looking forward to more contribs from you 😃

@swheaton swheaton merged commit bdae149 into voxel51:develop Apr 3, 2024
9 of 10 checks passed
@SergioRAgostinho SergioRAgostinho deleted the bug/rotation-from-vectors branch April 3, 2024 18:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BUG] Issue with Orthographic Projection when supplied projection_normal=(0, 0, -1)
3 participants