def segment_squared_distance( box: Box, segment: Segment, dot_producer: QuaternaryPointFunction[Scalar], segments_collision_detector: QuaternaryPointFunction[bool], point_cls: Type[Point]) -> Scalar: segment_start, segment_end = segment.start, segment.end min_x, min_y, max_x, max_y = (rationalize(box.min_x), rationalize( box.min_y), rationalize(box.max_x), rationalize(box.max_y)) return ( 0 if ((min_x <= segment_start.x <= max_x and min_y <= segment_start.y <= max_y) or (min_x <= segment_end.x <= max_x and min_y <= segment_end.y <= max_y)) else ((segment_point_squared_distance(segment_start, segment_end, point_cls(min_x, min_y), dot_producer) if min_y == max_y else segment_segment_squared_distance( segment_start, segment_end, point_cls(min_x, min_y), point_cls(min_x, max_y), dot_producer, segments_collision_detector)) if min_x == max_x else (segment_segment_squared_distance( segment_start, segment_end, point_cls(min_x, min_y), point_cls(max_x, min_y), dot_producer, segments_collision_detector ) if min_y == max_y else _non_degenerate_segment_squared_distance( max_x, max_y, min_x, min_y, segment_start, segment_end, dot_producer, segments_collision_detector, point_cls))))
def centroid(multipoint: Multipoint, point_cls: Type[Point], inverse: Callable[[int], Fraction] = Fraction(1).__truediv__ ) -> Point: result_x = result_y = 0 for point in multipoint.points: result_x += rationalize(point.x) result_y += rationalize(point.y) inverted_points_count = inverse(len(multipoint.points)) return point_cls(result_x * inverted_points_count, result_y * inverted_points_count)
def signed_area(contour: Contour[Scalar], *, _half: Fraction = Fraction(1, 2)) -> Scalar: vertices = contour.vertices result, vertex = 0, vertices[-1] vertex_x, vertex_y = rationalize(vertex.x), rationalize(vertex.y) for next_vertex in vertices: next_vertex_x, next_vertex_y = (rationalize(next_vertex.x), rationalize(next_vertex.y)) result += vertex_x * next_vertex_y - next_vertex_x * vertex_y vertex_x, vertex_y = next_vertex_x, next_vertex_y return _half * result
def centroid_components( vertices: Sequence[Point]) -> Tuple[Scalar, Scalar, Scalar]: double_area = x_numerator = y_numerator = 0 prev_vertex = vertices[-1] prev_x, prev_y = rationalize(prev_vertex.x), rationalize(prev_vertex.y) for vertex in vertices: x, y = rationalize(vertex.x), rationalize(vertex.y) area_component = prev_x * y - prev_y * x double_area += area_component x_numerator += (prev_x + x) * area_component y_numerator += (prev_y + y) * area_component prev_x, prev_y = x, y return x_numerator, y_numerator, double_area
def centroid(multisegment: Multisegment, point_cls: Type[Point], sqrt: Callable[[Scalar], Scalar]) -> Point: accumulated_x = accumulated_y = accumulated_length = 0 for segment in multisegment.segments: start, end = segment.start, segment.end start_x, start_y = rationalize(start.x), rationalize(start.y) end_x, end_y = rationalize(end.x), rationalize(end.y) length = sqrt((end_x - start_x)**2 + (end_y - start_y)**2) accumulated_x += (start_x + end_x) * length accumulated_y += (start_y + end_y) * length accumulated_length += length inverted_divisor = 1 / (2 * accumulated_length) return point_cls(accumulated_x * inverted_divisor, accumulated_y * inverted_divisor)
def multiply(first_start: Point, first_end: Point, second_start: Point, second_end: Point) -> Scalar: return ((rationalize(first_end.x) - rationalize(first_start.x)) * (rationalize(second_end.x) - rationalize(second_start.x)) + (rationalize(first_end.y) - rationalize(first_start.y)) * (rationalize(second_end.y) - rationalize(second_start.y)))
def centroid(contour: Contour, point_cls: Type[Point], sqrt: Callable[[Scalar], Scalar]) -> Point: vertices = contour.vertices accumulated_x = accumulated_y = accumulated_length = 0 vertex = vertices[-1] start_x, start_y = rationalize(vertex.x), rationalize(vertex.y) for vertex in vertices: end_x, end_y = rationalize(vertex.x), rationalize(vertex.y) length = sqrt((end_x - start_x)**2 + (end_y - start_y)**2) accumulated_x += (start_x + end_x) * length accumulated_y += (start_y + end_y) * length accumulated_length += length start_x, start_y = end_x, end_y inverted_divisor = 1 / (2 * accumulated_length) return point_cls(accumulated_x * inverted_divisor, accumulated_y * inverted_divisor)
def rotate_translate_point(point: Point, cosine: Scalar, sine: Scalar, step_x: Scalar, step_y: Scalar, point_cls: Type[Point]) -> Point: x, y = rationalize(point.x), rationalize(point.y) cosine, sine = rationalize(cosine), rationalize(sine) return point_cls(cosine * x - sine * y + rationalize(step_x), sine * x + cosine * y + rationalize(step_y))
def test(point: Point, first: Point, second: Point, third: Point) -> Scalar: point_x, point_y = rationalize(point.x), rationalize(point.y) first_dx, first_dy = (rationalize(first.x) - point_x, rationalize(first.y) - point_y) second_dx, second_dy = (rationalize(second.x) - point_x, rationalize(second.y) - point_y) third_dx, third_dy = (rationalize(third.x) - point_x, rationalize(third.y) - point_y) return Location(1 + to_sign((first_dx * first_dx + first_dy * first_dy) * (second_dx * third_dy - second_dy * third_dx) - (second_dx * second_dx + second_dy * second_dy) * (first_dx * third_dy - first_dy * third_dx) + (third_dx * third_dx + third_dy * third_dy) * (first_dx * second_dy - first_dy * second_dx)))
def point_squared_distance(segment_start: Point, segment_end: Point, point: Point, dot_producer: QuaternaryPointFunction[Scalar] ) -> Scalar: end_factor = max(0, min(1, dot_producer(segment_start, point, segment_start, segment_end) / point_point_squared_distance(segment_start, segment_end))) start_factor = 1 - end_factor return ((start_factor * rationalize(segment_start.x) + end_factor * rationalize(segment_end.x) - rationalize(point.x)) ** 2 + (start_factor * rationalize(segment_start.y) + end_factor * rationalize(segment_end.y) - rationalize(point.y)) ** 2)
def translate_point(point: Point, step_x: Scalar, step_y: Scalar, point_cls: Type[Point]) -> Point: return point_cls( rationalize(point.x) + rationalize(step_x), rationalize(point.y) + rationalize(step_y))
def point_squared_distance(box: Box, point: Point) -> Scalar: return (_linear_interval_distance(rationalize( box.min_x), rationalize(box.max_x), rationalize(point.x))**2 + _linear_interval_distance(rationalize( box.min_y), rationalize(box.max_y), rationalize(point.y))**2)
def scale_point(point: Point, factor_x: Scalar, factor_y: Scalar, point_cls: Type[Point]) -> Point: return point_cls( rationalize(point.x) * rationalize(factor_x), rationalize(point.y) * rationalize(factor_y))
def centroid(segment: Segment, point_cls: Type[Point]) -> Point: return point_cls( (rationalize(segment.start.x) + rationalize(segment.end.x)) / 2, (rationalize(segment.start.y) + rationalize(segment.end.y)) / 2)
def rotate_point_around_origin(point: Point, cosine: Scalar, sine: Scalar, point_cls: Type[Point]) -> Point: cosine, sine = rationalize(cosine), rationalize(sine) x, y = rationalize(point.x), rationalize(point.y) return point_cls(cosine * x - sine * y, sine * x + cosine * y)
def point_to_step(point: Point, cosine: Scalar, sine: Scalar) -> Tuple[Scalar, Scalar]: x, y = rationalize(point.x), rationalize(point.y) cosine, sine = rationalize(cosine), rationalize(sine) return x - (cosine * x - sine * y), y - (sine * x + cosine * y)