def to_star_contour_vertices(points: Sequence[Point[Scalar]], context: Context) -> Sequence[Point[Scalar]]: centroid = context.multipoint_centroid(context.multipoint_cls(points)) contour_cls, region_centroid_constructor, orienteer = ( context.contour_cls, context.region_centroid, context.angle_orientation) result, prev_size = points, len(points) + 1 while 2 < len(result) < prev_size: prev_size = len(result) result = [ deque(candidates, maxlen=1)[0][1] for _, candidates in groupby(sorted( (_to_segment_angle(centroid, point), point) for point in result), key=itemgetter(0)) ] if len(result) > 2: centroid = region_centroid_constructor(contour_cls(result)) index = 0 while max(index, 2) < len(result): if not angle_contains_point(result[index], result[index - 1], result[(index + 1) % len(result)], centroid, orienteer): del result[index] index += 1 compress_contour(result, orienteer) return result
def intersect_segments(first: Segment, second: Segment, context: Context) -> Union_[Empty, Multipoint, Segment]: relation = context.segments_relation(first, second) if relation is Relation.DISJOINT: return context.empty elif relation is Relation.TOUCH or relation is Relation.CROSS: return context.multipoint_cls([context.segments_intersection(first, second)]) else: return (first if relation is Relation.EQUAL or relation is Relation.COMPONENT else (second if relation is Relation.COMPOSITE else _intersect_segments_overlap(first, second, context)))
def unpack_points(points: Sequence[Point], context: Context ) -> Union[Empty, Multipoint]: return context.multipoint_cls(points) if points else context.empty