Module Auto-GUI.auto_features.path_creation

Expand source code
import math
from miscellaneous import important_variables

from miscellaneous.utility_functions import *

from miscellaneous.colors import path_action_point_color


def get_closest_path_point(left_edge, top_edge):
    """
        Returns:
            list[float]: [left_edge, top_edge]; the closest point on the path to the path_action_point. IMPORTANT the unit for the
            left_edge, top_edge, and path_points must all be equal (meters, pixel, etc.)"""

    return points.path_points[get_closest_path_point_index(left_edge, top_edge)]


def get_closest_path_point_index(left_edge, top_edge):
    """
            Returns:
                int: the index of the closest path point"""

    shortest_distance = float('inf')
    closest_point_index = 0

    for i in range(len(points.path_points)):
        current_distance = math.dist(points.path_points[i], (left_edge, top_edge))

        if current_distance < shortest_distance:
            shortest_distance = current_distance
            closest_point_index = i

    return closest_point_index


def draw_path_lines(field_canvas, path_modifying_point_line_width, path_line_width):
    """Draws the path and the path_action_points which are connected to the path"""

    pixel_path_points = get_pixel_path_points()

    for j in range(len(pixel_path_points) - 1):
        start_point = pixel_path_points[j]
        end_point = pixel_path_points[j + 1]
        field_canvas.create_line(start_point, end_point, fill=path_modifying_point_color, width=path_line_width)

    # for path_action_point in points.path_action_points:
    #     closest_point = get_closest_path_point(path_action_point.left_edge, path_action_point.top_edge, pixel_path_points, path_action_point)
    #     field_canvas.create_line((path_action_point.left_edge, path_action_point.top_edge), closest_point, fill=path_action_point_color, width=path_modifying_point_line_width)
    #
    # for required_point in points.required_points:
    #         closest_point = get_closest_path_point(required_point.left_edge, required_point.top_edge, pixel_path_points, required_point)
    #         field_canvas.create_line((required_point.left_edge, required_point.top_edge), closest_point, fill=required_point_color, width=path_modifying_point_line_width)


def get_pixel_location(left_edge, top_edge):
    """
            Returns:
                list[float]: [left_edge, top_edge]; the pixel location that the GUI uses. This converts from the Swerve Code
                locations to the GUI code locations."""

    return [int(meters_to_pixels(left_edge)), int(meters_to_pixels(top_edge))]

# The reason this function has very similar code to get_meter_path_points() is because calling get_meter_path_points()
# And then getting the pixel points requires going through the same points twice, which is too slow
def get_pixel_path_points():
    """
            Returns:
                list[list[float]]: [[x1, y1], [x2, y2]]; the points along the path (in pixels)"""

    pixel_path_points = []
    file = open("swerve_output.txt", "r")

    # The last line has no data as of now, so that line should be ignored (hence list[:-1])
    for line in get_lines(file.read()[:-1]):
        is_path_action_point_line = line.__contains__("Control Point")

        if is_path_action_point_line:
            continue

        point_coordinates = line.split(",")
        left_edge, top_edge = float(point_coordinates[0]), float(point_coordinates[1])
        left_edge, top_edge = get_gui_centric_coordinates(left_edge, top_edge)
        pixel_locations = get_pixel_location(left_edge, top_edge)

        if not pixel_path_points.__contains__(pixel_locations):
            pixel_path_points.append(pixel_locations)

    file.close()
    return pixel_path_points

def update_meter_path_points():
    """Updates 'points.path_points' to reflect what was written to swerve_output.txt"""

    path_points = []
    file = open("swerve_output.txt", "r")

    for line in get_lines(file.read()[:-1]):
        is_path_action_point_line = line.__contains__("Control Point")

        # The lines that does not contain control points then it has the path points
        if not is_path_action_point_line:
            point_coordinates = line.split(",")
            left_edge, top_edge = float(point_coordinates[0]), float(point_coordinates[1])

            # Have to convert from the (0, 0) of the coordinates being the top left edge of the screen to the (0, 0) being the center of the hub
            # left_edge, top_edge = get_hub_centric_coordinates(left_edge, top_edge)

            path_points.append([left_edge, top_edge])

    file.close()

    points.path_points = path_points
    points.path_modifying_point_path_indexes = get_path_modifying_point_path_indexes()

def get_hub_centric_coordinates(left_edge, top_edge):
    """ The meter left_edge and top_edge (location user modifies) has (0, 0) at the center of the hub and the pixel location
        (GUI location) has (0,0) at the top left edge of the screen. When the pixel coordinates are converted to meters by a scalar multiplier,
        therefore, offsets must be subtracted to have (0, 0) once again be the center of the hub

        Args:
            left_edge (float): the left_edge of a point that has (0, 0) at the top left edge of the screen instead of the center of the hub
            top_edge (double): the top_edge of a point that has (0, 0) at the top left edge of the screen instead of the center of the hub

        Returns:
            list[double]: {converted_left_edge, converted_top_edge}; the left_edge and top_edge that has the center of the hub be (0, 0)
    """

    left_edge -= important_variables.CENTER_OF_FIELD_HORIZONTAL_OFFSET
    top_edge -= CENTER_OF_FIELD_VERTICAL_OFFSET

    top_edge *= -1  # Because of how the GUI is set up the number will be the negative version of the correct meter number

    return [left_edge, top_edge]

def get_gui_centric_coordinates(left_edge, top_edge):
    """ The meter left_edge and top_edge (location user modifies) has (0, 0) at the center of the hub and the pixel location
        (GUI location) has (0,0) at the top left edge of the screen. When the pixel coordinates are converted to meters by a scalar multiplier,
        therefore, offsets must be added to have (0, 0) once again be the top left edge of the screen

        Args:
            left_edge (float): the left_edge of a point that has (0, 0) at the center of the hub instead of the top left edge of the screen
            top_edge (float): the top_edge of a point that has (0, 0) at the center of the hub instead of the top left edge of the screen

        Returns:
            list[float]: {converted_left_edge, converted_top_edge}; the left_edge and top_edge that has the top left edge of the screen be (0, 0)
    """

    top_edge *= -1  # The numbers are multiplied by -1 to convert to hub_centric, so it must be multiplied by -1 to convert it to gui
    left_edge += important_variables.CENTER_OF_FIELD_HORIZONTAL_OFFSET
    top_edge += CENTER_OF_FIELD_VERTICAL_OFFSET

    return [left_edge, top_edge]

def get_meter_location(left_edge, top_edge):
    """
            Returns:
                list[float]: [left_edge, top_edge]; the location that the AutoFollower.jar file needs to create the path - converts
                the values into meters and puts all the numbers based off of the base_left_edge and base_top_edge"""

    return [pixels_to_meters(left_edge), pixels_to_meters(top_edge)]


def get_path_modifying_point_path_indexes():
    """
            Returns:
                list[int]: the path indexes of the path modifying points"""

    return_value = []
    file = open("swerve_output.txt", "r")
    path_modifying_point_index = -1  # So the first path modifying point index starts at 0 not 1

    for line in get_lines(file.read()[:-1]):
        is_path_action_point_line = line.__contains__("Control Point")

        # The lines that does not contain control points then it has the path points
        if is_path_action_point_line:
            amount_added = -1 if path_modifying_point_index == -1 else 0  # It starts at -1, which is not a valid index
            return_value.append(path_modifying_point_index + 1)

        else:
            path_modifying_point_index += 1

    file.close()

    return return_value

def update_path_modifying_point_information(path_action_points=None, path_modifying_points=None, required_points=None):
    """Updates the information that the path modifying points need specifically which required point affects the angle of the robot"""

    required_point_path_indexes = []

    # Updating the required point paths
    path_action_points = points.path_action_points if path_action_points is None else path_action_points
    required_points = points.required_points if required_points is None else required_points
    path_modifying_points = points.path_modifying_points if path_modifying_points is None else path_modifying_points

    path_modifying_point_path_indexes = get_path_modifying_point_path_indexes()
    for x in range(len(points.path_modifying_points)):
        path_modifying_points[x].path_index = path_modifying_point_path_indexes[x]

    for required_point in required_points:
        index = get_t_value_path_index(required_point, path_modifying_point_path_indexes)
        required_point_path_indexes.append(index)

    update_path_modifying_point_angle_at_points(path_modifying_points, required_points, required_point_path_indexes)

    return [points.path_points, required_point_path_indexes, path_modifying_point_path_indexes]

def update_path_modifying_point_angle_at_points(path_modifying_points, required_points, required_point_path_indexes):
    """Updates the path_modifying_point's 'angle_at_point' attribute, so the angle of the robot lines can be drawn"""

    # Updating the angles of the path_modifying_points
    for path_modifying_point in path_modifying_points:
        last_angle = required_points[0].get_angle()
        next_angle = required_points[1].get_angle()

        previous_required_point_path_index = float("-inf")
        next_required_point_path_index = float("inf")
        path_modifying_point_path_index = path_modifying_point.path_index

        for i in range(len(required_point_path_indexes)):
            required_point_path_index = required_point_path_indexes[i]

            if (required_point_path_index <= path_modifying_point_path_index and
                    required_point_path_index > previous_required_point_path_index):

                previous_required_point_path_index = required_point_path_index
                last_angle = required_points[i].get_angle()

            if (required_point_path_index >= path_modifying_point_path_index and
                    required_point_path_index < next_required_point_path_index):

                next_required_point_path_index = required_point_path_index
                next_angle = required_points[i].get_angle()

        angle = get_angle_at_point(path_modifying_point_path_index,
                                   previous_required_point_path_index,
                                   next_required_point_path_index, last_angle,
                                   next_angle)

        path_modifying_point.set_angle_at_point(angle)

def update_path_action_and_required_point_location(path_action_points, required_points, path_modifying_point_path_indexes, path_modifying_points):
    """Updates the t values of all the path_action_points. The t values allow the robot to know what to execute along the path"""

    for point in path_action_points + required_points:
        path_index = get_t_value_path_index(point, path_modifying_point_path_indexes)
        path_point = points.path_points[path_index]

        # Path point(s) are in this format: [left_edge, top_edge]
        point.set_field_left_edge(path_point[0], want_rounding=True)
        point.set_field_top_edge(path_point[1], want_rounding=True)

def get_path_index_t_value(left_edge, top_edge):
    """
            Returns:
                float: the t_value at that path_index"""

    # Finding the values for the math below
    path_index = points.path_points.index([left_edge, top_edge])

    previous_path_modifying_point_index = float("-inf")
    next_path_modifying_point_index = float("inf")

    previous_path_modifying_point_number = 0

    path_modifying_point_path_indexes = get_path_modifying_point_path_indexes()

    for x in range(len(path_modifying_point_path_indexes)):
        index = path_modifying_point_path_indexes[x]

        if index <= path_index and index > previous_path_modifying_point_index:
            previous_path_modifying_point_index = index
            previous_path_modifying_point_number = x

        if index >= path_index and index < next_path_modifying_point_index:
            next_path_modifying_point_index = index

    # Doing the math
    arc_distance = get_distance(previous_path_modifying_point_index, next_path_modifying_point_index)
    distance_to_path_point = get_distance(previous_path_modifying_point_index, path_index)

    t_value = previous_path_modifying_point_number

    # T values can have a value that is part of the way to another one like 1.5 would be halfway between path modifying
    # point 1 and path modifying point 2
    if arc_distance != 0:
        t_value += distance_to_path_point / arc_distance

    return truncate(t_value, INPUT_FIELD_DECIMAL_ACCURACY)

def get_t_value_path_index(point, path_modifying_point_path_indexes):
    """
            Returns:
                int: the path_index that the t value represents"""

    # T values and indexes are the same except t values need the decimal 'chopped off'
    path_modifying_point_index = int(point.get_t_value())

    return_value = path_modifying_point_path_indexes[path_modifying_point_index]

    # If the t value is not a plain number, then we need to calculate the top edge (2 would be plain while 2.1 would not be plain)
    if path_modifying_point_index != point.get_t_value():
        path_indexes = [path_modifying_point_path_indexes[path_modifying_point_index],
                        path_modifying_point_path_indexes[path_modifying_point_index + 1]]

        # Only keeping the decimal part of the t value
        t_value_proportion = point.get_t_value() - int(point.get_t_value())

        arc_distance = get_distance(*path_indexes)
        return_value = get_point_index_at_closest_distance(path_indexes[0], arc_distance * t_value_proportion)

    return return_value


def get_point_index_at_closest_distance(start_index, distance):
    """
            Returns:
                list[float]: {left_edge, top_edge}; the closest point that is the 'distance' from 'start_index'"""

    end_index = len(points.path_points) - 1
    current_distance = 0
    last_distance = 0
    return_value = end_index

    # You have to add 1 to 'end_index' to get the for loop to go to that value
    for x in range(start_index, end_index):

        last_point_index = x
        current_point_index = x + 1

        last_point = points.path_points[last_point_index]
        current_point = points.path_points[current_point_index]
        
        current_distance += math.dist(last_point, current_point)
        
        last_distance_delta = abs(distance - last_distance)
        current_distance_delta = abs(distance - current_distance)

        if current_distance >= distance and last_distance_delta < current_distance_delta:
            return_value = last_point_index
            break
        
        elif current_distance >= distance and current_distance_delta < last_distance_delta:
            return_value = last_point_index
            break
            
    return return_value
            

def get_angle_at_point(path_modifying_point_path_index, previous_required_point_path_index,
                        next_required_point_path_index, last_angle, next_angle):

    """ 
            Returns:
                float: the angle at the path modifying point (gotten from figuring out how much each required point
                angle affects the path modifying point"""

    return_value = None

    # No proportion calculations need to be done because the required point is on the path modifying point
    if previous_required_point_path_index == next_required_point_path_index:
        return_value = last_angle

    else:
        last_required_point_distance_from_path_modifying_point = get_distance(previous_required_point_path_index, path_modifying_point_path_index)
        next_required_point_distance_from_path_modifying_point = get_distance(path_modifying_point_path_index, next_required_point_path_index)

        total_distance = last_required_point_distance_from_path_modifying_point + next_required_point_distance_from_path_modifying_point
        last_required_point_proportion = 1 - (last_required_point_distance_from_path_modifying_point / total_distance)
        next_required_point_proportion = 1 - (next_required_point_distance_from_path_modifying_point / total_distance)

        last_angle = math.radians(last_angle)
        next_angle = math.radians(next_angle)

        return_value = last_required_point_proportion * last_angle + next_required_point_proportion * next_angle

    return return_value

def get_distance(first_index, last_index):
    """Gets the distance from all the lines of the path points"""

    current_distance = 0
    for x in range(first_index, last_index):
        point1 = points.path_points[x]
        point2 = points.path_points[x + 1]

        current_distance += math.dist(point1, point2)

    return current_distance

Functions

def draw_path_lines(field_canvas, path_modifying_point_line_width, path_line_width)

Draws the path and the path_action_points which are connected to the path

Expand source code
def draw_path_lines(field_canvas, path_modifying_point_line_width, path_line_width):
    """Draws the path and the path_action_points which are connected to the path"""

    pixel_path_points = get_pixel_path_points()

    for j in range(len(pixel_path_points) - 1):
        start_point = pixel_path_points[j]
        end_point = pixel_path_points[j + 1]
        field_canvas.create_line(start_point, end_point, fill=path_modifying_point_color, width=path_line_width)

    # for path_action_point in points.path_action_points:
    #     closest_point = get_closest_path_point(path_action_point.left_edge, path_action_point.top_edge, pixel_path_points, path_action_point)
    #     field_canvas.create_line((path_action_point.left_edge, path_action_point.top_edge), closest_point, fill=path_action_point_color, width=path_modifying_point_line_width)
    #
    # for required_point in points.required_points:
    #         closest_point = get_closest_path_point(required_point.left_edge, required_point.top_edge, pixel_path_points, required_point)
    #         field_canvas.create_line((required_point.left_edge, required_point.top_edge), closest_point, fill=required_point_color, width=path_modifying_point_line_width)
def get_angle_at_point(path_modifying_point_path_index, previous_required_point_path_index, next_required_point_path_index, last_angle, next_angle)

Returns

float
the angle at the path modifying point (gotten from figuring out how much each required point

angle affects the path modifying point

Expand source code
def get_angle_at_point(path_modifying_point_path_index, previous_required_point_path_index,
                        next_required_point_path_index, last_angle, next_angle):

    """ 
            Returns:
                float: the angle at the path modifying point (gotten from figuring out how much each required point
                angle affects the path modifying point"""

    return_value = None

    # No proportion calculations need to be done because the required point is on the path modifying point
    if previous_required_point_path_index == next_required_point_path_index:
        return_value = last_angle

    else:
        last_required_point_distance_from_path_modifying_point = get_distance(previous_required_point_path_index, path_modifying_point_path_index)
        next_required_point_distance_from_path_modifying_point = get_distance(path_modifying_point_path_index, next_required_point_path_index)

        total_distance = last_required_point_distance_from_path_modifying_point + next_required_point_distance_from_path_modifying_point
        last_required_point_proportion = 1 - (last_required_point_distance_from_path_modifying_point / total_distance)
        next_required_point_proportion = 1 - (next_required_point_distance_from_path_modifying_point / total_distance)

        last_angle = math.radians(last_angle)
        next_angle = math.radians(next_angle)

        return_value = last_required_point_proportion * last_angle + next_required_point_proportion * next_angle

    return return_value
def get_closest_path_point(left_edge, top_edge)

Returns

list[float]
[left_edge, top_edge]; the closest point on the path to the path_action_point. IMPORTANT the unit for the

left_edge, top_edge, and path_points must all be equal (meters, pixel, etc.)

Expand source code
def get_closest_path_point(left_edge, top_edge):
    """
        Returns:
            list[float]: [left_edge, top_edge]; the closest point on the path to the path_action_point. IMPORTANT the unit for the
            left_edge, top_edge, and path_points must all be equal (meters, pixel, etc.)"""

    return points.path_points[get_closest_path_point_index(left_edge, top_edge)]
def get_closest_path_point_index(left_edge, top_edge)

Returns

int
the index of the closest path point
Expand source code
def get_closest_path_point_index(left_edge, top_edge):
    """
            Returns:
                int: the index of the closest path point"""

    shortest_distance = float('inf')
    closest_point_index = 0

    for i in range(len(points.path_points)):
        current_distance = math.dist(points.path_points[i], (left_edge, top_edge))

        if current_distance < shortest_distance:
            shortest_distance = current_distance
            closest_point_index = i

    return closest_point_index
def get_distance(first_index, last_index)

Gets the distance from all the lines of the path points

Expand source code
def get_distance(first_index, last_index):
    """Gets the distance from all the lines of the path points"""

    current_distance = 0
    for x in range(first_index, last_index):
        point1 = points.path_points[x]
        point2 = points.path_points[x + 1]

        current_distance += math.dist(point1, point2)

    return current_distance
def get_gui_centric_coordinates(left_edge, top_edge)

The meter left_edge and top_edge (location user modifies) has (0, 0) at the center of the hub and the pixel location (GUI location) has (0,0) at the top left edge of the screen. When the pixel coordinates are converted to meters by a scalar multiplier, therefore, offsets must be added to have (0, 0) once again be the top left edge of the screen

Args

left_edge : float
the left_edge of a point that has (0, 0) at the center of the hub instead of the top left edge of the screen
top_edge : float
the top_edge of a point that has (0, 0) at the center of the hub instead of the top left edge of the screen

Returns

list[float]
{converted_left_edge, converted_top_edge}; the left_edge and top_edge that has the top left edge of the screen be (0, 0)
Expand source code
def get_gui_centric_coordinates(left_edge, top_edge):
    """ The meter left_edge and top_edge (location user modifies) has (0, 0) at the center of the hub and the pixel location
        (GUI location) has (0,0) at the top left edge of the screen. When the pixel coordinates are converted to meters by a scalar multiplier,
        therefore, offsets must be added to have (0, 0) once again be the top left edge of the screen

        Args:
            left_edge (float): the left_edge of a point that has (0, 0) at the center of the hub instead of the top left edge of the screen
            top_edge (float): the top_edge of a point that has (0, 0) at the center of the hub instead of the top left edge of the screen

        Returns:
            list[float]: {converted_left_edge, converted_top_edge}; the left_edge and top_edge that has the top left edge of the screen be (0, 0)
    """

    top_edge *= -1  # The numbers are multiplied by -1 to convert to hub_centric, so it must be multiplied by -1 to convert it to gui
    left_edge += important_variables.CENTER_OF_FIELD_HORIZONTAL_OFFSET
    top_edge += CENTER_OF_FIELD_VERTICAL_OFFSET

    return [left_edge, top_edge]
def get_hub_centric_coordinates(left_edge, top_edge)

The meter left_edge and top_edge (location user modifies) has (0, 0) at the center of the hub and the pixel location (GUI location) has (0,0) at the top left edge of the screen. When the pixel coordinates are converted to meters by a scalar multiplier, therefore, offsets must be subtracted to have (0, 0) once again be the center of the hub

Args

left_edge : float
the left_edge of a point that has (0, 0) at the top left edge of the screen instead of the center of the hub
top_edge : double
the top_edge of a point that has (0, 0) at the top left edge of the screen instead of the center of the hub

Returns

list[double]
{converted_left_edge, converted_top_edge}; the left_edge and top_edge that has the center of the hub be (0, 0)
Expand source code
def get_hub_centric_coordinates(left_edge, top_edge):
    """ The meter left_edge and top_edge (location user modifies) has (0, 0) at the center of the hub and the pixel location
        (GUI location) has (0,0) at the top left edge of the screen. When the pixel coordinates are converted to meters by a scalar multiplier,
        therefore, offsets must be subtracted to have (0, 0) once again be the center of the hub

        Args:
            left_edge (float): the left_edge of a point that has (0, 0) at the top left edge of the screen instead of the center of the hub
            top_edge (double): the top_edge of a point that has (0, 0) at the top left edge of the screen instead of the center of the hub

        Returns:
            list[double]: {converted_left_edge, converted_top_edge}; the left_edge and top_edge that has the center of the hub be (0, 0)
    """

    left_edge -= important_variables.CENTER_OF_FIELD_HORIZONTAL_OFFSET
    top_edge -= CENTER_OF_FIELD_VERTICAL_OFFSET

    top_edge *= -1  # Because of how the GUI is set up the number will be the negative version of the correct meter number

    return [left_edge, top_edge]
def get_meter_location(left_edge, top_edge)

Returns

list[float]
[left_edge, top_edge]; the location that the AutoFollower.jar file needs to create the path - converts

the values into meters and puts all the numbers based off of the base_left_edge and base_top_edge

Expand source code
def get_meter_location(left_edge, top_edge):
    """
            Returns:
                list[float]: [left_edge, top_edge]; the location that the AutoFollower.jar file needs to create the path - converts
                the values into meters and puts all the numbers based off of the base_left_edge and base_top_edge"""

    return [pixels_to_meters(left_edge), pixels_to_meters(top_edge)]
def get_path_index_t_value(left_edge, top_edge)

Returns

float
the t_value at that path_index
Expand source code
def get_path_index_t_value(left_edge, top_edge):
    """
            Returns:
                float: the t_value at that path_index"""

    # Finding the values for the math below
    path_index = points.path_points.index([left_edge, top_edge])

    previous_path_modifying_point_index = float("-inf")
    next_path_modifying_point_index = float("inf")

    previous_path_modifying_point_number = 0

    path_modifying_point_path_indexes = get_path_modifying_point_path_indexes()

    for x in range(len(path_modifying_point_path_indexes)):
        index = path_modifying_point_path_indexes[x]

        if index <= path_index and index > previous_path_modifying_point_index:
            previous_path_modifying_point_index = index
            previous_path_modifying_point_number = x

        if index >= path_index and index < next_path_modifying_point_index:
            next_path_modifying_point_index = index

    # Doing the math
    arc_distance = get_distance(previous_path_modifying_point_index, next_path_modifying_point_index)
    distance_to_path_point = get_distance(previous_path_modifying_point_index, path_index)

    t_value = previous_path_modifying_point_number

    # T values can have a value that is part of the way to another one like 1.5 would be halfway between path modifying
    # point 1 and path modifying point 2
    if arc_distance != 0:
        t_value += distance_to_path_point / arc_distance

    return truncate(t_value, INPUT_FIELD_DECIMAL_ACCURACY)
def get_path_modifying_point_path_indexes()

Returns

list[int]
the path indexes of the path modifying points
Expand source code
def get_path_modifying_point_path_indexes():
    """
            Returns:
                list[int]: the path indexes of the path modifying points"""

    return_value = []
    file = open("swerve_output.txt", "r")
    path_modifying_point_index = -1  # So the first path modifying point index starts at 0 not 1

    for line in get_lines(file.read()[:-1]):
        is_path_action_point_line = line.__contains__("Control Point")

        # The lines that does not contain control points then it has the path points
        if is_path_action_point_line:
            amount_added = -1 if path_modifying_point_index == -1 else 0  # It starts at -1, which is not a valid index
            return_value.append(path_modifying_point_index + 1)

        else:
            path_modifying_point_index += 1

    file.close()

    return return_value
def get_pixel_location(left_edge, top_edge)

Returns

list[float]
[left_edge, top_edge]; the pixel location that the GUI uses. This converts from the Swerve Code

locations to the GUI code locations.

Expand source code
def get_pixel_location(left_edge, top_edge):
    """
            Returns:
                list[float]: [left_edge, top_edge]; the pixel location that the GUI uses. This converts from the Swerve Code
                locations to the GUI code locations."""

    return [int(meters_to_pixels(left_edge)), int(meters_to_pixels(top_edge))]
def get_pixel_path_points()

Returns

list[list[float]]
[[x1, y1], [x2, y2]]; the points along the path (in pixels)
Expand source code
def get_pixel_path_points():
    """
            Returns:
                list[list[float]]: [[x1, y1], [x2, y2]]; the points along the path (in pixels)"""

    pixel_path_points = []
    file = open("swerve_output.txt", "r")

    # The last line has no data as of now, so that line should be ignored (hence list[:-1])
    for line in get_lines(file.read()[:-1]):
        is_path_action_point_line = line.__contains__("Control Point")

        if is_path_action_point_line:
            continue

        point_coordinates = line.split(",")
        left_edge, top_edge = float(point_coordinates[0]), float(point_coordinates[1])
        left_edge, top_edge = get_gui_centric_coordinates(left_edge, top_edge)
        pixel_locations = get_pixel_location(left_edge, top_edge)

        if not pixel_path_points.__contains__(pixel_locations):
            pixel_path_points.append(pixel_locations)

    file.close()
    return pixel_path_points
def get_point_index_at_closest_distance(start_index, distance)

Returns

list[float]
{left_edge, top_edge}; the closest point that is the 'distance' from 'start_index'
Expand source code
def get_point_index_at_closest_distance(start_index, distance):
    """
            Returns:
                list[float]: {left_edge, top_edge}; the closest point that is the 'distance' from 'start_index'"""

    end_index = len(points.path_points) - 1
    current_distance = 0
    last_distance = 0
    return_value = end_index

    # You have to add 1 to 'end_index' to get the for loop to go to that value
    for x in range(start_index, end_index):

        last_point_index = x
        current_point_index = x + 1

        last_point = points.path_points[last_point_index]
        current_point = points.path_points[current_point_index]
        
        current_distance += math.dist(last_point, current_point)
        
        last_distance_delta = abs(distance - last_distance)
        current_distance_delta = abs(distance - current_distance)

        if current_distance >= distance and last_distance_delta < current_distance_delta:
            return_value = last_point_index
            break
        
        elif current_distance >= distance and current_distance_delta < last_distance_delta:
            return_value = last_point_index
            break
            
    return return_value
def get_t_value_path_index(point, path_modifying_point_path_indexes)

Returns

int
the path_index that the t value represents
Expand source code
def get_t_value_path_index(point, path_modifying_point_path_indexes):
    """
            Returns:
                int: the path_index that the t value represents"""

    # T values and indexes are the same except t values need the decimal 'chopped off'
    path_modifying_point_index = int(point.get_t_value())

    return_value = path_modifying_point_path_indexes[path_modifying_point_index]

    # If the t value is not a plain number, then we need to calculate the top edge (2 would be plain while 2.1 would not be plain)
    if path_modifying_point_index != point.get_t_value():
        path_indexes = [path_modifying_point_path_indexes[path_modifying_point_index],
                        path_modifying_point_path_indexes[path_modifying_point_index + 1]]

        # Only keeping the decimal part of the t value
        t_value_proportion = point.get_t_value() - int(point.get_t_value())

        arc_distance = get_distance(*path_indexes)
        return_value = get_point_index_at_closest_distance(path_indexes[0], arc_distance * t_value_proportion)

    return return_value
def update_meter_path_points()

Updates 'points.path_points' to reflect what was written to swerve_output.txt

Expand source code
def update_meter_path_points():
    """Updates 'points.path_points' to reflect what was written to swerve_output.txt"""

    path_points = []
    file = open("swerve_output.txt", "r")

    for line in get_lines(file.read()[:-1]):
        is_path_action_point_line = line.__contains__("Control Point")

        # The lines that does not contain control points then it has the path points
        if not is_path_action_point_line:
            point_coordinates = line.split(",")
            left_edge, top_edge = float(point_coordinates[0]), float(point_coordinates[1])

            # Have to convert from the (0, 0) of the coordinates being the top left edge of the screen to the (0, 0) being the center of the hub
            # left_edge, top_edge = get_hub_centric_coordinates(left_edge, top_edge)

            path_points.append([left_edge, top_edge])

    file.close()

    points.path_points = path_points
    points.path_modifying_point_path_indexes = get_path_modifying_point_path_indexes()
def update_path_action_and_required_point_location(path_action_points, required_points, path_modifying_point_path_indexes, path_modifying_points)

Updates the t values of all the path_action_points. The t values allow the robot to know what to execute along the path

Expand source code
def update_path_action_and_required_point_location(path_action_points, required_points, path_modifying_point_path_indexes, path_modifying_points):
    """Updates the t values of all the path_action_points. The t values allow the robot to know what to execute along the path"""

    for point in path_action_points + required_points:
        path_index = get_t_value_path_index(point, path_modifying_point_path_indexes)
        path_point = points.path_points[path_index]

        # Path point(s) are in this format: [left_edge, top_edge]
        point.set_field_left_edge(path_point[0], want_rounding=True)
        point.set_field_top_edge(path_point[1], want_rounding=True)
def update_path_modifying_point_angle_at_points(path_modifying_points, required_points, required_point_path_indexes)

Updates the path_modifying_point's 'angle_at_point' attribute, so the angle of the robot lines can be drawn

Expand source code
def update_path_modifying_point_angle_at_points(path_modifying_points, required_points, required_point_path_indexes):
    """Updates the path_modifying_point's 'angle_at_point' attribute, so the angle of the robot lines can be drawn"""

    # Updating the angles of the path_modifying_points
    for path_modifying_point in path_modifying_points:
        last_angle = required_points[0].get_angle()
        next_angle = required_points[1].get_angle()

        previous_required_point_path_index = float("-inf")
        next_required_point_path_index = float("inf")
        path_modifying_point_path_index = path_modifying_point.path_index

        for i in range(len(required_point_path_indexes)):
            required_point_path_index = required_point_path_indexes[i]

            if (required_point_path_index <= path_modifying_point_path_index and
                    required_point_path_index > previous_required_point_path_index):

                previous_required_point_path_index = required_point_path_index
                last_angle = required_points[i].get_angle()

            if (required_point_path_index >= path_modifying_point_path_index and
                    required_point_path_index < next_required_point_path_index):

                next_required_point_path_index = required_point_path_index
                next_angle = required_points[i].get_angle()

        angle = get_angle_at_point(path_modifying_point_path_index,
                                   previous_required_point_path_index,
                                   next_required_point_path_index, last_angle,
                                   next_angle)

        path_modifying_point.set_angle_at_point(angle)
def update_path_modifying_point_information(path_action_points=None, path_modifying_points=None, required_points=None)

Updates the information that the path modifying points need specifically which required point affects the angle of the robot

Expand source code
def update_path_modifying_point_information(path_action_points=None, path_modifying_points=None, required_points=None):
    """Updates the information that the path modifying points need specifically which required point affects the angle of the robot"""

    required_point_path_indexes = []

    # Updating the required point paths
    path_action_points = points.path_action_points if path_action_points is None else path_action_points
    required_points = points.required_points if required_points is None else required_points
    path_modifying_points = points.path_modifying_points if path_modifying_points is None else path_modifying_points

    path_modifying_point_path_indexes = get_path_modifying_point_path_indexes()
    for x in range(len(points.path_modifying_points)):
        path_modifying_points[x].path_index = path_modifying_point_path_indexes[x]

    for required_point in required_points:
        index = get_t_value_path_index(required_point, path_modifying_point_path_indexes)
        required_point_path_indexes.append(index)

    update_path_modifying_point_angle_at_points(path_modifying_points, required_points, required_point_path_indexes)

    return [points.path_points, required_point_path_indexes, path_modifying_point_path_indexes]