Beispiel #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
Beispiel #2
0
def in_subpolygon(polygon: Polygon, q1: Point, q2: Point, t: Point,
                  t_trapezoid: Trapezoid) -> bool:
    """O(1): Return whether `t` lies inside the subpolygon of `polygon` to the right of `q1`,`q2`."""
    assert isinstance(q1, (PolygonPoint, EdgePoint))
    assert isinstance(q2, (PolygonPoint, EdgePoint))
    assert isinstance(t, Point)
    assert isinstance(t_trapezoid, Trapezoid)
    assert isinstance(polygon, Polygon)

    # Because our line (q1,q2) can start and/or end on edges we need to be careful in taking decisions.

    # Find the vertex indices for q1,q2. If q1 lies on an edge we need to increase the index by one to have the smaller
    # subpolygon.
    ix1 = q1.index
    if isinstance(q1, EdgePoint):
        ix1 = polygon.next(ix1)
    # The second index does not need special treatment since the index already shrinks the polygon.
    ix2 = q2.index

    if ix1 == ix2:
        assert isinstance(q1, EdgePoint)
        return Point.turn(q1, q2, t) != Point.CCW_TURN

    # First we check in which part of the (possibly) smaller subpolygon our trapezoid lies.
    small_polygon_position = trapezoid_subpolygon_position(
        polygon, ix1, ix2, t_trapezoid)

    # If the trapezoid lies right to the line it is safe.
    if small_polygon_position == 1:
        return True
    # In the other cases we should have a closer look.

    # Now we widen the subpolygon s.t. we can check whether t lies completely outside our range.
    if isinstance(q1, EdgePoint):
        ix1 = polygon.prev(ix1)
    if isinstance(q2, EdgePoint):
        ix2 = polygon.next(ix2)

    # If the point does not lie inside this bigger subpolygon we can safely say it does not lie in the actual
    # subpolygon
    if ix1 != ix2:
        big_polygon_position = trapezoid_subpolygon_position(
            polygon, ix1, ix2, t_trapezoid)
        if big_polygon_position == small_polygon_position == -1:
            return False

    # Now the trapezoid lies somewhere between the small and the big subpolygon.
    # First we can decide with respect to the x-coordinates -- just checking where t lies with respect to line(q1,q2)
    # does not work!
    if t.is_right_of(q1) and t.is_right_of(q2):
        if ((isinstance(q1, EdgePoint) and q1.index == t_trapezoid.bot_edge_ix)
                or (isinstance(q2, EdgePoint)
                    and q2.index == t_trapezoid.top_edge_ix)):
            return True
        if ((isinstance(q1, EdgePoint) and q1.index == t_trapezoid.top_edge_ix)
                or (isinstance(q2, EdgePoint)
                    and q2.index == t_trapezoid.bot_edge_ix)):
            return False
    if t.left_of(q1) and t.left_of(q2):
        if ((isinstance(q1, EdgePoint) and q1.index == t_trapezoid.top_edge_ix)
                or (isinstance(q2, EdgePoint)
                    and q2.index == t_trapezoid.bot_edge_ix)):
            return True
        if ((isinstance(q1, EdgePoint) and q1.index == t_trapezoid.bot_edge_ix)
                or (isinstance(q2, EdgePoint)
                    and q2.index == t_trapezoid.top_edge_ix)):
            return False

    return Point.turn(q1, q2, t) != Point.CCW_TURN