gardesk/garcalc / 68f2023

Browse files

Adjust graph rendering behavior and formatting

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
68f20234b699d8fecde6850cadb3a6221f11af4d
Parents
acc0efc
Tree
fea30ce

4 changed files

StatusFile+-
M garcalc-geometry/src/lib.rs 22 5
M garcalc-graph/src/lib.rs 26 6
M garcalc-graph/src/plot2d.rs 114 22
M garcalc-graph/src/plot3d.rs 64 28
garcalc-geometry/src/lib.rsmodified
@@ -21,11 +21,28 @@ pub type ShapeId = u64;
2121
 #[derive(Debug, Clone, Serialize, Deserialize)]
2222
 pub enum Shape {
2323
     Point(Point2D),
24
-    Line { p1: Point2D, p2: Point2D },
25
-    Segment { p1: Point2D, p2: Point2D },
26
-    Ray { origin: Point2D, direction: Point2D },
27
-    Circle { center: Point2D, radius: f64 },
28
-    Arc { center: Point2D, radius: f64, start_angle: f64, end_angle: f64 },
24
+    Line {
25
+        p1: Point2D,
26
+        p2: Point2D,
27
+    },
28
+    Segment {
29
+        p1: Point2D,
30
+        p2: Point2D,
31
+    },
32
+    Ray {
33
+        origin: Point2D,
34
+        direction: Point2D,
35
+    },
36
+    Circle {
37
+        center: Point2D,
38
+        radius: f64,
39
+    },
40
+    Arc {
41
+        center: Point2D,
42
+        radius: f64,
43
+        start_angle: f64,
44
+        end_angle: f64,
45
+    },
2946
     Polygon(Vec<Point2D>),
3047
 }
3148
 
garcalc-graph/src/lib.rsmodified
@@ -6,8 +6,8 @@
66
 pub mod plot2d;
77
 pub mod plot3d;
88
 
9
-pub use plot2d::{Graph2D, PlotConfig, CURVE_COLORS};
10
-pub use plot3d::{Graph3D, Plot3DConfig, Camera3D, Viewport3D, Colormap, RenderMode};
9
+pub use plot2d::{CURVE_COLORS, Graph2D, PlotConfig};
10
+pub use plot3d::{Camera3D, Colormap, Graph3D, Plot3DConfig, RenderMode, Viewport3D};
1111
 
1212
 use garcalc_cas::Expr;
1313
 use serde::{Deserialize, Serialize};
@@ -22,10 +22,30 @@ pub struct Color {
2222
 }
2323
 
2424
 impl Color {
25
-    pub const RED: Self = Self { r: 255, g: 0, b: 0, a: 255 };
26
-    pub const BLUE: Self = Self { r: 0, g: 0, b: 255, a: 255 };
27
-    pub const GREEN: Self = Self { r: 0, g: 128, b: 0, a: 255 };
28
-    pub const BLACK: Self = Self { r: 0, g: 0, b: 0, a: 255 };
25
+    pub const RED: Self = Self {
26
+        r: 255,
27
+        g: 0,
28
+        b: 0,
29
+        a: 255,
30
+    };
31
+    pub const BLUE: Self = Self {
32
+        r: 0,
33
+        g: 0,
34
+        b: 255,
35
+        a: 255,
36
+    };
37
+    pub const GREEN: Self = Self {
38
+        r: 0,
39
+        g: 128,
40
+        b: 0,
41
+        a: 255,
42
+    };
43
+    pub const BLACK: Self = Self {
44
+        r: 0,
45
+        g: 0,
46
+        b: 0,
47
+        a: 255,
48
+    };
2949
 }
3050
 
3151
 /// Line style for curves
garcalc-graph/src/plot2d.rsmodified
@@ -40,10 +40,30 @@ pub struct PlotConfig {
4040
 impl Default for PlotConfig {
4141
     fn default() -> Self {
4242
         Self {
43
-            background: Color { r: 30, g: 30, b: 46, a: 255 },
44
-            axis_color: Color { r: 166, g: 173, b: 200, a: 255 },
45
-            grid_color: Color { r: 69, g: 71, b: 90, a: 255 },
46
-            label_color: Color { r: 166, g: 173, b: 200, a: 255 },
43
+            background: Color {
44
+                r: 30,
45
+                g: 30,
46
+                b: 46,
47
+                a: 255,
48
+            },
49
+            axis_color: Color {
50
+                r: 166,
51
+                g: 173,
52
+                b: 200,
53
+                a: 255,
54
+            },
55
+            grid_color: Color {
56
+                r: 69,
57
+                g: 71,
58
+                b: 90,
59
+                a: 255,
60
+            },
61
+            label_color: Color {
62
+                r: 166,
63
+                g: 173,
64
+                b: 200,
65
+                a: 255,
66
+            },
4767
             show_grid: true,
4868
             show_labels: true,
4969
             curve_width: 2.0,
@@ -56,12 +76,42 @@ impl Default for PlotConfig {
5676
 
5777
 /// Default curve colors (catppuccin palette)
5878
 pub const CURVE_COLORS: [Color; 6] = [
59
-    Color { r: 137, g: 180, b: 250, a: 255 }, // blue
60
-    Color { r: 166, g: 227, b: 161, a: 255 }, // green
61
-    Color { r: 249, g: 226, b: 175, a: 255 }, // yellow
62
-    Color { r: 243, g: 139, b: 168, a: 255 }, // red
63
-    Color { r: 203, g: 166, b: 247, a: 255 }, // mauve
64
-    Color { r: 148, g: 226, b: 213, a: 255 }, // teal
79
+    Color {
80
+        r: 137,
81
+        g: 180,
82
+        b: 250,
83
+        a: 255,
84
+    }, // blue
85
+    Color {
86
+        r: 166,
87
+        g: 227,
88
+        b: 161,
89
+        a: 255,
90
+    }, // green
91
+    Color {
92
+        r: 249,
93
+        g: 226,
94
+        b: 175,
95
+        a: 255,
96
+    }, // yellow
97
+    Color {
98
+        r: 243,
99
+        g: 139,
100
+        b: 168,
101
+        a: 255,
102
+    }, // red
103
+    Color {
104
+        r: 203,
105
+        g: 166,
106
+        b: 247,
107
+        a: 255,
108
+    }, // mauve
109
+    Color {
110
+        r: 148,
111
+        g: 226,
112
+        b: 213,
113
+        a: 255,
114
+    }, // teal
65115
 ];
66116
 
67117
 /// 2D graph state and renderer
@@ -351,13 +401,29 @@ impl Graph2D {
351401
 
352402
     fn draw_function(&self, ctx: &Context, func: &Plottable, width: u32, height: u32) {
353403
         match func {
354
-            Plottable::Explicit2D { expr, x_var, color, style } => {
404
+            Plottable::Explicit2D {
405
+                expr,
406
+                x_var,
407
+                color,
408
+                style,
409
+            } => {
355410
                 self.draw_explicit(ctx, expr, x_var, *color, *style, width, height);
356411
             }
357
-            Plottable::Implicit2D { expr, x_var, y_var, color } => {
412
+            Plottable::Implicit2D {
413
+                expr,
414
+                x_var,
415
+                y_var,
416
+                color,
417
+            } => {
358418
                 self.draw_implicit(ctx, expr, x_var, y_var, *color, width, height);
359419
             }
360
-            Plottable::Parametric2D { x_expr, y_expr, t_var, t_range, color } => {
420
+            Plottable::Parametric2D {
421
+                x_expr,
422
+                y_expr,
423
+                t_var,
424
+                t_range,
425
+                color,
426
+            } => {
361427
                 self.draw_parametric(ctx, x_expr, y_expr, t_var, *t_range, *color, width, height);
362428
             }
363429
             _ => {}
@@ -400,7 +466,8 @@ impl Graph2D {
400466
 
401467
             if let Ok(result) = evaluator.eval(expr) {
402468
                 if let Ok(math_y) = expr_to_f64(&result) {
403
-                    if math_y.is_finite() && math_y >= self.viewport.y_min - x_range
469
+                    if math_y.is_finite()
470
+                        && math_y >= self.viewport.y_min - x_range
404471
                         && math_y <= self.viewport.y_max + x_range
405472
                     {
406473
                         let (sx, sy) = self.math_to_screen(math_x, math_y, width, height);
@@ -543,18 +610,35 @@ impl Graph2D {
543610
                 let s11 = v11 >= 0.0;
544611
 
545612
                 // Build case index (4-bit)
546
-                let case = (s00 as u8) | ((s10 as u8) << 1) | ((s01 as u8) << 2) | ((s11 as u8) << 3);
613
+                let case =
614
+                    (s00 as u8) | ((s10 as u8) << 1) | ((s01 as u8) << 2) | ((s11 as u8) << 3);
547615
 
548616
                 // Linear interpolation to find zero crossing on an edge
549617
                 let interp = |va: f64, vb: f64| -> f64 {
550
-                    if (va - vb).abs() < 1e-15 { 0.5 } else { va / (va - vb) }
618
+                    if (va - vb).abs() < 1e-15 {
619
+                        0.5
620
+                    } else {
621
+                        va / (va - vb)
622
+                    }
551623
                 };
552624
 
553625
                 // Edge midpoints where contour crosses
554
-                let e_bottom = || { let t = interp(v00, v10); (x0 + t * dx, y0) };
555
-                let e_top = || { let t = interp(v01, v11); (x0 + t * dx, y1) };
556
-                let e_left = || { let t = interp(v00, v01); (x0, y0 + t * dy) };
557
-                let e_right = || { let t = interp(v10, v11); (x1, y0 + t * dy) };
626
+                let e_bottom = || {
627
+                    let t = interp(v00, v10);
628
+                    (x0 + t * dx, y0)
629
+                };
630
+                let e_top = || {
631
+                    let t = interp(v01, v11);
632
+                    (x0 + t * dx, y1)
633
+                };
634
+                let e_left = || {
635
+                    let t = interp(v00, v01);
636
+                    (x0, y0 + t * dy)
637
+                };
638
+                let e_right = || {
639
+                    let t = interp(v10, v11);
640
+                    (x1, y0 + t * dy)
641
+                };
558642
 
559643
                 // Draw line segments based on marching squares case
560644
                 let draw_line = |p1: (f64, f64), p2: (f64, f64)| {
@@ -603,7 +687,15 @@ impl Graph2D {
603687
         ctx.set_dash(&[], 0.0);
604688
 
605689
         // Coordinate display
606
-        set_color(ctx, Color { r: 30, g: 30, b: 46, a: 200 });
690
+        set_color(
691
+            ctx,
692
+            Color {
693
+                r: 30,
694
+                g: 30,
695
+                b: 46,
696
+                a: 200,
697
+            },
698
+        );
607699
         let label = format!("({:.4}, {:.4})", mx, my);
608700
         let label_w = label.len() as f64 * 7.0 + 8.0;
609701
         let label_h = 18.0;
@@ -637,7 +729,7 @@ fn nice_step(rough: f64) -> f64 {
637729
 
638730
     let nice = if frac < 1.5 {
639731
         1.0
640
-    } else if frac < 3.0 {
732
+    } else if frac <= 3.0 {
641733
         2.0
642734
     } else if frac < 7.0 {
643735
         5.0
garcalc-graph/src/plot3d.rsmodified
@@ -40,8 +40,8 @@ impl Camera3D {
4040
     /// Rotate the camera by delta angles
4141
     pub fn rotate(&mut self, d_azimuth: f64, d_elevation: f64) {
4242
         self.azimuth += d_azimuth;
43
-        self.elevation = (self.elevation + d_elevation)
44
-            .clamp(-89.0_f64.to_radians(), 89.0_f64.to_radians());
43
+        self.elevation =
44
+            (self.elevation + d_elevation).clamp(-89.0_f64.to_radians(), 89.0_f64.to_radians());
4545
     }
4646
 
4747
     /// Zoom by a factor
@@ -107,7 +107,12 @@ impl Colormap {
107107
             Colormap::Coolwarm => coolwarm(t),
108108
             Colormap::Grayscale => {
109109
                 let v = (t * 255.0) as u8;
110
-                Color { r: v, g: v, b: v, a: 255 }
110
+                Color {
111
+                    r: v,
112
+                    g: v,
113
+                    b: v,
114
+                    a: 255,
115
+                }
111116
             }
112117
         }
113118
     }
@@ -158,9 +163,24 @@ pub struct Plot3DConfig {
158163
 impl Default for Plot3DConfig {
159164
     fn default() -> Self {
160165
         Self {
161
-            background: Color { r: 30, g: 30, b: 46, a: 255 },
162
-            axis_color: Color { r: 166, g: 173, b: 200, a: 255 },
163
-            wireframe_color: Color { r: 100, g: 100, b: 120, a: 255 },
166
+            background: Color {
167
+                r: 30,
168
+                g: 30,
169
+                b: 46,
170
+                a: 255,
171
+            },
172
+            axis_color: Color {
173
+                r: 166,
174
+                g: 173,
175
+                b: 200,
176
+                a: 255,
177
+            },
178
+            wireframe_color: Color {
179
+                r: 100,
180
+                g: 100,
181
+                b: 120,
182
+                a: 255,
183
+            },
164184
             colormap: Colormap::Viridis,
165185
             render_mode: RenderMode::FilledWithWireframe,
166186
             grid_lines: 40,
@@ -256,7 +276,11 @@ impl Graph3D {
256276
             forward.0 * world_up.1 - forward.1 * world_up.0,
257277
         );
258278
         let right_len = (right.0 * right.0 + right.1 * right.1 + right.2 * right.2).sqrt();
259
-        let right = (right.0 / right_len, right.1 / right_len, right.2 / right_len);
279
+        let right = (
280
+            right.0 / right_len,
281
+            right.1 / right_len,
282
+            right.2 / right_len,
283
+        );
260284
 
261285
         // Actual up = right x forward
262286
         let up = (
@@ -361,9 +385,17 @@ impl Graph3D {
361385
             Surface3D::Explicit { expr, x_var, y_var } => {
362386
                 self.draw_explicit_surface(ctx, expr, x_var, y_var, width, height);
363387
             }
364
-            Surface3D::Parametric { x_expr, y_expr, z_expr, u_var, v_var, u_range, v_range } => {
388
+            Surface3D::Parametric {
389
+                x_expr,
390
+                y_expr,
391
+                z_expr,
392
+                u_var,
393
+                v_var,
394
+                u_range,
395
+                v_range,
396
+            } => {
365397
                 self.draw_parametric_surface(
366
-                    ctx, x_expr, y_expr, z_expr, u_var, v_var, *u_range, *v_range, width, height
398
+                    ctx, x_expr, y_expr, z_expr, u_var, v_var, *u_range, *v_range, width, height,
367399
                 );
368400
             }
369401
         }
@@ -446,8 +478,8 @@ impl Graph3D {
446478
                     let cy = (p00.1 + p10.1 + p11.1 + p01.1) / 4.0;
447479
                     let cz = (p00.2 + p10.2 + p11.2 + p01.2) / 4.0;
448480
                     let depth = (cx - cam_pos.0).powi(2)
449
-                              + (cy - cam_pos.1).powi(2)
450
-                              + (cz - cam_pos.2).powi(2);
481
+                        + (cy - cam_pos.1).powi(2)
482
+                        + (cz - cam_pos.2).powi(2);
451483
 
452484
                     quads.push(Quad {
453485
                         corners: [p00, p10, p11, p01],
@@ -459,11 +491,16 @@ impl Graph3D {
459491
         }
460492
 
461493
         // Sort by depth (painter's algorithm - far to near)
462
-        quads.sort_by(|a, b| b.depth.partial_cmp(&a.depth).unwrap_or(std::cmp::Ordering::Equal));
494
+        quads.sort_by(|a, b| {
495
+            b.depth
496
+                .partial_cmp(&a.depth)
497
+                .unwrap_or(std::cmp::Ordering::Equal)
498
+        });
463499
 
464500
         // Draw quads
465501
         for quad in &quads {
466
-            let corners: Vec<(f64, f64)> = quad.corners
502
+            let corners: Vec<(f64, f64)> = quad
503
+                .corners
467504
                 .iter()
468505
                 .map(|p| self.project(p.0, p.1, p.2, width, height))
469506
                 .collect();
@@ -532,7 +569,9 @@ impl Graph3D {
532569
                 let z_result = evaluator.eval(z_expr);
533570
 
534571
                 if let (Ok(xr), Ok(yr), Ok(zr)) = (x_result, y_result, z_result) {
535
-                    if let (Ok(x), Ok(y), Ok(z)) = (expr_to_f64(&xr), expr_to_f64(&yr), expr_to_f64(&zr)) {
572
+                    if let (Ok(x), Ok(y), Ok(z)) =
573
+                        (expr_to_f64(&xr), expr_to_f64(&yr), expr_to_f64(&zr))
574
+                    {
536575
                         if x.is_finite() && y.is_finite() && z.is_finite() {
537576
                             z_min = z_min.min(z);
538577
                             z_max = z_max.max(z);
@@ -574,8 +613,8 @@ impl Graph3D {
574613
                     let cy = (p00.1 + p10.1 + p11.1 + p01.1) / 4.0;
575614
                     let cz = (p00.2 + p10.2 + p11.2 + p01.2) / 4.0;
576615
                     let depth = (cx - cam_pos.0).powi(2)
577
-                              + (cy - cam_pos.1).powi(2)
578
-                              + (cz - cam_pos.2).powi(2);
616
+                        + (cy - cam_pos.1).powi(2)
617
+                        + (cz - cam_pos.2).powi(2);
579618
 
580619
                     quads.push(Quad {
581620
                         corners: [p00, p10, p11, p01],
@@ -586,10 +625,15 @@ impl Graph3D {
586625
             }
587626
         }
588627
 
589
-        quads.sort_by(|a, b| b.depth.partial_cmp(&a.depth).unwrap_or(std::cmp::Ordering::Equal));
628
+        quads.sort_by(|a, b| {
629
+            b.depth
630
+                .partial_cmp(&a.depth)
631
+                .unwrap_or(std::cmp::Ordering::Equal)
632
+        });
590633
 
591634
         for quad in &quads {
592
-            let corners: Vec<(f64, f64)> = quad.corners
635
+            let corners: Vec<(f64, f64)> = quad
636
+                .corners
593637
                 .iter()
594638
                 .map(|p| self.project(p.0, p.1, p.2, width, height))
595639
                 .collect();
@@ -675,21 +719,13 @@ fn plasma(t: f64) -> Color {
675719
 
676720
 fn coolwarm(t: f64) -> Color {
677721
     // Blue (cool) to red (warm)
678
-    let r = if t < 0.5 {
679
-        0.2 + t * 1.6
680
-    } else {
681
-        1.0
682
-    };
722
+    let r = if t < 0.5 { 0.2 + t * 1.6 } else { 1.0 };
683723
     let g = if t < 0.5 {
684724
         0.2 + t * 1.2
685725
     } else {
686726
         0.8 - (t - 0.5) * 1.6
687727
     };
688
-    let b = if t < 0.5 {
689
-        1.0
690
-    } else {
691
-        1.0 - (t - 0.5) * 1.6
692
-    };
728
+    let b = if t < 0.5 { 1.0 } else { 1.0 - (t - 0.5) * 1.6 };
693729
     Color {
694730
         r: (r.clamp(0.0, 1.0) * 255.0) as u8,
695731
         g: (g.clamp(0.0, 1.0) * 255.0) as u8,