Module Auto-GUI.auto_features.json_file_writer
Expand source code
import math
import uuid
from tkinter import messagebox
from auto_components.path_action_point import PathActionPoint
from miscellaneous.important_variables import *
from auto_features.path_creation import *
from auto_features.commands_retriever import commands_retriever
from miscellaneous.utility_functions import truncate
class JSONFileWriter:
"""The class that writes all the files"""
path_action_point_json_items = []
path_action_point_left_edge = 0
path_action_point_top_edge = 0
last_angle = 0
path_modifying_point_to_current_angle = {}
path_modifying_point_path_indexes_length = []
path_modifying_point_to_angle = {}
required_point_index_to_angle = {}
path_modifying_point_path_indexes = None
def write_file(self, file, all_path_modifying_points, all_path_action_points,
start_all_json_contents, first_required_point, last_required_point, placement_angle):
""""Writes the JSON file that the Auto Path code uses"""
self.last_angle = math.radians(placement_angle) # So it is converted to radians
self.path_modifying_point_path_indexes = get_path_modifying_point_path_indexes()
all_json_contents = start_all_json_contents
required_points = points.required_points
required_points = [first_required_point] + required_points + [last_required_point]
update_path_modifying_point_information(all_path_action_points, all_path_modifying_points, required_points)
# All the lists need an empty line after them and the last list does not need a comma
# ALso have to call the make_*_accurate because the input fields don't always reflect what the GUI shows
self.update_path_modifying_point_json(all_json_contents, all_path_modifying_points)
self.update_required_points_json(all_json_contents, required_points)
self.update_path_action_points_json(all_json_contents, all_path_action_points)
json.dump(all_json_contents, file, indent=JSON_MAX_INDENT)
def update_path_modifying_point_json(self, all_json_contents, path_modifying_points):
""" Updates 'all_json_contents' so it contains the 'path_modifying_points' in it, so the file that is eventually written
can contain all the information necessary for the Auto Path Follower"""
# The contents of the control points list
path_modifying_point_json_items = []
# So all_json_contents can now contain all the control points (and modifications to 'path_modifying_point_json_items' will be tracked
# How the GUI and Auto Follower name points is different, which is why these names are different
all_json_contents["ControlPoints"] = path_modifying_point_json_items
for path_modifying_point in path_modifying_points:
left_edge = path_modifying_point.get_field_left_edge()
top_edge = path_modifying_point.get_field_top_edge()
spline_order = path_modifying_point.get_spline_order()
new_path_modifying_point_list_item = {
"X": left_edge,
"Y": top_edge,
"Vx": path_modifying_point.get_horizontal_velocity(),
"Vy": path_modifying_point.get_vertical_velocity(),
"order": spline_order
}
path_modifying_point_json_items.append(new_path_modifying_point_list_item)
def update_required_points_json(self, all_json_contents, required_points):
""" Updates 'all_json_contents' so it contains the 'required_points' in it, so the file that is eventually written
can contain all the information necessary for the Auto Path Follower"""
# The contents of the control points list
required_points_json = []
# So all_json_contents can now contain all the required points (and modifications to 'required_points_json' will be tracked
all_json_contents["RequiredPoints"] = required_points_json
for required_point in required_points:
left_edge = required_point.get_field_left_edge()
top_edge = required_point.get_field_top_edge()
new_required_point_json = {
"X": left_edge,
"Y": top_edge,
"angle-GUI": required_point.get_angle(),
"angle": math.radians(required_point.get_angle()),
"t": required_point.get_t_value()
}
new_required_point_json_args = {}
new_required_point_json["args"] = new_required_point_json_args
new_required_point_json["isNeeded"] = required_point.is_needed
required_points_json.append(new_required_point_json)
def update_path_action_points_json(self, all_json_contents, all_path_action_points):
"""
Returns:
str: the path_action_points JSON"""
path_action_points = points.path_action_points
self.path_action_point_json_items = []
# How the GUI and Auto Follower define points is different, which is why the names are different here
all_json_contents["WayPoints"] = self.path_action_point_json_items
for path_action_point in path_action_points:
self.update_path_action_point_command_components_json(path_action_point)
def update_path_action_point_command_components_json(self, path_action_point: PathActionPoint):
"""Updates the command components; some commands are a conglomerate of 2+ commands, so this provides that architecture"""
base_command_name = path_action_point.get_command_name()
command_component_names = []
# If there are no components for that command, then the components should be 0
if commands_retriever.combined_commands.get(base_command_name) is not None:
# The first one should be ignored because that is the base command, which is already accounted for
command_component_names = commands_retriever.combined_commands.get(base_command_name)[1:]
self.path_action_point_left_edge, self.path_action_point_top_edge = path_action_point.get_field_left_edge(), path_action_point.get_field_top_edge()
base_command_unique_identifier = str(uuid.uuid4())[:4] # Only first 4 digits are needed for a unique value
self.update_path_action_point_command_json(path_action_point, base_command_name, base_command_unique_identifier, True, 0, path_action_point.is_needed)
# Have to set these, so the next point will be the closest to the point of the base command
index = get_t_value_path_index(path_action_point, points.path_modifying_point_path_indexes)
self.path_action_point_left_edge, self.path_action_point_top_edge = points.path_points[index]
for x in range(len(command_component_names)):
self.path_action_point_left_edge, self.path_action_point_top_edge = self.get_next_path_action_point_coordinates([self.path_action_point_left_edge, self.path_action_point_top_edge])
t_value = self.get_path_index_t_value([self.path_action_point_left_edge, self.path_action_point_top_edge])
path_action_point.set_t_value(t_value)
self.update_path_action_point_command_json(path_action_point, command_component_names[x],
base_command_unique_identifier, False, x + 1, path_action_point.is_needed)
def get_surrounding_path_modifying_point_indexes(self, path_index):
"""
Returns:
list[int]: {previous_path_modifying_point_index, next_path_modifying_point_index}; the indexes of the
path modifying points that are before and after the 'path_index'"""
previous_path_modifying_point_path_index = self.path_modifying_point_path_indexes[0]
next_path_modifying_point_path_index = self.path_modifying_point_path_indexes[1]
for path_modifying_point_path_index in self.path_modifying_point_path_indexes:
if (path_modifying_point_path_index > previous_path_modifying_point_path_index and
path_modifying_point_path_index <= path_index):
previous_path_modifying_point_path_index = path_modifying_point_path_index
if (path_modifying_point_path_index < next_path_modifying_point_path_index and
path_modifying_point_path_index >= path_index):
next_path_modifying_point_path_index = path_modifying_point_path_index
def update_path_action_point_command_json(self, path_action_point, base_command_name, base_command_unique_identifier, is_base_command, command_component_number, is_needed):
""" Updates the json for the base path modifying point command or command component- The data for all of these will be in
commands.json"""
new_path_action_point_json_item = {}
current_command_parameter_names = commands_retriever.get_command_parameter_base_names(base_command_name)
self.add_path_action_point_tracking_values(new_path_action_point_json_item, is_base_command, base_command_unique_identifier, command_component_number)
self.add_keys_and_values_to_dictionary(["X", "Y", "Speed", "Command", "t"],
[self.path_action_point_left_edge, self.path_action_point_top_edge, path_action_point.get_speed(),
base_command_name, path_action_point.get_t_value()],
new_path_action_point_json_item)
current_command_parameter_values = self.get_command_parameters_values(current_command_parameter_names,
path_action_point)
new_path_action_point_json_item_args = {}
new_path_action_point_json_item["args"] = new_path_action_point_json_item_args
self.add_keys_and_values_to_dictionary(current_command_parameter_names, current_command_parameter_values,
new_path_action_point_json_item_args)
self.path_action_point_json_items.append(new_path_action_point_json_item)
new_path_action_point_json_item["isNeeded"] = is_needed
def add_path_action_point_tracking_values(self, new_path_action_point_json_item, is_base_command, base_command_unique_identifier, subcomponent_number):
""" Adds the values that are used for tracking where components of a command belong to in 'new_path_action_point_json_item'
the tracking values are 'name' and 'belongsTo'"""
if is_base_command:
new_path_action_point_json_item["name"] = base_command_unique_identifier
new_path_action_point_json_item["belongsTo"] = "self"
else:
new_path_action_point_json_item["name"] = f"{base_command_unique_identifier} [{subcomponent_number}]"
new_path_action_point_json_item["belongsTo"] = base_command_unique_identifier
def get_command_parameters_values(self, current_parameter_names, path_action_point):
"""
Returns:
list[str]: the values of the command parameters for the 'path_action_point'"""
command_parameters_values = []
for current_parameter_name in current_parameter_names:
parameter_value = path_action_point.get_command_parameter_value(current_parameter_name)
command_parameters_values.append(parameter_value)
return command_parameters_values
def get_next_path_action_point_coordinates(self, previous_coordinates):
"""
Returns:
list[float]: [left_edge, top_edge]; the coordinates of the next path modifying point. This is important because if one GUI path modifying point command
is the combination of 2+ Auto path modifying point commands then those 2+ points need to be spaced apart otherwise the Auto code
raises an error"""
return_value = []
previous_coordinates_index = points.path_points.index(previous_coordinates)
distance = 0
for x in range(previous_coordinates_index, len(points.path_points)):
new_coordinates = points.path_points[x]
distance += math.dist(previous_coordinates, new_coordinates)
if distance >= MINIMUM_DISTANCE_BETWEEN_PATH_MODIYFING_POINTS:
return_value = new_coordinates
break
# If it could not find coordinates that are not far enough from the previous path modifying point then a path modifying point can't be there
# Because the Auto code will raise an Error if path modifying points are too close to each other
if len(return_value) == 0:
raise ValueError("It is not possible to have a path modifying point there because it will be too close" +
"to other path modifying points")
return return_value
def add_keys_and_values_to_dictionary(self, keys, values, dictionary):
"""Adds the key value pairs to the dictionary"""
for x in range(len(keys)):
dictionary_key = keys[x]
dictionary_value = values[x]
dictionary[dictionary_key] = dictionary_value
def update_angle_key_and_value_pairs(self, keys, values):
"""Updates all the key value pairs that are angles: the key has 'angle' in its name"""
for x in range(len(keys)):
dictionary_key = keys[x]
dictionary_value = values[x]
if dictionary_key.__contains__("angle") or dictionary_key.__contains__("Angle"):
current_radian_angle = float(dictionary_value) * math.pi / 180
delta_angle = current_radian_angle - self.last_angle
values[x] = delta_angle
keys.append(f"{dictionary_key}-GUI")
values.append(dictionary_value)
# So the GUI angle (field centric) can be stored also.
self.last_angle = current_radian_angle
def write_positions_to_file(self):
"""Writes the control points [x, y] to a file, so the JAR file can give all the points for the path"""
all_json_contents = {}
self.update_path_modifying_point_json(all_json_contents, points.path_modifying_points)
json.dump(all_json_contents, open("swerve_input.txt", "w+"), indent=JSON_MAX_INDENT)
os.system("java -jar AutoFollower.jar swerve_input.txt swerve_output.txt")
swerve_output_reading = open("swerve_output.txt", "r")
file_current_contents = get_string(swerve_output_reading.read()[:-1]) # The last enter must be deleted
file_current_contents_list = file_current_contents.split("\n")
last_path_point = file_current_contents_list[-1]
# remaining_file_current_contents = get_string(file_current_contents_list[:-1])
remaining_file_current_contents = ""
for item in file_current_contents_list[:-1]:
remaining_file_current_contents += f"{item}\n"
if len(file_current_contents.split("\n")) <= 2:
messagebox.showerror("ERROR", "Java does not seem to be installed on your system !!!")
raise ValueError("Java does not seem to be installed on your system !!!")
swerve_output = open("swerve_output.txt", "w+")
# The file does not have the last Path Action Point number
swerve_output.write(f"{remaining_file_current_contents}Control Point: {len(points.path_modifying_points) - 1}\n{last_path_point}")
swerve_output.close()
update_meter_path_points()
json_file_writer = JSONFileWriter()
Classes
class JSONFileWriter
-
The class that writes all the files
Expand source code
class JSONFileWriter: """The class that writes all the files""" path_action_point_json_items = [] path_action_point_left_edge = 0 path_action_point_top_edge = 0 last_angle = 0 path_modifying_point_to_current_angle = {} path_modifying_point_path_indexes_length = [] path_modifying_point_to_angle = {} required_point_index_to_angle = {} path_modifying_point_path_indexes = None def write_file(self, file, all_path_modifying_points, all_path_action_points, start_all_json_contents, first_required_point, last_required_point, placement_angle): """"Writes the JSON file that the Auto Path code uses""" self.last_angle = math.radians(placement_angle) # So it is converted to radians self.path_modifying_point_path_indexes = get_path_modifying_point_path_indexes() all_json_contents = start_all_json_contents required_points = points.required_points required_points = [first_required_point] + required_points + [last_required_point] update_path_modifying_point_information(all_path_action_points, all_path_modifying_points, required_points) # All the lists need an empty line after them and the last list does not need a comma # ALso have to call the make_*_accurate because the input fields don't always reflect what the GUI shows self.update_path_modifying_point_json(all_json_contents, all_path_modifying_points) self.update_required_points_json(all_json_contents, required_points) self.update_path_action_points_json(all_json_contents, all_path_action_points) json.dump(all_json_contents, file, indent=JSON_MAX_INDENT) def update_path_modifying_point_json(self, all_json_contents, path_modifying_points): """ Updates 'all_json_contents' so it contains the 'path_modifying_points' in it, so the file that is eventually written can contain all the information necessary for the Auto Path Follower""" # The contents of the control points list path_modifying_point_json_items = [] # So all_json_contents can now contain all the control points (and modifications to 'path_modifying_point_json_items' will be tracked # How the GUI and Auto Follower name points is different, which is why these names are different all_json_contents["ControlPoints"] = path_modifying_point_json_items for path_modifying_point in path_modifying_points: left_edge = path_modifying_point.get_field_left_edge() top_edge = path_modifying_point.get_field_top_edge() spline_order = path_modifying_point.get_spline_order() new_path_modifying_point_list_item = { "X": left_edge, "Y": top_edge, "Vx": path_modifying_point.get_horizontal_velocity(), "Vy": path_modifying_point.get_vertical_velocity(), "order": spline_order } path_modifying_point_json_items.append(new_path_modifying_point_list_item) def update_required_points_json(self, all_json_contents, required_points): """ Updates 'all_json_contents' so it contains the 'required_points' in it, so the file that is eventually written can contain all the information necessary for the Auto Path Follower""" # The contents of the control points list required_points_json = [] # So all_json_contents can now contain all the required points (and modifications to 'required_points_json' will be tracked all_json_contents["RequiredPoints"] = required_points_json for required_point in required_points: left_edge = required_point.get_field_left_edge() top_edge = required_point.get_field_top_edge() new_required_point_json = { "X": left_edge, "Y": top_edge, "angle-GUI": required_point.get_angle(), "angle": math.radians(required_point.get_angle()), "t": required_point.get_t_value() } new_required_point_json_args = {} new_required_point_json["args"] = new_required_point_json_args new_required_point_json["isNeeded"] = required_point.is_needed required_points_json.append(new_required_point_json) def update_path_action_points_json(self, all_json_contents, all_path_action_points): """ Returns: str: the path_action_points JSON""" path_action_points = points.path_action_points self.path_action_point_json_items = [] # How the GUI and Auto Follower define points is different, which is why the names are different here all_json_contents["WayPoints"] = self.path_action_point_json_items for path_action_point in path_action_points: self.update_path_action_point_command_components_json(path_action_point) def update_path_action_point_command_components_json(self, path_action_point: PathActionPoint): """Updates the command components; some commands are a conglomerate of 2+ commands, so this provides that architecture""" base_command_name = path_action_point.get_command_name() command_component_names = [] # If there are no components for that command, then the components should be 0 if commands_retriever.combined_commands.get(base_command_name) is not None: # The first one should be ignored because that is the base command, which is already accounted for command_component_names = commands_retriever.combined_commands.get(base_command_name)[1:] self.path_action_point_left_edge, self.path_action_point_top_edge = path_action_point.get_field_left_edge(), path_action_point.get_field_top_edge() base_command_unique_identifier = str(uuid.uuid4())[:4] # Only first 4 digits are needed for a unique value self.update_path_action_point_command_json(path_action_point, base_command_name, base_command_unique_identifier, True, 0, path_action_point.is_needed) # Have to set these, so the next point will be the closest to the point of the base command index = get_t_value_path_index(path_action_point, points.path_modifying_point_path_indexes) self.path_action_point_left_edge, self.path_action_point_top_edge = points.path_points[index] for x in range(len(command_component_names)): self.path_action_point_left_edge, self.path_action_point_top_edge = self.get_next_path_action_point_coordinates([self.path_action_point_left_edge, self.path_action_point_top_edge]) t_value = self.get_path_index_t_value([self.path_action_point_left_edge, self.path_action_point_top_edge]) path_action_point.set_t_value(t_value) self.update_path_action_point_command_json(path_action_point, command_component_names[x], base_command_unique_identifier, False, x + 1, path_action_point.is_needed) def get_surrounding_path_modifying_point_indexes(self, path_index): """ Returns: list[int]: {previous_path_modifying_point_index, next_path_modifying_point_index}; the indexes of the path modifying points that are before and after the 'path_index'""" previous_path_modifying_point_path_index = self.path_modifying_point_path_indexes[0] next_path_modifying_point_path_index = self.path_modifying_point_path_indexes[1] for path_modifying_point_path_index in self.path_modifying_point_path_indexes: if (path_modifying_point_path_index > previous_path_modifying_point_path_index and path_modifying_point_path_index <= path_index): previous_path_modifying_point_path_index = path_modifying_point_path_index if (path_modifying_point_path_index < next_path_modifying_point_path_index and path_modifying_point_path_index >= path_index): next_path_modifying_point_path_index = path_modifying_point_path_index def update_path_action_point_command_json(self, path_action_point, base_command_name, base_command_unique_identifier, is_base_command, command_component_number, is_needed): """ Updates the json for the base path modifying point command or command component- The data for all of these will be in commands.json""" new_path_action_point_json_item = {} current_command_parameter_names = commands_retriever.get_command_parameter_base_names(base_command_name) self.add_path_action_point_tracking_values(new_path_action_point_json_item, is_base_command, base_command_unique_identifier, command_component_number) self.add_keys_and_values_to_dictionary(["X", "Y", "Speed", "Command", "t"], [self.path_action_point_left_edge, self.path_action_point_top_edge, path_action_point.get_speed(), base_command_name, path_action_point.get_t_value()], new_path_action_point_json_item) current_command_parameter_values = self.get_command_parameters_values(current_command_parameter_names, path_action_point) new_path_action_point_json_item_args = {} new_path_action_point_json_item["args"] = new_path_action_point_json_item_args self.add_keys_and_values_to_dictionary(current_command_parameter_names, current_command_parameter_values, new_path_action_point_json_item_args) self.path_action_point_json_items.append(new_path_action_point_json_item) new_path_action_point_json_item["isNeeded"] = is_needed def add_path_action_point_tracking_values(self, new_path_action_point_json_item, is_base_command, base_command_unique_identifier, subcomponent_number): """ Adds the values that are used for tracking where components of a command belong to in 'new_path_action_point_json_item' the tracking values are 'name' and 'belongsTo'""" if is_base_command: new_path_action_point_json_item["name"] = base_command_unique_identifier new_path_action_point_json_item["belongsTo"] = "self" else: new_path_action_point_json_item["name"] = f"{base_command_unique_identifier} [{subcomponent_number}]" new_path_action_point_json_item["belongsTo"] = base_command_unique_identifier def get_command_parameters_values(self, current_parameter_names, path_action_point): """ Returns: list[str]: the values of the command parameters for the 'path_action_point'""" command_parameters_values = [] for current_parameter_name in current_parameter_names: parameter_value = path_action_point.get_command_parameter_value(current_parameter_name) command_parameters_values.append(parameter_value) return command_parameters_values def get_next_path_action_point_coordinates(self, previous_coordinates): """ Returns: list[float]: [left_edge, top_edge]; the coordinates of the next path modifying point. This is important because if one GUI path modifying point command is the combination of 2+ Auto path modifying point commands then those 2+ points need to be spaced apart otherwise the Auto code raises an error""" return_value = [] previous_coordinates_index = points.path_points.index(previous_coordinates) distance = 0 for x in range(previous_coordinates_index, len(points.path_points)): new_coordinates = points.path_points[x] distance += math.dist(previous_coordinates, new_coordinates) if distance >= MINIMUM_DISTANCE_BETWEEN_PATH_MODIYFING_POINTS: return_value = new_coordinates break # If it could not find coordinates that are not far enough from the previous path modifying point then a path modifying point can't be there # Because the Auto code will raise an Error if path modifying points are too close to each other if len(return_value) == 0: raise ValueError("It is not possible to have a path modifying point there because it will be too close" + "to other path modifying points") return return_value def add_keys_and_values_to_dictionary(self, keys, values, dictionary): """Adds the key value pairs to the dictionary""" for x in range(len(keys)): dictionary_key = keys[x] dictionary_value = values[x] dictionary[dictionary_key] = dictionary_value def update_angle_key_and_value_pairs(self, keys, values): """Updates all the key value pairs that are angles: the key has 'angle' in its name""" for x in range(len(keys)): dictionary_key = keys[x] dictionary_value = values[x] if dictionary_key.__contains__("angle") or dictionary_key.__contains__("Angle"): current_radian_angle = float(dictionary_value) * math.pi / 180 delta_angle = current_radian_angle - self.last_angle values[x] = delta_angle keys.append(f"{dictionary_key}-GUI") values.append(dictionary_value) # So the GUI angle (field centric) can be stored also. self.last_angle = current_radian_angle def write_positions_to_file(self): """Writes the control points [x, y] to a file, so the JAR file can give all the points for the path""" all_json_contents = {} self.update_path_modifying_point_json(all_json_contents, points.path_modifying_points) json.dump(all_json_contents, open("swerve_input.txt", "w+"), indent=JSON_MAX_INDENT) os.system("java -jar AutoFollower.jar swerve_input.txt swerve_output.txt") swerve_output_reading = open("swerve_output.txt", "r") file_current_contents = get_string(swerve_output_reading.read()[:-1]) # The last enter must be deleted file_current_contents_list = file_current_contents.split("\n") last_path_point = file_current_contents_list[-1] # remaining_file_current_contents = get_string(file_current_contents_list[:-1]) remaining_file_current_contents = "" for item in file_current_contents_list[:-1]: remaining_file_current_contents += f"{item}\n" if len(file_current_contents.split("\n")) <= 2: messagebox.showerror("ERROR", "Java does not seem to be installed on your system !!!") raise ValueError("Java does not seem to be installed on your system !!!") swerve_output = open("swerve_output.txt", "w+") # The file does not have the last Path Action Point number swerve_output.write(f"{remaining_file_current_contents}Control Point: {len(points.path_modifying_points) - 1}\n{last_path_point}") swerve_output.close() update_meter_path_points()
Class variables
var last_angle
var path_action_point_json_items
var path_action_point_left_edge
var path_action_point_top_edge
var path_modifying_point_path_indexes
var path_modifying_point_path_indexes_length
var path_modifying_point_to_angle
var path_modifying_point_to_current_angle
var required_point_index_to_angle
Methods
def add_keys_and_values_to_dictionary(self, keys, values, dictionary)
-
Adds the key value pairs to the dictionary
Expand source code
def add_keys_and_values_to_dictionary(self, keys, values, dictionary): """Adds the key value pairs to the dictionary""" for x in range(len(keys)): dictionary_key = keys[x] dictionary_value = values[x] dictionary[dictionary_key] = dictionary_value
def add_path_action_point_tracking_values(self, new_path_action_point_json_item, is_base_command, base_command_unique_identifier, subcomponent_number)
-
Adds the values that are used for tracking where components of a command belong to in 'new_path_action_point_json_item' the tracking values are 'name' and 'belongsTo'
Expand source code
def add_path_action_point_tracking_values(self, new_path_action_point_json_item, is_base_command, base_command_unique_identifier, subcomponent_number): """ Adds the values that are used for tracking where components of a command belong to in 'new_path_action_point_json_item' the tracking values are 'name' and 'belongsTo'""" if is_base_command: new_path_action_point_json_item["name"] = base_command_unique_identifier new_path_action_point_json_item["belongsTo"] = "self" else: new_path_action_point_json_item["name"] = f"{base_command_unique_identifier} [{subcomponent_number}]" new_path_action_point_json_item["belongsTo"] = base_command_unique_identifier
def get_command_parameters_values(self, current_parameter_names, path_action_point)
-
Returns
list[str]
- the values of the command parameters for the 'path_action_point'
Expand source code
def get_command_parameters_values(self, current_parameter_names, path_action_point): """ Returns: list[str]: the values of the command parameters for the 'path_action_point'""" command_parameters_values = [] for current_parameter_name in current_parameter_names: parameter_value = path_action_point.get_command_parameter_value(current_parameter_name) command_parameters_values.append(parameter_value) return command_parameters_values
def get_next_path_action_point_coordinates(self, previous_coordinates)
-
Returns
list[float]
- [left_edge, top_edge]; the coordinates of the next path modifying point. This is important because if one GUI path modifying point command
is the combination of 2+ Auto path modifying point commands then those 2+ points need to be spaced apart otherwise the Auto code raises an error
Expand source code
def get_next_path_action_point_coordinates(self, previous_coordinates): """ Returns: list[float]: [left_edge, top_edge]; the coordinates of the next path modifying point. This is important because if one GUI path modifying point command is the combination of 2+ Auto path modifying point commands then those 2+ points need to be spaced apart otherwise the Auto code raises an error""" return_value = [] previous_coordinates_index = points.path_points.index(previous_coordinates) distance = 0 for x in range(previous_coordinates_index, len(points.path_points)): new_coordinates = points.path_points[x] distance += math.dist(previous_coordinates, new_coordinates) if distance >= MINIMUM_DISTANCE_BETWEEN_PATH_MODIYFING_POINTS: return_value = new_coordinates break # If it could not find coordinates that are not far enough from the previous path modifying point then a path modifying point can't be there # Because the Auto code will raise an Error if path modifying points are too close to each other if len(return_value) == 0: raise ValueError("It is not possible to have a path modifying point there because it will be too close" + "to other path modifying points") return return_value
def get_surrounding_path_modifying_point_indexes(self, path_index)
-
Returns
list[int]
- {previous_path_modifying_point_index, next_path_modifying_point_index}; the indexes of the
path modifying points that are before and after the 'path_index'
Expand source code
def get_surrounding_path_modifying_point_indexes(self, path_index): """ Returns: list[int]: {previous_path_modifying_point_index, next_path_modifying_point_index}; the indexes of the path modifying points that are before and after the 'path_index'""" previous_path_modifying_point_path_index = self.path_modifying_point_path_indexes[0] next_path_modifying_point_path_index = self.path_modifying_point_path_indexes[1] for path_modifying_point_path_index in self.path_modifying_point_path_indexes: if (path_modifying_point_path_index > previous_path_modifying_point_path_index and path_modifying_point_path_index <= path_index): previous_path_modifying_point_path_index = path_modifying_point_path_index if (path_modifying_point_path_index < next_path_modifying_point_path_index and path_modifying_point_path_index >= path_index): next_path_modifying_point_path_index = path_modifying_point_path_index
def update_angle_key_and_value_pairs(self, keys, values)
-
Updates all the key value pairs that are angles: the key has 'angle' in its name
Expand source code
def update_angle_key_and_value_pairs(self, keys, values): """Updates all the key value pairs that are angles: the key has 'angle' in its name""" for x in range(len(keys)): dictionary_key = keys[x] dictionary_value = values[x] if dictionary_key.__contains__("angle") or dictionary_key.__contains__("Angle"): current_radian_angle = float(dictionary_value) * math.pi / 180 delta_angle = current_radian_angle - self.last_angle values[x] = delta_angle keys.append(f"{dictionary_key}-GUI") values.append(dictionary_value) # So the GUI angle (field centric) can be stored also. self.last_angle = current_radian_angle
def update_path_action_point_command_components_json(self, path_action_point: auto_components.path_action_point.PathActionPoint)
-
Updates the command components; some commands are a conglomerate of 2+ commands, so this provides that architecture
Expand source code
def update_path_action_point_command_components_json(self, path_action_point: PathActionPoint): """Updates the command components; some commands are a conglomerate of 2+ commands, so this provides that architecture""" base_command_name = path_action_point.get_command_name() command_component_names = [] # If there are no components for that command, then the components should be 0 if commands_retriever.combined_commands.get(base_command_name) is not None: # The first one should be ignored because that is the base command, which is already accounted for command_component_names = commands_retriever.combined_commands.get(base_command_name)[1:] self.path_action_point_left_edge, self.path_action_point_top_edge = path_action_point.get_field_left_edge(), path_action_point.get_field_top_edge() base_command_unique_identifier = str(uuid.uuid4())[:4] # Only first 4 digits are needed for a unique value self.update_path_action_point_command_json(path_action_point, base_command_name, base_command_unique_identifier, True, 0, path_action_point.is_needed) # Have to set these, so the next point will be the closest to the point of the base command index = get_t_value_path_index(path_action_point, points.path_modifying_point_path_indexes) self.path_action_point_left_edge, self.path_action_point_top_edge = points.path_points[index] for x in range(len(command_component_names)): self.path_action_point_left_edge, self.path_action_point_top_edge = self.get_next_path_action_point_coordinates([self.path_action_point_left_edge, self.path_action_point_top_edge]) t_value = self.get_path_index_t_value([self.path_action_point_left_edge, self.path_action_point_top_edge]) path_action_point.set_t_value(t_value) self.update_path_action_point_command_json(path_action_point, command_component_names[x], base_command_unique_identifier, False, x + 1, path_action_point.is_needed)
def update_path_action_point_command_json(self, path_action_point, base_command_name, base_command_unique_identifier, is_base_command, command_component_number, is_needed)
-
Updates the json for the base path modifying point command or command component- The data for all of these will be in commands.json
Expand source code
def update_path_action_point_command_json(self, path_action_point, base_command_name, base_command_unique_identifier, is_base_command, command_component_number, is_needed): """ Updates the json for the base path modifying point command or command component- The data for all of these will be in commands.json""" new_path_action_point_json_item = {} current_command_parameter_names = commands_retriever.get_command_parameter_base_names(base_command_name) self.add_path_action_point_tracking_values(new_path_action_point_json_item, is_base_command, base_command_unique_identifier, command_component_number) self.add_keys_and_values_to_dictionary(["X", "Y", "Speed", "Command", "t"], [self.path_action_point_left_edge, self.path_action_point_top_edge, path_action_point.get_speed(), base_command_name, path_action_point.get_t_value()], new_path_action_point_json_item) current_command_parameter_values = self.get_command_parameters_values(current_command_parameter_names, path_action_point) new_path_action_point_json_item_args = {} new_path_action_point_json_item["args"] = new_path_action_point_json_item_args self.add_keys_and_values_to_dictionary(current_command_parameter_names, current_command_parameter_values, new_path_action_point_json_item_args) self.path_action_point_json_items.append(new_path_action_point_json_item) new_path_action_point_json_item["isNeeded"] = is_needed
def update_path_action_points_json(self, all_json_contents, all_path_action_points)
-
Returns
str
- the path_action_points JSON
Expand source code
def update_path_action_points_json(self, all_json_contents, all_path_action_points): """ Returns: str: the path_action_points JSON""" path_action_points = points.path_action_points self.path_action_point_json_items = [] # How the GUI and Auto Follower define points is different, which is why the names are different here all_json_contents["WayPoints"] = self.path_action_point_json_items for path_action_point in path_action_points: self.update_path_action_point_command_components_json(path_action_point)
def update_path_modifying_point_json(self, all_json_contents, path_modifying_points)
-
Updates 'all_json_contents' so it contains the 'path_modifying_points' in it, so the file that is eventually written can contain all the information necessary for the Auto Path Follower
Expand source code
def update_path_modifying_point_json(self, all_json_contents, path_modifying_points): """ Updates 'all_json_contents' so it contains the 'path_modifying_points' in it, so the file that is eventually written can contain all the information necessary for the Auto Path Follower""" # The contents of the control points list path_modifying_point_json_items = [] # So all_json_contents can now contain all the control points (and modifications to 'path_modifying_point_json_items' will be tracked # How the GUI and Auto Follower name points is different, which is why these names are different all_json_contents["ControlPoints"] = path_modifying_point_json_items for path_modifying_point in path_modifying_points: left_edge = path_modifying_point.get_field_left_edge() top_edge = path_modifying_point.get_field_top_edge() spline_order = path_modifying_point.get_spline_order() new_path_modifying_point_list_item = { "X": left_edge, "Y": top_edge, "Vx": path_modifying_point.get_horizontal_velocity(), "Vy": path_modifying_point.get_vertical_velocity(), "order": spline_order } path_modifying_point_json_items.append(new_path_modifying_point_list_item)
def update_required_points_json(self, all_json_contents, required_points)
-
Updates 'all_json_contents' so it contains the 'required_points' in it, so the file that is eventually written can contain all the information necessary for the Auto Path Follower
Expand source code
def update_required_points_json(self, all_json_contents, required_points): """ Updates 'all_json_contents' so it contains the 'required_points' in it, so the file that is eventually written can contain all the information necessary for the Auto Path Follower""" # The contents of the control points list required_points_json = [] # So all_json_contents can now contain all the required points (and modifications to 'required_points_json' will be tracked all_json_contents["RequiredPoints"] = required_points_json for required_point in required_points: left_edge = required_point.get_field_left_edge() top_edge = required_point.get_field_top_edge() new_required_point_json = { "X": left_edge, "Y": top_edge, "angle-GUI": required_point.get_angle(), "angle": math.radians(required_point.get_angle()), "t": required_point.get_t_value() } new_required_point_json_args = {} new_required_point_json["args"] = new_required_point_json_args new_required_point_json["isNeeded"] = required_point.is_needed required_points_json.append(new_required_point_json)
def write_file(self, file, all_path_modifying_points, all_path_action_points, start_all_json_contents, first_required_point, last_required_point, placement_angle)
-
"Writes the JSON file that the Auto Path code uses
Expand source code
def write_file(self, file, all_path_modifying_points, all_path_action_points, start_all_json_contents, first_required_point, last_required_point, placement_angle): """"Writes the JSON file that the Auto Path code uses""" self.last_angle = math.radians(placement_angle) # So it is converted to radians self.path_modifying_point_path_indexes = get_path_modifying_point_path_indexes() all_json_contents = start_all_json_contents required_points = points.required_points required_points = [first_required_point] + required_points + [last_required_point] update_path_modifying_point_information(all_path_action_points, all_path_modifying_points, required_points) # All the lists need an empty line after them and the last list does not need a comma # ALso have to call the make_*_accurate because the input fields don't always reflect what the GUI shows self.update_path_modifying_point_json(all_json_contents, all_path_modifying_points) self.update_required_points_json(all_json_contents, required_points) self.update_path_action_points_json(all_json_contents, all_path_action_points) json.dump(all_json_contents, file, indent=JSON_MAX_INDENT)
def write_positions_to_file(self)
-
Writes the control points [x, y] to a file, so the JAR file can give all the points for the path
Expand source code
def write_positions_to_file(self): """Writes the control points [x, y] to a file, so the JAR file can give all the points for the path""" all_json_contents = {} self.update_path_modifying_point_json(all_json_contents, points.path_modifying_points) json.dump(all_json_contents, open("swerve_input.txt", "w+"), indent=JSON_MAX_INDENT) os.system("java -jar AutoFollower.jar swerve_input.txt swerve_output.txt") swerve_output_reading = open("swerve_output.txt", "r") file_current_contents = get_string(swerve_output_reading.read()[:-1]) # The last enter must be deleted file_current_contents_list = file_current_contents.split("\n") last_path_point = file_current_contents_list[-1] # remaining_file_current_contents = get_string(file_current_contents_list[:-1]) remaining_file_current_contents = "" for item in file_current_contents_list[:-1]: remaining_file_current_contents += f"{item}\n" if len(file_current_contents.split("\n")) <= 2: messagebox.showerror("ERROR", "Java does not seem to be installed on your system !!!") raise ValueError("Java does not seem to be installed on your system !!!") swerve_output = open("swerve_output.txt", "w+") # The file does not have the last Path Action Point number swerve_output.write(f"{remaining_file_current_contents}Control Point: {len(points.path_modifying_points) - 1}\n{last_path_point}") swerve_output.close() update_meter_path_points()