marcomusy / vedo

A python module for scientific analysis of 3D data based on VTK and Numpy
https://vedo.embl.es
MIT License
2.03k stars 265 forks source link

Mesh intersect_with_line irregular processing time #1017

Open Cryaaa opened 8 months ago

Cryaaa commented 8 months ago

Hello, I'm using vedo for a project of mine, where I have an optimization problem that requires finding a point on the intersection of a vedo mesh with a line. This optimization is called thousands of times and the bottleneck of the processing time seems to be finding the intersection of the line with the mesh.

The strange thing is that most intersection function calls take 0 ns but some take much longer (15 ms) and this does not depend on the line that is being used to calculate the intersect. I have called the intersection function with the same line over and over again and some function calls just take longer than others. Is there a way to avoid this or is it due to how the intersection is being calculated?

Here is some example code to reproduce this phenomenon:

import vedo
import pandas as pd
import time

sphere = vedo.shapes.Sphere()
line = [[-2,0,0],[2,0,0]]

intersect_times = []

for i in range(100000):
    start = time.process_time_ns()
    surface_intersect = sphere.intersect_with_line(*line)
    stop = time.process_time_ns()
    intersect_times.append(stop-start)

df = pd.Series(intersect_times)
df.value_counts()

which will output:

0           99610
15625000      376
31250000       13
46875000        1
Name: count, dtype: int64

This also seems to be influenced by the complexity of the mesh as the same code with sphere = vedo.shapes.Sphere(res = 5) yields these counts:

0           99949
15625000       50
31250000        1
Name: count, dtype: int64
marcomusy commented 8 months ago

Hi, thanks for reporting this... in my system I never see zero time...

import time
import numpy as np
import vedo

sphere = vedo.shapes.Sphere().alpha(0.8)

intersect_times = []
pts = []
for i in range(10000):
    line = [[-2, 0.2, 0.3],[3, np.random.randn()*0.5, 0.1]]
    start = time.process_time_ns()
    surface_intersect = sphere.intersect_with_line(*line)
    stop = time.process_time_ns()
    intersect_times.append(stop-start)
    pts.extend(surface_intersect)
intersect_times = np.array(intersect_times) / 1e6
vpts = vedo.Points(pts).color("blue6")

h = vedo.pyplot.histogram(intersect_times, bins=100, xlim=(0,0.25))
vedo.show(sphere, vpts, h.clone2d())

Screenshot from 2024-01-15 11-49-22

Internally intersect_with_line a point locator is built (OBBTree), I am not sure how this is parsed. The only other possibility that comes to my mind is to use the trimesh version of it, maybe it's faster (?) https://github.com/marcomusy/vedo/blob/master/examples/other/trimesh/ray.py

Cryaaa commented 8 months ago

Strange, Even with your code it seems to be mostly 0 for me with the few exceptions just as in my original post. Thanks for the fast reply and the suggestion to use the trimesh intersection. The trimesh function seems to be optimized for parallel processing of many lines, which is not exactly what I was looking for but I believe I can refactor my code to make use of that speed up.

Have a nice day!