@empet
I wrote the below code according above links. But seems here is some errors?! (I have installed pyvista)
(I get the error you assigned in the alphashape3d function βFor a 3d point cloud only unconnected points3d, edges, triangles and tetrahedra are set upβ)
import numpy as np
import plotly.graph_objs as go
import pyvista as pv #pip install pyvista
def pcloud(points3d, marker_size=1.5, marker_color='#454F8C'):
#define the trace representing the point cloud
points3d=np.asarray(points3d)
if points3d.ndim != 2 or points3d.shape[1] != 3:
raise ValueError('your data is not a 3D point cloud')
return go.Scatter3d(
name='',
mode='markers',
x=points3d[:,0],
y=points3d[:,1],
z=points3d[:,2],
marker_size=marker_size,
marker_color=marker_color
)
def get_mesh(points3d, faces, color='lightblue', opacity=1):
# define the Mesh3d representing the alpha-shape
points3d=np.asarray(points3d)
if points3d.ndim != 2 or points3d.shape[1] != 3:
raise ValueError('your data is not a 3D point cloud')
faces = np.asarray(faces)
i, j, k = np.asarray(faces).T
return go.Mesh3d(
color=color,
opacity=opacity,
i=i, j=j, k=k,
x =points3d[:,0],
y= points3d[:,1],
z= points3d[:,2],
flatshading=True
)
def alphashape3d(points3d, alpha=1):
#extract 0, 1, 2, 3-simplices of the alpha shape constructed from points3d
# Here alpha =1/alphahull, where alphahull is a property of a Plotly alpha shape
cloud = pv.PolyData(points3d)
mesh = cloud.delaunay_3d(alpha=alpha)
unconnected_points3d = [] #isolated 0-simplices
edges = [] # isolated edges, 1-simplices
faces = [] # triangles that are not faces of some tetrahedra
tetrahedra = [] # 3-simplices
for k in mesh.offset:
length = mesh.cells[k]
if length == 2:
edges.append(list(mesh.cells[k+1: k+length+1]))
elif length ==3:
faces.append(list(mesh.cells[k+1: k+length+1]))
elif length == 4:
tetrahedra.append(list(mesh.cells[k+1: k+length+1]))
elif length == 1:
unconnected_points3d.append(mesh.cells[k+1])
else:
raise ValueError('For a 3d point cloud only unconneted points3d, edges,\
triangles and tetrahedra are set up')
return unconnected_points3d, edges, faces, tetrahedra
def get_tetrahedra_faces(tetrahedra, faces):
# extract tetrahedra faces and append them to the existing faces
for t in tetrahedra:
faces.extend([[t[0], t[1], t[2]],
[t[0], t[2], t[3]],
[t[0], t[3], t[1]],
[t[1], t[2], t[3]]])
return faces
def edge_trace(points, edges):
# define the trace for isolated edges of an alpha shape
Xe = []
Ye = []
Ze = []
for e in edge:
Xe.extend([points[e[0], 0], points[e[1], 0], None])
Ye.extend([points[e[0], 1], points[e[1], 1], None])
Ze.extend([points[e[0], 2], points[e[1], 2], None])
return go.Scatter3d(x=Xe, y=Ye, z=Ze,
mode='lines',
line_width=1,
line_color='rgb(50,50,50)')
######################################################################################
pts = np.loadtxt(np.DataSource().open('https://raw.githubusercontent.com/empet/Plotly-plots/master/Data/data-file.txt'))
alpha= 0.5
title = f'Alpha Shape of a 3D Point Cloud<br>alpha={alpha}'
scatt = pcloud(pts, marker_color='#454F8C', marker_size=3)
#Extract the simplicial structure of the alpha shape defined via pyvista
unconnected_points, edges, faces, tetrahedra = alphashape3d(pts, alpha=alpha)
faces = get_tetrahedra_faces(tetrahedra, faces)
alphashape = get_mesh(pts, faces, opacity=1)
fig1 = go.Figure(data =[scatt, alphashape])
fig1.update_layout(title_text=title, title_x=0.5, width=800, height=800)
fig1.show()