def contour_distance(drive_contour: np.ndarray, drive_center: Tuple[float, float], driven_contour: np.ndarray,
                     driven_center: Tuple[float, float], sampling_accuracy: int = 1024, k: int = 1) \
        -> Tuple[float, List[float], List[float], float, float]:
    """
    Determine the distance between two contours
    :return: the distance, two d_phi functions and center distances
    """
    drive_polar = toExteriorPolarCoord(Point(*drive_center), drive_contour, sampling_accuracy)
    driven_polar = toExteriorPolarCoord(Point(*driven_center), driven_contour, sampling_accuracy)
    return phi_distance(drive_polar, driven_polar, k)
Ejemplo n.º 2
0
def get_duals(drive_model: Model, x_sample_count: int, y_sample_count: int,
              horizontal_shifting: float):
    """
    Get duals of a given drive model, self-creating debugger
    :param drive_model: the driving model
    :param x_sample_count: count of samples in x direction
    :param y_sample_count: count of samples in y direction
    :param horizontal_shifting: shifting in x direction to keep the drive away from input
    :return: None
    """
    debugger, _, plotter = initialize((drive_model, ), None, ['duals'])
    drive_contour = shape_factory.get_shape_contour(drive_model, True, None,
                                                    drive_model.smooth)
    logging.debug('drive model loaded')

    # get the bounding
    drive_polygon = Polygon(drive_contour)
    min_x, min_y, max_x, max_y = drive_polygon.bounds
    drive_windows = [(min_x, max_x, min_y, max_y)]
    drive_windows = split_window(drive_windows[0], x_sample_count,
                                 y_sample_count)
    centers = [center_of_window(window) for window in drive_windows]

    # start finding the dual
    for index, center in enumerate(centers):
        if not point_in_contour(drive_contour, *center):
            logging.info(f'Point #{index}{center} not in contour')
            continue

        drive_polar = toExteriorPolarCoord(Point(*center), drive_contour, 1024)
        driven_polar, center_distance, phi = compute_dual_gear(drive_polar)
        drive_new_contour = toCartesianCoordAsNp(drive_polar,
                                                 horizontal_shifting, 0)
        driven_contour = toCartesianCoordAsNp(
            driven_polar, horizontal_shifting + center_distance, 0)
        driven_contour = np.array(
            rotate(driven_contour, phi[0],
                   (horizontal_shifting + center_distance, 0)))

        # move things back to center
        drive_new_contour += np.array((center[0], center[1]))
        driven_contour += np.array((center[0], center[1]))

        plotter.draw_contours(
            debugger.file_path(f'{index}.png'),
            [('input_drive', drive_contour), ('math_drive', drive_new_contour),
             ('math_driven', driven_contour)],
            [(horizontal_shifting + center[0], center[1]),
             (horizontal_shifting + center_distance + center[0], center[1])])
Ejemplo n.º 3
0
def math_cut(drive_model: Model,
             cart_drive: np.ndarray,
             reporter: Reporter,
             plotter: Optional[Plotter],
             animation=False,
             center_point: Optional[Tuple[float, float]] = None):
    center = center_point or drive_model.center_point
    polar_math_drive = toExteriorPolarCoord(Point(center[0], center[1]),
                                            cart_drive, drive_model.sample_num)
    polar_math_driven, center_distance, phi = compute_dual_gear(
        polar_math_drive, k=drive_model.k)

    if animation:
        plot_sampled_function((polar_math_drive, polar_math_driven), (phi, ),
                              reporter.get_math_debug_dir_name(),
                              100,
                              0.001, [(0, 0), (center_distance, 0)], (8, 8),
                              ((-0.5, 1.5), (-1.1, 1.1)),
                              plotter=plotter)

    # save figures
    plotter.draw_contours(
        reporter.file_path('math_drive.png'),
        [('math_drive', toCartesianCoordAsNp(polar_math_drive, 0, 0))], None)
    plotter.draw_contours(
        reporter.file_path('math_driven.png'),
        [('math_driven', toCartesianCoordAsNp(polar_math_driven, 0, 0))], None)
    plotter.draw_contours(
        reporter.file_path('math_results.png'),
        [('math_drive', toCartesianCoordAsNp(polar_math_drive, 0, 0)),
         ('math_driven',
          np.array(
              rotate(
                  list(
                      toCartesianCoordAsNp(polar_math_driven, center_distance,
                                           0)), phi[0],
                  (center_distance, 0))))], [(0, 0), (center_distance, 0)])

    logging.info('math rotate complete')
    logging.info(f'Center Distance = {center_distance}')

    return center_distance, phi, polar_math_drive, polar_math_driven
def sample_result(drive_contour: np.ndarray, drive_polygon: Polygon,
                  sample_window: Tuple[float, float, float, float], k: int) \
        -> Union[Tuple[float, float, float, np.ndarray], None]:
    """
    sample the center of the sample window and get the driven gear
    :param drive_contour: the drive gear contour
    :param drive_polygon: the driving polygon
    :param sample_window: the window in which to take sample (minx, maxx, miny, maxy)
    :param k: the drive/driven ratio
    :return: center_x, center_y, center_distance, the driven gear | None if not possible
    """
    min_x, max_x, min_y, max_y = sample_window
    center_x, center_y = (min_x + max_x) / 2, (min_y + max_y) / 2
    if not drive_polygon.contains(Point(center_x, center_y)):
        return None
    polar_coordinates = toExteriorPolarCoord(Point(center_x,
                                                   center_y), drive_contour,
                                             drive_contour.shape[0])
    driven, center_distance, phi = compute_dual_gear(polar_coordinates, k)
    driven_contour = toCartesianCoordAsNp(driven, 0, 0)
    return center_x, center_y, center_distance, driven_contour
def sampling_optimization(drive_contour: np.ndarray, driven_contour: np.ndarray, k: int, sampling_count: (int, int),
                          keep_count: int, resampling_accuracy: int, comparing_accuracy: int, debugger: Reporter,
                          max_sample_depth: int = 5, max_iteration: int = 1, smoothing: Tuple[int, int] = (0, 0),
                          visualization: Union[Dict, None] = None, draw_tar_functions: bool = False) \
        -> List[Tuple[float, float, float, float, float, np.ndarray, np.ndarray]]:
    """
    perform sampling optimization for drive contour and driven contour
    :param drive_contour: the driving gear's contour
    :param driven_contour: the driven gear's contour
    :param k: drive/driven ratio
    :param sampling_count: the number of samples in each dimension
    :param keep_count: the count of samples kept
    :param resampling_accuracy: count of points in the sampling procedure
    :param comparing_accuracy: count of samples during comparison
    :param debugger: the debugger for storing data
    :param max_sample_depth: maximum depth for the sampling optimization to use
    :param max_iteration: maximum time for drive/driven to swap and iterate
    :param smoothing: smoothing level to be taken by uniform re-sampling
    :param visualization: None for no figure, otherwise for visualization configuration
    :param draw_tar_functions: True for drawing tar functions in debug windows (affect performance)
    :return: final total score, score, center_x, center_y, center_distance, drive contour and driven contour
    """
    drive_contour = counterclockwise_orientation(drive_contour)
    driven_contour = counterclockwise_orientation(driven_contour)
    drive_polygon = Polygon(drive_contour)
    driven_polygon = Polygon(driven_contour)
    drive_polar = toExteriorPolarCoord(drive_polygon.centroid, drive_contour,
                                       resampling_accuracy)
    driven_polar = toExteriorPolarCoord(driven_polygon.centroid,
                                        driven_contour, resampling_accuracy)
    drive_smoothing, driven_smoothing = smoothing
    drive_contour = getUniformContourSampledShape(drive_contour,
                                                  resampling_accuracy,
                                                  drive_smoothing > 0)
    driven_contour = getUniformContourSampledShape(driven_contour,
                                                   resampling_accuracy,
                                                   driven_smoothing > 0)
    visualize_config = {
        'fig_size': (16, 9),
    }
    subplots = None
    if visualization is not None:
        visualize_config.update(visualization)
        plt.ion()
        fig, subplots = plt.subplots(3, 2)
        fig.set_size_inches(*visualize_config['fig_size'])
        update_polygon_subplots(drive_contour, driven_contour, subplots[0])

    debugging_root_directory = debugger.get_root_debug_dir_name()
    results = []
    # following two variables change during iteration
    drive = drive_contour
    driven = driven_contour
    for iteration_count in range(max_iteration):
        debug_directory = os.path.join(debugging_root_directory,
                                       f'iteration_{iteration_count}')
        os.makedirs(debug_directory, exist_ok=True)
        drive = counterclockwise_orientation(drive)
        new_res = sample_drive_gear(
            drive, driven_contour, k, sampling_count, keep_count,
            comparing_accuracy, max_sample_depth, debug_directory,
            subplots[1] if subplots is not None else None)
        results += [(None, score, *center, center_distance, drive, driven)
                    for score, *center, center_distance, driven in new_res]
        for index, result in enumerate(results):
            total_score, score, *center, center_distance, this_drive, driven = result
            if subplots is not None:
                update_polygon_subplots(
                    drive_contour, driven_contour,
                    subplots[0])  # so that the two subplots can iterate
                update_polygon_subplots(this_drive, driven, subplots[1])
                subplots[1][0].scatter(center[0], center[1], 3)
                subplots[1][0].text(0, 0, str(center))
                subplots[1][1].text(0, 0, str(score))
                subplots[1][1].scatter(0, 0, 3)
                if draw_tar_functions:
                    tars = [
                        triangle_area_representation(contour,
                                                     comparing_accuracy)
                        for contour in (this_drive, driven)
                    ]
                    for subplot, tar in zip(subplots[2], tars):
                        tar = tar[:, 0]
                        subplot.clear()
                        subplot.plot(range(len(tar)), tar, color='blue')
                if total_score is None:
                    total_score = score + shape_difference_rating(
                        this_drive,
                        drive_contour,
                        comparing_accuracy,
                        distance_function=trivial_distance)
                    results[index] = (total_score, *result[1:])
                score_str = "%.8f" % total_score
                plt.savefig(
                    os.path.join(debug_directory,
                                 f'final_result_{index}_{score_str}.png'))
                save_contour(
                    os.path.join(debug_directory,
                                 f'final_result_{index}_drive.dat'),
                    this_drive)
                save_contour(
                    os.path.join(debug_directory,
                                 f'final_result_{index}_driven.dat'), driven)
        *_, drive, driven = results[-1]  # get the last result
        drive_contour, driven_contour = driven_contour, drive_contour
        drive_polygon, driven_polygon = driven_polygon, drive_polygon
        drive_polar, driven_polar = driven_polar, drive_polar
        drive, driven = driven, drive
        drive_smoothing, driven_smoothing = driven_smoothing, drive_smoothing
        # drive_poly = Polygon(drive)
        # drive = shape_average(drive_polar, toExteriorPolarCoord(Polygon(drive).centroid, drive, resampling_accuracy),
        #                       drive_polygon.area, drive_poly.area)
        drive = phi_average.shape_average(
            drive_polar,
            toExteriorPolarCoord(
                Polygon(drive).centroid, drive, resampling_accuracy))
        drive = toCartesianCoordAsNp(drive, 0, 0)
        drive = getUniformContourSampledShape(drive, resampling_accuracy,
                                              drive_smoothing > 0)
        for subplot in subplots[2]:
            subplot.clear()
    return results