blob: 959b382c11b92c875b7b7583647e6404bcf6f660 [file] [log] [blame]
Tabitha Jarvis1007a132018-12-12 21:47:54 -08001#!/usr/bin/python3
Tabitha Jarvis1007a132018-12-12 21:47:54 -08002from __future__ import print_function
3import os
Andrew Runke0f945fd2019-01-27 21:10:37 -08004import sys
Ravago Jones6d460fe2021-07-03 16:59:55 -07005from color import palette
6from graph import Graph
Tabitha Jarvis1007a132018-12-12 21:47:54 -08007import gi
8import numpy as np
Tabitha Jarvis1007a132018-12-12 21:47:54 -08009gi.require_version('Gtk', '3.0')
John Park91e69732019-03-03 13:12:43 -080010gi.require_version('Gdk', '3.0')
Andrew Runke6842bf92019-01-26 15:38:25 -080011from gi.repository import Gdk, Gtk, GLib
Tabitha Jarvis1007a132018-12-12 21:47:54 -080012import cairo
Ravago Jones6d460fe2021-07-03 16:59:55 -070013from libspline import Spline
Tabitha Jarvis1007a132018-12-12 21:47:54 -080014import enum
John Park91e69732019-03-03 13:12:43 -080015import json
Ravago Jones797c49c2021-07-31 14:51:59 -070016from constants import FIELD
17from constants import get_json_folder
18from constants import ROBOT_SIDE_TO_BALL_CENTER, ROBOT_SIDE_TO_HATCH_PANEL, HATCH_PANEL_WIDTH, BALL_RADIUS
Ravago Jones6d460fe2021-07-03 16:59:55 -070019from drawing_constants import set_color, draw_px_cross, draw_px_x, display_text, draw_control_points
John Park91e69732019-03-03 13:12:43 -080020from points import Points
Ravago Jones6d460fe2021-07-03 16:59:55 -070021import time
Andrew Runke6842bf92019-01-26 15:38:25 -080022
Tabitha Jarvis1007a132018-12-12 21:47:54 -080023
24class Mode(enum.Enum):
25 kViewing = 0
26 kPlacing = 1
27 kEditing = 2
Andrew Runke6842bf92019-01-26 15:38:25 -080028
29
Ravago Jones6d460fe2021-07-03 16:59:55 -070030class FieldWidget(Gtk.DrawingArea):
Andrew Runke6842bf92019-01-26 15:38:25 -080031 """Create a GTK+ widget on which we will draw using Cairo"""
Ravago Jones26f7ad02021-02-05 15:45:59 -080032
Tabitha Jarvis1007a132018-12-12 21:47:54 -080033 def __init__(self):
Ravago Jones6d460fe2021-07-03 16:59:55 -070034 super(FieldWidget, self).__init__()
Ravago Jones797c49c2021-07-31 14:51:59 -070035 self.set_size_request(
36 self.mToPx(FIELD.width), self.mToPx(FIELD.length))
Tabitha Jarvis1007a132018-12-12 21:47:54 -080037
John Park91e69732019-03-03 13:12:43 -080038 self.points = Points()
Ravago Jones6d460fe2021-07-03 16:59:55 -070039 self.graph = Graph()
40 self.set_vexpand(True)
41 self.set_hexpand(True)
John Park91e69732019-03-03 13:12:43 -080042
Tabitha Jarvis1007a132018-12-12 21:47:54 -080043 # init field drawing
44 # add default spline for testing purposes
45 # init editing / viewing modes and pointer location
46 self.mode = Mode.kPlacing
Ravago Jones6d460fe2021-07-03 16:59:55 -070047 self.mousex = 0
48 self.mousey = 0
49 self.module_path = os.path.dirname(os.path.realpath(sys.argv[0]))
50 self.path_to_export = os.path.join(self.module_path,
John Park91e69732019-03-03 13:12:43 -080051 'points_for_pathedit.json')
52
Tabitha Jarvis1007a132018-12-12 21:47:54 -080053 # For the editing mode
Andrew Runke6842bf92019-01-26 15:38:25 -080054 self.index_of_edit = -1 # Can't be zero beause array starts at 0
Tabitha Jarvis1007a132018-12-12 21:47:54 -080055 self.held_x = 0
Andrew Runke6842bf92019-01-26 15:38:25 -080056 self.spline_edit = -1
Tabitha Jarvis1007a132018-12-12 21:47:54 -080057
Ravago Jones797c49c2021-07-31 14:51:59 -070058 self.transform = cairo.Matrix()
59
Ravago Jonesc26b9162021-06-30 20:12:48 -070060 try:
Ravago Jones6d460fe2021-07-03 16:59:55 -070061 self.field_png = cairo.ImageSurface.create_from_png(
62 "frc971/control_loops/python/field_images/" + FIELD.field_id +
63 ".png")
Ravago Jonesc26b9162021-06-30 20:12:48 -070064 except cairo.Error:
65 self.field_png = None
66
Ravago Jones797c49c2021-07-31 14:51:59 -070067 # returns the transform from widget space to field space
68 @property
69 def input_transform(self):
70 xx, yx, xy, yy, x0, y0 = self.transform
71 matrix = cairo.Matrix(xx, yx, xy, yy, x0, y0)
72 # the transform for input needs to be the opposite of the transform for drawing
73 matrix.invert()
74 return matrix
75
76 # returns the scale from pixels in field space to meters in field space
77 def pxToM_scale(self):
78 available_space = self.get_allocation()
79 return np.maximum(FIELD.width / available_space.width,
80 FIELD.length / available_space.height)
81
82 def pxToM(self, p):
83 return p * self.pxToM_scale()
84
85 def mToPx(self, m):
86 return m / self.pxToM_scale()
87
John Park91e69732019-03-03 13:12:43 -080088 def draw_robot_at_point(self, cr, i, p, spline):
Ravago Jones797c49c2021-07-31 14:51:59 -070089 p1 = [self.mToPx(spline.Point(i)[0]), self.mToPx(spline.Point(i)[1])]
90 p2 = [
91 self.mToPx(spline.Point(i + p)[0]),
92 self.mToPx(spline.Point(i + p)[1])
93 ]
Tabitha Jarvis1007a132018-12-12 21:47:54 -080094
John Park91e69732019-03-03 13:12:43 -080095 #Calculate Robot
96 distance = np.sqrt((p2[1] - p1[1])**2 + (p2[0] - p1[0])**2)
97 x_difference_o = p2[0] - p1[0]
98 y_difference_o = p2[1] - p1[1]
Ravago Jones797c49c2021-07-31 14:51:59 -070099 x_difference = x_difference_o * self.mToPx(
Ravago Jones6d460fe2021-07-03 16:59:55 -0700100 FIELD.robot.length / 2) / distance
Ravago Jones797c49c2021-07-31 14:51:59 -0700101 y_difference = y_difference_o * self.mToPx(
Ravago Jones6d460fe2021-07-03 16:59:55 -0700102 FIELD.robot.length / 2) / distance
John Park91e69732019-03-03 13:12:43 -0800103
104 front_middle = []
105 front_middle.append(p1[0] + x_difference)
106 front_middle.append(p1[1] + y_difference)
107
108 back_middle = []
109 back_middle.append(p1[0] - x_difference)
110 back_middle.append(p1[1] - y_difference)
111
112 slope = [-(1 / x_difference_o) / (1 / y_difference_o)]
113 angle = np.arctan(slope)
114
Ravago Jones797c49c2021-07-31 14:51:59 -0700115 x_difference = np.sin(angle[0]) * self.mToPx(FIELD.robot.width / 2)
116 y_difference = np.cos(angle[0]) * self.mToPx(FIELD.robot.width / 2)
John Park91e69732019-03-03 13:12:43 -0800117
118 front_1 = []
119 front_1.append(front_middle[0] - x_difference)
120 front_1.append(front_middle[1] - y_difference)
121
122 front_2 = []
123 front_2.append(front_middle[0] + x_difference)
124 front_2.append(front_middle[1] + y_difference)
125
126 back_1 = []
127 back_1.append(back_middle[0] - x_difference)
128 back_1.append(back_middle[1] - y_difference)
129
130 back_2 = []
131 back_2.append(back_middle[0] + x_difference)
132 back_2.append(back_middle[1] + y_difference)
133
Ravago Jones797c49c2021-07-31 14:51:59 -0700134 x_difference = x_difference_o * self.mToPx(
Ravago Jones5e09c072021-03-27 13:21:03 -0700135 FIELD.robot.length / 2 + ROBOT_SIDE_TO_BALL_CENTER) / distance
Ravago Jones797c49c2021-07-31 14:51:59 -0700136 y_difference = y_difference_o * self.mToPx(
Ravago Jones5e09c072021-03-27 13:21:03 -0700137 FIELD.robot.length / 2 + ROBOT_SIDE_TO_BALL_CENTER) / distance
John Park91e69732019-03-03 13:12:43 -0800138
139 #Calculate Ball
140 ball_center = []
141 ball_center.append(p1[0] + x_difference)
142 ball_center.append(p1[1] + y_difference)
143
Ravago Jones797c49c2021-07-31 14:51:59 -0700144 x_difference = x_difference_o * self.mToPx(
Ravago Jones5e09c072021-03-27 13:21:03 -0700145 FIELD.robot.length / 2 + ROBOT_SIDE_TO_HATCH_PANEL) / distance
Ravago Jones797c49c2021-07-31 14:51:59 -0700146 y_difference = y_difference_o * self.mToPx(
Ravago Jones5e09c072021-03-27 13:21:03 -0700147 FIELD.robot.length / 2 + ROBOT_SIDE_TO_HATCH_PANEL) / distance
John Park91e69732019-03-03 13:12:43 -0800148
149 #Calculate Panel
150 panel_center = []
151 panel_center.append(p1[0] + x_difference)
152 panel_center.append(p1[1] + y_difference)
153
Ravago Jones797c49c2021-07-31 14:51:59 -0700154 x_difference = np.sin(angle[0]) * self.mToPx(HATCH_PANEL_WIDTH / 2)
155 y_difference = np.cos(angle[0]) * self.mToPx(HATCH_PANEL_WIDTH / 2)
John Park91e69732019-03-03 13:12:43 -0800156
157 panel_1 = []
158 panel_1.append(panel_center[0] + x_difference)
159 panel_1.append(panel_center[1] + y_difference)
160
161 panel_2 = []
162 panel_2.append(panel_center[0] - x_difference)
163 panel_2.append(panel_center[1] - y_difference)
164
165 #Draw Robot
166 cr.move_to(front_1[0], front_1[1])
167 cr.line_to(back_1[0], back_1[1])
168 cr.line_to(back_2[0], back_2[1])
169 cr.line_to(front_2[0], front_2[1])
170 cr.line_to(front_1[0], front_1[1])
171
172 cr.stroke()
173
174 #Draw Ball
175 set_color(cr, palette["ORANGE"], 0.5)
176 cr.move_to(back_middle[0], back_middle[1])
177 cr.line_to(ball_center[0], ball_center[1])
Ravago Jones797c49c2021-07-31 14:51:59 -0700178 cr.arc(ball_center[0], ball_center[1], self.mToPx(BALL_RADIUS), 0,
John Park91e69732019-03-03 13:12:43 -0800179 2 * np.pi)
180 cr.stroke()
181
182 #Draw Panel
183 set_color(cr, palette["YELLOW"], 0.5)
184 cr.move_to(panel_1[0], panel_1[1])
185 cr.line_to(panel_2[0], panel_2[1])
186
187 cr.stroke()
188 cr.set_source_rgba(0, 0, 0, 1)
189
Ravago Jones6d460fe2021-07-03 16:59:55 -0700190 def do_draw(self, cr): # main
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800191
Ravago Jones6d460fe2021-07-03 16:59:55 -0700192 start_time = time.perf_counter()
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800193
Ravago Jones797c49c2021-07-31 14:51:59 -0700194 cr.set_matrix(self.transform.multiply(cr.get_matrix()))
195
James Kuszmaul1c933e02020-03-07 16:17:51 -0800196 cr.save()
Ravago Jones797c49c2021-07-31 14:51:59 -0700197
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800198 set_color(cr, palette["BLACK"])
Ravago Jones5f787df2021-01-23 16:26:27 -0800199
Ravago Jones797c49c2021-07-31 14:51:59 -0700200 cr.set_line_width(1.0)
201 cr.rectangle(0, 0, self.mToPx(FIELD.width), self.mToPx(FIELD.length))
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800202 cr.set_line_join(cairo.LINE_JOIN_ROUND)
203 cr.stroke()
Ravago Jones5f787df2021-01-23 16:26:27 -0800204
Ravago Jonesc26b9162021-06-30 20:12:48 -0700205 if self.field_png:
206 cr.save()
Ravago Jonesc26b9162021-06-30 20:12:48 -0700207 cr.scale(
Ravago Jones797c49c2021-07-31 14:51:59 -0700208 self.mToPx(FIELD.width) / self.field_png.get_width(),
209 self.mToPx(FIELD.length) / self.field_png.get_height(),
Ravago Jones6d460fe2021-07-03 16:59:55 -0700210 )
Ravago Jonesc26b9162021-06-30 20:12:48 -0700211 cr.set_source_surface(self.field_png)
212 cr.paint()
213 cr.restore()
Andrew Runke6842bf92019-01-26 15:38:25 -0800214
John Park91e69732019-03-03 13:12:43 -0800215 # update everything
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800216
Ravago Jones797c49c2021-07-31 14:51:59 -0700217 cr.set_line_width(2.0)
John Park91e69732019-03-03 13:12:43 -0800218 if self.mode == Mode.kPlacing or self.mode == Mode.kViewing:
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800219 set_color(cr, palette["BLACK"])
Ravago Jones36c92f02021-07-24 16:35:33 -0700220 for i, point in enumerate(self.points.getPoints()):
Ravago Jones797c49c2021-07-31 14:51:59 -0700221 draw_px_x(cr, self.mToPx(point[0]), self.mToPx(point[1]), 10)
John Park91e69732019-03-03 13:12:43 -0800222 set_color(cr, palette["WHITE"])
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800223 elif self.mode == Mode.kEditing:
224 set_color(cr, palette["BLACK"])
John Park91e69732019-03-03 13:12:43 -0800225 if self.points.getSplines():
226 self.draw_splines(cr)
227 for i, points in enumerate(self.points.getSplines()):
Andrew Runke6842bf92019-01-26 15:38:25 -0800228
Ravago Jones36c92f02021-07-24 16:35:33 -0700229 points = [
Ravago Jones797c49c2021-07-31 14:51:59 -0700230 np.array([self.mToPx(x), self.mToPx(y)])
Ravago Jones36c92f02021-07-24 16:35:33 -0700231 for (x, y) in points
232 ]
233 draw_control_points(cr, points)
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800234
Ravago Jones36c92f02021-07-24 16:35:33 -0700235 p0, p1, p2, p3, p4, p5 = points
John Park91e69732019-03-03 13:12:43 -0800236 first_tangent = p0 + 2.0 * (p1 - p0)
237 second_tangent = p5 + 2.0 * (p4 - p5)
238 cr.set_source_rgb(0, 0.5, 0)
239 cr.move_to(p0[0], p0[1])
240 cr.set_line_width(1.0)
241 cr.line_to(first_tangent[0], first_tangent[1])
242 cr.move_to(first_tangent[0], first_tangent[1])
243 cr.line_to(p2[0], p2[1])
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800244
John Park91e69732019-03-03 13:12:43 -0800245 cr.move_to(p5[0], p5[1])
246 cr.line_to(second_tangent[0], second_tangent[1])
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800247
John Park91e69732019-03-03 13:12:43 -0800248 cr.move_to(second_tangent[0], second_tangent[1])
249 cr.line_to(p3[0], p3[1])
250
251 cr.stroke()
252 cr.set_line_width(2.0)
John Park91e69732019-03-03 13:12:43 -0800253 set_color(cr, palette["WHITE"])
254
255 cr.paint_with_alpha(0.2)
256
Ravago Jones6d460fe2021-07-03 16:59:55 -0700257 draw_px_cross(cr, self.mousex, self.mousey, 10)
James Kuszmaul1c933e02020-03-07 16:17:51 -0800258 cr.restore()
Ravago Jones6d460fe2021-07-03 16:59:55 -0700259
John Park91e69732019-03-03 13:12:43 -0800260 def draw_splines(self, cr):
John Park91e69732019-03-03 13:12:43 -0800261 for i, points in enumerate(self.points.getSplines()):
262 array = np.zeros(shape=(6, 2), dtype=float)
263 for j, point in enumerate(points):
264 array[j, 0] = point[0]
265 array[j, 1] = point[1]
266 spline = Spline(np.ascontiguousarray(np.transpose(array)))
267 for k in np.linspace(0.01, 1, 100):
Ravago Jones26f7ad02021-02-05 15:45:59 -0800268 cr.move_to(
Ravago Jones797c49c2021-07-31 14:51:59 -0700269 self.mToPx(spline.Point(k - 0.01)[0]),
270 self.mToPx(spline.Point(k - 0.01)[1]))
Ravago Jones26f7ad02021-02-05 15:45:59 -0800271 cr.line_to(
Ravago Jones797c49c2021-07-31 14:51:59 -0700272 self.mToPx(spline.Point(k)[0]),
273 self.mToPx(spline.Point(k)[1]))
John Park91e69732019-03-03 13:12:43 -0800274 cr.stroke()
John Park91e69732019-03-03 13:12:43 -0800275 if i == 0:
276 self.draw_robot_at_point(cr, 0.00, 0.01, spline)
277 self.draw_robot_at_point(cr, 1, 0.01, spline)
John Park91e69732019-03-03 13:12:43 -0800278
279 def mouse_move(self, event):
Ravago Jones6d460fe2021-07-03 16:59:55 -0700280 old_x = self.mousex
281 old_y = self.mousey
Ravago Jones797c49c2021-07-31 14:51:59 -0700282 self.mousex, self.mousey = self.input_transform.transform_point(
283 event.x, event.y)
Ravago Jones6d460fe2021-07-03 16:59:55 -0700284 dif_x = self.mousex - old_x
285 dif_y = self.mousey - old_y
Ravago Jones797c49c2021-07-31 14:51:59 -0700286 difs = np.array([self.pxToM(dif_x), self.pxToM(dif_y)])
John Park91e69732019-03-03 13:12:43 -0800287
Ravago Jones128fb992021-07-31 13:56:58 -0700288 if self.mode == Mode.kEditing and self.spline_edit != -1:
Ravago Jones6d460fe2021-07-03 16:59:55 -0700289 self.points.updates_for_mouse_move(self.index_of_edit,
Ravago Jones36c92f02021-07-24 16:35:33 -0700290 self.spline_edit,
Ravago Jones797c49c2021-07-31 14:51:59 -0700291 self.pxToM(self.mousex),
292 self.pxToM(self.mousey), difs)
John Park91e69732019-03-03 13:12:43 -0800293
Ravago Jones128fb992021-07-31 13:56:58 -0700294 self.points.update_lib_spline()
Ravago Jones56941a52021-07-31 14:42:38 -0700295 self.graph.schedule_recalculate(self.points)
Ravago Jones128fb992021-07-31 13:56:58 -0700296 self.queue_draw()
297
John Park909c0392020-03-05 23:56:30 -0800298 def export_json(self, file_name):
Ravago Jones09f59722021-03-03 21:11:41 -0800299 self.path_to_export = os.path.join(
300 self.module_path, # position of the python
301 "../../..", # root of the repository
302 get_json_folder(FIELD), # path from the root
303 file_name # selected file
304 )
Ravago Jones3b92afa2021-02-05 14:27:32 -0800305
Ravago Jones6d460fe2021-07-03 16:59:55 -0700306 # Will export to json file
307 multi_spline = self.points.toMultiSpline()
308 print(multi_spline)
309 with open(self.path_to_export, mode='w') as points_file:
310 json.dump(multi_spline, points_file)
John Park909c0392020-03-05 23:56:30 -0800311
312 def import_json(self, file_name):
Ravago Jones09f59722021-03-03 21:11:41 -0800313 self.path_to_export = os.path.join(
314 self.module_path, # position of the python
315 "../../..", # root of the repository
316 get_json_folder(FIELD), # path from the root
317 file_name # selected file
318 )
319
Ravago Jones6d460fe2021-07-03 16:59:55 -0700320 # import from json file
321 print("LOADING LOAD FROM " + file_name) # Load takes a few seconds
322 with open(self.path_to_export) as points_file:
323 multi_spline = json.load(points_file)
John Park909c0392020-03-05 23:56:30 -0800324
Ravago Jones6d460fe2021-07-03 16:59:55 -0700325 # if people messed with the spline json,
326 # it might not be the right length
327 # so give them a nice error message
328 try: # try to salvage as many segments of the spline as possible
329 self.points.fromMultiSpline(multi_spline)
330 except IndexError:
331 # check if they're both 6+5*(k-1) long
332 expected_length = 6 + 5 * (multi_spline["spline_count"] - 1)
333 x_len = len(multi_spline["spline_x"])
334 y_len = len(multi_spline["spline_x"])
335 if x_len is not expected_length:
336 print(
337 "Error: spline x values were not the expected length; expected {} got {}"
338 .format(expected_length, x_len))
339 elif y_len is not expected_length:
340 print(
341 "Error: spline y values were not the expected length; expected {} got {}"
342 .format(expected_length, y_len))
Ravago Jones3b92afa2021-02-05 14:27:32 -0800343
Ravago Jones6d460fe2021-07-03 16:59:55 -0700344 print("SPLINES LOADED")
345 self.mode = Mode.kEditing
John Park909c0392020-03-05 23:56:30 -0800346
Ravago Jones128fb992021-07-31 13:56:58 -0700347 def key_press(self, event):
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800348 keyval = Gdk.keyval_to_lower(event.keyval)
John Park91e69732019-03-03 13:12:43 -0800349
Ravago Jones6d460fe2021-07-03 16:59:55 -0700350 # TODO: This should be a button
Andrew Runke6842bf92019-01-26 15:38:25 -0800351 if keyval == Gdk.KEY_p:
352 self.mode = Mode.kPlacing
353 # F0 = A1
354 # B1 = 2F0 - E0
355 # C1= d0 + 4F0 - 4E0
John Park91e69732019-03-03 13:12:43 -0800356 spline_index = len(self.points.getSplines()) - 1
357 self.points.resetPoints()
358 self.points.extrapolate(
359 self.points.getSplines()[len(self.points.getSplines()) - 1][5],
360 self.points.getSplines()[len(self.points.getSplines()) - 1][4],
361 self.points.getSplines()[len(self.points.getSplines()) - 1][3])
Ravago Jones128fb992021-07-31 13:56:58 -0700362 self.queue_draw()
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800363
Ravago Jones6d460fe2021-07-03 16:59:55 -0700364 def button_press(self, event):
Ravago Jones797c49c2021-07-31 14:51:59 -0700365 self.mousex, self.mousey = self.input_transform.transform_point(
366 event.x, event.y)
Ravago Jones6d460fe2021-07-03 16:59:55 -0700367
Andrew Runke6842bf92019-01-26 15:38:25 -0800368 if self.mode == Mode.kPlacing:
Ravago Jones36c92f02021-07-24 16:35:33 -0700369 if self.points.add_point(
Ravago Jones797c49c2021-07-31 14:51:59 -0700370 self.pxToM(self.mousex), self.pxToM(self.mousey)):
John Park91e69732019-03-03 13:12:43 -0800371 self.mode = Mode.kEditing
Andrew Runke6842bf92019-01-26 15:38:25 -0800372 elif self.mode == Mode.kEditing:
373 # Now after index_of_edit is not -1, the point is selected, so
374 # user can click for new point
Ravago Jones128fb992021-07-31 13:56:58 -0700375 if self.index_of_edit == -1:
Andrew Runke6842bf92019-01-26 15:38:25 -0800376 # Get clicked point
377 # Find nearest
378 # Move nearest to clicked
Ravago Jones797c49c2021-07-31 14:51:59 -0700379 cur_p = [self.pxToM(self.mousex), self.pxToM(self.mousey)]
Andrew Runke6842bf92019-01-26 15:38:25 -0800380 # Get the distance between each for x and y
381 # Save the index of the point closest
John Park13d3e282019-01-26 20:16:48 -0800382 nearest = 1 # Max distance away a the selected point can be in meters
Andrew Runke6842bf92019-01-26 15:38:25 -0800383 index_of_closest = 0
James Kuszmaul1c933e02020-03-07 16:17:51 -0800384 for index_splines, points in enumerate(
385 self.points.getSplines()):
Andrew Runke6842bf92019-01-26 15:38:25 -0800386 for index_points, val in enumerate(points):
Andrew Runke6842bf92019-01-26 15:38:25 -0800387 distance = np.sqrt((cur_p[0] - val[0])**2 +
388 (cur_p[1] - val[1])**2)
389 if distance < nearest:
390 nearest = distance
391 index_of_closest = index_points
392 print("Nearest: " + str(nearest))
393 print("Index: " + str(index_of_closest))
394 self.index_of_edit = index_of_closest
395 self.spline_edit = index_splines
Ravago Jones6d460fe2021-07-03 16:59:55 -0700396 self.held_x = self.mousex
Ravago Jones128fb992021-07-31 13:56:58 -0700397 self.queue_draw()
398
399 def button_release(self, event):
Ravago Jones797c49c2021-07-31 14:51:59 -0700400 self.mousex, self.mousey = self.input_transform.transform_point(
401 event.x, event.y)
Ravago Jones128fb992021-07-31 13:56:58 -0700402 if self.mode == Mode.kEditing:
403 if self.index_of_edit > -1 and self.held_x != self.mousex:
404
405 self.points.setSplines(self.spline_edit, self.index_of_edit,
Ravago Jones797c49c2021-07-31 14:51:59 -0700406 self.pxToM(self.mousex),
407 self.pxToM(self.mousey))
Ravago Jones128fb992021-07-31 13:56:58 -0700408
409 self.points.splineExtrapolate(self.spline_edit)
410
411 self.points.update_lib_spline()
Ravago Jones56941a52021-07-31 14:42:38 -0700412 self.graph.schedule_recalculate(self.points)
Ravago Jones128fb992021-07-31 13:56:58 -0700413
414 self.index_of_edit = -1
415 self.spline_edit = -1
Ravago Jones01781202021-08-01 15:25:11 -0700416
417 def mouse_scroll(self, event):
418 self.mousex, self.mousey = self.input_transform.transform_point(
419 event.x, event.y)
420
421 step_size = 20 # px
422
423 if event.direction == Gdk.ScrollDirection.UP:
424 # zoom out
425 scale_by = step_size
426 elif event.direction == Gdk.ScrollDirection.DOWN:
427 # zoom in
428 scale_by = -step_size
429 else:
430 return
431
432 apparent_width, apparent_height = self.transform.transform_distance(
433 self.mToPx(FIELD.width), self.mToPx(FIELD.length))
434 scale = (apparent_width + scale_by) / apparent_width
435
436 # scale from point in field coordinates
437 point = self.mousex, self.mousey
438
439 # move the origin to point
440 self.transform.translate(point[0], point[1])
441
442 # scale from new origin
443 self.transform.scale(scale, scale)
444
445 # move back
446 self.transform.translate(-point[0], -point[1])
447
448 # snap to the edge when near 1x scaling
449 if 0.99 < self.transform.xx < 1.01 and -50 < self.transform.x0 < 50:
450 self.transform.x0 = 0
451 self.transform.y0 = 0
452 print("snap")
453
454 self.queue_draw()