예제 #1
0
def hit_polygon_boundary(p: Union[PolygonPoint, EdgePoint], q: Point,
                         polygon: Polygon) -> EdgePoint:
    """O(n): Return the index of the edge we hit when shooting from p to q."""
    assert isinstance(p, (PolygonPoint, EdgePoint))
    assert isinstance(q, Point)
    assert isinstance(polygon, Polygon)

    # We save some edge indices which are ignored when testing edge intersections.
    # This is to take rounding errors into account.
    # The forbidden indices are either both edges left and right of the starting point (which in this case is a vertex)
    # or the edge index. If a starting point has a "None" index we get (None, ) but this is ok for us.
    forbidden_indices = (p.index, )
    if isinstance(p, PolygonPoint) and p.index is not None:
        forbidden_indices = (p.index, polygon.prev(p.index))

    # We now construct a ray from p through q and check for intersection with every polygon edge.
    # We take the intersection point with the shortest distance to p since this is the only points which can be seen
    # from p.
    ray = Ray(p, q)
    hit_point = None
    distance = None
    for ix in polygon.indices():
        edge = polygon.edge(ix)
        if ix not in forbidden_indices and ray.properly_intersects(edge):
            tmp_hit = ray.intersection_point(edge)
            tmp_distance = p.squared_distance_to(tmp_hit)
            if distance is None or tmp_distance < distance:
                hit_point = EdgePoint(tmp_hit, edge.a.index)
                distance = tmp_distance

    # TODO: Remember what exactly this was for.
    if hit_point is None:
        hit_point = q

    return hit_point
예제 #2
0
def jarvis_march(
    polygon: Polygon,
    start_index: int,
    end_index: int,
    direction: int,
    good_turn: int,
    predicate: Callable[[Point], T],
    ignore: Callable[[Point, Point],
                     bool] = lambda x: False) -> Iterable[Point]:
    """Do a Jarvis march on the given polygon.

    We start at start_index going into direction stopping at end_index. For
    every vertex we consider appropriate predicate is applied. If it yields
    something which not evaluates to False we immediately stop the march and
    return the predicate result together with the vertex and a list of all
    points visited beforehand.

    Args:
        ignore: A function which is called for every vertex and should return True iff this vertex is to be ignored
            during the jarvis march.
        polygon: A polygon.
        start_index: The index of the starting vertex.
        end_index: The index of the last vertex to consider.
        direction: The direction in which we walk along the polygon edge. Needs
            to be either 1 or -1.
        good_turn: If the current, the next and a third vertex form a turn that
            is the same as good_turn, the third will be chosen over the next.
        predicate: A function that takes a vertex as an argument and decides
            whether to continue the march or stop.

    Returns:
        A 3-tuple (result, point, visited) in which result is the result of the
        predicate function, point is the point which fulfils the predicate and
        visited is a list of vertices visited in between.

    Raises:
        AssertionError:
            a) A type check fails.
            b) None of the vertices in the specified range fulfilled
                the predicate.
    """
    # ==========================================================================
    # Type checking.
    # ==========================================================================
    assert isinstance(polygon, Polygon)
    assert isinstance(start_index, int)
    assert isinstance(end_index, int)
    assert isinstance(direction, int)
    assert isinstance(good_turn, int)

    first = polygon.point(start_index)
    while True:
        point_loc.properties['predicates'] += 1
        result = predicate(first)

        # If the result does not evaluate to False return
        if result:
            return result, first

        # If this assertion fails none of the vertices fulfilled the predicate
        assert first.index != end_index

        second = polygon.point(first.index + direction)

        if second.index != end_index:
            for index in polygon.indices(second.index + direction, end_index,
                                         direction):
                point = polygon.point(index)
                point_loc.properties['ignores_theo'] += 1
                if Point.turn(first, second, point) == good_turn:
                    point_loc.properties['ignores'] += 1
                    if not ignore(first, point):
                        second = point

        yield first
        first = second