Browse Source

Maybe working skew code

Kevin Lee 3 months ago
parent
commit
63787168b7
3 changed files with 135 additions and 17 deletions
  1. 8 9
      src/ezcad/objects/ellipse.rs
  2. 111 8
      src/ezcad/objects/mod.rs
  3. 16 0
      src/ezcad/types.rs

+ 8 - 9
src/ezcad/objects/ellipse.rs

@@ -2,6 +2,7 @@ use std::fmt::{Debug, Display};
 
 use binrw::{BinRead, BinWrite};
 use diff::Diff;
+use log::{debug, warn};
 
 use crate::{
     field_of::FieldOf,
@@ -28,21 +29,19 @@ pub struct Ellipse {
 
 impl Display for Ellipse {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        let width: f64 = (self.drawn_corner_a.x.max(self.drawn_corner_b.x)
-            - self.drawn_corner_a.x.min(self.drawn_corner_b.x))
-            * self.modifier.modifiers.x_scale;
-        let height: f64 = (self.drawn_corner_a.y.max(self.drawn_corner_b.y)
-            - self.drawn_corner_a.y.min(self.drawn_corner_b.y))
-            * self.modifier.modifiers.y_scale;
+        let (origin, width, height) = self
+            .modifier
+            .corrected(*self.drawn_corner_a, *self.drawn_corner_b);
 
-        let drawn_origin: Coordinate =
-            (*self.drawn_corner_a + *self.drawn_corner_b) / Coordinate { x: 2.0, y: 2.0 };
+        if format!("{}", origin) !=  format!("{}", *self.core.origin) {
+            warn!("Origin mismatch! Core: {}, Calculated: {}", *self.core.origin, origin);
+        }
 
         write!(
             f,
             "{}, Origin: {}, Width: {:.2}, Height: {:.2}, Start Radian: {:.2}, End Radian: {:.2}, Open Curve: {}", 
             self.core,
-            self.modifier.correction() + drawn_origin * self.modifier.scale(),
+            origin,
             width,
             height,
                 *self.start_angle,

+ 111 - 8
src/ezcad/objects/mod.rs

@@ -7,6 +7,8 @@ use std::{
 
 use binrw::{BinRead, BinWrite, BinWriterExt};
 use diff::Diff;
+use itertools::Itertools;
+use log::debug;
 use modular_bitfield::{
     bitfield,
     specifiers::{B1, B14},
@@ -305,10 +307,113 @@ impl ObjectModifier {
 
     pub fn skew(&self) -> Coordinate {
         Coordinate {
-            x: self.modifiers.x_skew,
-            y: self.modifiers.y_skew,
+            x: self.modifiers.y_skew.asin(), // Radians from X axis
+            y: self.modifiers.x_skew.asin(), // Radians from Y axis
         }
     }
+
+    /// Returns origin, width, and height of bounding box given two rectangular corners
+    pub fn corrected(&self, pt1: Coordinate, pt2: Coordinate) -> (Coordinate, f64, f64) {
+        debug!(
+            "Skew degree from X axis: {:.2}",
+            self.modifiers.x_skew.asin().to_degrees()
+        );
+        debug!(
+            "Skew degree from Y axis: {:.2}",
+            self.modifiers.y_skew.asin().to_degrees()
+        );
+
+        // // Calculated unskewed width and height
+        // let Coordinate {
+        //     x: width,
+        //     y: height,
+        // } = (pt1.max(pt2) - pt1.min(pt2)) * self.scale();
+
+        // debug!("Drawn point 1: {}", pt1);
+        // debug!("Drawn point 2: {}", pt2);
+
+        // Calculate all 4 points of drawn rectangle
+        let points: Vec<Coordinate> = vec![
+            Coordinate {
+                x: pt1.min(pt2).x,
+                y: pt1.min(pt2).y,
+            },
+            Coordinate {
+                x: pt1.min(pt2).x,
+                y: pt1.max(pt2).y,
+            },
+            Coordinate {
+                x: pt1.max(pt2).x,
+                y: pt1.max(pt2).y,
+            },
+            Coordinate {
+                x: pt1.max(pt2).x,
+                y: pt1.min(pt2).y,
+            },
+        ];
+
+        debug!(
+            "Drawn points: {}",
+            points
+                .iter()
+                .map(|x| format!("{x}"))
+                .collect_vec()
+                .join(", ")
+        );
+
+        // trace!("X skew asin tan: {:.3}", self.modifiers.x_skew.asin().tan());
+        // trace!("Y skew asin tan: {:.3}", self.modifiers.y_skew.asin().tan());
+
+        // let skew = |pt: Coordinate| -> Coordinate {
+        //     Coordinate {
+        //         x: pt.x + pt.y * self.modifiers.x_skew.asin().tan(),
+        //         y: pt.y + pt.x * self.modifiers.y_skew.asin().tan(),
+        //     }
+        // };
+
+        let skewed_points: Vec<Coordinate> = points
+            .iter()
+            .map(|pt| Coordinate {
+                x: pt.x + pt.y * self.modifiers.x_skew.asin().tan(),
+                y: pt.y + pt.x * self.modifiers.y_skew.asin().tan(),
+            })
+            .collect_vec();
+
+        debug!(
+            "Skewed points: {}",
+            skewed_points
+                .iter()
+                .map(|x| format!("{x}"))
+                .collect_vec()
+                .join(", ")
+        );
+
+        let min_x: f64 = skewed_points.iter().fold(f64::MAX, |acc, pt| acc.min(pt.x));
+        let max_x: f64 = skewed_points.iter().fold(f64::MIN, |acc, pt| acc.max(pt.x));
+        let min_y: f64 = skewed_points.iter().fold(f64::MAX, |acc, pt| acc.min(pt.y));
+        let max_y: f64 = skewed_points.iter().fold(f64::MIN, |acc, pt| acc.max(pt.y));
+
+        let bounding_box_pts: (Coordinate, Coordinate) = (
+            Coordinate { x: min_x, y: min_y },
+            Coordinate { x: max_x, y: max_y },
+        );
+
+        debug!(
+            "Bounding box (scaled): {}, {}",
+            bounding_box_pts.0, bounding_box_pts.1
+        );
+
+        let origin: Coordinate = self.correction()
+            + self.scale() * (bounding_box_pts.0 + bounding_box_pts.1)
+                / Coordinate::from((2.0, 2.0));
+
+        let Coordinate {
+            x: width,
+            y: height,
+        } = (bounding_box_pts.1 - bounding_box_pts.0) * self.scale();
+
+        (origin, width, height)
+    }
 }
 
 impl Default for ObjectModifier {
@@ -326,12 +431,10 @@ impl Default for ObjectModifier {
 ))]
 pub struct ScaleValues {
     pub x_scale: f64, // X scaled ratio on drawn object
-    // #[br(assert(_unknown_1 == 0.0))]
-    pub x_skew: f64,
+    pub y_skew: f64,
     #[br(assert(_unknown_2 == 0.0))]
     _unknown_2: f64,
-    // #[br(assert(_unknown_3 == 0.0))]
-    pub y_skew: f64,
+    pub x_skew: f64,
     pub y_scale: f64, // Y scaled ratio on drawn object
     #[br(assert(_unknown_4 == 0.0))]
     _unknown_4: f64,
@@ -344,9 +447,9 @@ impl Default for ScaleValues {
     fn default() -> Self {
         Self {
             x_scale: 1.0.into(),
-            x_skew: 0.0.into(),
-            _unknown_2: 0.0.into(),
             y_skew: 0.0.into(),
+            _unknown_2: 0.0.into(),
+            x_skew: 0.0.into(),
             y_scale: 1.0.into(),
             _unknown_4: 0.0.into(),
             correction: (0.0, 0.0).into(),

+ 16 - 0
src/ezcad/types.rs

@@ -212,6 +212,22 @@ impl From<(f64, f64)> for Coordinate {
     }
 }
 
+impl Coordinate {
+    pub fn min(&self, rhs: Coordinate) -> Coordinate {
+        Coordinate {
+            x: self.x.min(rhs.x),
+            y: self.y.min(rhs.y),
+        }
+    }
+
+    pub fn max(&self, rhs: Coordinate) -> Coordinate {
+        Coordinate {
+            x: self.x.max(rhs.x),
+            y: self.y.max(rhs.y),
+        }
+    }
+}
+
 #[derive(Clone, Debug, Diff, PartialEq, BinRead, BinWrite, strum::Display)]
 #[diff(attr(
     #[derive(Debug, PartialEq)]