blob: 868885a6c4b572c5d7feb0f7cee73f55232ca8c1 [file] [log] [blame]
John Park91e69732019-03-03 13:12:43 -08001from constants import *
2import numpy as np
Ravago Jonesb170ed32022-06-01 21:16:15 -07003import scipy.optimize
John Park91e69732019-03-03 13:12:43 -08004from libspline import Spline, DistanceSpline, Trajectory
Ravago Jones56941a52021-07-31 14:42:38 -07005import copy
John Park91e69732019-03-03 13:12:43 -08006
Ravago Jones8da89c42022-07-17 19:34:06 -07007
John Park91e69732019-03-03 13:12:43 -08008class Points():
9 def __init__(self):
10 self.points = [] # Holds all points not yet in spline
11 self.libsplines = [] # Formatted for libspline library usage
12 self.splines = [] # Formatted for drawing
Ravago Jones3b92afa2021-02-05 14:27:32 -080013 self.constraints = [ # default constraints
14 {
15 "constraint_type": "LONGITUDINAL_ACCELERATION",
16 "value": 3
17 }, {
18 "constraint_type": "LATERAL_ACCELERATION",
19 "value": 2
20 }, {
21 "constraint_type": "VOLTAGE",
22 "value": 10
23 }
24 ]
John Park91e69732019-03-03 13:12:43 -080025
Ravago Jones56941a52021-07-31 14:42:38 -070026 def __deepcopy__(self, memo):
27 new_copy = Points()
28 new_copy.points = copy.deepcopy(self.points, memo)
29 new_copy.splines = copy.deepcopy(self.splines, memo)
30 new_copy.constraints = copy.deepcopy(self.constraints, memo)
31 new_copy.update_lib_spline()
32 return new_copy
33
John Park91e69732019-03-03 13:12:43 -080034 def getPoints(self):
35 return self.points
36
37 def resetPoints(self):
38 self.points = []
39
40 def getLibsplines(self):
41 return self.libsplines
42
Ravago Jones3b92afa2021-02-05 14:27:32 -080043 def setConstraint(self, id, value):
44 for constraint in self.constraints:
45 if constraint["constraint_type"] == id:
46 constraint["value"] = value
47 break
48
kyle96e46e12021-02-10 21:47:55 -080049 def getConstraint(self, id):
50 for constraint in self.constraints:
51 if constraint["constraint_type"] == id:
52 return constraint["value"]
53
Ravago Jones3b92afa2021-02-05 14:27:32 -080054 def addConstraintsToTrajectory(self, trajectory):
55 for constraint in self.constraints:
56 if constraint["constraint_type"] == "VOLTAGE":
57 trajectory.SetVoltageLimit(constraint["value"])
58 elif constraint["constraint_type"] == "LATERAL_ACCELERATION":
59 trajectory.SetLateralAcceleration(constraint["value"])
60 elif constraint["constraint_type"] == "LONGITUDINAL_ACCELERATION":
61 trajectory.SetLongitudinalAcceleration(constraint["value"])
62
John Park91e69732019-03-03 13:12:43 -080063 def splineExtrapolate(self, o_spline_edit):
64 spline_edit = o_spline_edit
65 if not spline_edit == len(self.splines) - 1:
John Park91e69732019-03-03 13:12:43 -080066 f = self.splines[spline_edit][5]
67 e = self.splines[spline_edit][4]
68 d = self.splines[spline_edit][3]
James Kuszmaulb33b07c2021-02-25 22:39:24 -080069 self.splines[spline_edit + 1][0] = f
70 self.splines[spline_edit + 1][1] = f * 2 + e * -1
71 self.splines[spline_edit + 1][2] = d + f * 4 + e * -4
John Park91e69732019-03-03 13:12:43 -080072
73 if not spline_edit == 0:
John Park91e69732019-03-03 13:12:43 -080074 a = self.splines[spline_edit][0]
75 b = self.splines[spline_edit][1]
76 c = self.splines[spline_edit][2]
James Kuszmaulb33b07c2021-02-25 22:39:24 -080077 self.splines[spline_edit - 1][5] = a
78 self.splines[spline_edit - 1][4] = a * 2 + b * -1
79 self.splines[spline_edit - 1][3] = c + a * 4 + b * -4
John Park91e69732019-03-03 13:12:43 -080080
81 def updates_for_mouse_move(self, index_of_edit, spline_edit, x, y, difs):
82 if index_of_edit > -1:
Ravago Jones36c92f02021-07-24 16:35:33 -070083 self.splines[spline_edit][index_of_edit] = [x, y]
John Park91e69732019-03-03 13:12:43 -080084
85 if index_of_edit == 5:
86 self.splines[spline_edit][
87 index_of_edit -
88 2] = self.splines[spline_edit][index_of_edit - 2] + difs
89 self.splines[spline_edit][
90 index_of_edit -
91 1] = self.splines[spline_edit][index_of_edit - 1] + difs
92
93 if index_of_edit == 0:
94 self.splines[spline_edit][
95 index_of_edit +
96 2] = self.splines[spline_edit][index_of_edit + 2] + difs
97 self.splines[spline_edit][
98 index_of_edit +
99 1] = self.splines[spline_edit][index_of_edit + 1] + difs
100
101 if index_of_edit == 4:
102 self.splines[spline_edit][
103 index_of_edit -
104 1] = self.splines[spline_edit][index_of_edit - 1] + difs
105
106 if index_of_edit == 1:
107 self.splines[spline_edit][
108 index_of_edit +
109 1] = self.splines[spline_edit][index_of_edit + 1] + difs
110
James Kuszmaulb33b07c2021-02-25 22:39:24 -0800111 self.splineExtrapolate(spline_edit)
John Park91e69732019-03-03 13:12:43 -0800112
113 def update_lib_spline(self):
114 self.libsplines = []
115 array = np.zeros(shape=(6, 2), dtype=float)
116 for points in self.splines:
117 for j, point in enumerate(points):
118 array[j, 0] = point[0]
119 array[j, 1] = point[1]
120 spline = Spline(np.ascontiguousarray(np.transpose(array)))
121 self.libsplines.append(spline)
122
Ravago Jonesb170ed32022-06-01 21:16:15 -0700123 def nearest_distance(self, point):
124 """Finds the distance along the DistanceSpline that is closest to the
125 given point on the field"""
126 def distance(t, distance_spline, point):
127 return np.sum((distance_spline.XY(t) - point)**2)
128
129 # We know the derivative of the function,
130 # so scipy doesn't need to compute it every time
131 def ddistance(t, distance_spline, point):
132 return np.sum(2 * (distance_spline.XY(t) - point) *
133 distance_spline.DXY(t))
134
135 distance_spline = DistanceSpline(self.getLibsplines())
136 best_result = None
137
138 # The optimizer finds local minima that often aren't what we want,
139 # so try from multiple locations to find a better minimum.
140 guess_points = np.linspace(0, distance_spline.Length(), num=5)
141
142 for guess in guess_points:
143 result = scipy.optimize.minimize(
144 distance,
145 guess,
146 args=(distance_spline, point),
147 bounds=((0, distance_spline.Length()), ),
148 jac=ddistance,
149 )
150
151 if result.success and (best_result == None
152 or result.fun < best_result.fun):
153 best_result = result
154
155 return best_result, distance_spline
156
Ravago Jones3b92afa2021-02-05 14:27:32 -0800157 def toMultiSpline(self):
158 multi_spline = {
159 "spline_count": 0,
160 "spline_x": [],
161 "spline_y": [],
162 "constraints": self.constraints,
163 }
164 for points in self.splines:
165 multi_spline["spline_count"] += 1
166 for j, point in enumerate(points):
167 if j == 0 and multi_spline["spline_count"] > 1:
168 continue # skip overlapping points
169 multi_spline["spline_x"].append(point[0])
170 multi_spline["spline_y"].append(point[1])
171 return multi_spline
172
173 def fromMultiSpline(self, multi_spline):
174 self.constraints = multi_spline["constraints"]
175 self.splines = []
176 self.points = []
177
178 i = 0
179 for j in range(multi_spline["spline_count"]):
180 # get the last point of the last spline
181 # and read in another 6 points
182 for i in range(i, i + 6):
183 self.points.append(
184 [multi_spline["spline_x"][i], multi_spline["spline_y"][i]])
185 self.splines.append(np.array(self.points))
186 self.points = []
187 self.update_lib_spline()
188
John Park91e69732019-03-03 13:12:43 -0800189 def getSplines(self):
190 return self.splines
191
John Park91e69732019-03-03 13:12:43 -0800192 def setSplines(self, spline_edit, index_of_edit, x, y):
193 self.splines[spline_edit][index_of_edit] = [x, y]
194
195 def add_point(self, x, y):
196 if (len(self.points) < 6):
Ravago Jones36c92f02021-07-24 16:35:33 -0700197 self.points.append([x, y])
John Park91e69732019-03-03 13:12:43 -0800198 if (len(self.points) == 6):
199 self.splines.append(np.array(self.points))
200 self.points = []
201 self.update_lib_spline()
202 return True
203
204 def extrapolate(self, point1, point2,
205 point3): # where point3 is 3rd to last point
206 self.points.append(point1)
207 self.points.append(point1 * 2 - point2)
208 self.points.append(point3 + point1 * 4 - point2 * 4)