def separate_closed_paths(paths):
    """takes a list of path strings
    breaks non continuous paths and
    joins connecting paths together
    to return a list of closed paths """
    discrete_paths = []
    closed_paths = []
    open_paths = []
    dead_ends = []
    for path in paths:
        discrete_paths += divide_pathstring_parts(path)
    for path in discrete_paths:
        parsed_path = SVGPT.parse_path(path)
        if parsed_path.isclosed():
            closed_paths.append(path)
        else:
            open_paths.append(parsed_path)
    while open_paths:
        path = open_paths.pop()
        new_path = None
        for other_path in open_paths:
            if path.end == other_path.start:
                new_path = path.d() + " " + other_path.d().replace('M', 'L')
                open_paths.remove(other_path)
                break
            elif path.start == other_path.end:
                new_path = other_path.d() + " " + path.d().replace('M', 'L')
                open_paths.remove(other_path)
                break
            elif path.end == other_path.end:
                new_path = path.d() + " " + other_path.reversed().d().replace(
                    'M', 'L')
                open_paths.remove(other_path)
                break
            elif path.start == other_path.start:
                new_path = path.reversed().d() + " " + other_path.d().replace(
                    'M', 'L')
                open_paths.remove(other_path)
                break
        if new_path is not None:
            parsed_new_path = SVGPT.parse_path(new_path)
            if parsed_new_path.isclosed():
                closed_paths.append(new_path)
            else:
                open_paths.append(parsed_new_path)
        else:
            dead_ends.append(path.d())

    open_paths = dead_ends
    return closed_paths, open_paths
def path_to_segments(path_string):
    """breaks down a path into a list of segments"""
    segments = []
    path = SVGPT.parse_path(path_string)
    for segment in path:
        if isinstance(segment, SVGPT.path.Line):  # pylint: disable=maybe-no-member
            points = points_from_line(segment)
            new_path_string = f"M {points[0][0]} {points[0][1]} L {points[1][0]} {points[1][1]}"
            segments.append(new_path_string)
    return segments
def segments_overlap(first, second):
    """returns true if segments share more than a single point"""
    first_path_string = points_to_path(first, closed=False)
    second_path_string = points_to_path(second, closed=False)
    first_path = SVGPT.parse_path(first_path_string)[0]
    second_path = SVGPT.parse_path(second_path_string)[0]
    overlaps = []
    for point in first:
        complex_point = xy_to_complex(point)
        place_on_path = second_path.point_to_t(complex_point)
        if place_on_path is not None:
            if point not in overlaps:
                overlaps.append(point)
    for point in second:
        complex_point = xy_to_complex(point)
        place_on_path = first_path.point_to_t(complex_point)
        if place_on_path is not None:
            if point not in overlaps:
                overlaps.append(point)
    overlap = len(overlaps) >= 2
    return overlap
def rotate_path(path_string, angle_degrees, xy_point):
    """rotates a path string a given number of degrees (CCW) around point (x, y)"""
    path = SVGPT.parse_path(path_string)

    empty = SVGPT.Path()
    if path == empty:
        return ""

    complex_point = xy_to_complex(xy_point)
    rotated_path = path.rotated(angle_degrees, origin=complex_point)
    rotated_string = rotated_path.d()
    return rotated_string
def move_path(path_string, xy_translation):
    """Takes a path string and xy_translation (x, y), and moves it x units over, and y units down"""

    path = SVGPT.parse_path(path_string)

    empty = SVGPT.Path()
    if path == empty:
        return ""

    complex_translation = xy_to_complex(xy_translation)
    translated_path = path.translated(complex_translation)
    translated_string = translated_path.d()
    return translated_string
def path_string_to_points(path_string):
    """Convert path string into a list of points"""
    path = SVGPT.parse_path(path_string)

    empty = SVGPT.Path()
    if path == empty:
        return None
    points = []
    for segment in path:
        segment_points = subpath_to_points(segment)
        for point in segment_points:
            if points == [] or point != points[-1]:
                points.append(point)
    return points
def get_start(path_string):
    """returns start point (x, y) of a path string"""
    path = SVGPT.parse_path(path_string)
    start_xy = complex_to_xy(path.start)
    return start_xy
def get_length(path_string):
    """returns the length of a path string"""
    path = SVGPT.parse_path(path_string)
    return path.length()
def get_angle(path_string):
    """measures the angle in degrees (CCW) from the path positive X axis (0,0), (0,1)"""
    path = SVGPT.parse_path(path_string)
    vector = path.point(1) - path.point(0)
    angle = np.angle(vector, deg=True)
    return angle
def scale_path(path_string, scale):
    """scales a path string by a scale factor (float)"""
    path = SVGPT.parse_path(path_string)
    scaled_path = path.scaled(scale)
    new_path_string = scaled_path.d()
    return new_path_string