From b2673730aea8471d92efba1875962050b1d117b8 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Fri, 18 Mar 2022 13:37:51 +0100 Subject: [PATCH 1/6] Add `ShapeProcessor` This takes some code out of `main`, which is much needed, and provides opportunity for re-use. --- fj-app/src/main.rs | 94 ++++++++++++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 36 deletions(-) diff --git a/fj-app/src/main.rs b/fj-app/src/main.rs index 6b5819866..e12d97b24 100644 --- a/fj-app/src/main.rs +++ b/fj-app/src/main.rs @@ -13,7 +13,7 @@ use std::path::PathBuf; use std::{collections::HashMap, sync::mpsc, time::Instant}; use fj_debug::DebugInfo; -use fj_math::Scalar; +use fj_math::{Aabb, Scalar, Triangle}; use fj_operations::ToShape as _; use futures::executor::block_on; use notify::Watcher as _; @@ -94,42 +94,11 @@ fn main() -> anyhow::Result<()> { // https://github.com/hannobraun/fornjot/issues/32 let shape = model.load(¶meters)?; - let mut aabb = shape.bounding_volume(); - - let tolerance = match args.tolerance { - None => { - // Compute a reasonable default for the tolerance value. To do this, we just - // look at the smallest non-zero extent of the bounding box and divide that - // by some value. - let mut min_extent = Scalar::MAX; - for extent in aabb.size().components { - if extent > Scalar::ZERO && extent < min_extent { - min_extent = extent; - } - } - - // `tolerance` must not be zero, or we'll run into trouble. - let tolerance = min_extent / Scalar::from_f64(1000.); - assert!(tolerance > Scalar::ZERO); - - tolerance - } - Some(user_defined_tolerance) => { - if user_defined_tolerance > 0.0 { - Scalar::from_f64(user_defined_tolerance) - } else { - anyhow::bail!("Invalid user defined model deviation tolerance: {}. Tolerance must be larger than zero", - user_defined_tolerance) - } - } + let shape_processor = ShapeProcessor { + tolerance: args.tolerance, }; - - let mut debug_info = DebugInfo::new(); - let mut triangles = Vec::new(); - shape - .to_shape(tolerance, &mut debug_info) - .topology() - .triangles(tolerance, &mut triangles, &mut debug_info); + let (tolerance, mut aabb, mut triangles, mut debug_info) = + shape_processor.process(&shape)?; if let Some(path) = args.export { let mut mesh_maker = MeshMaker::new(); @@ -363,3 +332,56 @@ fn main() -> anyhow::Result<()> { } }); } + +struct ShapeProcessor { + tolerance: Option, +} + +impl ShapeProcessor { + fn process( + &self, + shape: &fj::Shape, + ) -> anyhow::Result<(Scalar, Aabb<3>, Vec>, DebugInfo)> { + let aabb = shape.bounding_volume(); + + let tolerance = match self.tolerance { + None => { + // Compute a reasonable default for the tolerance value. To do + // this, we just look at the smallest non-zero extent of the + // bounding box and divide that by some value. + let mut min_extent = Scalar::MAX; + for extent in aabb.size().components { + if extent > Scalar::ZERO && extent < min_extent { + min_extent = extent; + } + } + + // `tolerance` must not be zero, or we'll run into trouble. + let tolerance = min_extent / Scalar::from_f64(1000.); + assert!(tolerance > Scalar::ZERO); + + tolerance + } + Some(user_defined_tolerance) => { + if user_defined_tolerance > 0.0 { + Scalar::from_f64(user_defined_tolerance) + } else { + anyhow::bail!( + "Invalid user defined model deviation tolerance: {}.\n\ + Tolerance must be larger than zero", + user_defined_tolerance + ) + } + } + }; + + let mut debug_info = DebugInfo::new(); + let mut triangles = Vec::new(); + shape + .to_shape(tolerance, &mut debug_info) + .topology() + .triangles(tolerance, &mut triangles, &mut debug_info); + + Ok((tolerance, aabb, triangles, debug_info)) + } +} From eafa7d6960b93d1943030d750365ce4502b6a55e Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Fri, 18 Mar 2022 13:42:30 +0100 Subject: [PATCH 2/6] Consolidate processed shape data in single struct --- fj-app/src/main.rs | 61 ++++++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/fj-app/src/main.rs b/fj-app/src/main.rs index e12d97b24..c352d565b 100644 --- a/fj-app/src/main.rs +++ b/fj-app/src/main.rs @@ -97,13 +97,12 @@ fn main() -> anyhow::Result<()> { let shape_processor = ShapeProcessor { tolerance: args.tolerance, }; - let (tolerance, mut aabb, mut triangles, mut debug_info) = - shape_processor.process(&shape)?; + let mut processed_shape = shape_processor.process(&shape)?; if let Some(path) = args.export { let mut mesh_maker = MeshMaker::new(); - for triangle in triangles { + for triangle in processed_shape.triangles { for vertex in triangle.points() { mesh_maker.push(vertex); } @@ -204,10 +203,14 @@ fn main() -> anyhow::Result<()> { let mut input_handler = input::Handler::new(previous_time); let mut renderer = block_on(Renderer::new(&window))?; - renderer.update_geometry((&triangles).into(), (&debug_info).into(), aabb); + renderer.update_geometry( + (&processed_shape.triangles).into(), + (&processed_shape.debug_info).into(), + processed_shape.aabb, + ); let mut draw_config = DrawConfig::default(); - let mut camera = Camera::new(&aabb); + let mut camera = Camera::new(&processed_shape.aabb); event_loop.run(move |event, _, control_flow| { trace!("Handling event: {:?}", event); @@ -218,19 +221,26 @@ fn main() -> anyhow::Result<()> { match watcher_rx.try_recv() { Ok(shape) => { - debug_info.clear(); - triangles.clear(); + processed_shape.debug_info.clear(); + processed_shape.triangles.clear(); - aabb = shape.bounding_volume(); + processed_shape.aabb = shape.bounding_volume(); shape - .to_shape(tolerance, &mut debug_info) + .to_shape( + processed_shape.tolerance, + &mut processed_shape.debug_info, + ) .topology() - .triangles(tolerance, &mut triangles, &mut debug_info); + .triangles( + processed_shape.tolerance, + &mut processed_shape.triangles, + &mut processed_shape.debug_info, + ); renderer.update_geometry( - (&triangles).into(), - (&debug_info).into(), - aabb, + (&processed_shape.triangles).into(), + (&processed_shape.debug_info).into(), + processed_shape.aabb, ); } Err(mpsc::TryRecvError::Empty) => { @@ -280,7 +290,7 @@ fn main() -> anyhow::Result<()> { let focus_point = camera.focus_point( &window, input_handler.cursor(), - &triangles, + &processed_shape.triangles, ); input_handler.handle_mouse_input(button, state, focus_point); @@ -300,13 +310,13 @@ fn main() -> anyhow::Result<()> { now, &mut camera, &window, - &triangles, + &processed_shape.triangles, ); window.inner().request_redraw(); } Event::RedrawRequested(_) => { - camera.update_planes(&aabb); + camera.update_planes(&processed_shape.aabb); match renderer.draw(&camera, &draw_config) { Ok(()) => {} @@ -338,10 +348,7 @@ struct ShapeProcessor { } impl ShapeProcessor { - fn process( - &self, - shape: &fj::Shape, - ) -> anyhow::Result<(Scalar, Aabb<3>, Vec>, DebugInfo)> { + fn process(&self, shape: &fj::Shape) -> anyhow::Result { let aabb = shape.bounding_volume(); let tolerance = match self.tolerance { @@ -382,6 +389,18 @@ impl ShapeProcessor { .topology() .triangles(tolerance, &mut triangles, &mut debug_info); - Ok((tolerance, aabb, triangles, debug_info)) + Ok(ProcessedShape { + tolerance, + aabb, + triangles, + debug_info, + }) } } + +struct ProcessedShape { + tolerance: Scalar, + aabb: Aabb<3>, + triangles: Vec>, + debug_info: DebugInfo, +} From 0f2631fece831c56825db9b7c6aa2697a9f21f94 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Fri, 18 Mar 2022 13:56:05 +0100 Subject: [PATCH 3/6] Validate tolerance on `ShapeProcessor` creation --- fj-app/src/main.rs | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/fj-app/src/main.rs b/fj-app/src/main.rs index c352d565b..fd1114769 100644 --- a/fj-app/src/main.rs +++ b/fj-app/src/main.rs @@ -94,9 +94,7 @@ fn main() -> anyhow::Result<()> { // https://github.com/hannobraun/fornjot/issues/32 let shape = model.load(¶meters)?; - let shape_processor = ShapeProcessor { - tolerance: args.tolerance, - }; + let shape_processor = ShapeProcessor::new(args.tolerance)?; let mut processed_shape = shape_processor.process(&shape)?; if let Some(path) = args.export { @@ -344,10 +342,26 @@ fn main() -> anyhow::Result<()> { } struct ShapeProcessor { - tolerance: Option, + tolerance: Option, } impl ShapeProcessor { + fn new(tolerance: Option) -> anyhow::Result { + if let Some(tolerance) = tolerance { + if tolerance <= 0. { + anyhow::bail!( + "Invalid user defined model deviation tolerance: {}.\n\ + Tolerance must be larger than zero", + tolerance + ); + } + } + + let tolerance = tolerance.map(Scalar::from_f64); + + Ok(Self { tolerance }) + } + fn process(&self, shape: &fj::Shape) -> anyhow::Result { let aabb = shape.bounding_volume(); @@ -369,17 +383,7 @@ impl ShapeProcessor { tolerance } - Some(user_defined_tolerance) => { - if user_defined_tolerance > 0.0 { - Scalar::from_f64(user_defined_tolerance) - } else { - anyhow::bail!( - "Invalid user defined model deviation tolerance: {}.\n\ - Tolerance must be larger than zero", - user_defined_tolerance - ) - } - } + Some(user_defined_tolerance) => user_defined_tolerance, }; let mut debug_info = DebugInfo::new(); From 2ba91313efd96cbe74af8a5f73f559188bc7f0b8 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Fri, 18 Mar 2022 13:57:10 +0100 Subject: [PATCH 4/6] Simplify method return value --- fj-app/src/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fj-app/src/main.rs b/fj-app/src/main.rs index fd1114769..729145c18 100644 --- a/fj-app/src/main.rs +++ b/fj-app/src/main.rs @@ -95,7 +95,7 @@ fn main() -> anyhow::Result<()> { let shape = model.load(¶meters)?; let shape_processor = ShapeProcessor::new(args.tolerance)?; - let mut processed_shape = shape_processor.process(&shape)?; + let mut processed_shape = shape_processor.process(&shape); if let Some(path) = args.export { let mut mesh_maker = MeshMaker::new(); @@ -362,7 +362,7 @@ impl ShapeProcessor { Ok(Self { tolerance }) } - fn process(&self, shape: &fj::Shape) -> anyhow::Result { + fn process(&self, shape: &fj::Shape) -> ProcessedShape { let aabb = shape.bounding_volume(); let tolerance = match self.tolerance { @@ -393,12 +393,12 @@ impl ShapeProcessor { .topology() .triangles(tolerance, &mut triangles, &mut debug_info); - Ok(ProcessedShape { + ProcessedShape { tolerance, aabb, triangles, debug_info, - }) + } } } From 15439c95866ad00c2e50d8f61e7dc4bd9474b988 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Fri, 18 Mar 2022 13:59:04 +0100 Subject: [PATCH 5/6] Fix tolerance not being updated on model reload --- fj-app/src/main.rs | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/fj-app/src/main.rs b/fj-app/src/main.rs index 729145c18..9462d6e3d 100644 --- a/fj-app/src/main.rs +++ b/fj-app/src/main.rs @@ -219,21 +219,7 @@ fn main() -> anyhow::Result<()> { match watcher_rx.try_recv() { Ok(shape) => { - processed_shape.debug_info.clear(); - processed_shape.triangles.clear(); - - processed_shape.aabb = shape.bounding_volume(); - shape - .to_shape( - processed_shape.tolerance, - &mut processed_shape.debug_info, - ) - .topology() - .triangles( - processed_shape.tolerance, - &mut processed_shape.triangles, - &mut processed_shape.debug_info, - ); + processed_shape = shape_processor.process(&shape); renderer.update_geometry( (&processed_shape.triangles).into(), @@ -394,7 +380,6 @@ impl ShapeProcessor { .triangles(tolerance, &mut triangles, &mut debug_info); ProcessedShape { - tolerance, aabb, triangles, debug_info, @@ -403,7 +388,6 @@ impl ShapeProcessor { } struct ProcessedShape { - tolerance: Scalar, aabb: Aabb<3>, triangles: Vec>, debug_info: DebugInfo, From f1feff28796fa0dd3c2ecb4457fc3044d14325fb Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Fri, 18 Mar 2022 14:01:40 +0100 Subject: [PATCH 6/6] Consolidate duplicated code --- fj-app/src/main.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/fj-app/src/main.rs b/fj-app/src/main.rs index 9462d6e3d..e4385dbcd 100644 --- a/fj-app/src/main.rs +++ b/fj-app/src/main.rs @@ -201,11 +201,7 @@ fn main() -> anyhow::Result<()> { let mut input_handler = input::Handler::new(previous_time); let mut renderer = block_on(Renderer::new(&window))?; - renderer.update_geometry( - (&processed_shape.triangles).into(), - (&processed_shape.debug_info).into(), - processed_shape.aabb, - ); + processed_shape.update_geometry(&mut renderer); let mut draw_config = DrawConfig::default(); let mut camera = Camera::new(&processed_shape.aabb); @@ -220,12 +216,7 @@ fn main() -> anyhow::Result<()> { match watcher_rx.try_recv() { Ok(shape) => { processed_shape = shape_processor.process(&shape); - - renderer.update_geometry( - (&processed_shape.triangles).into(), - (&processed_shape.debug_info).into(), - processed_shape.aabb, - ); + processed_shape.update_geometry(&mut renderer); } Err(mpsc::TryRecvError::Empty) => { // Nothing to receive from the channel. We don't care. @@ -392,3 +383,13 @@ struct ProcessedShape { triangles: Vec>, debug_info: DebugInfo, } + +impl ProcessedShape { + fn update_geometry(&self, renderer: &mut Renderer) { + renderer.update_geometry( + (&self.triangles).into(), + (&self.debug_info).into(), + self.aabb, + ); + } +}