use super::*;
use crate::cross_section::CrossSection;
use std::f64::consts::PI;
fn bracelet_base(
width: f64,
radius: f64,
decor_radius: f64,
twist_radius: f64,
n_decor: i32,
inner_radius: f64,
outer_radius: f64,
cut: f64,
n_cut: i32,
n_division: i32,
) -> Manifold {
let mut base = Manifold::cylinder(width, radius + twist_radius / 2.0, -1.0, 0);
let circle = CrossSection::circle(decor_radius, n_division)
.translate(Vec2::new(twist_radius, 0.0));
let decor = Manifold::extrude(&circle.to_polygons(), width, n_division, 180.0, Vec2::new(1.0, 1.0))
.scale(Vec3::new(1.0, 0.5, 1.0))
.translate(Vec3::new(0.0, radius, 0.0));
for i in 0..n_decor {
let angle_deg = (360.0 / n_decor as f64) * i as f64;
base = base.union(&decor.rotate(0.0, 0.0, angle_deg));
}
let d_phi_rad = 2.0 * PI / n_cut as f64;
let p0 = Vec2::new(outer_radius, 0.0);
let p1 = Vec2::new(inner_radius, -cut);
let p2 = Vec2::new(inner_radius, cut);
let rot = |theta: f64, v: Vec2| -> Vec2 {
let c = theta.cos();
let s = theta.sin();
Vec2::new(c * v.x - s * v.y, s * v.x + c * v.y)
};
let mut ring: Vec<Vec2> = Vec::with_capacity(n_cut as usize * 4);
for i in 0..n_cut {
let t = d_phi_rad * i as f64;
ring.push(rot(t, p0));
ring.push(rot(t, p1));
ring.push(rot(t, p2));
ring.push(rot(t, p0));
}
let stretch: Polygons = vec![ring];
base = Manifold::extrude(&stretch, width, 0, 0.0, Vec2::new(1.0, 1.0))
.intersection(&base);
base.as_original()
}
fn stretchy_bracelet() -> Manifold {
let radius: f64 = 30.0;
let height: f64 = 8.0;
let width: f64 = 15.0;
let thickness: f64 = 0.4;
let n_decor: i32 = 20;
let n_cut: i32 = 27;
let n_division: i32 = 30;
let twist_radius = PI * radius / n_decor as f64;
let decor_radius = twist_radius * 1.5;
let outer_radius = radius + (decor_radius + twist_radius) * 0.5;
let inner_radius = outer_radius - height;
let cut = 0.5 * (PI * 2.0 * inner_radius / n_cut as f64 - thickness);
let adj_thickness = 0.5 * thickness * height / cut;
let outer = bracelet_base(
width,
radius,
decor_radius,
twist_radius,
n_decor,
inner_radius + thickness,
outer_radius + adj_thickness,
cut - adj_thickness,
n_cut,
n_division,
);
let inner = bracelet_base(
width,
radius - thickness,
decor_radius,
twist_radius,
n_decor,
inner_radius,
outer_radius + 3.0 * adj_thickness,
cut,
n_cut,
n_division,
);
outer.difference(&inner)
}
#[test]
fn test_cpp_properties_mingap_stretchy_bracelet() {
let a = stretchy_bracelet();
let b = stretchy_bracelet().translate(Vec3::new(0.0, 0.0, 20.0));
let distance = a.min_gap(&b, 10.0);
assert!((distance - 5.0).abs() < 0.001,
"MingapStretchyBracelet: distance={}, expected ~5", distance);
}