Bladeren bron

F64 compare and support for layer queries

Kevin Lee 1 maand geleden
bovenliggende
commit
07b1a7423f

+ 10 - 0
Cargo.lock

@@ -276,6 +276,15 @@ version = "2.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
 
+[[package]]
+name = "float-cmp"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b09cf3155332e944990140d967ff5eceb70df778b34f77d8075db46e4704e6d8"
+dependencies = [
+ "num-traits",
+]
+
 [[package]]
 name = "getrandom"
 version = "0.2.11"
@@ -390,6 +399,7 @@ dependencies = [
  "dialoguer",
  "diff-struct",
  "env_logger",
+ "float-cmp",
  "human-repr",
  "itertools",
  "log",

+ 1 - 0
Cargo.toml

@@ -20,6 +20,7 @@ clap-verbosity-flag = "2.1.1"
 dialoguer = "0.11.0"
 diff-struct = "0.5.3"
 env_logger = "0.10.1"
+float-cmp = "0.10.0"
 human-repr = { version = "1.1.0", features = ["serde"] }
 itertools = "0.12.0"
 log = "0.4.20"

+ 12 - 9
src/config/hatch.rs

@@ -1,4 +1,7 @@
-use ezcad::objects::{hatch::HatchSetting, Object};
+use ezcad::{
+    objects::{hatch::HatchSetting, Object},
+    FP,
+};
 use itertools::Itertools;
 use log::debug;
 use serde::{Deserialize, Serialize};
@@ -58,7 +61,7 @@ impl PatternHatchField {
                 PatternHatchField::LineSpacing(incr) => {
                     let value: f64 = *prev.line_spacing + incr;
                     debug!(
-                        "Patching line spacing for object #{} to {:.3}",
+                        "Patching line spacing for object #{} to {:.FP$}",
                         next_idx, value
                     );
                     *next.line_spacing = value;
@@ -66,7 +69,7 @@ impl PatternHatchField {
                 PatternHatchField::EdgeOffset(incr) => {
                     let value: f64 = *prev.edge_offset + incr;
                     debug!(
-                        "Patching edge offset for object #{} to {:.3}",
+                        "Patching edge offset for object #{} to {:.FP$}",
                         next_idx, value
                     );
                     *next.edge_offset = value;
@@ -74,7 +77,7 @@ impl PatternHatchField {
                 PatternHatchField::StartOffset(incr) => {
                     let value: f64 = *prev.start_offset + incr;
                     debug!(
-                        "Patching start offset for object #{} to {:.3}",
+                        "Patching start offset for object #{} to {:.FP$}",
                         next_idx, value
                     );
                     *next.start_offset = value;
@@ -82,20 +85,20 @@ impl PatternHatchField {
                 PatternHatchField::EndOffset(incr) => {
                     let value: f64 = *prev.end_offset + incr;
                     debug!(
-                        "Patching end offset for object #{} to {:.3}",
+                        "Patching end offset for object #{} to {:.FP$}",
                         next_idx, value
                     );
                     *next.end_offset = value;
                 }
                 PatternHatchField::Angle(incr) => {
                     let value: f64 = *prev.angle + incr;
-                    debug!("Patching angle for object #{} to {:.3}", next_idx, value);
+                    debug!("Patching angle for object #{} to {:.FP$}", next_idx, value);
                     *next.angle = value;
                 }
                 PatternHatchField::RotateAngle(incr) => {
                     let value: f64 = *prev.rotate_angle + incr;
                     debug!(
-                        "Patching rotate angle for object #{} to {:.3}",
+                        "Patching rotate angle for object #{} to {:.FP$}",
                         next_idx, value
                     );
                     *next.rotate_angle = value;
@@ -103,7 +106,7 @@ impl PatternHatchField {
                 PatternHatchField::LineReduction(incr) => {
                     let value: f64 = *prev.line_reduction + incr;
                     debug!(
-                        "Patching line reduction for object #{} to {:.3}",
+                        "Patching line reduction for object #{} to {:.FP$}",
                         next_idx, value
                     );
                     *next.line_reduction = value;
@@ -111,7 +114,7 @@ impl PatternHatchField {
                 PatternHatchField::LoopDistance(incr) => {
                     let value: f64 = *prev.loop_distance + incr;
                     debug!(
-                        "Patching loop distance for object #{} to {:.3}",
+                        "Patching loop distance for object #{} to {:.FP$}",
                         next_idx, value
                     );
                     *next.loop_distance = value;

+ 5 - 4
src/ezcad/objects/circle.rs

@@ -2,11 +2,13 @@ use std::fmt::{Debug, Display};
 
 use binrw::{BinRead, BinWrite};
 use diff::Diff;
+use float_cmp::approx_eq;
 use log::warn;
 
 use crate::{
     field_of::FieldOf,
     types::{ObjectType, Point, F64, U32},
+    FP,
 };
 
 use super::{ObjectCore, ObjectModifier, Translate};
@@ -31,17 +33,16 @@ impl Display for Circle {
             *self.drawn_origin - Point::from(*self.radius),
             *self.drawn_origin + Point::from(*self.radius),
         );
-
-        if format!("{}", origin) != format!("{}", *self.core.origin) {
+        if origin != *self.core.origin {
             warn!(
-                "Origin mismatch! Core: {}, Calculated: {}",
+                "Origin mismatch! Core: {:.FP$}, Calculated: {:.FP$}",
                 *self.core.origin, origin
             );
         }
 
         write!(
             f,
-            "{}, Origin: {}, Width : {:.3}, Height: {:.3}, Start Radian: {:.3}, Clockwise: {}",
+            "{}, Origin: {}, Width : {:.FP$}, Height: {:.FP$}, Start Radian: {:.FP$}, Clockwise: {}",
             self.core,
             origin,
             width,

+ 4 - 3
src/ezcad/objects/ellipse.rs

@@ -7,6 +7,7 @@ use log::warn;
 use crate::{
     field_of::FieldOf,
     types::{ObjectType, Point, F64, U32},
+    FP,
 };
 
 use super::{ObjectCore, ObjectModifier, Translate};
@@ -33,16 +34,16 @@ impl Display for Ellipse {
             .modifier
             .corrected(*self.drawn_corner_a, *self.drawn_corner_b);
 
-        if format!("{}", origin) != format!("{}", *self.core.origin) {
+        if origin != *self.core.origin {
             warn!(
-                "Origin mismatch! Core: {}, Calculated: {}",
+                "Origin mismatch! Core: {:.FP$}, Calculated: {:.FP$}",
                 *self.core.origin, origin
             );
         }
 
         write!(
             f,
-            "{}, Origin: {}, Width: {:.3}, Height: {:.3}, Start Radian: {:.3}, End Radian: {:.3}, Open Curve: {}", 
+            "{}, Origin: {}, Width: {:.FP$}, Height: {:.FP$}, Start Radian: {:.FP$}, End Radian: {:.FP$}, Open Curve: {}", 
             self.core,
             origin,
             width,

+ 3 - 2
src/ezcad/objects/hatch.rs

@@ -4,6 +4,7 @@ use crate::{
     array_of::ArrayOf,
     field_of::FieldOf,
     types::{Field, Point, F64, U32},
+    FP,
 };
 use binrw::{binrw, BinRead, BinWrite};
 use diff::Diff;
@@ -410,7 +411,7 @@ impl Display for Hatch {
             if setting.enabled.into() {
                 write!(
                     f,
-                    "\nHatch #{}: All Calc: {}, Follow Edge Once: {}, Cross Hatch: {}, Pattern: {}, Angle: {:.3}, Pen: {}, Count: {}, Line Space: {:.3}, Avg Distribte Line: {}",
+                    "\nHatch #{}: All Calc: {}, Follow Edge Once: {}, Cross Hatch: {}, Pattern: {}, Angle: {:.FP$}, Pen: {}, Count: {}, Line Space: {:.FP$}, Avg Distribte Line: {}",
                     index,
                     setting.flags.all_calc() != 0,
                     setting.flags.follow_edge_once() != 0,
@@ -424,7 +425,7 @@ impl Display for Hatch {
                 )?;
                 write!(
                     f,
-                    "\n          Edge Offset: {:.3}, Start Offset: {:.3}, End Offset: {:.3}, Line Reduction: {:.3}, Loop Count: {}, Loop Distance: {:.3}, Auto Rotate: {}, Auto Rotate Angle: {:.3}",
+                    "\n          Edge Offset: {:.FP$}, Start Offset: {:.FP$}, End Offset: {:.FP$}, Line Reduction: {:.FP$}, Loop Count: {}, Loop Distance: {:.FP$}, Auto Rotate: {}, Auto Rotate Angle: {:.FP$}",
                     *setting.edge_offset,
                     *setting.start_offset,
                     *setting.end_offset,

+ 2 - 1
src/ezcad/objects/mod.rs

@@ -17,6 +17,7 @@ use modular_bitfield::{
 use crate::{
     field_of::FieldOf,
     types::{Field, ObjectType, Point, WString, F64, U16, U32},
+    FP,
 };
 
 use self::{
@@ -79,7 +80,7 @@ impl Display for ObjectCore {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         write!(
             f,
-            "Type: {}, Enabled: {}, Pen: {}, Count: {}, Z: {:.3}",
+            "Type: {}, Enabled: {}, Pen: {}, Count: {}, Z: {:.FP$}",
             self.obj_type,
             (self.flags.disabled() == 0),
             self.pen,

+ 4 - 3
src/ezcad/objects/polygon.rs

@@ -7,6 +7,7 @@ use log::warn;
 use crate::{
     field_of::FieldOf,
     types::{ObjectType, Point, F64, U32},
+    FP,
 };
 
 use super::{ObjectCore, ObjectModifier, Translate};
@@ -35,16 +36,16 @@ impl Display for Polygon {
             .modifier
             .corrected(*self.drawn_corner_a, *self.drawn_corner_b);
 
-        if format!("{}", origin) != format!("{}", *self.core.origin) {
+        if origin != *self.core.origin {
             warn!(
-                "Origin mismatch! Core: {}, Calculated: {}",
+                "Origin mismatch! Core: {:.FP$}, Calculated: {:.FP$}",
                 *self.core.origin, origin
             );
         }
 
         write!(
             f,
-            "{}, Origin: {}, Width: {:.3}, Height: {:.3}, Inverted: {}, Offset CX: {:.3}, Offset CY: {:.3}, Offset DX: {:.3}, Offset: DY: {:.3}, Edges: {}",
+            "{}, Origin: {}, Width: {:.FP$}, Height: {:.FP$}, Inverted: {}, Offset CX: {:.FP$}, Offset CY: {:.FP$}, Offset DX: {:.FP$}, Offset: DY: {:.FP$}, Edges: {}",
             self.core,
             origin,
             width,

+ 4 - 3
src/ezcad/objects/rectangle.rs

@@ -7,6 +7,7 @@ use log::warn;
 use crate::{
     field_of::FieldOf,
     types::{ObjectType, Point, F64},
+    FP,
 };
 
 use super::{ObjectCore, ObjectModifier, Translate};
@@ -33,16 +34,16 @@ impl Display for Rectangle {
             .modifier
             .corrected(*self.drawn_corner_a, *self.drawn_corner_b);
 
-        if format!("{}", origin) != format!("{}", *self.core.origin) {
+        if origin != *self.core.origin {
             warn!(
-                "Origin mismatch! Core: {}, Calculated: {}",
+                "Origin mismatch! Core: {:.FP$}, Calculated: {:.FP$}",
                 *self.core.origin, origin
             );
         }
 
         write!(
             f,
-            "{}, Origin: {}, Width: {:.3}, Height: {:.3}",
+            "{}, Origin: {}, Width: {:.FP$}, Height: {:.FP$}",
             self.core, origin, width, height,
         )
     }

+ 3 - 2
src/ezcad/pen.rs

@@ -13,6 +13,7 @@ use log::{error, warn};
 use crate::{
     field_of::FieldOf,
     types::{Bool, Field, PulseWidth, Rgba, WString, WobbleType, F64, U32},
+    FP,
 };
 
 #[derive(BinRead, Debug)]
@@ -128,7 +129,7 @@ impl Pen {
 
         if *self.frequency != *self.frequency_2 as u32 {
             error!(
-                "Mismatch pen internal frequency setting: ({}, {:.3})",
+                "Mismatch pen internal frequency setting: ({}, {:.FP$})",
                 *self.frequency, *self.frequency_2
             );
             ret = false;
@@ -136,7 +137,7 @@ impl Pen {
 
         if *self.pulse_width != *self.pulse_width_2 as u32 {
             error!(
-                "Mismatch pen internal pulse width setting: ({}, {:.3})",
+                "Mismatch pen internal pulse width setting: ({}, {:.FP$})",
                 *self.pulse_width, *self.pulse_width_2
             );
             ret = false;

+ 10 - 5
src/ezcad/types.rs

@@ -5,13 +5,14 @@ use std::{
 
 use binrw::{binrw, BinRead, BinWrite};
 use diff::{Diff, VecDiff};
+use float_cmp::approx_eq;
 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};
+use crate::{array_of::ArrayOfPrimitive, field_of::FieldOf, FP};
 
 /// Generic field with structure of length + data
 pub type Field = ArrayOfPrimitive<u8>;
@@ -127,9 +128,7 @@ impl Rgba {
     }
 }
 
-#[derive(
-    Copy, Clone, Debug, Default, Diff, PartialEq, BinRead, BinWrite, Serialize, Deserialize,
-)]
+#[derive(Copy, Clone, Debug, Default, Diff, BinRead, BinWrite, Serialize, Deserialize)]
 #[diff(attr(
     #[derive(Debug, PartialEq)]
 ))]
@@ -139,9 +138,15 @@ pub struct Point {
     pub y: f64,
 }
 
+impl PartialEq for Point {
+    fn eq(&self, other: &Self) -> bool {
+        approx_eq!(f64, self.x, other.x) && approx_eq!(f64, self.y, other.y)
+    }
+}
+
 impl Display for Point {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        write!(f, "({:.3}, {:.3})", self.x, self.y)
+        write!(f, "({:.FP$}, {:.FP$})", self.x, self.y)
     }
 }
 

+ 6 - 3
src/lib.rs

@@ -1,3 +1,6 @@
-pub mod ezcad;
-
-pub use ezcad::*;
+pub mod ezcad;
+
+pub use ezcad::*;
+
+// Precision when comparing/printing float values
+pub const FP: usize = 3;

+ 82 - 33
src/main.rs

@@ -9,10 +9,12 @@ use std::{
 use binrw::{BinRead, BinWrite, BinWriterExt};
 use clap::{error::ErrorKind, Args, Error, Parser, Subcommand};
 use clap_verbosity_flag::{InfoLevel, Verbosity};
+use config::object;
 use dialoguer::Confirm;
 use diff::Diff;
 use env_logger::Target;
 use ezcad::{file::EzCadHeader, layer::Layer, objects::Object, pen::Pen, types::PulseWidth};
+use itertools::Itertools;
 use log::{info, trace, warn};
 use num_enum::TryFromPrimitive;
 use num_format::{Locale, ToFormattedString};
@@ -219,42 +221,89 @@ fn main() {
             });
 
             // Process object query
-            args.object.map(|obj_range| {
-                warn!("Object origin, width, and height values may be incorrect if object is skewed or rotated");
-
-                let layer_index: usize = args.object_layer.unwrap_or(0);
-                let layer: &Layer = file
-                    .layers_offset
-                    .get(layer_index)
-                    .expect("Invalid layer index");
-
-                for object_index in obj_range {
-                    let object: &Object = layer
-                        .objects
-                        .get(object_index)
-                        .expect("Invalid object index");
-                    let pen_index: u32 = *object.core().pen;
-                    let pen: &Pen = pens.get(pen_index as usize).expect("Invalid pen index in object");
+            let layer_idx: usize = args.object_layer.unwrap_or(0);
+            let layer: &Layer = file
+                .layers_offset
+                .get(layer_idx)
+                .expect("Invalid layer index");
+
+            warn!("Object origin, width, and height values may be incorrect if object is skewed or rotated");
+            let objects: Vec<(usize, &Object)> = if let Some(obj_range) = args.object {
+                obj_range
+                    .clone()
+                    .zip(
+                        layer
+                            .objects
+                            .get(obj_range)
+                            .expect("Invalid object query range")
+                            .iter(),
+                    )
+                    .collect_vec()
+            } else {
+                layer.objects.iter().enumerate().collect_vec()
+            };
+
+            for (obj_idx, object) in objects {
+                let pen_idx: u32 = *object.core().pen;
+                let pen: &Pen = pens
+                    .get(pen_idx as usize)
+                    .expect("Invalid pen index in object");
+                info!(
+                    "Layer #{}, Object #{}:\n{}\nPen: #{}: {}",
+                    layer_idx, obj_idx, object, pen_idx, pen
+                );
+                if let Object::Hatch(hatch) = object {
+                    let line_spacing: f64 = *hatch
+                        .hatch_settings
+                        .iter()
+                        .find(|h| h.enabled.into())
+                        .expect("Hatch object does not have enabled settings")
+                        .line_spacing;
+                    let power: f64 = *pen.power;
+                    let speed: f64 = *pen.speed;
+                    let frequency: f64 = f64::from(*pen.frequency);
+                    let pulse: f64 = PulseWidth::try_from_primitive(*pen.pulse_width)
+                        .expect("Invalid pen pulse width")
+                        .power_ratio();
+
+                    let calc_power: u64 =
+                        ((1.0 / line_spacing) * power * (1.0 / speed) * frequency * pulse) as u64;
                     info!(
-                        "Layer #{}, Object #{}:\n{}\nPen: #{}: {}",
-                        layer_index,
-                        object_index,
-                        object,
-                        pen_index,
-                        pen
+                        "Hatch object calculated power: {}",
+                        calc_power.to_formatted_string(&Locale::en)
                     );
-                    if let Object::Hatch(hatch) = object {
-                        let line_spacing: f64 = *hatch.hatch_settings.iter().find(|h| h.enabled.into()).expect("Hatch object does not have enabled settings").line_spacing;
-                        let power: f64 = *pen.power;
-                        let speed: f64 = *pen.speed;
-                        let frequency: f64 = f64::from(*pen.frequency);
-                        let pulse: f64 = PulseWidth::try_from_primitive(*pen.pulse_width).expect("Invalid pen pulse width").power_ratio();
-
-                        let calc_power: u64 = ((1.0/line_spacing) * power * (1.0/speed) * frequency * pulse) as u64;
-                        info!("Hatch object calculated power: {}", calc_power.to_formatted_string(&Locale::en));
-                    }
                 }
-            });
+            }
+
+            // args.object.map(|obj_range| {
+
+            //     for object_index in obj_range {
+            //         let object: &Object = layer
+            //             .objects
+            //             .get(object_index)
+            //             .expect("Invalid object index");
+            //         let pen_index: u32 = *object.core().pen;
+            //         let pen: &Pen = pens.get(pen_index as usize).expect("Invalid pen index in object");
+            //         info!(
+            //             "Layer #{}, Object #{}:\n{}\nPen: #{}: {}",
+            //             layer_index,
+            //             object_index,
+            //             object,
+            //             pen_index,
+            //             pen
+            //         );
+            //         if let Object::Hatch(hatch) = object {
+            //             let line_spacing: f64 = *hatch.hatch_settings.iter().find(|h| h.enabled.into()).expect("Hatch object does not have enabled settings").line_spacing;
+            //             let power: f64 = *pen.power;
+            //             let speed: f64 = *pen.speed;
+            //             let frequency: f64 = f64::from(*pen.frequency);
+            //             let pulse: f64 = PulseWidth::try_from_primitive(*pen.pulse_width).expect("Invalid pen pulse width").power_ratio();
+
+            //             let calc_power: u64 = ((1.0/line_spacing) * power * (1.0/speed) * frequency * pulse) as u64;
+            //             info!("Hatch object calculated power: {}", calc_power.to_formatted_string(&Locale::en));
+            //         }
+            //     }
+            // });
         }
         SubCommands::Apply(args) => {
             // Process config