Browse Source

Use non-iterator version of WindowMut

Kevin Lee 1 month ago
parent
commit
122ab2a3fa
3 changed files with 135 additions and 250 deletions
  1. 76 171
      src/config/hatch.rs
  2. 21 0
      src/config/mod.rs
  3. 38 79
      src/config/pen.rs

+ 76 - 171
src/config/hatch.rs

@@ -1,7 +1,10 @@
 use ezcad::objects::{hatch::HatchSetting, Object};
+use itertools::Itertools;
 use log::debug;
 use serde::{Deserialize, Serialize};
 
+use super::double_window_mut;
+
 #[derive(Debug, Serialize, Deserialize)]
 
 pub enum PatternHatchField {
@@ -19,204 +22,106 @@ pub enum PatternHatchField {
 
 impl PatternHatchField {
     pub fn pattern(&self, objects: &mut dyn Iterator<Item = (usize, &mut Object)>) {
-        let (src_idx, src) = objects
-            .next()
-            .expect("Pattern must involve at least one pen");
-
-        // Obtain settings from first object
-        let mut setting: PatternHatchField = match src {
-            Object::Hatch(src) => {
-                let setting = src
-                    .hatch_settings
-                    .iter()
-                    .find(|h| h.enabled.into())
-                    .expect("Hatch missing enabled settings");
+        let mut objects: Vec<(usize, &mut Object)> = objects.collect_vec();
 
-                let setting: PatternHatchField = match self {
-                    PatternHatchField::Count(_) => {
-                        debug!(
-                            "Initial hatch count from object #{} is {}",
-                            src_idx, *setting.count
-                        );
-                        PatternHatchField::Count(*setting.count)
-                    }
-                    PatternHatchField::LineSpacing(_) => {
-                        debug!(
-                            "Initial hatch line spacing from object #{} is {:.3}",
-                            src_idx, *setting.line_spacing
-                        );
-                        PatternHatchField::LineSpacing(*setting.line_spacing)
-                    }
-                    PatternHatchField::EdgeOffset(_) => {
-                        debug!(
-                            "Initial hatch edge offset from object #{} is {:.3}",
-                            src_idx, *setting.edge_offset
-                        );
-                        PatternHatchField::EdgeOffset(*setting.edge_offset)
-                    }
-                    PatternHatchField::StartOffset(_) => {
-                        debug!(
-                            "Initial hatch start offset from object #{} is {:.3}",
-                            src_idx, *setting.start_offset
-                        );
-                        PatternHatchField::StartOffset(*setting.start_offset)
-                    }
-                    PatternHatchField::EndOffset(_) => {
-                        debug!(
-                            "Initial hatch end offset from object #{} is {:.3}",
-                            src_idx, *setting.end_offset
-                        );
-                        PatternHatchField::EndOffset(*setting.end_offset)
-                    }
-                    PatternHatchField::Angle(_) => {
-                        debug!(
-                            "Initial hatch angle from object #{} is {:.3}",
-                            src_idx, *setting.angle
-                        );
-                        PatternHatchField::Angle(*setting.angle)
-                    }
-                    PatternHatchField::RotateAngle(_) => {
-                        debug!(
-                            "Initial hatch rotate angle from object #{} is {:.3}",
-                            src_idx, *setting.rotate_angle
-                        );
-                        PatternHatchField::RotateAngle(*setting.rotate_angle)
-                    }
-                    PatternHatchField::LineReduction(_) => {
-                        debug!(
-                            "Initial hatch line reduction angle from object #{} is {:.3}",
-                            src_idx, *setting.line_reduction
-                        );
-                        PatternHatchField::LineReduction(*setting.line_reduction)
-                    }
-                    PatternHatchField::LoopDistance(_) => {
-                        debug!(
-                            "Initial hatch loop distance from object #{} is {:.3}",
-                            src_idx, *setting.loop_distance
-                        );
-                        PatternHatchField::LoopDistance(*setting.loop_distance)
-                    }
-                    PatternHatchField::LoopCount(_) => {
-                        debug!(
-                            "Initial hatch loop count from object #{} is {:.3}",
-                            src_idx, *setting.loop_count
-                        );
-                        PatternHatchField::LoopCount(*setting.loop_count)
-                    }
-                };
+        double_window_mut(&mut objects[..], |prev, next| {
+            let (_prev_idx, prev): (usize, &mut HatchSetting) = match prev.1 {
+                Object::Hatch(hatch) => (
+                    prev.0,
+                    hatch
+                        .hatch_settings
+                        .iter_mut()
+                        .find(|h| h.enabled.into())
+                        .expect("Hatch missing enabled setting"),
+                ),
+                _ => panic!("Object #{} not a hatch object", prev.0),
+            };
 
-                setting
-            }
-            _ => panic!("Object #{} not a hatch object", src_idx),
-        };
+            let (next_idx, next): (usize, &mut HatchSetting) = match next.1 {
+                Object::Hatch(hatch) => (
+                    next.0,
+                    hatch
+                        .hatch_settings
+                        .iter_mut()
+                        .find(|h| h.enabled.into())
+                        .expect("Hatch missing enabled setting"),
+                ),
+                _ => panic!("Object #{} not a hatch object", next.0),
+            };
 
-        for (idx, dst) in objects {
-            // Calculate new setting
-            setting = match (setting, self) {
-                (PatternHatchField::Count(prev), PatternHatchField::Count(incr)) => {
-                    let value: u32 = prev + incr;
-                    debug!("Patching hatch count for object #{} to {:.3}", idx, value);
-                    PatternHatchField::Count(value)
+            match self {
+                PatternHatchField::Count(incr) => {
+                    let value: u32 = *prev.count + incr;
+                    debug!("Patching hatch count for object #{} to {}", next_idx, value);
+                    *next.count = value;
                 }
-                (PatternHatchField::LineSpacing(prev), PatternHatchField::LineSpacing(incr)) => {
-                    let value: f64 = prev + incr;
+                PatternHatchField::LineSpacing(incr) => {
+                    let value: f64 = *prev.line_spacing + incr;
                     debug!(
-                        "Patching hatch line spacing for object #{} to {:.3}",
-                        idx, value
+                        "Patching line spacing for object #{} to {:.3}",
+                        next_idx, value
                     );
-                    PatternHatchField::LineSpacing(value)
+                    *next.line_spacing = value;
                 }
-                (PatternHatchField::EdgeOffset(prev), PatternHatchField::EdgeOffset(incr)) => {
-                    let value: f64 = prev + incr;
+                PatternHatchField::EdgeOffset(incr) => {
+                    let value: f64 = *prev.edge_offset + incr;
                     debug!(
-                        "Patching hatch edge offset for object #{} to {:.3}",
-                        idx, value
+                        "Patching edge offset for object #{} to {:.3}",
+                        next_idx, value
                     );
-                    PatternHatchField::EdgeOffset(value)
+                    *next.edge_offset = value;
                 }
-                (PatternHatchField::StartOffset(prev), PatternHatchField::StartOffset(incr)) => {
-                    let value: f64 = prev + incr;
+                PatternHatchField::StartOffset(incr) => {
+                    let value: f64 = *prev.start_offset + incr;
                     debug!(
-                        "Patching hatch start offset for object #{} to {:.3}",
-                        idx, value
+                        "Patching start offset for object #{} to {:.3}",
+                        next_idx, value
                     );
-                    PatternHatchField::StartOffset(value)
+                    *next.start_offset = value;
                 }
-                (PatternHatchField::EndOffset(prev), PatternHatchField::LineSpacing(incr)) => {
-                    let value: f64 = prev + incr;
+                PatternHatchField::EndOffset(incr) => {
+                    let value: f64 = *prev.end_offset + incr;
                     debug!(
-                        "Patching hatch end offset for object #{} to {:.3}",
-                        idx, value
+                        "Patching end offset for object #{} to {:.3}",
+                        next_idx, value
                     );
-                    PatternHatchField::EndOffset(value)
+                    *next.end_offset = value;
                 }
-                (PatternHatchField::Angle(prev), PatternHatchField::Angle(incr)) => {
-                    let value: f64 = prev + incr;
-                    debug!("Patching hatch angle for object #{} to {:.3}", idx, value);
-                    PatternHatchField::Angle(value)
+                PatternHatchField::Angle(incr) => {
+                    let value: f64 = *prev.angle + incr;
+                    debug!("Patching angle for object #{} to {:.3}", next_idx, value);
+                    *next.angle = value;
                 }
-                (PatternHatchField::RotateAngle(prev), PatternHatchField::RotateAngle(incr)) => {
-                    let value: f64 = prev + incr;
+                PatternHatchField::RotateAngle(incr) => {
+                    let value: f64 = *prev.rotate_angle + incr;
                     debug!(
-                        "Patching hatch rotate angle for object #{} to {:.3}",
-                        idx, value
+                        "Patching rotate angle for object #{} to {:.3}",
+                        next_idx, value
                     );
-                    PatternHatchField::RotateAngle(value)
+                    *next.rotate_angle = value;
                 }
-                (
-                    PatternHatchField::LineReduction(prev),
-                    PatternHatchField::LineReduction(incr),
-                ) => {
-                    let value: f64 = prev + incr;
+                PatternHatchField::LineReduction(incr) => {
+                    let value: f64 = *prev.line_reduction + incr;
                     debug!(
-                        "Patching hatch line reduction for object #{} to {:.3}",
-                        idx, value
+                        "Patching line reduction for object #{} to {:.3}",
+                        next_idx, value
                     );
-                    PatternHatchField::LineReduction(value)
+                    *next.line_reduction = value;
                 }
-                (PatternHatchField::LoopDistance(prev), PatternHatchField::LoopDistance(incr)) => {
-                    let value: f64 = prev + incr;
+                PatternHatchField::LoopDistance(incr) => {
+                    let value: f64 = *prev.loop_distance + incr;
                     debug!(
-                        "Patching hatch loop distance for object #{} to {:.3}",
-                        idx, value
+                        "Patching loop distance for object #{} to {:.3}",
+                        next_idx, value
                     );
-                    PatternHatchField::LoopDistance(value)
+                    *next.loop_distance = value;
                 }
-                (PatternHatchField::LoopCount(prev), PatternHatchField::LoopCount(incr)) => {
-                    let value: u32 = prev + incr;
-                    debug!(
-                        "Patching hatch loop count for object #{} to {:.3}",
-                        idx, value
-                    );
-                    PatternHatchField::LoopCount(value)
-                }
-                _ => unreachable!(),
-            };
-
-            // Apply setting
-            match dst {
-                Object::Hatch(dst) => {
-                    let dst: &mut HatchSetting = dst
-                        .hatch_settings
-                        .iter_mut()
-                        .find(|h| h.enabled.into())
-                        .expect("Hatch missing enabled settings");
-
-                    match setting {
-                        PatternHatchField::Count(x) => *dst.count = x,
-                        PatternHatchField::LineSpacing(x) => *dst.line_spacing = x,
-                        PatternHatchField::EdgeOffset(x) => *dst.edge_offset = x,
-                        PatternHatchField::StartOffset(x) => *dst.start_offset = x,
-                        PatternHatchField::EndOffset(x) => *dst.end_offset = x,
-                        PatternHatchField::Angle(x) => *dst.angle = x,
-                        PatternHatchField::RotateAngle(x) => *dst.rotate_angle = x,
-                        PatternHatchField::LineReduction(x) => *dst.line_reduction = x,
-                        PatternHatchField::LoopDistance(x) => *dst.loop_distance = x,
-                        PatternHatchField::LoopCount(x) => *dst.loop_count = x,
-                    }
+                PatternHatchField::LoopCount(incr) => {
+                    let value: u32 = *prev.loop_count + incr;
+                    debug!("Patching loop count for object #{} to {}", next_idx, value);
+                    *next.loop_count = value;
                 }
-                _ => panic!("Object #{} not a hatch object", src_idx),
             }
-        }
+        });
     }
 }

+ 21 - 0
src/config/mod.rs

@@ -48,3 +48,24 @@ impl Operations for Vec<Operation> {
 pub struct Config {
     pub ops: Vec<Operation>,
 }
+
+/// Helper function that returns a window of two mutable elements
+pub fn double_window_mut<T, F>(slice: &mut [T], mut function: F)
+where
+    F: FnMut(&mut T, &mut T),
+{
+    for start in 0..(slice.len().saturating_sub(1)) {
+        let (a, b) = slice.split_at_mut(start + 1);
+        function(&mut a[a.len() - 1], &mut b[0])
+    }
+}
+
+#[test]
+fn test() {
+    let mut data: Vec<u8> = vec![1, 2, 3, 4, 5];
+    double_window_mut(&mut data[..], |prev, next| {
+        println!("Prev: {}, Next: {}", prev, next);
+        *next = *prev * 2;
+    });
+    assert_eq!(data, vec![1, 2, 4, 8, 16]);
+}

+ 38 - 79
src/config/pen.rs

@@ -10,6 +10,8 @@ use rand::{seq::SliceRandom, Rng};
 use serde::{Deserialize, Serialize};
 use strum::IntoEnumIterator;
 
+use super::double_window_mut;
+
 const SPEED_MIN: f64 = 0.0;
 const SPEED_MAX: f64 = 100000.0;
 const POWER_MIN: f64 = 0.0;
@@ -179,75 +181,46 @@ pub enum PatternPenField {
 
 impl PatternPenField {
     pub fn pattern(&self, pens: &mut dyn Iterator<Item = (usize, &mut Pen)>) {
-        // Obtain settings from source (first) pen
-        let (src_idx, src) = pens.next().expect("Pattern must involve at least one pen");
-
-        let mut setting: PatternPenField = match self {
-            PatternPenField::Loops(_) => {
-                debug!(
-                    "Initial loop count from pen #{} is {}",
-                    src_idx, *src.loop_count
-                );
-                PatternPenField::Loops((*src.loop_count).try_into().unwrap())
-            }
-            PatternPenField::Speed(_) => {
-                debug!("Initial speed from pen #{} is {}", src_idx, *src.speed);
-                PatternPenField::Speed(*src.speed)
-            }
-            PatternPenField::Power(_) => {
-                debug!("Initial power from pen #{} is {}", src_idx, *src.power);
-                PatternPenField::Power(*src.power)
-            }
-            PatternPenField::Frequency(_) => {
-                debug!(
-                    "Initial frequency from pen #{} is {}",
-                    src_idx, *src.frequency
-                );
-                PatternPenField::Frequency((*src.frequency).try_into().unwrap())
-            }
-            PatternPenField::PulseWidth(_) => {
-                debug!(
-                    "Initial pulse width from pen #{} is {}ns",
-                    src_idx, *src.pulse_width
-                );
-                PatternPenField::PulseWidth(*src.pulse_width)
-            }
-        };
-
-        for (idx, dst) in pens {
-            // Calculate new setting
-            setting = match (setting, self) {
-                (PatternPenField::Loops(prev), PatternPenField::Loops(incr)) => {
-                    let value: i32 = prev + incr;
-                    debug!("Patching loop count for pen #{} to {}", idx, value);
+        let mut pens: Vec<(usize, &mut Pen)> = pens.collect_vec();
+
+        double_window_mut(&mut pens[..], |prev, next| {
+            let _prev_idx: usize = prev.0;
+            let prev: &mut Pen = prev.1;
+            let next_idx: usize = next.0;
+            let next: &mut Pen = next.1;
+
+            match self {
+                PatternPenField::Loops(incr) => {
+                    let value: i32 = i32::try_from(*prev.loop_count).unwrap() + incr;
+                    debug!("Patching loop count for pen #{} to {}", next_idx, value);
                     assert!(value > 0, "Pen loop count must be greater than zero");
-                    PatternPenField::Loops(value)
+                    *next.loop_count = value.try_into().unwrap()
                 }
-                (PatternPenField::Speed(prev), PatternPenField::Speed(incr)) => {
-                    let value: f64 = prev + incr;
-                    debug!("Patching speed for pen #{} to {}", idx, value);
+                PatternPenField::Speed(incr) => {
+                    let value: f64 = *prev.speed + incr;
+                    debug!("Patching speed for pen #{} to {}", next_idx, value);
                     assert!(
                         value > SPEED_MIN && value <= SPEED_MAX,
                         "Pen speed must be between {} and {}",
                         SPEED_MIN,
                         SPEED_MAX
                     );
-                    PatternPenField::Speed(value)
+                    *next.speed = value;
                 }
-                (PatternPenField::Power(prev), PatternPenField::Power(incr)) => {
-                    let value: f64 = prev + incr;
-                    debug!("Patching power for pen #{} to {}", idx, value);
+                PatternPenField::Power(incr) => {
+                    let value: f64 = *prev.power + incr;
+                    debug!("Patching power for pen #{} to {}", next_idx, value);
                     assert!(
                         value > POWER_MIN && value <= POWER_MAX,
                         "Pen power must be between {} and {}",
                         POWER_MIN,
                         POWER_MAX
                     );
-                    PatternPenField::Power(value)
+                    *next.power = value;
                 }
-                (PatternPenField::Frequency(prev), PatternPenField::Frequency(incr)) => {
-                    let value: i32 = prev + incr;
-                    debug!("Patching frequency for pen #{} to {}", idx, value);
+                PatternPenField::Frequency(incr) => {
+                    let value: i32 = i32::try_from(*prev.frequency).unwrap() + incr;
+                    debug!("Patching frequency for pen #{} to {}", next_idx, value);
                     assert!(
                         value >= FREQUENCY_MIN.try_into().unwrap()
                             && value <= FREQUENCY_MAX.try_into().unwrap(),
@@ -255,45 +228,31 @@ impl PatternPenField {
                         FREQUENCY_MIN,
                         FREQUENCY_MAX
                     );
-                    PatternPenField::Frequency(value)
+                    *next.frequency = value.try_into().unwrap();
+                    *next.frequency_2 = value.try_into().unwrap();
                 }
-                (PatternPenField::PulseWidth(prev), PatternPenField::PulseWidth(incr)) => {
+                PatternPenField::PulseWidth(incr) => {
                     let mut pw = PulseWidth::iter();
                     let _ = pw
-                        .find(|x| u32::from(*x) == prev)
+                        .find(|x| u32::from(*x) == *prev.pulse_width)
                         .expect("Unknown pulse width");
 
                     let mut pw = pw.skip((*incr - 1).try_into().unwrap());
-                    let next: u32 = pw.next().expect("Pulse width out of bounds").into();
-                    debug!("Patching pulse width for pen #{} to {}ns", idx, next);
-                    PatternPenField::PulseWidth(next)
-                }
-                _ => unreachable!(),
-            };
-
-            // Patch updated value
-            match setting {
-                PatternPenField::Loops(x) => *dst.loop_count = x.try_into().unwrap(),
-                PatternPenField::Speed(x) => *dst.speed = x,
-                PatternPenField::Power(x) => *dst.power = x,
-                PatternPenField::Frequency(x) => {
-                    *dst.frequency = x.try_into().unwrap();
-                    *dst.frequency_2 = x.try_into().unwrap();
-                }
-                PatternPenField::PulseWidth(x) => {
-                    *dst.pulse_width = x;
-                    *dst.pulse_width_2 = x.try_into().unwrap();
+                    let pw: u32 = pw.next().expect("Pulse width out of bounds").into();
+                    debug!("Patching pulse width for pen #{} to {}ns", next_idx, next);
+                    *next.pulse_width = pw;
+                    *next.pulse_width_2 = pw.try_into().unwrap();
                 }
             }
 
             // Randomize pen color
-            *dst.color = Rgba::random().into();
+            *next.color = Rgba::random().into();
 
             // Always enable custom settings for pen
-            *dst.use_default = 0;
+            *next.use_default = 0;
 
-            dst.valid_settings();
-        }
+            next.valid_settings();
+        });
     }
 }