def _linear_interval_distance(min_coordinate: Scalar, max_coordinate: Scalar, coordinate: Scalar) -> Expansion: return (Expansion(min_coordinate, -coordinate) if coordinate < min_coordinate else (Expansion(coordinate, -max_coordinate) if coordinate > max_coordinate else Expansion()))
def signed_area(contour: Contour[Scalar], *, _half: Fraction = Fraction(1, 2)) -> Scalar: vertices = contour.vertices result, vertex = Expansion(), vertices[-1] for next_vertex in vertices: result = result + to_cross_product(vertex.x, vertex.y, next_vertex.x, next_vertex.y) vertex = next_vertex return result * _half
def centroid( multipoint: Multipoint, point_cls: Type[Point], inverse: Callable[[int], Fraction] = Fraction(1).__truediv__) -> Point: result_x = result_y = Expansion() for point in multipoint.points: result_x += point.x result_y += point.y inverted_points_count = inverse(len(multipoint.points)) return point_cls(result_x * inverted_points_count, result_y * inverted_points_count)
def centroid_components( vertices: Sequence[Point]) -> Tuple[Expansion, Expansion, Expansion]: double_area = x_numerator = y_numerator = Expansion() prev = vertices[-1] prev_x, prev_y = prev.x, prev.y for vertex in vertices: x, y = vertex.x, vertex.y area_component = to_cross_product(prev_x, prev_y, x, y) double_area = double_area + area_component x_numerator = x_numerator + area_component * (prev_x + x) y_numerator = y_numerator + area_component * (prev_y + y) 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 = Expansion() for segment in multisegment.segments: start, end = segment.start, segment.end length = sqrt( to_squared_points_distance(end.x, end.y, start.x, start.y)) 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 point_squared_distance( start: Point, end: Point, point: Point, dot_producer: QuaternaryPointFunction[Scalar]) -> Scalar: segment_squared_norm = dot_producer(start, end, start, end) point_end_projection = dot_producer(point, end, start, end) start_point_projection = dot_producer(start, point, start, end) start_factor = ((point_end_projection if point_end_projection > 0 else 0) if point_end_projection < segment_squared_norm else segment_squared_norm) end_factor = ((start_point_projection if start_point_projection > 0 else 0) if start_point_projection < segment_squared_norm else segment_squared_norm) return ((square(segment_squared_norm * Expansion(start.x, -point.x) + end_factor * Expansion(end.x, -start.x)) + square(segment_squared_norm * Expansion(start.y, -point.y) + end_factor * Expansion(end.y, -start.y)) if (abs(segment_squared_norm - end_factor) < abs(segment_squared_norm - start_factor)) else (square(segment_squared_norm * Expansion(end.x, -point.x) + start_factor * Expansion(start.x, -end.x)) + square(segment_squared_norm * Expansion(end.y, -point.y) + start_factor * Expansion(start.y, -end.y)))) / square(segment_squared_norm))
def centroid(segment: Segment, point_cls: Type[Point]) -> Point: return point_cls(Expansion(segment.start.x, segment.end.x) / 2, Expansion(segment.start.y, segment.end.y) / 2)
def scale_point(point: Point, factor_x: Scalar, factor_y: Scalar, point_cls: Type[Point]) -> Point: return point_cls( Expansion(point.x) * factor_x, Expansion(point.y) * factor_y)
def translate_point(point: Point, step_x: Scalar, step_y: Scalar, point_cls: Type[Point]) -> Point: return point_cls(Expansion(point.x) + step_x, Expansion(point.y) + step_y)
def to_cross_product(first_x: Scalar, first_y: Scalar, second_x: Scalar, second_y: Scalar) -> Expansion: """ Returns expansion of vectors' cross product. """ return Expansion(first_x) * second_y - Expansion(second_x) * first_y
def to_squared_points_distance(first_x: Scalar, first_y: Scalar, second_x: Scalar, second_y: Scalar) -> Expansion: return (square(Expansion(first_x, -second_x)) + square(Expansion(first_y, -second_y)))
def rotate_point_around_origin(point: Point, cosine: Scalar, sine: Scalar, point_cls: Type[Point]) -> Point: cosine, sine = Expansion(cosine), Expansion(sine) return point_cls(cosine * point.x - sine * point.y, sine * point.x + cosine * point.y)
def point_to_step(point: Point, cosine: Scalar, sine: Scalar) -> Tuple[Scalar, Scalar]: cosine, sine = Expansion(cosine), Expansion(sine) return (point.x - (cosine * point.x - sine * point.y), point.y - (sine * point.x + cosine * point.y))
def rotate_translate_point(point: Point, cosine: Scalar, sine: Scalar, step_x: Scalar, step_y: Scalar, point_cls: Type[Point]) -> Point: cosine, sine = Expansion(cosine), Expansion(sine) return point_cls(cosine * point.x - sine * point.y + step_x, sine * point.x + cosine * point.y + step_y)