浏览代码

Add readme file

Kevin Lee 1 年之前
父节点
当前提交
c4b4525a74
共有 5 个文件被更改,包括 155 次插入149 次删除
  1. 65 0
      README.md
  2. 0 131
      Shapes.txt
  3. 7 2
      config.yml
  4. 78 10
      src/config.rs
  5. 5 6
      src/main.rs

+ 65 - 0
README.md

@@ -0,0 +1,65 @@
+# EzCAD Patcher
+
+This tool parses and patches EZCAD files with values specified in a YAML config file.
+
+## Usage
+
+``` text
+Usage: ezcad_patcher.exe [OPTIONS] --input <INPUT>
+
+Options:
+  -i, --input <INPUT>    Input file to parse
+  -o, --output <OUTPUT>  Output file to write to
+  -c, --config <CONFIG>  Configuration file
+  -v, --verbose...       Increase logging verbosity
+  -q, --quiet...         Decrease logging verbosity
+  -h, --help             Print help
+```
+
+## Patching Pen Settings
+
+Three operations are supported for patching pen settings:
+
+1. Setting values of specific fields for a given pen:
+
+``` yaml
+Pens: 
+  - !Patch
+    Pen: 0                  # Required - pen index
+    Color: [127, 127, 127]  # Optional - pen RGB color
+    Enabled: true           # Optional - pen enable flag
+    LoopCount: 3            # Optional - pen loop count
+    Speed: 1.234            # Optional - pen speed
+    Power: 10.5             # Optional - pen power 
+    Frequency: 10000        # Optional - pen frequency
+```
+
+2. Cloning one pen to another:
+
+``` yaml
+Pens: 
+  - !Clone
+    From: 0
+    To: 1
+    # Color: [127, 127, 127]  # Optional - cloned pen RGB color
+    # Enabled: true           # Optional - cloned pen enable flag
+    # LoopCount: 3            # Optional - cloned pen loop count
+    # Speed: 1.234            # Optional - cloned pen speed
+    # Power: 10.5             # Optional - cloned pen power 
+    # Frequency: 10000        # Optional - cloned pen frequency
+```
+
+3. Incrementing a specific field across a sequence of pens:
+
+``` yaml
+Pens: 
+  - !Pattern
+    From: 1
+    To: 5
+    # Field: !Loops 1         # Choose one
+    # Field: !Speed 100.0     # Choose one
+    # Field: !Power 10.0      # Choose one
+    # Field: !Frequency 1000  # Choose one
+```
+
+Patching operations will be applied in the order that they are defined.

+ 0 - 131
Shapes.txt

@@ -1,131 +0,0 @@
-Point 		01 00 00 00
-				00 00 00 00
-			01 00 00 00 00 00
-				A8 42 B4 E1 F3 47 2E C0 80 97 3C 18 70 C6 05 40
-
-Line 		01 00 00 00
-				00 00 00 00
-			00 01 00 00 00 00
-				02 00 00 00
-					58 BD 4B 1E 0C 38 3B C0 14 A2 0D 9F 3F E6 2B 40
-					F8 63 8E D2 ED AB 20 C0 78 97 3C 18 70 C6 15 40
-
- Multiline	01 00 00 00
- 				00 00 00 00
- 			00 01 00 00 00 00
- 				04 00 00 00
-					36 7C FE 98 A3 74 36 C0 2C 12 D4 54 88 B6 22 40
-					30 7C FE 98 A3 74 16 C0 40 BD 4B 1E 0C 38 EB 3F
-					40 50 53 21 DA F0 1D C0 70 2D 12 D4 54 08 22 C0
-					48 50 53 21 DA F0 2D C0 A0 A6 42 B4 E1 33 32 C0
-
-Curve 		01 00 00 00
-				00 00 00 00
-			00 03 00 00 00 00
-				04 00 00 00
-					AE 45 82 9A 0A D1 37 C0 FC CA EA 5D F2 E0 2A 40
-					BA E4 C1 80 33 6E 3D C0 E0 F3 C7 1C A5 DB 19 40
-					28 0F 06 9C 71 2D 39 C0 30 79 30 E0 8C EB 2C C0
-					28 0F 06 9C 71 2D 29 C0 A0 A6 42 B4 E1 33 32 C0
-Multicurve	02 00 00 00
-				00 00 00 00
-			00 03 00 00 00 00
-				04 00 00 00
-					EC 2B AB 77 C9 43 35 C0 5C BD 4B 1E 0C 38 2B 40
-					9C D8 89 9D D8 89 3A C0 9C 71 2D 12 D4 54 20 40
-					AC 45 82 9A 0A D1 37 C0 4C 50 53 21 DA F0 2D C0
-					78 97 3C 18 70 C6 25 C0 58 56 EF 92 07 03 31 C0
-			00 03 00 00 00 00
-				04 00 00 00
-					78 97 3C 18 70 C6 25 C0 58 56 EF 92 07 03 31 C0
-					A0 71 2D 12 D4 54 00 40 8A 04 35 15 A2 0D 33 C0
-					C0 B2 7A 97 3C 18 25 40 88 6B 91 A0 A6 42 2D C0
-					58 BD 4B 1E 0C 38 2B 40 88 6B 91 A0 A6 42 1D C0
-Multicurve2 03 00 00 00
-				00 00 00 00
-			00 03 00 00 00 00
-				04 00 00 00
-					10 6D F8 FC 31 07 3A C0 E4 F3 C7 1C A5 DB 29 40
-					B2 7A 97 3C 18 B0 39 C0 60 BD 4B 1E 0C 38 0B 40
-					3C E6 28 DD BE 32 3A C0 B4 48 50 53 21 5A 31 C0
-					88 6B 91 A0 A6 42 2D C0 12 3B B1 13 3B B1 31 C0
-			00 03 00 00 00 00
-				04 00 00 00
-					88 6B 91 A0 A6 42 2D C0 12 3B B1 13 3B B1 31 C0
-					60 2A 44 1B 3E 7F 08 C0 70 2D 12 D4 54 08 32 C0
-					FC 63 8E D2 ED AB 30 40 F4 95 D5 BB E4 01 39 C0
-					8C 04 35 15 A2 0D 33 40 2C 79 30 E0 8C EB 2C C0
-			00 03 00 00 00 00
-				04 00 00 00
-					8C 04 35 15 A2 0D 33 40 2C 79 30 E0 8C EB 2C C0
-					1C A5 DB 57 56 6F 35 40 C0 19 D7 22 41 4D 0F C0
-					A0 A6 42 B4 E1 33 32 40 78 6B 91 A0 A6 42 1D 40
-					F0 60 C0 19 D7 22 27 40 9A 71 2D 12 D4 54 30 40
-Rectangle	08 00 00 00
-				10 00 00 00
-					B2 7A 97 3C 18 B0 39 C0 2C 12 D4 54 88 B6 22 40
-				10 00 00 00
-					40 50 53 21 DA F0 FD 3F F8 63 8E D2 ED AB 20 C0
-				08 00 00 00
-					00 00 00 00 00 00 00 00
-				08 00 00 00
-					00 00 00 00 00 00 00 00
-				08 00 00 00
-					00 00 00 00 00 00 00 00
-				08 00 00 00
-					00 00 00 00 00 00 00 00
-				04 00 00 00
-					00 00 00 00
-				48 00 00 00
-					70 00 00 00 00 00 F0 3F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F0 3F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F0 3F
-Circle		06 00 00 00
-				10 00 00 00
-					00 35 15 A2 0D 9F 1E C0 80 04 35 15 A2 0D F3 3F
-				08 00 00 00
-					7F 43 DA 09 B8 95 31 40
-				08 00 00 00
-					E0 86 44 54 FB 21 F9 3F
-				04 00 00 00
-					01 00 00 00
-				04 00 00 00
-					00 00 00 00
-				48 00 00 00
-					00 00 00 00 00 00 F0 3F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F0 3F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F0 3F
-Ellipse		08 00 00 00
-				04 00 00 00
-					00 00 00 00
-				10 00 00 00
-					00 CE B8 16 09 6A 24 C0 F0 60 C0 19 D7 22 17 C0
-				10 00 00 00
-					5C 8B 04 35 15 E2 32 40 7C 97 3C 18 70 C6 25 40
-				08 00 00 00
-					00 00 00 00 00 00 00 00
-				08 00 00 00
-					EA 2E 44 54 FB 21 19 40
-				04 00 00 00
-					00 00 00 00
-				48 00 00 00
-					00 00 00 00 00 00 F0 3F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F0 3F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F0 3F
-				04 00 00 00
-					00 00 00 00
-Polygon		0A 00 00 00
-				04 00 00 00
-					00 00 00 00
-				10 00 00 00
-					60 C0 19 D7 22 C1 34 C0 94 6E 5F 59 BD CB 26 C0
-				10 00 00 00
-					00 CE B8 16 09 6A 04 40 EE 92 07 03 CE 78 3F C0
-				08 00 00 00
-					00 00 00 00 00 00 00 00
-				08 00 00 00
-					00 00 00 00 00 00 00 00
-				08 00 00 00
-					00 00 00 00 00 00 00 00
-				08 00 00 00
-					00 00 00 00 00 00 00 00
-				04 00 00 00
-					06 00 00 00
-				04 00 00 00
-					FF 00 00 00
-				48 00 00 00
-					00 00 00 00 00 00 F0 3F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F0 3F 00 00 00 00 00 00 00 00 88 F9 95 D5 BB 64 13 C0 1C A5 DB 57 56 6F 25 40 00 00 00 00 00 00 F0 3F

+ 7 - 2
config.yml

@@ -1,12 +1,17 @@
 Pens: 
   - !Patch
     Pen: 0
+    Color: [127, 127, 127]
     Enabled: true
+    LoopCount: 3
+    Speed: 1.234
+    Power: 10.5
+    Frequency: 10000
   - !Clone
     From: 0
     To: 1
     Enabled: false
   - !Pattern
     From: 1
-    To: 3
-    Field: !Speed -100
+    To: 5
+    Field: !Speed 100

+ 78 - 10
src/config.rs

@@ -1,5 +1,5 @@
 use ezcad::pen::Pen;
-use log::trace;
+use log::debug;
 use serde::{Deserialize, Serialize};
 
 #[derive(Debug, Serialize, Deserialize)]
@@ -15,34 +15,41 @@ pub struct Patch {
 
 impl Patch {
     fn patch(&self, id: usize, target: &mut Vec<Pen>) {
-        trace!("Patching settings for pen #{}", id);
-
-        let to_patch = target.get_mut(id).expect("Invalid pen index");
+        let to_patch: &mut Pen = target.get_mut(id).expect("Invalid pen index");
 
         if let Some(color) = self.color {
+            debug!("Patching color for pen #{}: {:?}", id, color);
             *to_patch.color = color.into()
         }
 
         if let Some(enabled) = self.enabled {
+            debug!("Patching enablement for pen #{}: {}", id, enabled);
             *to_patch.disabled = !enabled as u32;
         }
 
         if let Some(loop_count) = self.loop_count {
+            debug!("Patching loop count for pen #{}: {}", id, loop_count);
             *to_patch.loop_count = loop_count;
         }
 
         if let Some(speed) = self.speed {
+            debug!("Patching speed for pen #{}: {}", id, speed);
             *to_patch.speed = speed;
         }
 
         if let Some(power) = self.power {
+            debug!("Patching power for pen #{}: {}", id, power);
             *to_patch.power = power;
         }
 
         if let Some(frequency) = self.frequency {
+            debug!("Patching frequency for pen #{}: {}", id, frequency);
             *to_patch.frequency = frequency;
             *to_patch.frequency_2 = frequency.try_into().unwrap();
         }
+
+        // Always enable custom settings for pen
+        *to_patch.use_default = 0;
     }
 }
 
@@ -71,15 +78,15 @@ pub struct ClonePen {
 
 impl ClonePen {
     fn clone(&self, target: &mut Vec<Pen>) {
-        trace!("Cloning pen #{} to #{}", self.from, self.to);
+        debug!("Cloning pen #{} to #{}", self.from, self.to);
         assert!(
             self.to > self.from,
             "Target pen must be greater than source pen"
         );
 
         // Clone pen
-        let src = target.get(self.from).expect("Invalid pen index").clone();
-        let dst = target.get_mut(self.to).expect("Invalid pen index");
+        let src: Pen = target.get(self.from).expect("Invalid pen index").clone();
+        let dst: &mut Pen = target.get_mut(self.to).expect("Invalid pen index");
         *dst = src;
 
         // Patch pen if needed
@@ -107,18 +114,79 @@ pub struct PatternPen {
 
 impl PatternPen {
     fn pattern(&self, target: &mut Vec<Pen>) {
-        trace!("Patterning from pen #{} to #{}", self.from, self.to);
+        debug!("Patterning from pen #{} to #{}", self.from, self.to);
         assert!(
             self.to > self.from,
             "Target pen(s) must be greater than source pen"
         );
 
         // Obtain settings from first pen
-        let src = target.get(self.from).expect("Invalid pen index").clone();
+        let src: Pen = target.get(self.from).expect("Invalid pen index").clone();
+
+        let mut setting: PatternField = match self.field {
+            PatternField::Loops(_) => {
+                debug!(
+                    "Initial loop count from pen #{}: {}",
+                    self.from, *src.loop_count
+                );
+                PatternField::Loops((*src.loop_count).try_into().unwrap())
+            }
+            PatternField::Speed(_) => {
+                debug!("Initial speed from pen #{}: {}", self.from, *src.speed);
+                PatternField::Speed(*src.speed)
+            }
+            PatternField::Power(_) => {
+                debug!("Initial power from pen #{}: {}", self.from, *src.power);
+                PatternField::Power(*src.power)
+            }
+            PatternField::Frequency(_) => {
+                debug!(
+                    "Initial frequency from pen #{}: {}",
+                    self.from, *src.frequency
+                );
+                PatternField::Frequency((*src.frequency).try_into().unwrap())
+            }
+        };
 
-        // Clone to target pen and patch pattern setting
         for dst in (self.from..=self.to).skip(1) {
+            // Clone to target pen
+            let pen: &mut Pen = target.get_mut(dst).expect("Invalid pen index");
+            *pen = src.clone();
+
+            // Calculate new setting
+            setting = match (setting, &self.field) {
+                (PatternField::Loops(prev), PatternField::Loops(incr)) => {
+                    debug!("Patching loop count for pen #{}: {}", dst, prev + incr);
+                    PatternField::Loops(prev + incr)
+                }
+                (PatternField::Speed(prev), PatternField::Speed(incr)) => {
+                    debug!("Patching speed for pen #{}: {}", dst, prev + incr);
+                    PatternField::Speed(prev + incr)
+                }
+                (PatternField::Power(prev), PatternField::Power(incr)) => {
+                    debug!("Patching power for pen #{}: {}", dst, prev + incr);
+                    PatternField::Power(prev + incr)
+                }
+                (PatternField::Frequency(prev), PatternField::Frequency(incr)) => {
+                    debug!("Patching frequency for pen #{}: {}", dst, prev + incr);
+                    PatternField::Frequency(prev + incr)
+                }
+                _ => unreachable!(),
+            };
+
+            // Patch updated value
+            match setting {
+                PatternField::Loops(x) => *pen.loop_count = x.try_into().unwrap(),
+                PatternField::Speed(x) => *pen.speed = x,
+                PatternField::Power(x) => *pen.power = x,
+                PatternField::Frequency(x) => {
+                    *pen.frequency = x.try_into().unwrap();
+                    *pen.frequency_2 = x.try_into().unwrap();
+                }
+            }
 
+            // Always enable custom settings for pen
+            *pen.use_default = 0;
         }
     }
 }

+ 5 - 6
src/main.rs

@@ -4,7 +4,7 @@ use binrw::{BinRead, BinWriterExt};
 use clap::Parser;
 use clap_verbosity_flag::{InfoLevel, Verbosity};
 use ezcad::file::EzCadHeader;
-use log::{debug, info};
+use log::{info, trace};
 
 use crate::config::{Config, PatchPens};
 
@@ -41,7 +41,7 @@ fn main() {
     let time: Instant = Instant::now();
     let mut file: EzCadHeader =
         EzCadHeader::read_le(&mut input).expect("Failed to parse input file as EZCAD format");
-    info!("Decode time: {:?}", time.elapsed());
+    info!("Input decode time: {:?}", time.elapsed());
 
     // Print info on pens with non-default settings
     for pen in file
@@ -51,13 +51,13 @@ fn main() {
         .iter()
         .filter(|x| *x.use_default == 0)
     {
-        debug!("{:#?}", pen);
+        trace!("{:#?}", pen);
     }
 
     // Print all objects
     for layer in file.layers_offset.iter() {
         for object in layer.objects.iter() {
-            debug!("{:#?}", object);
+            trace!("{:#?}", object);
         }
     }
 
@@ -65,7 +65,6 @@ fn main() {
         info!("Processing config file {}", config.to_string_lossy());
         let config: String = std::fs::read_to_string(config).expect("Failed to open config file");
         let config: Config = serde_yaml::from_str(&config).expect("Failed to parse config file");
-        debug!("{:#?}", config);
 
         // Patch pen settings
         config.pens.patch(&mut file.pens_offset.data.pens);
@@ -77,6 +76,6 @@ fn main() {
         output
             .write_le(&file)
             .expect("Failed to serialize contents in EZCAD format");
-        info!("Encode time: {:?}", time.elapsed());
+        info!("Output encode time: {:?}", time.elapsed());
     }
 }