-
Notifications
You must be signed in to change notification settings - Fork 9
/
is_inside_mesh.py
65 lines (44 loc) · 1.78 KB
/
is_inside_mesh.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import numpy
'''
Naive and straightforward implementation of the inside/outside point mesh test
'''
def is_inside_naive(triangles, X):
# Compute triangle vertices and their norms relative to X
M = triangles - X
M_norm = numpy.sqrt(numpy.sum(M ** 2, axis = 2))
# Accumulate generalized winding number per triangle
winding_number = 0.
for (A, B, C), (a, b, c) in zip(M, M_norm):
winding_number += numpy.arctan2(numpy.linalg.det(numpy.array([A, B, C])), (a * b * c) + c * numpy.dot(A, B) + a * numpy.dot(B, C) + b * numpy.dot(C, A))
# Job done
return winding_number >= 2. * numpy.pi
'''
Optimized for numpy implementation of the inside/outside point mesh test
'''
def is_inside_turbo(triangles, X):
# Compute euclidean norm along axis 1
def anorm2(X):
return numpy.sqrt(numpy.sum(X ** 2, axis = 1))
# Compute 3x3 determinant along axis 1
def adet(X, Y, Z):
ret = numpy.multiply(numpy.multiply(X[:,0], Y[:,1]), Z[:,2])
ret += numpy.multiply(numpy.multiply(Y[:,0], Z[:,1]), X[:,2])
ret += numpy.multiply(numpy.multiply(Z[:,0], X[:,1]), Y[:,2])
ret -= numpy.multiply(numpy.multiply(Z[:,0], Y[:,1]), X[:,2])
ret -= numpy.multiply(numpy.multiply(Y[:,0], X[:,1]), Z[:,2])
ret -= numpy.multiply(numpy.multiply(X[:,0], Z[:,1]), Y[:,2])
return ret
# One generalized winding number per input vertex
ret = numpy.zeros(X.shape[0], dtype = X.dtype)
# Accumulate generalized winding number for each triangle
for U, V, W in triangles:
A, B, C = U - X, V - X, W - X
omega = adet(A, B, C)
a, b, c = anorm2(A), anorm2(B), anorm2(C)
k = a * b * c
k += c * numpy.sum(numpy.multiply(A, B), axis = 1)
k += a * numpy.sum(numpy.multiply(B, C), axis = 1)
k += b * numpy.sum(numpy.multiply(C, A), axis = 1)
ret += numpy.arctan2(omega, k)
# Job done
return ret >= 2 * numpy.pi