1use crate::region::{polygon_from_int_contour, Region};
7use i_overlay::mesh::outline::offset::OutlineOffset;
8use i_overlay::mesh::style::{LineJoin, OutlineStyle};
9use klayout_core::Polygon;
10use std::f64::consts::PI;
11
12#[derive(Copy, Clone, Debug)]
13pub enum SizeJoin {
14 Miter,
16 Round,
18 Bevel,
20}
21
22pub fn size(r: &Region, delta: i64, join: SizeJoin) -> Region {
23 if delta == 0 || r.is_empty() {
24 return r.clone();
25 }
26 let shapes: Vec<Vec<Vec<[f64; 2]>>> = r
27 .polygons
28 .iter()
29 .map(polygon_to_floats)
30 .collect();
31 let style = OutlineStyle::<f64> {
32 outer_offset: delta as f64,
33 inner_offset: delta as f64,
34 join: match join {
35 SizeJoin::Miter => LineJoin::Miter(0.5 * PI),
36 SizeJoin::Round => LineJoin::Round(0.05 * PI),
37 SizeJoin::Bevel => LineJoin::Bevel,
38 },
39 };
40 let result = shapes.outline(&style);
41
42 let mut polys: Vec<Polygon> = Vec::with_capacity(result.len());
43 for shape in result {
44 let mut iter = shape.into_iter();
45 let Some(hull_f) = iter.next() else { continue };
46 let hull_int: Vec<(i64, i64)> = hull_f
47 .iter()
48 .map(|p| (p[0].round() as i64, p[1].round() as i64))
49 .collect();
50 let Some(mut poly) = polygon_from_int_contour(&hull_int) else { continue };
51 for hole_f in iter {
52 let hole_int: Vec<(i64, i64)> = hole_f
53 .iter()
54 .map(|p| (p[0].round() as i64, p[1].round() as i64))
55 .collect();
56 if hole_int.len() >= 3 {
57 poly.add_hole(
58 hole_int
59 .into_iter()
60 .map(|(x, y)| klayout_core::Point::new(x, y)),
61 );
62 }
63 }
64 polys.push(poly);
65 }
66
67 let mut out = Region::empty();
68 out.set_polygons(polys);
69 out
70}
71
72fn polygon_to_floats(p: &Polygon) -> Vec<Vec<[f64; 2]>> {
73 let mut out: Vec<Vec<[f64; 2]>> = Vec::with_capacity(1 + p.holes.len());
76 out.push(
77 p.hull
78 .iter()
79 .rev()
80 .map(|pt| [pt.x as f64, pt.y as f64])
81 .collect(),
82 );
83 for hole in &p.holes {
84 out.push(
85 hole.iter()
86 .rev()
87 .map(|pt| [pt.x as f64, pt.y as f64])
88 .collect(),
89 );
90 }
91 out
92}