Scipy 3D Delaunay. Different results when translating the set of points
Question:
I thought that given a set of points, the 3D Delaunay network would be unique. But moving all the points (without changing the relative distances) gives a different result.
import numpy as np
from scipy.spatial import Delaunay
points = np.array([ [-0.6, -0.1, -1.5], [0, 0, 0], [-1,-1,-1],[1, 0, 1], [1, 1, 2], [0, 1.1, -1]])
points = points+[0,5,0] #for translation
tri = Delaunay(points)
I have compared the results and the connection matrices, and they differ.
Case 0. No translation. Connection matrix.
array([[0., 1., 1., 1., 0., 0.],
[1., 0., 1., 1., 1., 1.],
[1., 1., 0., 1., 0., 1.],
[1., 1., 1., 0., 1., 1.],
[0., 1., 0., 1., 0., 1.],
[0., 1., 1., 1., 1., 0.]])
Image.
enter image description here
Case 1. Translating 5 units in y-direction. Connection matrix.
array([[0., 1., 0., 1., 0., 1.],
[1., 0., 1., 1., 1., 0.],
[0., 1., 0., 1., 0., 1.],
[1., 1., 1., 0., 1., 1.],
[0., 1., 0., 1., 0., 1.],
[1., 0., 1., 1., 1., 0.]])
Image.
enter image description here
Any idea why they are different?
The connection matrix is computed this way:
matrix = np.zeros((len(points),len(points))
for triangle in tri.simplices:
for i in range(4):
point_initial = triangulo[i]
point_final = triangulo[(i+1)%4]
if matrix[point_initial,point_final] == 1:
continue
matrix[point_initial,point_final] = 1
matrix[point_final,point_initial] = 1
You can see tri.simplices
are also different in both cases:
array([[1, 4, 3, 2],
[1, 4, 5, 2],
[1, 4, 5, 3],
[1, 0, 3, 2],
[1, 0, 5, 2],
[1, 0, 5, 3]], dtype=int32)
array([[1, 4, 3, 2],
[1, 4, 5, 2],
[1, 4, 5, 3],
[0, 1, 3, 2],
[0, 1, 5, 2],
[0, 1, 5, 3]], dtype=int32)
Answers:
@geofisue Thanks for the proposition for writing the answer.
As I described in the comment, the reason for the problem is that when transitioning from a 2D plane point to a 3D solid point, the simplices in the triangulation change from a triangle to a triangular pyramid.
So the number of the connections change from 3 to 6.
Then I modified the function for calculating the connection matrix, which can be used in nD:
import itertools
matrix = np.zeros((len(points),len(points)))
for triangle in tri.simplices:
connections = list(itertools.combinations(triangle, 2))
for connection in connections:
point_initial = connection [0]
point_final = connection[1]
if matrix[point_initial,point_final] == 1:
continue
matrix[point_initial,point_final] = 1
matrix[point_final,point_initial] = 1
The full codes:
import itertools
import numpy as np
from scipy.spatial import Delaunay
import matplotlib.pyplot as plt
points = np.array([ [-0.6, -0.1, -1.5], [0, 0, 0], [-1,-1,-1],[1, 0, 1], [1, 1, 2], [0, 1.1, -1]])
points_trans = points+[0,5,0] #for translation
tri = Delaunay(points)
tri_trans = Delaunay(points_trans)
def get_connection_matrix(points):
matrix = np.zeros((len(points),len(points)))
for triangle in tri.simplices:
connections = list(itertools.combinations(triangle, 2))
for connection in connections:
point_initial = connection [0]
point_final = connection[1]
if matrix[point_initial,point_final] == 1:
continue
matrix[point_initial,point_final] = 1
matrix[point_final,point_initial] = 1
return matrix
matrix = get_connection_matrix(points)
matrix_trans = get_connection_matrix(points_trans)
print(np.array_equal(matrix, matrix_trans))
The result :
> True
I thought that given a set of points, the 3D Delaunay network would be unique. But moving all the points (without changing the relative distances) gives a different result.
import numpy as np
from scipy.spatial import Delaunay
points = np.array([ [-0.6, -0.1, -1.5], [0, 0, 0], [-1,-1,-1],[1, 0, 1], [1, 1, 2], [0, 1.1, -1]])
points = points+[0,5,0] #for translation
tri = Delaunay(points)
I have compared the results and the connection matrices, and they differ.
Case 0. No translation. Connection matrix.
array([[0., 1., 1., 1., 0., 0.],
[1., 0., 1., 1., 1., 1.],
[1., 1., 0., 1., 0., 1.],
[1., 1., 1., 0., 1., 1.],
[0., 1., 0., 1., 0., 1.],
[0., 1., 1., 1., 1., 0.]])
Image.
enter image description here
Case 1. Translating 5 units in y-direction. Connection matrix.
array([[0., 1., 0., 1., 0., 1.],
[1., 0., 1., 1., 1., 0.],
[0., 1., 0., 1., 0., 1.],
[1., 1., 1., 0., 1., 1.],
[0., 1., 0., 1., 0., 1.],
[1., 0., 1., 1., 1., 0.]])
Image.
enter image description here
Any idea why they are different?
The connection matrix is computed this way:
matrix = np.zeros((len(points),len(points))
for triangle in tri.simplices:
for i in range(4):
point_initial = triangulo[i]
point_final = triangulo[(i+1)%4]
if matrix[point_initial,point_final] == 1:
continue
matrix[point_initial,point_final] = 1
matrix[point_final,point_initial] = 1
You can see tri.simplices
are also different in both cases:
array([[1, 4, 3, 2],
[1, 4, 5, 2],
[1, 4, 5, 3],
[1, 0, 3, 2],
[1, 0, 5, 2],
[1, 0, 5, 3]], dtype=int32)
array([[1, 4, 3, 2],
[1, 4, 5, 2],
[1, 4, 5, 3],
[0, 1, 3, 2],
[0, 1, 5, 2],
[0, 1, 5, 3]], dtype=int32)
@geofisue Thanks for the proposition for writing the answer.
As I described in the comment, the reason for the problem is that when transitioning from a 2D plane point to a 3D solid point, the simplices in the triangulation change from a triangle to a triangular pyramid.
So the number of the connections change from 3 to 6.
Then I modified the function for calculating the connection matrix, which can be used in nD:
import itertools
matrix = np.zeros((len(points),len(points)))
for triangle in tri.simplices:
connections = list(itertools.combinations(triangle, 2))
for connection in connections:
point_initial = connection [0]
point_final = connection[1]
if matrix[point_initial,point_final] == 1:
continue
matrix[point_initial,point_final] = 1
matrix[point_final,point_initial] = 1
The full codes:
import itertools
import numpy as np
from scipy.spatial import Delaunay
import matplotlib.pyplot as plt
points = np.array([ [-0.6, -0.1, -1.5], [0, 0, 0], [-1,-1,-1],[1, 0, 1], [1, 1, 2], [0, 1.1, -1]])
points_trans = points+[0,5,0] #for translation
tri = Delaunay(points)
tri_trans = Delaunay(points_trans)
def get_connection_matrix(points):
matrix = np.zeros((len(points),len(points)))
for triangle in tri.simplices:
connections = list(itertools.combinations(triangle, 2))
for connection in connections:
point_initial = connection [0]
point_final = connection[1]
if matrix[point_initial,point_final] == 1:
continue
matrix[point_initial,point_final] = 1
matrix[point_final,point_initial] = 1
return matrix
matrix = get_connection_matrix(points)
matrix_trans = get_connection_matrix(points_trans)
print(np.array_equal(matrix, matrix_trans))
The result :
> True