Skip to content

Commit

Permalink
shapes/polyline: add rough support for holes
Browse files Browse the repository at this point in the history
Clipping is missing.
  • Loading branch information
danieledapo committed Aug 24, 2020
1 parent 85a797e commit 82565d1
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 25 deletions.
45 changes: 32 additions & 13 deletions src/main.rs
Expand Up @@ -130,9 +130,9 @@ fn main() {
let container = {
let points = vec![
(0.0, -250.0), //
(-500.0, 0.0), //
(0.0, 250.0), //
(500.0, 0.0), //
(0.0, 250.0), //
(-500.0, 0.0), //
];

// let points = vec![
Expand All @@ -142,17 +142,36 @@ fn main() {
// (0.0, 250.0), //
// ];

let mut points = vec![];
for i in 0_u16..=180 {
let i = f32::from(i);
points.push((
30.0 * i,
800.0 * (8.0 * i / 180.0 * std::f32::consts::PI).sin(),
));
}
points.push((30.0 * 180.0 / 2.0, 900.0));

circle_packing::shapes::Polyline::new(points).unwrap()
// let mut points = vec![];
// for i in 0_u16..=180 {
// let i = f32::from(i);
// points.push((
// 30.0 * i,
// 800.0 * (8.0 * i / 180.0 * std::f32::consts::PI).sin(),
// ));
// }
// points.push((30.0 * 180.0 / 2.0, 900.0));

let mut poly = circle_packing::shapes::Polyline::new(points).unwrap();

let mut hole = circle_packing::shapes::Polyline::new(vec![
(0.0, -150.0), //
(400.0, 0.0), //
(0.0, 150.0), //
(-400.0, 0.0), //
])
.unwrap();
hole.push_hole(
circle_packing::shapes::Polyline::new(vec![
(0.0, -50.0), //
(300.0, 0.0), //
(0.0, 50.0), //
(-300.0, 0.0), //
])
.unwrap(),
);
poly.push_hole(hole);
poly
};
let mut root = PackShape::new(container);
root.color = 1 % settings.palette.len();
Expand Down
59 changes: 47 additions & 12 deletions src/shapes.rs
Expand Up @@ -25,6 +25,7 @@ pub struct Circle {
#[derive(Clone, Debug)]
pub struct Polyline {
points: Vec<(f32, f32)>,
holes: Vec<Polyline>,
cx: f32,
cy: f32,
bbox: Bbox,
Expand Down Expand Up @@ -157,7 +158,7 @@ impl Polyline {
} else {
let (mut cx, mut cy) = points[0];
let mut bbox = Bbox::new(cx, cy);
for &(x, y) in &points[1..] {
for &(x, y) in points.iter().skip(1) {
bbox.expand(x, y);
cx += x;
cy += y;
Expand All @@ -169,15 +170,45 @@ impl Polyline {
cx,
cy,
bbox,
holes: vec![],
})
}
}

/// as of now, hole must be completely contained in the polyline otherwise
/// it won't be added to the list of holes. This is to ensure the naive area
/// calculation is correct.
//
// TODO: clipping
pub fn push_hole(&mut self, hole: Polyline) -> bool {
let completely_contained = hole.points.iter().all(|&(x, y)| self.sdf(x, y) < 0.0);
if !completely_contained {
return false;
}

self.holes.push(hole);
true
}

fn get_d(&self) -> String {
let mut d = format!("M {},{}", self.points[0].0, self.points[0].1);
for &(x, y) in self.points.iter().skip(1) {
d += &format!("L {},{}", x, y);
}
d += "Z";

for hole in &self.holes {
d += &hole.get_d();
}

d
}
}

impl Shape for Polyline {
fn bbox(&self) -> Bbox {
let mut bbox = Bbox::new(self.points[0].0, self.points[0].1);
for &(x, y) in &self.points[1..] {
for &(x, y) in self.points.iter().skip(1) {
bbox.expand(x, y);
}
bbox
Expand Down Expand Up @@ -216,7 +247,13 @@ impl Shape for Polyline {
}
}

s * d.sqrt()
let mut d = s * d.sqrt();
for h in &self.holes {
let dd = h.sdf(x, y);
d = d.max(-dd);
}

d
}

fn area(&self) -> f32 {
Expand All @@ -230,7 +267,9 @@ impl Shape for Polyline {
area += x0 * y1 - x1 * y0;
}

area.abs() / 2.0
area = area.abs() / 2.0;

area - self.holes.iter().map(|h| h.area()).sum::<f32>()
}

fn random_point<R: Rng>(&self, rng: &mut R) -> (f32, f32) {
Expand All @@ -243,16 +282,12 @@ impl Shape for Polyline {
}

fn write_svg<W: Write>(&self, w: &mut W, fill: &str, stroke: &str) -> io::Result<()> {
let points = self
.points
.iter()
.map(|(x, y)| format!("{},{} ", x, y))
.collect::<String>();

writeln!(
w,
r#"<polyline points="{}" fill="{}" stroke="{}"/>"#,
points, fill, stroke
r#"<path d="{}" fill="{}" stroke="{}"/>"#,
self.get_d(),
fill,
stroke
)
}
}

0 comments on commit 82565d1

Please sign in to comment.