3 Commits 96bc7f853f ... 462554fb91

Author SHA1 Message Date
  Kevin Lee 462554fb91 Add support for pulse width patterning 3 months ago
  Kevin Lee e43a681102 Fix Y patterning 3 months ago
  Kevin Lee a9bc46f6e2 Cleanup 3 months ago
4 changed files with 192 additions and 105 deletions
  1. 7 1
      README.md
  2. 76 67
      src/config/object.rs
  3. 25 1
      src/config/pen.rs
  4. 84 36
      src/ezcad/types.rs

+ 7 - 1
README.md

@@ -80,6 +80,7 @@ Field: !Loops 1
 Field: !Speed 100.0
 Field: !Power 10.0
 Field: !Frequency 1000
+Field: !PulseWidth 2 # Increment
 ```
 
 Exporting a pen to a file:
@@ -147,7 +148,7 @@ Array:
   Spacing: 1.0
   RandomizeOrder: True
   StartingPen: 1
-  PatternX: <PenPattern>
+  PatternX: <PenPattern> // Optional
   PatternY: <PenPattern> // Optional
 ```
 
@@ -185,3 +186,8 @@ Pattern: !Background # (not supported)
 Pattern: !Fill
 Pattern: !Zigzag
 ```
+
+## Settings
+
+### Stainless Steel (mirror finish)
+

+ 76 - 67
src/config/object.rs

@@ -114,7 +114,7 @@ pub struct ArrayConfig {
     spacing: f64,
     randomize_order: bool,
     starting_pen: usize,
-    pattern_x: PatternField,
+    pattern_x: Option<PatternField>,
     pattern_y: Option<PatternField>,
 }
 
@@ -258,78 +258,87 @@ impl ObjectOperation {
         });
 
         // Process array generation of object
-        let new_objects = self.array.as_ref().map_or(vec![object.clone()], |array| {
-            let mut new_obj: Vec<Object> = vec![];
-
-            let bottom_left: Coordinate = Coordinate {
-                x: (array.columns - 1) as f64 * array.spacing / -2.0,
-                y: (array.rows - 1) as f64 * array.spacing / -2.0,
-            };
-
-            // Generate objects
-            for y in 0..array.rows {
-                for x in 0..array.columns {
-                    let delta: Coordinate = bottom_left
-                        + Coordinate {
-                            x: array.spacing * x as f64,
-                            y: array.spacing * y as f64,
-                        };
-
-                    let pen: usize = array.starting_pen + y * array.columns + x;
-
-                    let mut object: Object = object.clone();
-                    object.move_relative(Some(delta), None);
-                    object.set_pen(pen.try_into().unwrap());
-
-                    debug!(
-                        "Adding new object at {} with pen #{}",
-                        object.core().origin,
-                        pen
-                    );
-                    new_obj.push(object);
+        let new_objects = self.array.as_ref().map_or_else(
+            || vec![object.clone()],
+            |array| {
+                let mut new_obj: Vec<Object> = vec![];
+
+                let bottom_left: Coordinate = Coordinate {
+                    x: (array.columns - 1) as f64 * array.spacing / -2.0,
+                    y: (array.rows - 1) as f64 * array.spacing / -2.0,
+                };
+
+                // Generate objects
+                for y in 0..array.rows {
+                    for x in 0..array.columns {
+                        let delta: Coordinate = bottom_left
+                            + Coordinate {
+                                x: array.spacing * x as f64,
+                                y: array.spacing * y as f64,
+                            };
+
+                        let pen: usize = array.starting_pen + y * array.columns + x;
+
+                        let mut object: Object = object.clone();
+                        object.move_relative(Some(delta), None);
+                        object.set_pen(pen.try_into().unwrap());
+
+                        debug!(
+                            "Adding new object at {} with pen #{}",
+                            object.core().origin,
+                            pen
+                        );
+                        new_obj.push(object);
+                    }
                 }
-            }
 
-            // Generate pens
-            match &array.pattern_y {
-                None => {
-                    array.pattern_x.pattern(
-                        &mut pens
-                            .iter_mut()
-                            .enumerate()
-                            .skip(array.starting_pen)
-                            .take(array.columns * array.rows),
-                    );
-                }
-                Some(pattern_y) => {
-                    pattern_y.pattern(
-                        &mut pens
-                            .iter_mut()
-                            .enumerate()
-                            .skip(array.starting_pen)
-                            .step_by(array.columns)
-                            .take(array.rows),
-                    );
-                    for y in 0..array.rows {
-                        array.pattern_x.pattern(
-                            &mut pens
-                                .iter_mut()
-                                .enumerate()
-                                .skip(array.starting_pen)
-                                .skip(y * array.columns)
-                                .take(array.columns),
-                        )
+                // Generate pens
+                match &array.pattern_y {
+                    None => {
+                        if let Some(pattern_x) = &array.pattern_x {
+                            pattern_x.pattern(
+                                &mut pens
+                                    .iter_mut()
+                                    .enumerate()
+                                    .skip(array.starting_pen)
+                                    .take(array.columns * array.rows),
+                            );
+                        }
+                    }
+                    Some(pattern_y) => {
+                        for x in 0..array.columns {
+                            pattern_y.pattern(
+                                &mut pens
+                                    .iter_mut()
+                                    .enumerate()
+                                    .skip(x + array.starting_pen)
+                                    .step_by(array.columns)
+                                    .take(array.rows),
+                            );
+                        }
+                        if let Some(pattern_x) = &array.pattern_x {
+                            for y in 0..array.rows {
+                                pattern_x.pattern(
+                                    &mut pens
+                                        .iter_mut()
+                                        .enumerate()
+                                        .skip(array.starting_pen)
+                                        .skip(y * array.columns)
+                                        .take(array.columns),
+                                )
+                            }
+                        }
                     }
                 }
-            }
 
-            if array.randomize_order {
-                debug!("Randomizing draw order of array objects");
-                new_obj.shuffle(&mut thread_rng());
-            }
+                if array.randomize_order {
+                    debug!("Randomizing draw order of array objects");
+                    new_obj.shuffle(&mut thread_rng());
+                }
 
-            new_obj
-        });
+                new_obj
+            },
+        );
 
         let layer_id: usize = self.layer.unwrap_or(0);
         let layer: &mut Layer = layers.get_mut(layer_id).expect("Invalid layer index");

+ 25 - 1
src/config/pen.rs

@@ -6,6 +6,7 @@ use ezcad::{
 };
 use log::debug;
 use serde::{Deserialize, Serialize};
+use strum::IntoEnumIterator;
 
 const SPEED_MIN: f64 = 0.0;
 const SPEED_MAX: f64 = 100000.0;
@@ -122,7 +123,7 @@ impl ClonePen {
             self.from,
             self.to,
             match self.inclusive {
-                Some(true) => format!("(inclusive)"),
+                Some(true) => format!(" (inclusive)"),
                 _ => format!(""),
             }
         );
@@ -170,6 +171,7 @@ pub enum PatternField {
     Speed(f64),
     Power(f64),
     Frequency(i32),
+    PulseWidth(u32),
 }
 
 impl PatternField {
@@ -200,6 +202,13 @@ impl PatternField {
                 );
                 PatternField::Frequency((*src.frequency).try_into().unwrap())
             }
+            PatternField::PulseWidth(_) => {
+                debug!(
+                    "Initial pulse width from pen #{} is {}ns",
+                    src_idx, *src.pulse_width
+                );
+                PatternField::PulseWidth(*src.pulse_width)
+            }
         };
 
         for (idx, dst) in pens {
@@ -245,6 +254,17 @@ impl PatternField {
                     );
                     PatternField::Frequency(value)
                 }
+                (PatternField::PulseWidth(prev), PatternField::PulseWidth(incr)) => {
+                    let mut pw = PulseWidth::iter();
+                    let _ = pw
+                        .find(|x| u32::from(*x) == prev)
+                        .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);
+                    PatternField::PulseWidth(next)
+                }
                 _ => unreachable!(),
             };
 
@@ -257,6 +277,10 @@ impl PatternField {
                     *dst.frequency = x.try_into().unwrap();
                     *dst.frequency_2 = x.try_into().unwrap();
                 }
+                PatternField::PulseWidth(x) => {
+                    *dst.pulse_width = x;
+                    *dst.pulse_width_2 = x.try_into().unwrap();
+                }
             }
 
             // Randomize pen color

+ 84 - 36
src/ezcad/types.rs

@@ -5,10 +5,9 @@ use std::{
 
 use binrw::{binrw, BinRead, BinWrite};
 use diff::{Diff, VecDiff};
-use num_enum::{IntoPrimitive, TryFromPrimitive};
 use rand::{thread_rng, Rng};
 use serde::{Deserialize, Serialize};
-use serde_repr::{Deserialize_repr, Serialize_repr};
+use strum::EnumIter;
 
 use crate::{array_of::ArrayOfPrimitive, field_of::FieldOf};
 
@@ -118,9 +117,9 @@ impl From<(u8, u8, u8)> for Rgba {
 impl Rgba {
     pub fn random() -> Self {
         Self {
-            red: thread_rng().gen_range(0..=255),
-            green: thread_rng().gen_range(0..=255),
-            blue: thread_rng().gen_range(0..=255),
+            red: thread_rng().gen(),
+            green: thread_rng().gen(),
+            blue: thread_rng().gen(),
             alpha: 0,
         }
     }
@@ -255,40 +254,89 @@ impl Default for ObjectType {
     }
 }
 
-#[derive(
-    Copy,
-    Clone,
-    Debug,
-    Diff,
-    PartialEq,
-    BinRead,
-    BinWrite,
-    strum::Display,
-    Serialize_repr,
-    Deserialize_repr,
-    IntoPrimitive,
-    TryFromPrimitive,
-)]
+#[derive(Copy, Clone, Debug, Diff, PartialEq, strum::Display, Serialize, Deserialize, EnumIter)]
 #[diff(attr(
     #[derive(Debug, PartialEq)]
 ))]
-#[brw(repr(u32))]
+#[serde(try_from = "u32")]
+#[serde(into = "u32")]
 #[repr(u32)]
 pub enum PulseWidth {
-    Ns2 = 2,
-    Ns4 = 4,
-    Ns6 = 6,
-    Ns8 = 8,
-    Ns12 = 12,
-    Ns20 = 20,
-    Ns30 = 30,
-    Ns45 = 45,
-    Ns60 = 60,
-    Ns80 = 80,
-    Ns100 = 100,
-    Ns150 = 150,
-    Ns200 = 200,
-    Ns250 = 250,
-    Ns350 = 350,
-    Ns500 = 500,
+    Ns2,
+    Ns4,
+    Ns6,
+    Ns8,
+    Ns12,
+    Ns20,
+    Ns30,
+    Ns45,
+    Ns60,
+    Ns80,
+    Ns100,
+    Ns150,
+    Ns200,
+    Ns250,
+    Ns350,
+    Ns500,
+}
+
+impl From<PulseWidth> for u32 {
+    fn from(value: PulseWidth) -> Self {
+        match value {
+            PulseWidth::Ns2 => 2,
+            PulseWidth::Ns4 => 4,
+            PulseWidth::Ns6 => 6,
+            PulseWidth::Ns8 => 8,
+            PulseWidth::Ns12 => 12,
+            PulseWidth::Ns20 => 20,
+            PulseWidth::Ns30 => 30,
+            PulseWidth::Ns45 => 45,
+            PulseWidth::Ns60 => 60,
+            PulseWidth::Ns80 => 80,
+            PulseWidth::Ns100 => 100,
+            PulseWidth::Ns150 => 150,
+            PulseWidth::Ns200 => 200,
+            PulseWidth::Ns250 => 250,
+            PulseWidth::Ns350 => 350,
+            PulseWidth::Ns500 => 500,
+        }
+    }
+}
+
+pub enum PulseWidthError {
+    Unsupported,
+}
+
+impl Display for PulseWidthError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            PulseWidthError::Unsupported => write!(f, "Unsupported pulse width value"),
+        }
+    }
+}
+
+impl TryFrom<u32> for PulseWidth {
+    type Error = PulseWidthError;
+
+    fn try_from(value: u32) -> Result<Self, Self::Error> {
+        match value {
+            2 => Ok(PulseWidth::Ns2),
+            4 => Ok(PulseWidth::Ns4),
+            6 => Ok(PulseWidth::Ns6),
+            8 => Ok(PulseWidth::Ns8),
+            12 => Ok(PulseWidth::Ns12),
+            20 => Ok(PulseWidth::Ns20),
+            30 => Ok(PulseWidth::Ns30),
+            45 => Ok(PulseWidth::Ns45),
+            60 => Ok(PulseWidth::Ns60),
+            80 => Ok(PulseWidth::Ns80),
+            100 => Ok(PulseWidth::Ns100),
+            150 => Ok(PulseWidth::Ns150),
+            200 => Ok(PulseWidth::Ns200),
+            250 => Ok(PulseWidth::Ns250),
+            350 => Ok(PulseWidth::Ns350),
+            500 => Ok(PulseWidth::Ns500),
+            _ => Err(PulseWidthError::Unsupported),
+        }
+    }
 }