Tengo este problema Intento triangular puntos de nube por scipy.spatial.Delaunay. Solía:
tri = Delaunay(points) # points: np.array() of 3d points indices = tri.simplices vertices = points[indices]
Pero, este código devuelve el tetraedro. ¿Cómo es posible volver triángulo de superficie solamente?
Gracias
Para que funcione como código, debe parametrizar la superficie a 2D. Por ejemplo, en el caso de la bola (r, theta, psi), el radio es constante (descartarlo) y los puntos están dados por (theta, psi) que es 2D.
Scipy Delaunay es una triangulación tridimensional, por lo que si asigna puntos 3D, devolverá objetos 3D. Dale puntos 2D y devuelve objetos 2D.
A continuación se muestra un script que utilicé para crear poliedros para openSCAD. U y V son mi parametrización (xey) y estas son las coordenadas que le doy a Delaunay. Tenga en cuenta que ahora las “propiedades de triangulación de Delaunay” se aplican solo en las coordenadas u, v (los angularjs se maximizan en uv -space no xyz -space, etc.).
El ejemplo es una copia modificada de http://matplotlib.org/1.3.1/mpl_toolkits/mplot3d/tutorial.html que originalmente usa la función de triangulación (¿mapas a Delaunay eventualmente?)
import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D import matplotlib.tri as mtri from scipy.spatial import Delaunay # u, v are parameterisation variables u = np.array([0,0,0.5,1,1]) v = np.array([0,1,0.5,0,1]) x = u y = v z = np.array([0,0,1,0,0]) # Triangulate parameter space to determine the triangles #tri = mtri.Triangulation(u, v) tri = Delaunay(np.array([u,v]).T) print 'polyhedron(faces = [' #for vert in tri.triangles: for vert in tri.simplices: print '[%d,%d,%d],' % (vert[0],vert[1],vert[2]), print '], points = [' for i in range(x.shape[0]): print '[%f,%f,%f],' % (x[i], y[i], z[i]), print ']);' fig = plt.figure() ax = fig.add_subplot(1, 1, 1, projection='3d') # The triangles in parameter space determine which x, y, z points are # connected by an edge #ax.plot_trisurf(x, y, z, triangles=tri.triangles, cmap=plt.cm.Spectral) ax.plot_trisurf(x, y, z, triangles=tri.simplices, cmap=plt.cm.Spectral) plt.show()
A continuación se muestra la salida de texto (ligeramente más estructurada):
polyhedron( faces = [[2,1,0], [3,2,0], [4,2,3], [2,4,1], ], points = [[0.000000,0.000000,0.000000], [0.000000,1.000000,0.000000], [0.500000,0.500000,1.000000], [1.000000,0.000000,0.000000], [1.000000,1.000000,0.000000], ]);
Parece que quieres calcular el casco convexo de tu nube de puntos. Creo que esto es lo que quieres hacer:
from scipy.spatial import ConvexHull hull = ConvexHull(points) indices = hull.simplices vertices = points[indices]
Siguiendo la respuesta de Jaime, pero elaborando un poco más con un ejemplo:
import matplotlib as mpl import matplotlib.pyplot as plt import mpl_toolkits.mplot3d as a3 import numpy as np import scipy as sp from scipy import spatial as sp_spatial def icosahedron(): h = 0.5*(1+np.sqrt(5)) p1 = np.array([[0, 1, h], [0, 1, -h], [0, -1, h], [0, -1, -h]]) p2 = p1[:, [1, 2, 0]] p3 = p1[:, [2, 0, 1]] return np.vstack((p1, p2, p3)) def cube(): points = np.array([ [0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1], ]) return points points = icosahedron() # points = cube() hull = sp_spatial.ConvexHull(points) indices = hull.simplices faces = points[indices] print('area: ', hull.area) print('volume: ', hull.volume) fig = plt.figure() ax = fig.add_subplot(111, projection='3d') ax.dist = 30 ax.azim = -140 ax.set_xlim([0, 2]) ax.set_ylim([0, 2]) ax.set_zlim([0, 2]) ax.set_xlabel('x') ax.set_ylabel('y') ax.set_zlabel('z') for f in faces: face = a3.art3d.Poly3DCollection([f]) face.set_color(mpl.colors.rgb2hex(sp.rand(3))) face.set_edgecolor('k') face.set_alpha(0.5) ax.add_collection3d(face) plt.show()
Que debe representar la siguiente figura: