How to generate a random convex polygon?

前端 未结 6 1169
南旧
南旧 2021-02-05 11:19

I\'m trying to devise a method for generating random 2D convex polygons. It has to have the following properties:

  • coordinates should be integers;
  • the poly
6条回答
  •  别那么骄傲
    2021-02-05 11:34

    Following @Mangara answer there is JAVA implementation, if someone is interested in Python port of it

    import random
    from math import atan2
    
    
    def to_convex_contour(vertices_count,
                          x_generator=random.random,
                          y_generator=random.random):
        """
        Port of Valtr algorithm by Sander Verdonschot.
    
        Reference:
            http://cglab.ca/~sander/misc/ConvexGeneration/ValtrAlgorithm.java
    
        >>> contour = to_convex_contour(20)
        >>> len(contour) == 20
        True
        """
        xs = [x_generator() for _ in range(vertices_count)]
        ys = [y_generator() for _ in range(vertices_count)]
        xs = sorted(xs)
        ys = sorted(ys)
        min_x, *xs, max_x = xs
        min_y, *ys, max_y = ys
        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):
            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
        points = []
        for vector_x, vector_y in vectors:
            points.append((point_x, point_y))
            point_x += vector_x
            point_y += vector_y
            min_polygon_x = min(min_polygon_x, point_x)
            min_polygon_y = min(min_polygon_y, point_y)
        shift_x, shift_y = min_x - min_polygon_x, min_y - min_polygon_y
        return [(point_x + shift_x, point_y + shift_y)
                for point_x, point_y in points]
    
    
    def _to_vectors_coordinates(coordinates, min_coordinate, max_coordinate):
        last_min = last_max = min_coordinate
        result = []
        for coordinate in coordinates:
            if _to_random_boolean():
                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
    
    
    def _to_random_boolean():
        return random.getrandbits(1)
    

提交回复
热议问题