Address review comments; fix arc flattening logic
diff --git a/crates/encoding/src/math.rs b/crates/encoding/src/math.rs index 8efbff0..bb3224d 100644 --- a/crates/encoding/src/math.rs +++ b/crates/encoding/src/math.rs
@@ -123,7 +123,7 @@ } /// Convertes a 16-bit precision IEEE-754 binary16 float to a f32. -/// This implementation was adapted from Fabian Giesen's `half_to_float`() +/// This implementation was adapted from Fabian Giesen's `half_to_float()` /// function which can be found at <https://gist.github.com/rygorous/2156668#file-gistfile1-cpp-L574> pub fn f16_to_f32(bits: u16) -> f32 { let bits = bits as u32;
diff --git a/shader/flatten.wgsl b/shader/flatten.wgsl index e128915..f90e265 100644 --- a/shader/flatten.wgsl +++ b/shader/flatten.wgsl
@@ -297,17 +297,16 @@ var p0 = transform_apply(transform, begin); var r = begin - center; - let EPS = 1e-9; - let tol = 0.5; + let MIN_THETA = 0.0001; + let tol = 0.1; let radius = max(tol, length(p0 - transform_apply(transform, center))); - let x = 1. - tol / radius; - let theta = acos(clamp(2. * x * x - 1., -1., 1.)); - let MAX_LINES = 1000u; - let n_lines = select(min(MAX_LINES, u32(ceil(6.2831853 / theta))), MAX_LINES, theta <= EPS); + let theta = max(MIN_THETA, 2. * acos(1. - tol / radius)); - let th = angle / f32(n_lines); - let c = cos(th); - let s = sin(th); + // Always output at least one line so that we always draw the chord. + let n_lines = max(1u, u32(ceil(angle / theta))); + + let c = cos(theta); + let s = sin(theta); let rot = mat2x2(c, -s, s, c); let line_ix = atomicAdd(&bump.lines, n_lines);
diff --git a/src/cpu_shader/flatten.rs b/src/cpu_shader/flatten.rs index 0f0e378..fba7173 100644 --- a/src/cpu_shader/flatten.rs +++ b/src/cpu_shader/flatten.rs
@@ -126,6 +126,12 @@ bbox: &mut IntBbox, lines: &mut [LineSoup], ) { + assert!( + !p0.is_nan() && !p1.is_nan(), + "wrote line segment with NaN: p0: {:?}, p1: {:?}", + p0, + p1 + ); bbox.add_pt(p0); bbox.add_pt(p1); lines[line_ix] = LineSoup { @@ -322,22 +328,19 @@ lines: &mut [LineSoup], bbox: &mut IntBbox, ) { + const MIN_THETA: f32 = 0.0001; + let mut p0 = transform.apply(begin); let mut r = begin - center; - let tol: f32 = 0.5; + let tol: f32 = 0.1; let radius = tol.max((p0 - transform.apply(center)).length()); - let x = 1. - tol / radius; - let theta = (2. * x * x - 1.).clamp(-1., 1.).acos(); - const MAX_LINES: u32 = 1000; - let n_lines = if theta <= ROBUST_EPSILON { - MAX_LINES - } else { - MAX_LINES.min((std::f32::consts::TAU / theta).ceil() as u32) - }; + let theta = (2. * (1. - tol / radius).acos()).max(MIN_THETA); - let th = angle / (n_lines as f32); - let c = th.cos(); - let s = th.sin(); + // Always output at least one line so that we always draw the chord. + let n_lines = ((angle / theta).ceil() as u32).max(1); + + let c = theta.cos(); + let s = theta.sin(); let rot = Transform([c, -s, s, c, 0., 0.]); for _ in 0..(n_lines - 1) {
diff --git a/src/cpu_shader/util.rs b/src/cpu_shader/util.rs index ef0bb5b..da66f7b 100644 --- a/src/cpu_shader/util.rs +++ b/src/cpu_shader/util.rs
@@ -102,6 +102,10 @@ pub fn normalize(self) -> Vec2 { self / self.length() } + + pub fn is_nan(&self) -> bool { + self.x.is_nan() || self.y.is_nan() + } } #[derive(Clone)]