#![allow(dead_code)]
use crate::constants::GEOMETRIC_EPSILON;
use crate::prelude::*;
use robust::{Coord, incircle, orient2d};
use std::f64::consts::PI;
fn angle_in_range(angle: f64, start: f64, end: f64) -> bool {
if start <= end {
angle >= start && angle <= end
} else {
angle >= start || angle <= end
}
}
fn minimal_bounding_circle(points: &[Point]) -> Circle {
if points.is_empty() {
return Circle::new(point(0.0, 0.0), 0.0);
}
if points.len() == 1 {
return Circle::new(points[0], 0.0);
}
if points.len() == 2 {
let center = (points[0] + points[1]) * 0.5;
let radius = (points[1] - points[0]).norm() * 0.5;
return Circle::new(center, radius);
}
let mut circle = minimal_bounding_circle(&points[0..2]);
for &p in &points[2..] {
if (p - circle.c).norm() > circle.r + 1e-10 {
circle = minimal_circle_with_point(points, p);
}
}
circle
}
fn minimal_circle_with_point(points: &[Point], p: Point) -> Circle {
let mut best_circle = Circle::new(p, 0.0);
for &q in points {
if q != p {
let candidate = Circle::new((p + q) * 0.5, (q - p).norm() * 0.5);
if circle_contains_all_points(&candidate, points) && candidate.r > best_circle.r {
best_circle = candidate;
}
}
}
for i in 0..points.len() {
for j in i + 1..points.len() {
if let Some(candidate) = circumcircle(p, points[i], points[j]) {
if circle_contains_all_points(&candidate, points)
&& (best_circle.r == 0.0 || candidate.r < best_circle.r)
{
best_circle = candidate;
}
}
}
}
best_circle
}
fn circle_contains_all_points(circle: &Circle, points: &[Point]) -> bool {
points
.iter()
.all(|&p| (p - circle.c).norm() <= circle.r + GEOMETRIC_EPSILON)
}
fn _point_in_circle_robust(p: Point, circle_points: &[Point]) -> bool {
if circle_points.len() != 3 {
let center = circle_points
.iter()
.fold(point(0.0, 0.0), |acc, &pt| acc + pt)
/ circle_points.len() as f64;
let radius = circle_points
.iter()
.map(|&pt| (pt - center).norm())
.fold(0.0, f64::max);
return (p - center).norm() <= radius + 1e-10;
}
let result = incircle(
Coord {
x: circle_points[0].x,
y: circle_points[0].y,
},
Coord {
x: circle_points[1].x,
y: circle_points[1].y,
},
Coord {
x: circle_points[2].x,
y: circle_points[2].y,
},
Coord { x: p.x, y: p.y },
);
result > 0.0 }
fn circumcircle(p1: Point, p2: Point, p3: Point) -> Option<Circle> {
let orientation = orient2d(
Coord { x: p1.x, y: p1.y },
Coord { x: p2.x, y: p2.y },
Coord { x: p3.x, y: p3.y },
);
if orientation.abs() < 1e-10 {
return None; }
let ax = p1.x;
let ay = p1.y;
let bx = p2.x;
let by = p2.y;
let cx = p3.x;
let cy = p3.y;
let a_norm_sq = ax * ax + ay * ay;
let b_norm_sq = bx * bx + by * by;
let c_norm_sq = cx * cx + cy * cy;
let d = 2.0 * orientation;
let ux = (a_norm_sq * (by - cy) + b_norm_sq * (cy - ay) + c_norm_sq * (ay - by)) / d;
let uy = (a_norm_sq * (cx - bx) + b_norm_sq * (ax - cx) + c_norm_sq * (bx - ax)) / d;
let center = point(ux, uy);
let radius = (p1 - center).norm();
Some(Circle::new(center, radius))
}
#[cfg(test)]
mod test_arc_bounding_circle {
use super::*;
use crate::constants::GEOMETRIC_EPSILON;
use std::f64::consts::PI;
#[test]
fn test_line_segment_bounding() {
let line = arcseg(point(0.0, 0.0), point(3.0, 4.0));
let bounding = arc_bounding_circle(&line);
let expected_center = point(1.5, 2.0); let expected_radius = 2.5;
assert!((bounding.c.x - expected_center.x).abs() < GEOMETRIC_EPSILON);
assert!((bounding.c.y - expected_center.y).abs() < GEOMETRIC_EPSILON);
assert!((bounding.r - expected_radius).abs() < GEOMETRIC_EPSILON);
}
#[test]
fn test_full_circle_bounding() {
let center = point(0.0, 0.0);
let radius = 2.0;
let start_end = point(radius, 0.0);
let full_circle = arc(start_end, start_end, center, radius);
let bounding = arc_bounding_circle(&full_circle);
assert!(bounding.r >= radius - GEOMETRIC_EPSILON); assert!(bounding.r <= radius + 0.1);
let dist_to_point = (start_end - bounding.c).norm();
assert!(dist_to_point <= bounding.r + GEOMETRIC_EPSILON);
}
#[test]
fn test_semicircle_bounding() {
let center = point(0.0, 0.0);
let radius = 1.0;
let start = point(1.0, 0.0);
let end = point(-1.0, 0.0);
let semicircle = arc(start, end, center, radius);
let bounding = arc_bounding_circle(&semicircle);
assert!((bounding.c.x - center.x).abs() < GEOMETRIC_EPSILON);
assert!((bounding.c.y - center.y).abs() < GEOMETRIC_EPSILON);
assert!((bounding.r - radius).abs() < GEOMETRIC_EPSILON);
}
#[test]
fn test_quarter_circle_bounding() {
let center = point(0.0, 0.0);
let radius = 1.0;
let start = point(1.0, 0.0);
let end = point(0.0, 1.0);
let quarter_circle = arc(start, end, center, radius);
let bounding = arc_bounding_circle(&quarter_circle);
let top = point(0.0, 1.0);
let right = point(1.0, 0.0);
let dist_to_top = (top - bounding.c).norm();
let dist_to_right = (right - bounding.c).norm();
assert!(dist_to_top <= bounding.r + GEOMETRIC_EPSILON);
assert!(dist_to_right <= bounding.r + GEOMETRIC_EPSILON);
assert!(bounding.r <= radius + GEOMETRIC_EPSILON);
let dist_to_start = (start - bounding.c).norm();
let dist_to_end = (end - bounding.c).norm();
assert!(dist_to_start <= bounding.r + GEOMETRIC_EPSILON);
assert!(dist_to_end <= bounding.r + GEOMETRIC_EPSILON);
}
#[test]
fn test_small_arc_bounding() {
let center = point(0.0, 0.0);
let radius = 2.0;
let start = point(2.0, 0.0); let end = point(1.9318, 0.5176);
let small_arc = arc(start, end, center, radius);
let bounding = arc_bounding_circle(&small_arc);
let dist_to_start = (start - bounding.c).norm();
let dist_to_end = (end - bounding.c).norm();
assert!(dist_to_start <= bounding.r + GEOMETRIC_EPSILON);
assert!(dist_to_end <= bounding.r + GEOMETRIC_EPSILON);
assert!(bounding.r <= radius + GEOMETRIC_EPSILON); }
#[test]
fn test_arc_crossing_zero_angle() {
let center = point(0.0, 0.0);
let radius = 1.0;
let start = point(0.866, -0.5); let end = point(0.866, 0.5);
let crossing_arc = arc(start, end, center, radius);
let bounding = arc_bounding_circle(&crossing_arc);
let right_extreme = point(1.0, 0.0);
let dist_to_right = (right_extreme - bounding.c).norm();
assert!(dist_to_right <= bounding.r + GEOMETRIC_EPSILON);
let dist_to_start = (start - bounding.c).norm();
let dist_to_end = (end - bounding.c).norm();
assert!(dist_to_start <= bounding.r + GEOMETRIC_EPSILON);
assert!(dist_to_end <= bounding.r + GEOMETRIC_EPSILON);
}
#[test]
fn test_large_arc_bounding() {
let center = point(0.0, 0.0);
let radius = 1.0;
let start = point(1.0, 0.0); let end = point(-0.5, -0.866);
let large_arc = arc(start, end, center, radius);
let bounding = arc_bounding_circle(&large_arc);
let top = point(0.0, 1.0);
let right = point(1.0, 0.0);
let dist_to_top = (top - bounding.c).norm();
let dist_to_right = (right - bounding.c).norm();
assert!(dist_to_top <= bounding.r + GEOMETRIC_EPSILON);
assert!(dist_to_right <= bounding.r + GEOMETRIC_EPSILON);
assert!((bounding.c.x - center.x).abs() < GEOMETRIC_EPSILON);
assert!((bounding.c.y - center.y).abs() < GEOMETRIC_EPSILON);
assert!((bounding.r - radius).abs() < GEOMETRIC_EPSILON);
}
#[test]
fn test_pi_threshold_arc_bounding() {
let center = point(0.0, 0.0);
let radius = 2.0;
let start = point(2.0, 0.0); let end = point(-1.9, -0.3);
let threshold_arc = arc(start, end, center, radius);
let bounding = arc_bounding_circle(&threshold_arc);
assert!((bounding.c.x - center.x).abs() < GEOMETRIC_EPSILON);
assert!((bounding.c.y - center.y).abs() < GEOMETRIC_EPSILON);
assert!((bounding.r - radius).abs() < GEOMETRIC_EPSILON);
let end2 = point(-1.9, 0.3); let small_arc = arc(start, end2, center, radius);
let bounding2 = arc_bounding_circle(&small_arc);
assert!(bounding2.r < radius - GEOMETRIC_EPSILON);
}
#[test]
fn test_degenerate_arc_bounding() {
let center = point(0.0, 0.0);
let radius = 1.0;
let start = point(1.0, 0.0);
let end = point(0.9999, 0.0001);
let degenerate_arc = arc(start, end, center, radius);
let bounding = arc_bounding_circle(°enerate_arc);
let dist_to_start = (start - bounding.c).norm();
let dist_to_end = (end - bounding.c).norm();
assert!(dist_to_start <= bounding.r + GEOMETRIC_EPSILON);
assert!(dist_to_end <= bounding.r + GEOMETRIC_EPSILON);
assert!(bounding.r <= radius + GEOMETRIC_EPSILON);
}
#[test]
fn test_arc_with_translated_center() {
let center = point(5.0, 3.0);
let radius = 2.0;
let start = point(7.0, 3.0); let end = point(5.0, 5.0);
let translated_arc = arc(start, end, center, radius);
let bounding = arc_bounding_circle(&translated_arc);
let dist_to_start = (start - bounding.c).norm();
let dist_to_end = (end - bounding.c).norm();
assert!(dist_to_start <= bounding.r + GEOMETRIC_EPSILON);
assert!(dist_to_end <= bounding.r + GEOMETRIC_EPSILON);
assert!(bounding.r <= radius + GEOMETRIC_EPSILON);
assert!(bounding.r >= (end - start).norm() * 0.5 - GEOMETRIC_EPSILON); }
#[test]
fn test_zero_radius_arc() {
let center = point(1.0, 1.0);
let start = point(1.0, 1.0);
let end = point(1.0, 1.0);
let point_arc = arc(start, end, center, 0.0);
let bounding = arc_bounding_circle(&point_arc);
assert!(bounding.r < GEOMETRIC_EPSILON);
assert!((bounding.c.x - center.x).abs() < GEOMETRIC_EPSILON);
assert!((bounding.c.y - center.y).abs() < GEOMETRIC_EPSILON);
}
#[test]
fn test_angle_range_function() {
assert!(angle_in_range(PI / 4.0, 0.0, PI / 2.0));
assert!(!angle_in_range(3.0 * PI / 4.0, 0.0, PI / 2.0));
assert!(angle_in_range(0.1, 3.0 * PI / 2.0, PI / 4.0));
assert!(angle_in_range(7.0 * PI / 4.0, 3.0 * PI / 2.0, PI / 4.0));
assert!(!angle_in_range(PI / 2.0, 3.0 * PI / 2.0, PI / 4.0));
}
#[test]
fn test_minimal_bounding_circle_function() {
let empty: Vec<Point> = vec![];
let circle = minimal_bounding_circle(&empty);
assert!(circle.r < GEOMETRIC_EPSILON);
let single = vec![point(1.0, 2.0)];
let circle = minimal_bounding_circle(&single);
assert!(circle.r < GEOMETRIC_EPSILON);
assert!((circle.c.x - 1.0).abs() < GEOMETRIC_EPSILON);
assert!((circle.c.y - 2.0).abs() < GEOMETRIC_EPSILON);
let two = vec![point(0.0, 0.0), point(3.0, 4.0)];
let circle = minimal_bounding_circle(&two);
assert!((circle.r - 2.5).abs() < GEOMETRIC_EPSILON);
assert!((circle.c.x - 1.5).abs() < GEOMETRIC_EPSILON);
assert!((circle.c.y - 2.0).abs() < GEOMETRIC_EPSILON);
let triangle = vec![point(0.0, 0.0), point(4.0, 0.0), point(0.0, 3.0)];
let circle = minimal_bounding_circle(&triangle);
for &p in &triangle {
let dist = (p - circle.c).norm();
assert!(dist <= circle.r + GEOMETRIC_EPSILON);
}
}
}
#[cfg(test)]
mod test_arc_bounding_rect {
use super::*;
const GEOMETRIC_EPSILON: f64 = 1e-10;
#[test]
fn test_line_segment_bounding_rect() {
let line = arcseg(point(1.0, 2.0), point(4.0, 6.0));
let bounding = arc_bounding_rect(&line);
assert!((bounding.p1.x - 1.0).abs() < GEOMETRIC_EPSILON); assert!((bounding.p1.y - 2.0).abs() < GEOMETRIC_EPSILON); assert!((bounding.p2.x - 4.0).abs() < GEOMETRIC_EPSILON); assert!((bounding.p2.y - 6.0).abs() < GEOMETRIC_EPSILON); }
#[test]
fn test_full_circle_bounding_rect() {
let center = point(2.0, 3.0);
let radius = 1.5;
let start_end = point(center.x + radius, center.y);
let full_circle = arc(start_end, start_end, center, radius);
let bounding = arc_bounding_rect(&full_circle);
assert!((bounding.p1.x - (center.x - radius)).abs() < GEOMETRIC_EPSILON); assert!((bounding.p1.y - (center.y - radius)).abs() < GEOMETRIC_EPSILON); assert!((bounding.p2.x - (center.x + radius)).abs() < GEOMETRIC_EPSILON); assert!((bounding.p2.y - (center.y + radius)).abs() < GEOMETRIC_EPSILON); }
#[test]
fn test_semicircle_bounding_rect() {
let center = point(0.0, 0.0);
let radius = 1.0;
let start = point(-1.0, 0.0);
let end = point(1.0, 0.0);
let semicircle = arc(start, end, center, radius);
let bounding = arc_bounding_rect(&semicircle);
assert!((bounding.p1.x - (-1.0)).abs() < GEOMETRIC_EPSILON); assert!((bounding.p1.y - (-1.0)).abs() < GEOMETRIC_EPSILON); assert!((bounding.p2.x - 1.0).abs() < GEOMETRIC_EPSILON); assert!((bounding.p2.y - 0.0).abs() < GEOMETRIC_EPSILON); }
#[test]
fn test_quarter_circle_bounding_rect() {
let center = point(0.0, 0.0);
let radius = 1.0;
let start = point(1.0, 0.0);
let end = point(0.0, 1.0);
let quarter_circle = arc(start, end, center, radius);
let bounding = arc_bounding_rect(&quarter_circle);
assert!((bounding.p1.x - 0.0).abs() < GEOMETRIC_EPSILON); assert!((bounding.p1.y - 0.0).abs() < GEOMETRIC_EPSILON); assert!((bounding.p2.x - 1.0).abs() < GEOMETRIC_EPSILON); assert!((bounding.p2.y - 1.0).abs() < GEOMETRIC_EPSILON); }
#[test]
fn test_small_arc_bounding_rect() {
let center = point(0.0, 0.0);
let radius = 2.0;
let start = point(2.0, 0.0); let end = point(1.932, 0.518);
let small_arc = arc(start, end, center, radius);
let bounding = arc_bounding_rect(&small_arc);
let min_x = start.x.min(end.x);
let max_x = start.x.max(end.x);
let min_y = start.y.min(end.y);
let max_y = start.y.max(end.y);
assert!((bounding.p1.x - min_x).abs() < GEOMETRIC_EPSILON);
assert!((bounding.p1.y - min_y).abs() < GEOMETRIC_EPSILON);
assert!((bounding.p2.x - max_x).abs() < GEOMETRIC_EPSILON);
assert!((bounding.p2.y - max_y).abs() < GEOMETRIC_EPSILON);
}
#[test]
fn test_arc_crossing_zero_angle() {
let center = point(0.0, 0.0);
let radius = 1.0;
let start = point(0.866, -0.5); let end = point(0.866, 0.5);
let crossing_arc = arc(start, end, center, radius);
let bounding = arc_bounding_rect(&crossing_arc);
assert!((bounding.p1.x - 0.866).abs() < GEOMETRIC_EPSILON); assert!((bounding.p1.y - (-0.5)).abs() < GEOMETRIC_EPSILON); assert!((bounding.p2.x - 1.0).abs() < GEOMETRIC_EPSILON); assert!((bounding.p2.y - 0.5).abs() < GEOMETRIC_EPSILON); }
#[test]
fn test_large_arc_bounding_rect() {
let center = point(0.0, 0.0);
let radius = 1.0;
let start = point(1.0, 0.0); let end = point(-0.5, -0.866);
let large_arc = arc(start, end, center, radius);
let bounding = arc_bounding_rect(&large_arc);
assert!((bounding.p1.x - (-1.0)).abs() < GEOMETRIC_EPSILON); assert!((bounding.p1.y - (-0.866)).abs() < 0.001); assert!((bounding.p2.x - 1.0).abs() < GEOMETRIC_EPSILON); assert!((bounding.p2.y - 1.0).abs() < GEOMETRIC_EPSILON); }
#[test]
fn test_arc_with_all_extremes() {
let center = point(0.0, 0.0);
let radius = 1.0;
let start = point(1.0, 0.0); let end = point(0.0, -1.0);
let large_arc = arc(start, end, center, radius);
let bounding = arc_bounding_rect(&large_arc);
assert!((bounding.p1.x - (-1.0)).abs() < GEOMETRIC_EPSILON); assert!((bounding.p1.y - (-1.0)).abs() < GEOMETRIC_EPSILON); assert!((bounding.p2.x - 1.0).abs() < GEOMETRIC_EPSILON); assert!((bounding.p2.y - 1.0).abs() < GEOMETRIC_EPSILON); }
#[test]
fn test_arc_with_translated_center() {
let center = point(5.0, 3.0);
let radius = 2.0;
let start = point(7.0, 3.0); let end = point(5.0, 5.0);
let translated_arc = arc(start, end, center, radius);
let bounding = arc_bounding_rect(&translated_arc);
assert!((bounding.p1.x - 5.0).abs() < GEOMETRIC_EPSILON); assert!((bounding.p1.y - 3.0).abs() < GEOMETRIC_EPSILON); assert!((bounding.p2.x - 7.0).abs() < GEOMETRIC_EPSILON); assert!((bounding.p2.y - 5.0).abs() < GEOMETRIC_EPSILON); }
#[test]
fn test_zero_radius_arc() {
let center = point(1.0, 1.0);
let start = point(1.0, 1.0);
let end = point(1.0, 1.0);
let point_arc = arc(start, end, center, 0.0);
let bounding = arc_bounding_rect(&point_arc);
assert!((bounding.p1.x - 1.0).abs() < GEOMETRIC_EPSILON);
assert!((bounding.p1.y - 1.0).abs() < GEOMETRIC_EPSILON);
assert!((bounding.p2.x - 1.0).abs() < GEOMETRIC_EPSILON);
assert!((bounding.p2.y - 1.0).abs() < GEOMETRIC_EPSILON);
}
#[test]
fn test_vertical_line_segment() {
let line = arcseg(point(2.0, 1.0), point(2.0, 5.0));
let bounding = arc_bounding_rect(&line);
assert!((bounding.p1.x - 2.0).abs() < GEOMETRIC_EPSILON); assert!((bounding.p1.y - 1.0).abs() < GEOMETRIC_EPSILON); assert!((bounding.p2.x - 2.0).abs() < GEOMETRIC_EPSILON); assert!((bounding.p2.y - 5.0).abs() < GEOMETRIC_EPSILON); }
#[test]
fn test_horizontal_line_segment() {
let line = arcseg(point(1.0, 3.0), point(7.0, 3.0));
let bounding = arc_bounding_rect(&line);
assert!((bounding.p1.x - 1.0).abs() < GEOMETRIC_EPSILON); assert!((bounding.p1.y - 3.0).abs() < GEOMETRIC_EPSILON); assert!((bounding.p2.x - 7.0).abs() < GEOMETRIC_EPSILON); assert!((bounding.p2.y - 3.0).abs() < GEOMETRIC_EPSILON); }
#[test]
fn test_arc_spanning_all_quadrants() {
let center = point(0.0, 0.0);
let radius = 1.0;
let start = point(0.707, 0.707); let end = point(0.707, -0.707);
let spanning_arc = arc(start, end, center, radius);
let bounding = arc_bounding_rect(&spanning_arc);
assert!((bounding.p1.x - (-1.0)).abs() < GEOMETRIC_EPSILON); assert!((bounding.p1.y - (-1.0)).abs() < GEOMETRIC_EPSILON); assert!((bounding.p2.x - 0.707).abs() < 0.001); assert!((bounding.p2.y - 1.0).abs() < GEOMETRIC_EPSILON); }
}
#[must_use]
pub fn arc_bounding_circle(arc: &Arc) -> Circle {
if arc.is_seg() {
let chord_center = (arc.a + arc.b) * 0.5;
let chord_radius = (arc.b - arc.a).norm() * 0.5;
return Circle::new(chord_center, chord_radius);
}
if (arc.a - arc.b).norm() < 1e-10 {
if arc.r > 1e-10 {
return Circle::new(arc.c, arc.r);
} else {
return Circle::new(arc.a, 0.0);
}
}
let center = arc.c;
let radius = arc.r;
let start_angle = (arc.a - center).y.atan2((arc.a - center).x);
let end_angle = (arc.b - center).y.atan2((arc.b - center).x);
let mut span = end_angle - start_angle;
if span < 0.0 {
span += 2.0 * PI;
}
if span > PI {
return Circle::new(center, radius);
}
let mut candidate_points = vec![arc.a, arc.b];
let start_norm = if start_angle < 0.0 {
start_angle + 2.0 * PI
} else {
start_angle
};
let end_norm = if end_angle < 0.0 {
end_angle + 2.0 * PI
} else {
end_angle
};
let extreme_angles = [0.0, PI * 0.5, PI, PI * 1.5]; let extreme_points = [
center + point(radius, 0.0), center + point(0.0, radius), center + point(-radius, 0.0), center + point(0.0, -radius), ];
for (i, &angle) in extreme_angles.iter().enumerate() {
if angle_in_range(angle, start_norm, end_norm) {
candidate_points.push(extreme_points[i]);
}
}
minimal_bounding_circle(&candidate_points)
}
#[must_use]
pub fn arc_bounding_rect(arc: &Arc) -> Rect {
if arc.is_seg() {
let min_x = arc.a.x.min(arc.b.x);
let max_x = arc.a.x.max(arc.b.x);
let min_y = arc.a.y.min(arc.b.y);
let max_y = arc.a.y.max(arc.b.y);
return Rect::new(point(min_x, min_y), point(max_x, max_y));
}
if (arc.a - arc.b).norm() < 1e-10 {
if arc.r > 1e-10 {
let min_x = arc.c.x - arc.r;
let max_x = arc.c.x + arc.r;
let min_y = arc.c.y - arc.r;
let max_y = arc.c.y + arc.r;
return Rect::new(point(min_x, min_y), point(max_x, max_y));
} else {
return Rect::new(arc.a, arc.a);
}
}
let center = arc.c;
let radius = arc.r;
let mut min_x = arc.a.x.min(arc.b.x);
let mut max_x = arc.a.x.max(arc.b.x);
let mut min_y = arc.a.y.min(arc.b.y);
let mut max_y = arc.a.y.max(arc.b.y);
let start_angle = (arc.a - center).y.atan2((arc.a - center).x);
let end_angle = (arc.b - center).y.atan2((arc.b - center).x);
let start_norm = if start_angle < 0.0 {
start_angle + 2.0 * PI
} else {
start_angle
};
let end_norm = if end_angle < 0.0 {
end_angle + 2.0 * PI
} else {
end_angle
};
let extreme_angles = [0.0, PI * 0.5, PI, PI * 1.5]; let extreme_points = [
center + point(radius, 0.0), center + point(0.0, radius), center + point(-radius, 0.0), center + point(0.0, -radius), ];
for (i, &angle) in extreme_angles.iter().enumerate() {
if angle_in_range(angle, start_norm, end_norm) {
let extreme_point = extreme_points[i];
min_x = min_x.min(extreme_point.x);
max_x = max_x.max(extreme_point.x);
min_y = min_y.min(extreme_point.y);
max_y = max_y.max(extreme_point.y);
}
}
Rect::new(point(min_x, min_y), point(max_x, max_y))
}