isl-org / isl-org/Open3D

geometry::OrientedBoundingBox::Transform() always throws, even for a rigid transform

Open
#7,558 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
14k
Forks
2.6k
Avg merge
5d 18h
Merged PRs (30d)
6

Description

### Checklist

- [x] I have searched for [similar issues](https://github.com/isl-org/Open3D/issues). The closest one is #4875, which reports the same limitation as a question and is still open.
- [x] For Python issues, I have tested with the [latest development wheel](https://www.open3d.org/docs/latest/getting_started.html#development-version-pip). That page currently lists no wheel links, so I reproduced with 0.19.0 from PyPI and confirmed the code path is unchanged on `main` at 1a9eb990f9, see the permalink below.
- [x] I have checked the [release documentation](https://www.open3d.org/docs/release/) and the [latest documentation](https://www.open3d.org/docs/latest/) (for `main` branch).

### Describe the issue

`geometry::OrientedBoundingBox::Transform()` always raises, even for a plain rigid transform:

https://github.com/isl-org/Open3D/blob/1a9eb990f9a20936c30c428568c602bdef760744/cpp/open3d/geometry/BoundingVolume.cpp#L154-L160

An oriented bounding box is stored as a center, a rotation matrix and an extent, so it is closed under any similarity transform (rotation, uniform scale, translation): only the center and the rotation move, and the extent scales. That is exactly the case that matters in practice, where a box is carried between coordinate frames next to the point cloud it bounds:

```cpp
cloud.Transform(target_T_source);
box.Transform(target_T_source); // throws
```

Three things make the current behavior surprising:

1. Every other `Geometry3D` accepts `Transform()`, so a box cannot be moved through generic code that transforms a geometry.
2. The tensor API already implements it, as `Rotate()` followed by `Translate()`, so the legacy and tensor APIs disagree on the same operation:
https://github.com/isl-org/Open3D/blob/1a9eb990f9a20936c30c428568c602bdef760744/cpp/open3d/t/geometry/BoundingVolume.cpp#L464-L478
3. The suggested workaround ("Call Translate, Scale, and Rotate") is easy to get wrong, because `Rotate(R)` rotates about the box center by default while `Transform()` rotates about the origin. #4875 is exactly that mistake, and the usual fix people land on is to rebuild the box by hand:
```cpp
OrientedBoundingBox transformed(transform * box.center_,
transform.rotation() * box.R_, box.extent_);
```

`geometry::OrientedBoundingEllipsoid::Transform()` on `main` has the same body and the same limitation.

A general affine transform genuinely cannot be supported, since shear or non-uniform scale turns the box into a parallelepiped and the ellipsoid into a general quadric. Those cases should keep raising. The similarity case should not.

### Steps to reproduce the bug

```python
import numpy as np
import open3d as o3d

box = o3d.geometry.OrientedBoundingBox([1, 2, 3], np.eye(3), [2, 4, 6])

transformation = np.eye(4)
transformation[:3, 3] = [1, 0, 0] # translate by 1 along x

box.transform(transformation)
```

### Error message

```
Traceback (most recent call last):
File "", line 5, in
RuntimeError: [Open3D Error] (virtual open3d::geometry::OrientedBoundingBox& open3d::geometry::OrientedBoundingBox::Transform(const Matrix4d&)) /root/Open3D/cpp/open3d/geometry/BoundingVolume.cpp:58: A general transform of an OrientedBoundingBox is not implemented. Call Translate, Scale, and Rotate.
```

### Expected behavior

A similarity transform is applied to the box: `center_` is mapped by the transform, `R_` is premultiplied by its rotation part and `extent_` is multiplied by its uniform scale. The corners of the result are then the transformed corners of the original box, which is what transforming a point cloud of those corners with the same matrix gives.

A transform with shear, non-uniform scale, mirroring or a projective part keeps raising, with a message that names which part is not supported.

### Open3D, Python and System information

```markdown
- Operating system: Ubuntu 24.04 64-bit
- Python version: 3.12.3
- Open3D version: 0.19.0, and the source of `main` at 1a9eb990f9a20936c30c428568c602bdef760744
- System architecture: x86_64
- Is this a remote workstation?: no
- How did you install Open3D?: pip, and separately built from source for the C++ side
- Compiler version (if built from source): gcc 13.3
```

### Additional information

I have a fix ready and will open a PR that implements `Transform()` for similarity transforms on both `OrientedBoundingBox` and `OrientedBoundingEllipsoid`, reusing the existing `Rotate()`, `Scale()` and `Translate()` primitives, with C++ and Python unit tests for the supported and the rejected cases.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start at cpp/open3d/geometry/BoundingVolume.cpp, especially the OrientedBoundingBox::Transform() implementation linked in the issue, and compare it with the tensor BoundingVolume.cpp implementation. Check the corresponding OrientedBoundingEllipsoid path and add the mentioned C++ and Python unit tests. Done means similarity transforms work for both classes while shear, non-uniform scale, mirroring, and projective transforms still raise.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, python
Domain
computer-graphics
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.