compas-dev / compas

Core packages of the COMPAS framework.

Home Page:https://compas.dev/compas/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

LinAlgError on oriented_bounding_box_numpy with some inputs

beneltayar opened this issue · comments

There are some valid inputs that cause oriented_bounding_box_numpy to throw an numpy.linalg.LinAlgError

To Reproduce

import numpy as np

from compas.geometry import oriented_bounding_box_numpy

oriented_bounding_box_numpy(np.array([
    [198.71435547, -18.45817566, 61.03982544],
    [198.78266907, -18.38731384, 62.90990448],
    [198.78266907, -18.38731384, 61.03982544],
    [199.78454590, -17.34801292, 62.90990448],
    [199.26994324, -17.88183594, 75.31147766],
    [199.78454590, -17.34801292, 64.32066345],
    [199.78454590, -17.34801292, 62.90989685],
]))

Output

Traceback (most recent call last):
  File "C:\Users\benel\AppData\Roaming\JetBrains\PyCharm2022.3\scratches\scratch.py", line 8, in <module>
    oriented_bounding_box_numpy(np.array([
  File "C:\git\buildots\pycode\venv39\lib\site-packages\compas\geometry\bbox\bbox_numpy.py", line 133, in oriented_bounding_box_numpy
    rst = world_to_local_coordinates_numpy(frame, xyz)
  File "C:\git\buildots\pycode\venv39\lib\site-packages\compas\geometry\transformations\transformations_numpy.py", line 141, in world_to_local_coordinates_numpy
    rst = solve(uvw, xyz)
  File "C:\git\buildots\pycode\venv39\lib\site-packages\scipy\linalg\_basic.py", line 223, in solve
    _solve_check(n, info)
  File "C:\git\buildots\pycode\venv39\lib\site-packages\scipy\linalg\_basic.py", line 29, in _solve_check
    raise LinAlgError('Matrix is singular.')
numpy.linalg.LinAlgError: Matrix is singular.

Expected behavior
Getting an oriented bounding box of this specific set of points

Desktop:

  • OS: Windows11 - 64bit
  • Python version 3.9.10
  • Numpy version 1.23.5
  • Scipy version 1.10.0
  • Python package manager: pip

hi,

that is indeed a bug.
when possible, the code tries to use the convex hull of the points to build the oriented box, but it doesn't check the validity of the simplices of the hull during that process, which it should.

i will have a look at how this can be done more robustly.
in the meantime, you could use the function the algorithm normally falls back to if the convex hull algorithm fails.
it is more robust but doesn't always produce the smallest oriented box for the input.

from compas.geometry import Point, Box
from compas.geometry.bbox.bbox_numpy import oabb_numpy
from compas_view2.app import App

points = [
    [198.71435547, -18.45817566, 61.03982544],
    [198.78266907, -18.38731384, 62.90990448],
    [198.78266907, -18.38731384, 61.03982544],
    [199.78454590, -17.34801292, 62.90990448],
    [199.26994324, -17.88183594, 75.31147766],
    [199.78454590, -17.34801292, 64.32066345],
    [199.78454590, -17.34801292, 62.90989685],
]

box = oabb_numpy(points)
box = Box.from_bounding_box(box)

viewer = App()

for point in points:
    viewer.add(Point(*point))

viewer.add(box)

viewer.run()

Screenshot 2023-03-15 at 18 18 30

@beneltayar i think this is now resolved. would you mind having a look?