utils3D.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. import numpy as np
  2. from numpy.matlib import repmat
  3. import pyrr as pyrr
  4. # plotting
  5. import matplotlib.pyplot as plt
  6. from mpl_toolkits.mplot3d import Axes3D
  7. from mpl_toolkits.mplot3d.art3d import Poly3DCollection
  8. import mpl_toolkits.mplot3d as plt3d
  9. def getRay(x, y):
  10. direc = [y[0] - x[0], y[1] - x[1], y[2] - x[2]]
  11. return np.array([x, direc])
  12. def getAABB(blocks):
  13. AABB = []
  14. for i in blocks:
  15. AABB.append(np.array([np.add(i[0:3], -0), np.add(i[3:6], 0)])) # make AABBs alittle bit of larger
  16. return AABB
  17. def getDist(pos1, pos2):
  18. return np.sqrt(sum([(pos1[0] - pos2[0]) ** 2, (pos1[1] - pos2[1]) ** 2, (pos1[2] - pos2[2]) ** 2]))
  19. def draw_block_list(ax, blocks):
  20. '''
  21. Subroutine used by draw_map() to display the environment blocks
  22. '''
  23. v = np.array([[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0], [0, 0, 1], [1, 0, 1], [1, 1, 1], [0, 1, 1]],
  24. dtype='float')
  25. f = np.array([[0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7], [0, 1, 2, 3], [4, 5, 6, 7]])
  26. # clr = blocks[:,6:]/255
  27. n = blocks.shape[0]
  28. d = blocks[:, 3:6] - blocks[:, :3]
  29. vl = np.zeros((8 * n, 3))
  30. fl = np.zeros((6 * n, 4), dtype='int64')
  31. # fcl = np.zeros((6*n,3))
  32. for k in range(n):
  33. vl[k * 8:(k + 1) * 8, :] = v * d[k] + blocks[k, :3]
  34. fl[k * 6:(k + 1) * 6, :] = f + k * 8
  35. # fcl[k*6:(k+1)*6,:] = clr[k,:]
  36. if type(ax) is Poly3DCollection:
  37. ax.set_verts(vl[fl])
  38. else:
  39. pc = Poly3DCollection(vl[fl], alpha=0.15, linewidths=1, edgecolors='k')
  40. # pc.set_facecolor(fcl)
  41. h = ax.add_collection3d(pc)
  42. return h
  43. ''' The following utils can be used for rrt or rrt*,
  44. required param initparams should have
  45. env, environement generated from env3D
  46. V, node set
  47. E, edge set
  48. i, nodes added
  49. maxiter, maximum iteration allowed
  50. stepsize, leaf growth restriction
  51. '''
  52. def sampleFree(initparams):
  53. '''biased sampling'''
  54. x = np.random.uniform(initparams.env.boundary[0:3], initparams.env.boundary[3:6])
  55. i = np.random.random()
  56. if isinside(initparams, x):
  57. return sampleFree(initparams)
  58. else:
  59. if i < 0.05:
  60. return initparams.env.goal
  61. else: return np.array(x)
  62. def isinside(initparams, x):
  63. '''see if inside obstacle'''
  64. for i in initparams.env.blocks:
  65. if i[0] <= x[0] < i[3] and i[1] <= x[1] < i[4] and i[2] <= x[2] < i[5]:
  66. return True
  67. return False
  68. def isCollide(initparams, x, y):
  69. '''see if line intersects obstacle'''
  70. ray = getRay(x, y)
  71. dist = getDist(x, y)
  72. for i in getAABB(initparams.env.blocks):
  73. shot = pyrr.geometric_tests.ray_intersect_aabb(ray, i)
  74. if shot is not None:
  75. dist_wall = getDist(x, shot)
  76. if dist_wall <= dist: # collide
  77. return True
  78. return False
  79. def nearest(initparams, x):
  80. V = np.array(initparams.V)
  81. if initparams.i == 0:
  82. return initparams.V[0]
  83. xr = repmat(x, len(V), 1)
  84. dists = np.linalg.norm(xr - V, axis=1)
  85. return initparams.V[np.argmin(dists)]
  86. def steer(initparams, x, y):
  87. direc = (y - x) / np.linalg.norm(y - x)
  88. xnew = x + initparams.stepsize * direc
  89. return xnew
  90. def near(initparams, x):
  91. # TODO: r = min{gamma*log(card(V)/card(V)1/d),eta}
  92. r = initparams.stepsize
  93. V = np.array(initparams.V)
  94. if initparams.i == 0:
  95. return initparams.V[0]
  96. xr = repmat(x, len(V), 1)
  97. inside = np.linalg.norm(xr - V, axis=1) < r
  98. nearpoints = V[inside]
  99. return np.array(nearpoints)
  100. def cost(initparams, x):
  101. '''here use the additive recursive cost function'''
  102. if all(x == initparams.env.start):
  103. return 0
  104. xparent = initparams.Parent[str(x[0])][str(x[1])][str(x[2])]
  105. return cost(initparams, xparent) + getDist(x, xparent)
  106. def visualization(initparams):
  107. V = np.array(initparams.V)
  108. E = initparams.E
  109. Path = np.array(initparams.Path)
  110. start = initparams.env.start
  111. goal = initparams.env.goal
  112. ax = plt.subplot(111, projection='3d')
  113. ax.view_init(elev=0., azim=90)
  114. ax.clear()
  115. draw_block_list(ax, initparams.env.blocks)
  116. edges = E.get_edge()
  117. if edges != []:
  118. for i in edges:
  119. xs = i[0][0], i[1][0]
  120. ys = i[0][1], i[1][1]
  121. zs = i[0][2], i[1][2]
  122. line = plt3d.art3d.Line3D(xs, ys, zs)
  123. ax.add_line(line)
  124. if Path != []:
  125. for i in Path:
  126. xs = i[0][0], i[1][0]
  127. ys = i[0][1], i[1][1]
  128. zs = i[0][2], i[1][2]
  129. line = plt3d.art3d.Line3D(xs, ys, zs, color='r')
  130. ax.add_line(line)
  131. ax.plot(start[0:1], start[1:2], start[2:], 'go', markersize=7, markeredgecolor='k')
  132. ax.plot(goal[0:1], goal[1:2], goal[2:], 'ro', markersize=7, markeredgecolor='k')
  133. ax.scatter3D(V[:, 0], V[:, 1], V[:, 2])
  134. plt.xlim(initparams.env.boundary[0], initparams.env.boundary[3])
  135. plt.ylim(initparams.env.boundary[1], initparams.env.boundary[4])
  136. ax.set_zlim(initparams.env.boundary[2], initparams.env.boundary[5])
  137. plt.xlabel('x')
  138. plt.ylabel('y')
  139. if not Path != []:
  140. plt.pause(0.001)
  141. else:
  142. plt.show()
  143. def path(initparams, Path=[], dist=0):
  144. x = initparams.env.goal
  145. while not all(x == initparams.env.start):
  146. x2 = initparams.Parent[str(x[0])][str(x[1])][str(x[2])]
  147. Path.append(np.array([x, x2]))
  148. dist += getDist(x, x2)
  149. x = x2
  150. return Path, dist
  151. class edgeset(object):
  152. def __init__(self):
  153. self.E = {}
  154. def hash(self,x):
  155. return str(x[0])+' '+str(x[1])+' '+str(x[2])
  156. def dehash(self,x):
  157. return np.array([float(i) for i in x.split(' ')])
  158. def add_edge(self,edge):
  159. x, y = self.hash(edge[0]),self.hash(edge[1])
  160. if x in self.E:
  161. self.E[x].append(y)
  162. else:
  163. self.E[x] = [y]
  164. def remove_edge(self,edge):
  165. x, y = edge[0],edge[1]
  166. self.E[self.hash(x)].remove(self.hash(y))
  167. def get_edge(self):
  168. edges = []
  169. for v in self.E:
  170. for n in self.E[v]:
  171. #if (n,v) not in edges:
  172. edges.append((self.dehash(v),self.dehash(n)))
  173. return edges
  174. if __name__ == '__main__':
  175. x = np.array([1.0,2.3,3.3])
  176. y = np.array([1.2,2.4,3.5])
  177. E = edgeset()
  178. E.add_edge([x,y])
  179. print(E.get_edge())
  180. E.remove_edge([x,y])
  181. print(E.get_edge())