from scipy.interpolate import splprep, splev
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
from mpl_toolkits.mplot3d import Axes3D, proj3d, art3d
from mpl_toolkits.mplot3d.art3d import Line3DCollection
import vtk
from scipy import optimize
from tqdm import tqdm
import pyvista as pv
from ..branch_addition.basis import tangent_basis
from mpl_toolkits.mplot3d import art3d
[docs]def rotation_matrix(d):
"""
Calculates a rotation matrix given a vector d. The direction of d
corresponds to the rotation axis. The length of d corresponds to
the sin of the angle of rotation.
Variant of: http://mail.scipy.org/pipermail/numpy-discussion/2009-March/040806.html
"""
sin_angle = np.linalg.norm(d)
if sin_angle == 0:
return np.identity(3)
d /= sin_angle
eye = np.eye(3)
ddt = np.outer(d, d)
skew = np.array([[ 0, d[2], -d[1]],
[-d[2], 0, d[0]],
[d[1], -d[0], 0]], dtype=np.float64)
M = ddt + np.sqrt(1 - sin_angle**2) * (eye - ddt) + sin_angle * skew
return M
[docs]def pathpatch_2d_to_3d(pathpatch, z = 0, normal = 'z'):
"""
Transforms a 2D Patch to a 3D patch using the given normal vector.
The patch is projected into they XY plane, rotated about the origin
and finally translated by z.
"""
if type(normal) is str: #Translate strings to normal vectors
index = "xyz".index(normal)
normal = np.roll((1.0,0,0), index)
normal /= np.linalg.norm(normal) #Make sure the vector is normalised
path = pathpatch.get_path() #Get the path and the associated transform
trans = pathpatch.get_patch_transform()
path = trans.transform_path(path) #Apply the transform
pathpatch.__class__ = art3d.PathPatch3D #Change the class
pathpatch._code3d = path.codes #Copy the codes
pathpatch._facecolor3d = pathpatch.get_facecolor #Get the face color
verts = path.vertices #Get the vertices in 2D
d = np.cross(normal, (0, 0, 1)) #Obtain the rotation vector
M = rotation_matrix(d) #Get the rotation matrix
pathpatch._segment3d = np.array([np.dot(M, (x, y, 0)) + (0, 0, z) for x, y in verts])
[docs]def pathpatch_translate(pathpatch, delta):
"""
Translates the 3D pathpatch by the amount delta.
"""
pathpatch._segment3d += delta
[docs]def get_longest_path(data,seed_edge):
dig = True
temp_edges = [seed_edge]
while dig:
keep_digging = []
for edge in temp_edges:
if data[edge,15] > -1:
temp_edges.extend([int(data[edge,15])])
if data[edge,16] > -1:
temp_edges.extend([int(data[edge,16])])
temp_edges.remove(edge)
keep_digging.append(True)
else:
keep_digging.append(False)
dig = any(keep_digging)
if len(temp_edges) == 1:
return temp_edges
edge_depths = []
for edge in temp_edges:
edge_depths.append(data[edge,26])
max_depth = max(edge_depths)
max_edge_depths = [i for i,j in enumerate(edge_depths) if j == max_depth]
paths = [[temp_edges[i]] for i in max_edge_depths]
path_lengths = [data[i[0],20] for i in paths]
retrace = [True]*len(paths)
while np.any(retrace):
for i, path in enumerate(paths):
if retrace[i]:
path.insert(0,int(data[path[0],17]))
path_lengths[i] += data[path[0],20]
if paths[i][0] == seed_edge:
retrace[i] = False
return paths[path_lengths.index(max(path_lengths))]
[docs]def get_alternate_path(data,seed_edge,reference=None):
#print('reference: {}'.format(reference))
if reference is None:
reference = get_longest_path(data,seed_edge)
else:
pass
seed_edge_idx = reference.index(seed_edge)
if seed_edge_idx == len(reference)-1:
print('Seed edge is terminal and no alternative is '+
'possible. \n Computation finished.')
return None
else:
children = [int(data[seed_edge,15]),int(data[seed_edge,16])]
if children[0] not in reference:
alternate_path = get_longest_path(data,children[0])
else:
alternate_path = get_longest_path(data,children[1])
alternate_path.insert(0,seed_edge)
return alternate_path
[docs]def get_branches(data):
branches = []
seed_edge = 0
path = get_longest_path(data,seed_edge)
branches.append(path)
upcoming_evaluations = []
upcoming_evaluations.extend(path[:-1])
counter = [len(path[:-1])]
idx = 0
while len(upcoming_evaluations) > 0:
#print(upcoming_evaluations)
if data[upcoming_evaluations[-1],15] > -1 and data[upcoming_evaluations[-1],16] > -1:
pass
else:
upcoming_evaluations.pop(-1)
counter[idx] -= 1
if counter[idx] == 0:
counter[idx] = None
for i in reversed(range(len(counter))):
if counter[i] is not None:
idx = i
break
continue
path = get_alternate_path(data,upcoming_evaluations.pop(-1),reference=branches[idx])
counter[idx] -= 1
if counter[idx] == 0:
counter[idx] = None
for i in reversed(range(len(counter))):
if counter[i] is not None:
idx = i
break
branches.append(path)
if len(path) > 2:
upcoming_evaluations.extend(path[1:-1])
counter.append(len(path[1:-1]))
idx = len(counter) - 1
else:
counter.append(None)
return branches
[docs]def get_points(data,branches):
path_points = []
primed = False
for path in branches:
branch_points = []
for edge in reversed(path):
if edge == path[0] and primed:
branch_points.insert(0,data[edge,3:6].tolist())
elif edge == path[0] and edge == 0 and not primed:
branch_points.insert(0,data[edge,3:6].tolist())
three_fourths = data[edge,0:3]*(1/4) + data[edge,3:6]*(3/4) #new
branch_points.insert(0,three_fourths.tolist()) #new
mid_point = (data[edge,0:3] + data[edge,3:6])/2
branch_points.insert(0,mid_point.tolist())
one_fourth = data[edge,0:3]*(3/4) + data[edge,3:6]*(1/4) #new
branch_points.insert(0,one_fourth.tolist()) #new
branch_points.insert(0,data[edge,0:3].tolist())
primed = True
elif len(branch_points) == 0:
branch_points.insert(0,data[edge,3:6].tolist())
three_fourths = data[edge,0:3]*(1/4) + data[edge,3:6]*(3/4) #new
branch_points.insert(0,three_fourths.tolist()) #new
mid_point = (data[edge,0:3] + data[edge,3:6])/2
branch_points.insert(0,mid_point.tolist())
one_fourth = data[edge,0:3]*(3/4) + data[edge,3:6]*(1/4) #new
branch_points.insert(0,one_fourth.tolist()) #new
else:
branch_points.insert(0,data[edge,3:6].tolist())
three_fourths = data[edge,0:3]*(1/4) + data[edge,3:6]*(3/4) #new
branch_points.insert(0,three_fourths.tolist()) #new
mid_point = (data[edge,0:3] + data[edge,3:6])/2
branch_points.insert(0,mid_point.tolist())
one_fourth = data[edge,0:3]*(3/4) + data[edge,3:6]*(1/4) #new
branch_points.insert(0,one_fourth.tolist()) #new
path_points.append(branch_points)
return path_points
[docs]def get_points_v1(data,branches):
path_points = []
primed = False
for path in branches:
branch_points = []
for edge in reversed(path):
if edge == path[-1]:
branch_points.insert(0,data[edge,3:6].tolist())
elif edge == path[0] and edge == 0 and not primed:
branch_points.insert(0,data[edge,3:6].tolist())
branch_points.insert(0,data[edge,0:3].tolist())
primed = True
else:
branch_points.insert(0,data[edge,3:6].tolist())
path_points.append(branch_points)
return path_points
[docs]def get_radii(data,branches):
path_radii = []
primed = False
for path in branches:
branch_radii = []
for edge in reversed(path):
if edge == path[0] and primed:
branch_radii.insert(0,data[path[1],21])
elif edge == path[0] and edge == 0 and not primed:
branch_radii.insert(0,data[edge,21])
branch_radii.insert(0,data[edge,21])
branch_radii.insert(0,data[edge,21])
branch_radii.insert(0,data[edge,21]) #new
branch_radii.insert(0,data[edge,21]) #new
primed = True
elif len(branch_radii) == 0:
branch_radii.insert(0,data[edge,21])
branch_radii.insert(0,data[edge,21])
branch_radii.insert(0,data[edge,21]) #new
branch_radii.insert(0,data[edge,21]) #new
else:
branch_radii.insert(0,data[edge,21])
branch_radii.insert(0,data[edge,21])
branch_radii.insert(0,data[edge,21]) #new
branch_radii.insert(0,data[edge,21]) #new
path_radii.append(branch_radii)
return path_radii
[docs]def get_radii_v1(data,branches):
path_radii = []
primed = False
for path in branches:
branch_radii = []
for edge in reversed(path):
if edge == path[-1]:
branch_radii.insert(0,data[edge,21])
elif edge == path[0] and edge == 0 and not primed:
branch_radii.insert(0,(data[edge,21]+data[previous,21])/2)
branch_radii.insert(0,data[edge,21])
primed = True
else:
branch_radii.insert(0,(data[edge,21]+data[previous,21])/2)
previous = edge
path_radii.append(branch_radii)
return path_radii
[docs]def get_normals(data,branches):
path_normals = []
primed = False
for path in branches:
branch_normals = []
for edge in reversed(path):
if edge == path[0] and primed:
branch_normals.insert(0,data[path[1],12:15].tolist())
elif edge == path[0] and edge == 0 and not primed:
vector_1 = data[edge,12:15]
mid_vector = (vector_1+vector_2)/2
branch_normals.insert(0,mid_vector.tolist())
branch_normals.insert(0,data[edge,12:15].tolist())
branch_normals.insert(0,data[edge,12:15].tolist())
branch_normals.insert(0,data[edge,12:15].tolist()) #new
branch_normals.insert(0,data[edge,12:15].tolist()) #new
primed = True
elif len(branch_normals) == 0:
branch_normals.insert(0,data[edge,12:15].tolist())
branch_normals.insert(0,data[edge,12:15].tolist())
branch_normals.insert(0,data[edge,12:15].tolist()) #new
branch_normals.insert(0,data[edge,12:15].tolist()) #new
vector_2 = data[edge,12:15]
else:
vector_1 = data[edge,12:15]
mid_vector = (vector_1+vector_2)/2
branch_normals.insert(0,mid_vector.tolist())
branch_normals.insert(0,data[edge,12:15].tolist()) #new
branch_normals.insert(0,data[edge,12:15].tolist()) #new
branch_normals.insert(0,data[edge,12:15].tolist())
vector_2 = data[edge,12:15]
path_normals.append(branch_normals)
return path_normals
[docs]def get_normals_v1(data,branches):
path_normals = []
primed = False
for path in branches:
branch_normals = []
for edge in reversed(path):
if edge == path[-1]:
branch_normals.insert(0,data[edge,12:15].tolist())
elif edge == path[0] and edge == 0 and not primed:
branch_normals.insert(0,((data[edge,12:15]+data[previous,12:15])/2).tolist())
branch_normals.insert(0,data[edge,12:15].tolist())
primed = True
else:
branch_normals.insert(0,((data[edge,12:15]+data[previous,12:15])/2).tolist())
previous = edge
path_normals.append(branch_normals)
return path_normals
[docs]def plot_sv_data(data):
branches = get_branches(data)
points = get_points(data,branches)
radii = get_radii(data,branches)
normals = get_normals(data,branches)
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
for path in points:
tmp = np.array(path)
ax.plot3D(tmp[:,0],tmp[:,1],tmp[:,2])
ax.scatter3D(tmp[:,0],tmp[:,1],tmp[:,2])
plt.show()
[docs]def get_interpolated_sv_data(data):
branches = get_branches(data)
points = get_points(data,branches)
#print("Points: {}".format(points[0]))
radii = get_radii(data,branches)
#print("Radii: {}".format(radii[0]))
normals = get_normals(data,branches)
path_frames = []
for idx in range(len(branches)):
frames = []
for jdx in range(len(points[idx])):
frame = []
frame.extend(points[idx][jdx])
frame.append(radii[idx][jdx])
frame.extend(normals[idx][jdx])
frames.append(frame)
path_frames.append(frames)
interp_xyz = []
interp_r = []
interp_n = []
interp_xyzr = []
for idx in range(len(branches)):
p = np.array(points[idx]).T
r = np.array(radii[idx]).T
n = np.array(normals[idx]).T
if len(points[idx]) == 2:
interp_xyz.append(splprep(p,k=1,s=0))
rr = np.vstack((interp_xyz[-1][1],r))
interp_r.append(splprep(rr,k=1,s=0))
xyzr = np.vstack((p,r))
interp_xyzr.append(splprep(xyzr,k=1,s=0))
#interp_n.append(splprep(n,k=1,s=0))
elif len(points[idx]) == 3:
interp_xyz.append(splprep(p,k=2,s=0))
rr = np.vstack((interp_xyz[-1][1],r))
interp_r.append(splprep(rr,k=2,s=0))
xyzr = np.vstack((p,r))
interp_xyzr.append(splprep(xyzr,k=2,s=0))
#interp_n.append(splprep(n,k=2,s=0))
else:
interp_xyz.append(splprep(p,s=0))
rr = np.vstack((interp_xyz[-1][1],r))
interp_r.append(splprep(rr,s=0))
xyzr = np.vstack((p,r))
interp_xyzr.append(splprep(xyzr,s=0))
#interp_n.append(splprep(n,s=0))
return interp_xyz,interp_r,interp_n,path_frames,branches,interp_xyzr
[docs]def get_sv_data(network):
if isinstance(network,tree):
data = network.data
branches = get_branches(data)
points = get_points(data,branches)
radii = get_radii(data,branches)
normals = get_normals(data,branches)
elif isinstance(network,forest):
for idx, grafts in enumerate(network.grafts):
data = []
branches = []
connections = []
for jdx, graft in enumerate(grafts):
data.append(graft.data)
branches.append(get_branches(graft.data))
connections.append(network.connections[idx][jdx])
[docs]def plot_interp_vessels(interp_xyz,interp_r,normals=True):
n = np.linspace(0,1,200)
fig = plt.figure()
ax1 = fig.add_subplot(111,projection='3d')
#ax2 = fig.add_subplot(232,projection='3d')
#ax3 = fig.add_subplot(233,projection='3d')
#ax4 = fig.add_subplot(234,projection='3d')
#ax5 = fig.add_subplot(235,projection='3d')
#ax6 = fig.add_subplot(236,projection='3d')
for idx in enumerate(range(interp_xyz)):
if idx > 0:
break
x,y,z = splev(n,interp_xyz[idx][0])
nx,ny,nz = splev(n,interp_xyz[idx][0],der=1)
nxx,nyy,nzz = splev(n,inerp_xyz[idx][0],der=2)
#nxxx,nyyy,nzzz,_,_,_,_ = splev(n,b[0],der=3)
ax1.plot3D(x,y,z,c='b')
ax1.scatter3D(x[0],y[0],z[0],c='black')
ax1.scatter3D(x[-1],y[-1],z[-1],c='black')
#ax2.plot3D(x,y,z,c='b')
#ax3.plot3D(x,y,z,c='b')
idx_x = np.argwhere(np.diff(np.sign(nx))!=0).flatten()
idx_y = np.argwhere(np.diff(np.sign(ny))!=0).flatten()
idx_z = np.argwhere(np.diff(np.sign(nz))!=0).flatten()
ax1.scatter3D(x[idx_x],y[idx_x],z[idx_x],c='r')
ax1.scatter3D(x[idx_y],y[idx_y],z[idx_y],c='r')
ax1.scatter3D(x[idx_z],y[idx_z],z[idx_z],c='r')
idx_xx = np.argwhere(np.diff(np.sign(nxx))!=0).flatten()
idx_yy = np.argwhere(np.diff(np.sign(nyy))!=0).flatten()
idx_zz = np.argwhere(np.diff(np.sign(nzz))!=0).flatten()
ax1.scatter3D(x[idx_xx],y[idx_xx],z[idx_xx],c='g')
ax1.scatter3D(x[idx_yy],y[idx_yy],z[idx_yy],c='g')
ax1.scatter3D(x[idx_zz],y[idx_zz],z[idx_zz],c='g')
if b[0][-1] >= 3:
nxxx,nyyy,nzzz = splev(n,interp_xyz[idx][0],der=3)
idx_xxx = np.argwhere(np.diff(np.sign(nxxx))!=0).flatten()
idx_yyy = np.argwhere(np.diff(np.sign(nyyy))!=0).flatten()
idx_zzz = np.argwhere(np.diff(np.sign(nzzz))!=0).flatten()
ax1.scatter3D(x[idx_xxx],y[idx_xxx],z[idx_xxx],c='y')
ax1.scatter3D(x[idx_yyy],y[idx_yyy],z[idx_yyy],c='y')
ax1.scatter3D(x[idx_zzz],y[idx_zzz],z[idx_zzz],c='y')
#ax.plot3D(x,y,z)
#x_knot,y_knot,z_knot,_,_,_,_ = splev(b[1],b[0])
#ax.plot3D(x_knot,y_knot,z_knot,'go')
"""
if normals:
nx = -1/nx
ny = -1/ny
nz = -1/nz
l = np.linalg.norm(np.array([nx,ny,nz]),axis=0)
nx = (nx/l)*r
ny = (ny/l)*r
nz = (nz/l)*r
points0 = np.array([x,y,z]).T.reshape(-1,1,3)
points1 = np.array([x+nx,y+ny,z+nz]).T.reshape(-1,1,3)
segments = np.concatenate([points0,points1],axis=1)
lc = Line3DCollection(segments,color='black')
ax.add_collection3d(lc)
"""
plt.show()
from sympy import Point3D,Line3D,Plane,Float
[docs]def contour_collision(x1,y1,z1,nx1,ny1,nz1,r1,x2,y2,z2,nx2,ny2,nz2,r2,radius_buffer,contours,t1,t2,n_sides=4):
"""
d1 = x1*nx1+y1*ny1+z1*nz1
d2 = x2*nx2+y2*ny2+z2*nz2
length = ((x2-x1)**2+(y2-y1)**2+(z2-z1)**2)**(1/2)
if radius_buffer is not None:
r1 += radius_buffer*r1
r2 += radius_buffer*r2
if not np.isclose(nx1,0):
alpha = (nz1*nx2-nz2*nx1)/(ny2*nx1-ny1*nx2)
beta = (d1*nx2-d2*nx1)/(ny2*nx1-ny1*nx2)
c = ny1/nx1
a_pt = np.array([-d1/nx1-beta*c,beta,0])
pt1 = np.array([x1,y1,z1])
pt2 = np.array([x2,y2,z2])
n_line= np.array([-(alpha*c+nz1/nx1),alpha,1])
n_line=n_line/np.linalg.norm(n_line)
dist1 = np.linalg.norm((pt1-a_pt)-np.dot(pt1-a_pt,n_line)*n_line)
dist2 = np.linalg.norm((pt2-a_pt)-np.dot(pt2-a_pt,n_line)*n_line)
print('dist1: {} r1: {}'.format(dist1,r1))
print('dist2: {} r2: {}'.format(dist2,r2))
if dist1 < r1 or dist2 < r2:
return True
else:
return False
elif not np.isclose(ny1,0):
alpha = (nz1*ny2-nz2*ny1)/(nx2*ny1-nx1*ny2)
beta = (d1*ny2-d2*ny1)/(nx2*ny1-nx1*ny2)
c = nx1/ny1
a_pt = np.array([beta,-d1/ny1-beta*c,0])
pt1 = np.array([x1,y1,z1])
pt2 = np.array([x2,y2,z2])
n_line= np.array([alpha,-(alpha*c+nz1/ny1),1])
n_line=n_line/np.linalg.norm(n_line)
dist1 = np.linalg.norm((pt1-a_pt)-np.dot(pt1-a_pt,n_line)*n_line)
dist2 = np.linalg.norm((pt2-a_pt)-np.dot(pt2-a_pt,n_line)*n_line)
print('dist1: {} r1: {}'.format(dist1,r1))
print('dist2: {} r2: {}'.format(dist2,r2))
if dist1 < r1 or dist2 < r2:
return True
else:
return False
else:
return None
"""
n = np.linspace(t1,t2)
length = ((x2-x1)**2+(y2-y1)**2+(z2-z1)**2)**(1/2)
if radius_buffer is not None:
r1 += r1*radius_buffer
r2 += r2*radius_buffer
"""
contour_1 = vtk.vtkRegularPolygonSource()
contour_2 = vtk.vtkRegularPolygonSource()
contour_1.SetCenter([x1,y1,z1])
contour_2.SetCenter([x2,y2,z2])
contour_1.SetRadius(r1)
contour_2.SetRadius(r2)
contour_1.SetNormal([nx1,ny1,nz1])
contour_2.SetNormal([nx2,ny2,nz2])
contour_1.SetNumberOfSides(n_sides)
contour_2.SetNumberOfSides(n_sides)
contour_11 = vtk.vtkContourTriangulator()
contour_22 = vtk.vtkContourTriangulator()
contour_11.SetInputConnection(contour_1.GetOutputPort())
contour_22.SetInputConnection(contour_2.GetOutputPort())
collision = vtk.vtkCollisionDetectionFilter()
collision.SetInputConnection(0,contour_11.GetOutputPort())
collision.SetInputConnection(1,contour_22.GetOutputPort())
transform = vtk.vtkTransform()
matrix = vtk.vtkMatrix4x4()
collision.SetTransform(0,transform)
collision.SetMatrix(1,matrix)
collision.SetCollisionModeToAllContacts()
collision.GenerateScalarsOn()
collision.Update()
"""
contour_1 = pv.Disc(center=[x1,y1,z1],inner=0,outer=r1,normal=[nx1,ny1,nz1],r_res=5,c_res=20).triangulate()
contour_2 = pv.Disc(center=[x2,y2,z2],inner=0,outer=r2,normal=[nx2,ny2,nz2],r_res=5,c_res=20).triangulate()
collision,ncol = contour_1.collision(contour_2,contact_mode=0)
#if collision.GetNumberOfContacts() > 0:
if ncol > 0:
"""
actors = []
colors = vtk.vtkNamedColors()
mapper_1 = vtk.vtkPolyDataMapper()
mapper_2 = vtk.vtkPolyDataMapper()
actor_1 = vtk.vtkActor()
actor_2 = vtk.vtkActor()
mapper_1.SetInputConnection(contour_11.GetOutputPort())
mapper_2.SetInputConnection(contour_22.GetOutputPort())
actor_1.SetMapper(mapper_1)
actor_2.SetMapper(mapper_2)
actor_1.GetProperty().SetColor(colors.GetColor3d('blue'))
actor_2.GetProperty().SetColor(colors.GetColor3d('blue'))
actors.append(actor_1)
actors.append(actor_2)
renderer = vtk.vtkRenderer()
renderer.SetBackground(colors.GetColor3d('white'))
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
render_window.SetWindowName('Pathline with Contours')
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
for actor in actors:
renderer.AddActor(actor)
render_window.Render()
interactor.Start()
"""
return True
else:
return False
"""
#print('{},{},{}'.format(x1,y1,z1))
p1 = Point3D(Float(x1),Float(y1),Float(z1))
p2 = Point3D(Float(x2),Float(y2),Float(z2))
a = Plane(p1,normal_vector=(Float(nx1),Float(ny1),Float(nz1)))
b = Plane(p2,normal_vector=(Float(nx2),Float(ny2),Float(nz2)))
intersect = a.intersection(b)[0]
dist1 = intersect.distance(p1)
dist2 = intersect.distance(p2)
p_seg1 = intersect.perpendicular_line(p1)
p_seg2 = intersect.perpendicular_line(p2)
pi1 = intersect.intersection(p_seg1)[0]
pi2 = intersect.intersection(p_seg2)[0]
line_1 = np.array([[p1.x,p1.y,p1.z],[pi1.x,pi1.y,pi1.z]])
line_2 = np.array([[p2.x,p2.y,p2.z],[pi2.x,pi2.y,pi2.z]])
n1_vec = np.array([[p1.x,p1.y,p1.z],[p1.x+nx1,p1.y+ny1,p1.z+nz1]])
n2_vec = np.array([[p2.x,p2.y,p2.z],[p2.x+nx2,p2.y+ny2,p2.z+nz2]])
#print('dist1: {} r1: {}'.format(dist1,r1))
#print('dist2: {} r2: {}'.format(dist2,r2))
if dist1 < r1 or dist2 < r2:
return True
else:
return False
"""
[docs]def contour_check(interp_xyz,interp_r,t0,t1,radius_buffer,n_sides=4):
tl = (t1 - t0)/10
x1,y1,z1,r1 = splev(t0,interp_xyz[0])
#_,r1 = splev(t0,interp_r[0])
nx1,ny1,nz1,_ = splev(t0,interp_xyz[0],der=1)
n1 = np.array([nx1,ny1,nz1])
mag = np.linalg.norm(n1,axis=0)
n1 = n1/mag
x2,y2,z2,r2 = splev(t1,interp_xyz[0])
#_,r2 = splev(t1,interp_r[0])
nx2,ny2,nz2,_ = splev(t1,interp_xyz[0],der=1)
n2 = np.array([nx2,ny2,nz2])
mag = np.linalg.norm(n2,axis=0)
n2 = n2/mag
collision = contour_collision(x2,y2,z2,nx2,ny2,nz2,r2,x1,y1,z1,nx1,ny1,nz1,r1,radius_buffer,interp_xyz,t0,t1,n_sides=n_sides)
return collision
[docs]def contour_check_all(interp_xyz,interp_r,radius_buffer):
ANGLE_THRESHOLD = 20
sample_t = []
#n = np.linspace(0,1,1000)
desc1 = 'Extracting Loft Contours'
desc1 = desc1+' '*(40-len(desc1))
for kdx in tqdm(range(len(interp_xyz)),bar_format='{l_bar}{bar:10}{r_bar}{bar:-10b}',position=2,leave=False,desc=desc1):
tmp_t = []
t_list = []
t_list = np.linspace(0,1,10*len(interp_xyz[kdx][1]))
#plot_path_contours(interp_xyz[kdx],interp_r[kdx],t_list)
normal_list = []
x,y,z,r = splev(0,interp_xyz[kdx][0])
previous = [x,y,z,r]
nx,ny,nz,_ = splev(0,interp_xyz[kdx][0],der=1)
normal = np.array([nx,ny,nz])
normal = normal/np.linalg.norm(normal)
normal_list.append(normal)
# Clean out all contours that provide little information
tmp_t.append(t_list[0])
desc2 = 'Cleaning Out Redundant Contours'
desc2 = desc2+' '*(40-len(desc2))
for ct in tqdm(t_list[1:-1],bar_format='{l_bar}{bar:10}{r_bar}{bar:-10b}',position=3,leave=False,desc=desc2):
x,y,z,r = splev(ct,interp_xyz[kdx][0])
nx,ny,nz,_ = splev(ct,interp_xyz[kdx][0],der=1)
normal = np.array([nx,ny,nz])
normal = normal/np.linalg.norm(normal)
angle = abs((np.arccos(np.dot(normal_list[-1],normal.T))/np.pi)*180)
dist = ((previous[0]-x)**2+(previous[1]-y)**2+(previous[2]-z)**2)**(1/2)
if angle > ANGLE_THRESHOLD or (dist>(r+previous[3])):
normal_list.append(normal)
tmp_t.append(ct)
previous = [x,y,z,r]
tmp_t.append(t_list[-1])
#plot_path_contours(interp_xyz[kdx],interp_r[kdx],tmp_t)
"""
if len(tmp_t) > 2:
tmp_tmp_t = [tmp_t[0]]
for ct in tqdm(tmp_t[1:-1],position=2,desc="Cleaning Consecutive Colliding Contours"):
_,_,_,r = splev(ct,interp_xyz[kdx][0])
if contour_check(interp_xyz[kdx],interp_r[kdx],tmp_tmp_t[-1],ct,r*0.25,n_sides=20):
if len(tmp_tmp_t) > 1:
tmp_tmp_t[-1] = (ct+tmp_tmp_t[-1])/2
else:
tmp_tmp_t.append(ct)
tmp_tmp_t.append(tmp_t[-1])
else:
tmp_tmp_t = tmp_t
"""
tmp_tmp_t = tmp_t
#plot_path_contours(interp_xyz[kdx],interp_r[kdx],tmp_tmp_t)
if len(tmp_t) > 2:
tmp_tmp_tmp_t = [tmp_tmp_t[0]]
desc3 = 'Cleaning remaining collisions'
desc3 = desc3+' '*(40-len(desc3))
for ct in tqdm(tmp_tmp_t[1:-1],bar_format='{l_bar}{bar:10}{r_bar}{bar:-10b}',position=3,leave=False,desc=desc3):
_,_,_,r = splev(ct,interp_xyz[kdx][0])
include = True
for cct in tmp_tmp_t[1:-1]:
if cct==ct:
continue
if contour_check(interp_xyz[kdx],interp_r[kdx],ct,cct,r*0.25,n_sides=20):
include = False
break
if include:
tmp_tmp_tmp_t.append(ct)
tmp_tmp_tmp_t.append(tmp_t[-1])
else:
tmp_tmp_tmp_t = tmp_tmp_t
#plot_path_contours(interp_xyz[kdx],interp_r[kdx],tmp_tmp_tmp_t)
if len(tmp_tmp_t) > 2:
repeat = True
old_count = len(tmp_tmp_tmp_t)
resample_count = 1
while repeat:
tmp_tmp_tmp_tmp_t = [tmp_tmp_tmp_t[0]]
normal_list = []
nx,ny,nz,_ = splev(0,interp_xyz[kdx][0],der=1)
normal = np.array([nx,ny,nz])
normal = normal/np.linalg.norm(normal)
normal_list.append(normal)
highlight = []
count = 1
swap_list = []
total = len(tmp_tmp_tmp_t[1:-1])
desc4 = 'Resampling {}'.format(resample_count)
desc4 = desc4+' '*(40-len(desc4))
with tqdm(total=total,bar_format='{l_bar}{bar:10}{r_bar}{bar:-10b}',position=3,leave=False,desc=desc4) as pbar:
for ct_idx,ct in enumerate(tmp_tmp_tmp_t[1:-1]):
t_next = tmp_tmp_tmp_t[ct_idx + 2]
x,y,z,r = splev(ct,interp_xyz[kdx][0])
nx,ny,nz,_ = splev(ct,interp_xyz[kdx][0],der=1)
normal = np.array([nx,ny,nz])
normal = normal/np.linalg.norm(normal)
angle = abs((np.arccos(np.dot(normal_list[-1],normal.T))/np.pi)*180)
if angle > ANGLE_THRESHOLD+5:
t_op,f_op = optimize_contour(tmp_tmp_tmp_tmp_t[-1],ct,interp_xyz[kdx],interp_r[kdx],0.25,n_sides=20)
tnx,tny,tnz,_ = splev(t_op,interp_xyz[kdx][0],der=1)
next_nx,next_ny,next_nz,_ = splev(t_next,interp_xyz[kdx][0],der=1)
t_op_normal = np.array([tnx,tny,tnz])
t_op_normal = t_op_normal/np.linalg.norm(t_op_normal)
angle0 = abs((np.arccos(np.dot(normal_list[-1],t_op_normal.T))/np.pi)*180)
t_next_normal = np.array([next_nx,next_ny,next_nz])
t_next_normal = t_next_normal/np.linalg.norm(t_next_normal)
angle1 = abs((np.arccos(np.dot(t_op_normal,t_next_normal.T))/np.pi)*180)
if f_op < 0 and (angle0 > ANGLE_THRESHOLD*0.5 and angle1 > ANGLE_THRESHOLD*0.5):
#t_op = (tmp_tmp_tmp_t[-1]+ct)/2
tmp_tmp_tmp_tmp_t.append(t_op)
if count+1 < len(tmp_tmp_tmp_t)-1:
swap_list.append(count+1)
if count-1 > 0:
swap_list.append(count-1)
highlight.append(count)
count += 1
tmp_tmp_tmp_tmp_t.append(ct)
count += 1
else:
tmp_tmp_tmp_tmp_t.append(ct)
count += 1
normal_list.append(normal)
pbar.update(1)
tmp_tmp_tmp_tmp_t.append(tmp_tmp_t[-1])
#plot_path_contours(interp_xyz[kdx],interp_r[kdx],tmp_tmp_tmp_tmp_t,highlight=highlight)
if len(tmp_tmp_tmp_tmp_t) == old_count:
repeat = False
#else:
# better_t,better_idx = swap_contour(interp_xyz[kdx],tmp_tmp_tmp_tmp_t,0.25)
# tmp_tmp_tmp_tmp_t[better_idx] = better_t
# plot_path_contours(interp_xyz[kdx],interp_r[kdx],tmp_tmp_tmp_tmp_t,highlight=[better_idx])
for sw in swap_list:
tmp_tmp_tmp_tmp_t[sw] = swap_contour(interp_xyz[kdx],tmp_tmp_tmp_tmp_t,sw,0.25)
#plot_path_contours(interp_xyz[kdx],interp_r[kdx],tmp_tmp_tmp_tmp_t,highlight=swap_list)
tmp_tmp_tmp_tmp_t,better_idx = swap_worst_contour(interp_xyz[kdx],tmp_tmp_tmp_tmp_t,0.25,thresh=2*ANGLE_THRESHOLD)
#plot_path_contours(interp_xyz[kdx],interp_r[kdx],tmp_tmp_tmp_tmp_t,highlight=better_idx)
old_count = len(tmp_tmp_tmp_tmp_t)
tmp_tmp_tmp_t = tmp_tmp_tmp_tmp_t
resample_count += 1
else:
tmp_tmp_tmp_tmp_t = tmp_tmp_tmp_t
#plot_path_contours(interp_xyz[kdx],interp_r[kdx],tmp_tmp_tmp_tmp_t,highlight=highlight)
sample_t.append(tmp_tmp_tmp_tmp_t)
return sample_t
"""
ORIGINAL CONTOUR CHECKING
def contour_check_all(interp_xyz,interp_r,radius_buffer):
sample_t = []
n = np.linspace(0,1,200)
total_collisions = 0
for kdx in tqdm(range(len(interp_xyz)),desc='Resolving Overlaps'):
tmp_t = []
t_list = []
t_list = np.linspace(0,1,4*len(interp_xyz[kdx][1]))
collision_contours = set([])
collision_free = set([])
checking = set(list(range(1,len(t_list)-1)))
#t_op,f_op = optimize_contour(t_range[first],t_range[second],contours)
for idx in checking:
collide = False
for jdx in checking.difference(set([idx])):
if contour_check(interp_xyz[kdx],interp_r[kdx],t_list[idx],t_list[jdx],radius_buffer,n_sides=20):
collision_contours.add(idx)
collision_contours.add(jdx)
collide = True
break
if not collide:
collision_free.add(idx)
#checking = checking.difference(collision_contours)
checking = checking.difference(collision_free)
collision_free = list(collision_free)
collision_free.sort()
if len(collision_contours) > 0:
pass
plot_path_contours(interp_xyz[kdx],interp_r[kdx],t_list,highlight=list(collision_contours))
tmp_t.append(t_list[0])
for idx in range(len(collision_free)-1):
if collision_free[idx+1] - collision_free[idx]>1:
tmp_tmp_t = [t_list[collision_free[idx]],t_list[collision_free[idx+1]]]
#nx,ny,nz,_,_,_,_ = splev(tmp_tmp_t,contours,der=1)
#normals = np.array([nx,ny,nz]).T
#tmp_tmp_angles = [np.dot(normals[i,:],normals[i+1,:]) for i in range(normals.shape[0]-1)]
for jdx in range(collision_free[idx+1] - collision_free[idx]):
#max_diff = np.argmax(np.diff(tmp_tmp_angles))
nx,ny,nz,_ = splev(tmp_tmp_t,interp_xyz[kdx][0],der=1)
normals = np.array([nx,ny,nz]).T
tmp_tmp_angles = [np.dot(normals[i,:],normals[i+1,:]) for i in range(normals.shape[0]-1)]
max_diff = np.argmin(tmp_tmp_angles)
t_op,f_op = optimize_contour(tmp_tmp_t[max_diff],tmp_tmp_t[max_diff+1],interp_xyz[kdx],interp_r[kdx],radius_buffer,n_sides=20)
if f_op < 0:
tmp_tmp_t.append(t_op)
tmp_tmp_t.sort()
else:
break
tmp_tmp_t.pop(-1)
tmp_t.extend(tmp_tmp_t)
else:
tmp_t.append(t_list[collision_free[idx]])
tmp_t.append(t_list[collision_free[-1]])
tmp_t.append(t_list[-1])
if len(collision_contours) > 0:
pass
plot_path_contours(interp_xyz[kdx],interp_r[kdx],tmp_t)
if len(tmp_t) == 1:
tmp_t.append(1)
else:
tmp_t[-1] = 1
sample_t.append(tmp_t)
print('Total Collisions Resolved: '+str(total_collisions))
return sample_t
"""
[docs]def sv_data(interp_xyz,interp_r,radius_buffer=0.25):
points = []
radii = []
normals = []
sample_t = contour_check_all(interp_xyz,interp_r,radius_buffer)
#fig = plt.figure()
#ax = fig.add_subplot(111,projection='3d')
for idx in range(len(interp_xyz)):
x,y,z,r = splev(np.array(sample_t[idx]),interp_xyz[idx][0])
#_,r = splev(np.array(sample_t[idx]),interp_r[idx][0])
nx,ny,nz,_ = splev(np.array(sample_t[idx]),interp_xyz[idx][0],der=1)
l = np.linalg.norm(np.array([nx,ny,nz]),axis=0)
nx = nx/l
ny = ny/l
nz = nz/l
#ax.plot3D(x,y,z)
#for i in range(len(x)):
# patch = Circle((0,0),r[i],facecolor='r')
# ax.add_patch(patch)
# pathpatch_2d_to_3d(patch,z=0,normal=np.array([nx[i],ny[i],nz[i]]))
# pathpatch_translate(patch,(x[i],y[i],z[i]))
tmp_points = np.zeros((len(x),3))
tmp_points[:,0] = x
tmp_points[:,1] = y
tmp_points[:,2] = z
points.append(tmp_points.tolist())
tmp_normals = np.zeros((len(nx),3))
tmp_normals[:,0] = nx
tmp_normals[:,1] = ny
tmp_normals[:,2] = nz
radii.append(r.tolist())
normals.append(tmp_normals.tolist())
#plt.show()
return points,radii,normals
[docs]def plot_frames(frames):
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
for idx,f in enumerate(frames):
f = np.array(f)
x,y,z = (f[:,0],f[:,1],f[:,2])
ax.plot3D(x,y,z)
plt.show()
[docs]def plot_branches(data,branches):
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
for i,branch in enumerate(branches):
for idx in branch:
ax.plot3D([data[idx,0],data[idx,3]],
[data[idx,1],data[idx,4]],
[data[idx,2],data[idx,5]],label=str(i))
plt.legend()
plt.show()
[docs]def plot_path_contours(interp_xyz,interp_r,t_list,highlight=[]):
disks = []
lines = []
points = vtk.vtkPoints()
pts = []
radii = []
normals = []
actors = []
colors = vtk.vtkNamedColors()
for t in t_list:
x,y,z,r = splev(t,interp_xyz[0])
#_,r = splev(t,interp_r[0])
nx,ny,nz,_ = splev(t,interp_xyz[0],der=1)
points.InsertNextPoint([x,y,z])
radii.append(r)
normals.append([nx,ny,nz])
pts.append([x,y,z])
polyline = vtk.vtkPolyLine()
polyline.GetPointIds().SetNumberOfIds(len(t_list))
for i in range(len(t_list)):
polyline.GetPointIds().SetId(i,i)
cells = vtk.vtkCellArray()
cells.InsertNextCell(polyline)
polydata = vtk.vtkPolyData()
polydata.SetPoints(points)
polydata.SetLines(cells)
mapper = vtk.vtkPolyDataMapper()
actor = vtk.vtkActor()
mapper.SetInputDataObject(polydata)
actor.SetMapper(mapper)
actor.GetProperty().SetColor(colors.GetColor3d('red'))
actors.append(actor)
for r in range(len(radii)):
tmp_disk = vtk.vtkRegularPolygonSource()
tmp_disk.SetRadius(radii[r])
tmp_disk.SetCenter(pts[r])
tmp_disk.SetNormal(normals[r])
tmp_disk.SetNumberOfSides(100)
mapper = vtk.vtkPolyDataMapper()
actor = vtk.vtkActor()
mapper.SetInputConnection(tmp_disk.GetOutputPort())
actor.SetMapper(mapper)
if r in highlight:
actor.GetProperty().SetColor(colors.GetColor3d('blue'))
else:
actor.GetProperty().SetColor(colors.GetColor3d('red'))
disks.append(tmp_disk)
actors.append(actor)
renderer = vtk.vtkRenderer()
renderer.SetBackground(colors.GetColor3d('white'))
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
render_window.SetWindowName('Pathline with Contours')
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
for actor in actors:
renderer.AddActor(actor)
render_window.Render()
interactor.Start()
[docs]def optimize_contour(t0,t1,interp_xyz,interp_r,radius_buffer,t_buffer=0.1,n_sides=50):
nx0,ny0,nz0,_ = splev(t0,interp_xyz[0],der=1)
nx1,ny1,nz1,_ = splev(t1,interp_xyz[0],der=1)
n0 = np.array([nx0,ny0,nz0])
n1 = np.array([nx1,ny1,nz1])
n0 = n0/np.linalg.norm(n0) #.reshape(-1,1)
n1 = n1/np.linalg.norm(n1) #.reshape(-1,1)
t_bound_buff = (t1-t0)*t_buffer
def func(t,interp_xyz=interp_xyz,interp_r=interp_r,n0=n0,n1=n1,t0=t0,t1=t1):
x0,y0,z0,r0 = splev(t0,interp_xyz[0])
x1,y1,z1,r1 = splev(t1,interp_xyz[0])
x,y,z,r = splev(t,interp_xyz[0])
nx,ny,nz,_ = splev(t,interp_xyz[0],der=1)
n = np.array([nx,ny,nz])
n = n/np.linalg.norm(n) #.reshape(-1,1)
#print(-np.dot(n0,n)*np.dot(n1,n))
n_avg = (n0+n1)/2
a = np.dot(n_avg,n)
first_angle = np.arccos(np.dot(n0,n))
second_angle = np.arccos(np.dot(n1,n))
#l0 = ((x0-x)**(2)+(y0-y)**(2)+(z0-z)**(2))**(1/2)
#l1 = ((x1-x)**(2)+(y1-y)**(2)+(z1-z)**(2))**(1/2)
mx = (x0+x1)/2
my = (y0+y1)/2
mz = (z0+z1)/2
lm1 = ((x0-x)**(2)+(y0-y)**(2)+(z0-z)**(2))**(1/2)
lm2 = ((x1-x)**(2)+(y1-y)**(2)+(z1-z)**(2))**(1/2)
#d = (((x1-x0)**(2)+(y1-y0)**(2)+(z1-z0)**(2))**(1/2))/2
#d = d/2
lm = abs(lm1-lm2)/(lm1+lm2)
c = 0
if contour_check(interp_xyz,interp_r,t0,t,radius_buffer=radius_buffer,n_sides=n_sides):
c = 100
if contour_check(interp_xyz,interp_r,t1,t,radius_buffer=radius_buffer,n_sides=n_sides):
c += 100
if np.sin(first_angle)*(r0+r) > lm1:
c += 100
if np.sin(second_angle)*(r1+r) > lm2:
c += 100
#return -(a*b+(1-abs(a-b))) + c # + abs(l0-l1)
return -(a) + c + lm/100
result = optimize.minimize_scalar(func,bounds=(t0+t_bound_buff,t1-t_bound_buff),method='bounded')
return result.x,result.fun
[docs]def swap_worst_contour(interp_xyz,t_list,radius_buffer,thresh=20):
normal_list = []
nx,ny,nz,_ = splev(0,interp_xyz[0],der=1)
normal = np.array([nx,ny,nz])
normal = normal/np.linalg.norm(normal)
normal_list.append(normal)
#next_nx,next_ny,next_nz,_ = splev(t_list[1],interp_xyz[kdx][0],der=1)
#next_normal = np.array([next_nx,next_ny,next_nz])
#next_normal = next_normal/np.linalg.norm(next_normal)
#angle = abs((np.arccos(np.dot(normal_list[-1],next_normal.T))/np.pi)*180)
#scores = [angle]
scores = []
total = len(t_list[1:-1])
desc5 = 'Computing swap scores'
desc5 = desc5+' '*(40-len(desc5))
with tqdm(total=total,bar_format='{l_bar}{bar:10}{r_bar}{bar:-10b}',position=4,leave=False,desc=desc5) as pbar:
for idx,ct in enumerate(t_list[1:-1]):
next_t = t_list[idx+2]
nx,ny,nz,_ = splev(ct,interp_xyz[0],der=1)
normal = np.array([nx,ny,nz])
normal = normal/np.linalg.norm(normal)
angle0 = abs((np.arccos(np.dot(normal_list[-1],normal.T))/np.pi)*180)
next_nx,next_ny,next_nz,_ = splev(next_t,interp_xyz[0],der=1)
t_next_normal = np.array([next_nx,next_ny,next_nz])
t_next_normal = t_next_normal/np.linalg.norm(t_next_normal)
angle1 = abs((np.arccos(np.dot(normal,t_next_normal.T))/np.pi)*180)
scores.append(angle0+angle1)
normal_list.append(normal)
pbar.update(1)
worst_idx = np.argwhere(np.array(scores)>thresh).flatten()+1
worst_idx = worst_idx.tolist()
for wi in worst_idx:
t = t_list[wi]
t0,f0 = optimize_contour(t_list[wi-1],t_list[wi+1],interp_xyz,None,radius_buffer,t_buffer=0.1,n_sides=50)
if f0 < 0:
t_list[wi] = t0
return t_list,worst_idx
[docs]def swap_contour(interp_xyz,t_list,c_idx,radius_buffer):
value = t_list[c_idx]
t0,f0 = optimize_contour(t_list[c_idx-1],t_list[c_idx+1],interp_xyz,None,radius_buffer,t_buffer=0.1,n_sides=50)
if f0 < 0:
value = t0
return value
[docs]def truncate(data,radius=None,indicies=None):
if radius is None and indicies is None:
radius = np.median(data[:,21])
branches = get_branches(data)
include = []
exclude = []
for branch in branches:
tmp_include = []
tmp_exclude = []
for idx,vdx in enumerate(branch):
if indicies is None:
if data[vdx,21] >= radius:
tmp_include.append(vdx)
else:
tmp_exclude.append(vdx)
else:
if vdx in indicies:
tmp_include.append(vdx)
else:
tmp_exclude.append(vdx)
if len(tmp_include) > 1:
include.append(tmp_include)
if len(tmp_exclude) > 0:
exclude.append(tmp_exclude)
return include, exclude
[docs]def get_truncated_interpolated_sv_data(data,radius=None,indicies=None):
branches,_ = truncate(data,radius=radius,indicies=indicies)
points = get_points(data,branches)
#print("Points: {}".format(points[0]))
radii = get_radii(data,branches)
#print("Radii: {}".format(radii[0]))
normals = get_normals(data,branches)
path_frames = []
for idx in range(len(branches)):
frames = []
for jdx in range(len(points[idx])):
frame = []
frame.extend(points[idx][jdx])
frame.append(radii[idx][jdx])
frame.extend(normals[idx][jdx])
frames.append(frame)
path_frames.append(frames)
interp_xyz = []
interp_r = []
interp_n = []
interp_xyzr = []
for idx in range(len(branches)):
p = np.array(points[idx]).T
r = np.array(radii[idx]).T
n = np.array(normals[idx]).T
if len(points[idx]) == 2:
interp_xyz.append(splprep(p,k=1,s=0))
rr = np.vstack((interp_xyz[-1][1],r))
interp_r.append(splprep(rr,k=1,s=0))
xyzr = np.vstack((p,r))
interp_xyzr.append(splprep(xyzr,k=1,s=0))
#interp_n.append(splprep(n,k=1,s=0))
elif len(points[idx]) == 3:
interp_xyz.append(splprep(p,k=2,s=0))
rr = np.vstack((interp_xyz[-1][1],r))
interp_r.append(splprep(rr,k=2,s=0))
xyzr = np.vstack((p,r))
interp_xyzr.append(splprep(xyzr,k=2,s=0))
#interp_n.append(splprep(n,k=2,s=0))
else:
interp_xyz.append(splprep(p,s=0))
rr = np.vstack((interp_xyz[-1][1],r))
interp_r.append(splprep(rr,s=0))
xyzr = np.vstack((p,r))
interp_xyzr.append(splprep(xyzr,s=0))
#interp_n.append(splprep(n,s=0))
return interp_xyz,interp_r,interp_n,path_frames,branches,interp_xyzr