def __lt__(self, other: 'SweepLineKey') -> bool: """ Checks if the segment (or at least the point) associated with event is lower than other's. """ event, other_event = self.event, other.event if event is other_event: return False start, end = event.start, event.end other_start, other_end = other_event.start, other_event.end other_start_orientation = orientation(end, start, other_start) other_end_orientation = orientation(end, start, other_end) if other_start_orientation is other_end_orientation: return (other_event.from_left if other_start_orientation is Orientation.COLLINEAR else (other_start_orientation is Orientation.COUNTERCLOCKWISE)) start_orientation = orientation(other_end, other_start, start) end_orientation = orientation(other_end, other_start, end) if start_orientation is end_orientation: return start_orientation is Orientation.CLOCKWISE elif other_start_orientation is Orientation.COLLINEAR: return other_end_orientation is Orientation.COUNTERCLOCKWISE elif start_orientation is Orientation.COLLINEAR: return end_orientation is Orientation.CLOCKWISE elif end_orientation is Orientation.COLLINEAR: return start_orientation is Orientation.CLOCKWISE else: return other_start_orientation is Orientation.COUNTERCLOCKWISE
def __lt__(self, other: 'SweepLineKey') -> bool: """ Checks if the segment (or at least the point) associated with event is lower than other's. """ event, other_event = self.event, other.event if event is other_event: return False start, other_start = event.start, other_event.start end, other_end = event.end, other_event.end other_start_orientation = orientation(end, start, other_start) other_end_orientation = orientation(end, start, other_end) if other_start_orientation is other_end_orientation: start_x, start_y = event.start other_start_x, other_start_y = other_event.start if other_start_orientation is not Orientation.COLLINEAR: # other segment fully lies on one side return other_start_orientation is Orientation.COUNTERCLOCKWISE # segments are collinear elif start_x == other_start_x: end_x, end_y = end other_end_x, other_end_y = other_end if start_y != other_start_y: # segments are vertical return start_y < other_start_y # segments have same start elif end_y != other_end_y: return end_y < other_end_y elif end_x != other_end_x: # segments are horizontal return end_x < other_end_x else: # segments are equal event.segments_ids = other_event.segments_ids = merge_ids( event.segments_ids, other_event.segments_ids) return False elif start_y != other_start_y: return start_y < other_start_y else: # segments are horizontal return start_x < other_start_x start_orientation = orientation(other_end, other_start, start) end_orientation = orientation(other_end, other_start, end) if start_orientation is end_orientation: return start_orientation is Orientation.CLOCKWISE elif other_start_orientation is Orientation.COLLINEAR: return other_end_orientation is Orientation.COUNTERCLOCKWISE elif start_orientation is Orientation.COLLINEAR: return end_orientation is Orientation.CLOCKWISE elif event.is_vertical: return start_orientation is Orientation.CLOCKWISE elif other_event.is_vertical: return other_start_orientation is Orientation.COUNTERCLOCKWISE elif other_end_orientation is Orientation.COLLINEAR: return other_start_orientation is Orientation.COUNTERCLOCKWISE elif end_orientation is Orientation.COLLINEAR: return start_orientation is Orientation.CLOCKWISE else: current_x = self.sweep_line.current_x return event.y_at(current_x) < other_event.y_at(current_x)
def __lt__(self, other: 'EventsQueueKey') -> bool: event, other_event = self.event, other.event start_x, start_y = event.start other_start_x, other_start_y = other_event.start if start_x != other_start_x: # different x-coordinate, # the event with lower x-coordinate is processed first return start_x < other_start_x elif start_y != other_start_y: # different points, but same x-coordinate, # the event with lower y-coordinate is processed first return start_y < other_start_y elif event.is_left_endpoint is not other_event.is_left_endpoint: # same start, but one is a left endpoint # and the other a right endpoint, # the right endpoint is processed first return other_event.is_left_endpoint # same start, both events are left endpoints # or both are right endpoints else: other_end_orientation = orientation(event.end, event.start, other_event.end) # the lowest segment is processed first return (other_event.from_left if other_end_orientation is Orientation.COLLINEAR else other_end_orientation is (Orientation.COUNTERCLOCKWISE if event.is_left_endpoint else Orientation.CLOCKWISE))
def _to_sub_hull(points: Iterable[Point]) -> List[Point]: result = [] for point in points: while len(result) >= 2: if orientation(result[-1], result[-2], point) is not Orientation.COUNTERCLOCKWISE: del result[-1] else: break result.append(point) return result
def _triangulate_three_points(sorted_points: Sequence[Point]) -> Triangulation: left_point, mid_point, right_point = sorted_points first_edge, second_edge = (QuadEdge.factory(left_point, mid_point), QuadEdge.factory(mid_point, right_point)) first_edge.opposite.splice(second_edge) angle_orientation = orientation(left_point, mid_point, right_point) if angle_orientation is Orientation.COUNTERCLOCKWISE: third_edge = second_edge.connect(first_edge) return Triangulation(third_edge.opposite, third_edge) elif angle_orientation is Orientation.CLOCKWISE: second_edge.connect(first_edge) return Triangulation(first_edge, second_edge.opposite) else: return Triangulation(first_edge, second_edge.opposite)
def to_contour_orientation(contour: Contour) -> Orientation: index = arg_min(contour) return orientation(contour[index], contour[index - 1], contour[(index + 1) % len(contour)])
def normalize_contour(contour: Contour) -> Contour: min_index = arg_min(contour) contour = contour[min_index:] + contour[:min_index] return (contour[:1] + contour[1:][::-1] if (orientation(contour[-1], contour[0], contour[1]) is Orientation.COUNTERCLOCKWISE) else contour)
def _is_inner_segment_point(start: Point, end: Point, point: Point) -> bool: return ((start < point < end if start < end else end < point < start) and orientation(start, end, point) is Orientation.COLLINEAR)
def is_convex_contour(contour: Contour) -> bool: contour = normalize_contour(contour) return all(orientation(contour[index - 2], contour[index - 1], contour[index]) is Orientation.CLOCKWISE for index in range(len(contour)))
def points_do_not_lie_on_the_same_line(points: Sequence[Point]) -> bool: return any(orientation(points[index - 1], points[index], points[(index + 1) % len(points)]) is not Orientation.COLLINEAR for index in range(len(points)))
def orientation_with(self, point: Point) -> Orientation: return orientation(self.end, self._start, point)
def orientation_with(self, point: Point) -> Orientation: return orientation(self.right, self.left, point)