예제 #1
0
def constrict_convex_hull_size(
        points: Sequence[Point[Scalar]], *, context: Context,
        max_size: Optional[int]) -> Sequence[Point[Scalar]]:
    if max_size is None:
        return points
    convex_hull = context.points_convex_hull(points)
    if len(convex_hull) <= max_size:
        return points
    sorted_convex_hull = sorted(convex_hull,
                                key=partial(context.points_squared_distance,
                                            convex_hull[0]))
    new_border_points = []
    for index in range(max_size):
        quotient, remainder = divmod(index, 2)
        new_border_points.append(sorted_convex_hull[-quotient - 1] if remainder
                                 else sorted_convex_hull[quotient])
    orienteer = context.angle_orientation
    new_border = list(to_max_convex_hull(new_border_points, orienteer))
    new_border_extra_endpoints_pairs = tuple(
        {(new_border[index - 1], new_border[index])
         for index in range(len(new_border))} -
        {(convex_hull[index], convex_hull[index - 1])
         for index in range(len(convex_hull))})
    return (new_border + [
        point for point in set(points) - set(convex_hull) if all(
            orienteer(start, end, point) is Orientation.COUNTERCLOCKWISE
            for start, end in new_border_extra_endpoints_pairs)
    ])
예제 #2
0
def to_convex_vertices_sequence(points: Sequence[Point[Scalar]],
                                random: Random,
                                context: Context) -> Sequence[Point[Scalar]]:
    """
    Based on Valtr algorithm by Sander Verdonschot.

    Time complexity:
        ``O(len(points) * log len(points))``
    Memory complexity:
        ``O(len(points))``
    Reference:
        http://cglab.ca/~sander/misc/ConvexGeneration/convex.html
    """
    xs, ys = [point.x for point in points], [point.y for point in points]
    xs, ys = sorted(xs), sorted(ys)
    min_x, *xs, max_x = xs
    min_y, *ys, max_y = ys

    def to_vectors_coordinates(coordinates: List[Scalar],
                               min_coordinate: Scalar,
                               max_coordinate: Scalar) -> List[Scalar]:
        last_min = last_max = min_coordinate
        result = []
        for coordinate in coordinates:
            if random.getrandbits(1):
                result.append(coordinate - last_min)
                last_min = coordinate
            else:
                result.append(last_max - coordinate)
                last_max = coordinate
        result.extend((max_coordinate - last_min, last_max - max_coordinate))
        return result

    vectors_xs = to_vectors_coordinates(xs, min_x, max_x)
    vectors_ys = to_vectors_coordinates(ys, min_y, max_y)
    random.shuffle(vectors_ys)

    def to_vector_angle(vector: Tuple[Scalar, Scalar]) -> Key:
        x, y = vector
        return atan2(y, x)

    vectors = sorted(zip(vectors_xs, vectors_ys), key=to_vector_angle)
    point_x = point_y = 0
    min_polygon_x = min_polygon_y = 0
    coordinates_pairs = []
    for vector_x, vector_y in vectors:
        coordinates_pairs.append((point_x, point_y))
        point_x += vector_x
        point_y += vector_y
        min_polygon_x, min_polygon_y = (min(min_polygon_x, point_x),
                                        min(min_polygon_y, point_y))
    shift_x, shift_y = min_x - min_polygon_x, min_y - min_polygon_y
    point_cls = context.point_cls
    return context.points_convex_hull([
        point_cls(min(max(x + shift_x, min_x), max_x),
                  min(max(y + shift_y, min_y), max_y))
        for x, y in coordinates_pairs
    ])
예제 #3
0
def test_sizes(
        context: Context,
        polygon_with_extra_points: Tuple[Polygon, Sequence[Point]]) -> None:
    polygon, extra_points = polygon_with_extra_points

    result = Triangulation.constrained_delaunay(polygon,
                                                extra_points=extra_points,
                                                context=context)

    triangles = result.triangles()
    assert 0 < len(triangles) <= (2 * (len(
        to_distinct(
            chain(polygon.border.vertices, *
                  [hole.vertices
                   for hole in polygon.holes], extra_points))) - 1) - len(
                       context.points_convex_hull(polygon.border.vertices)))
    assert all(is_contour_triangular(triangle) for triangle in triangles)