@@ -40,8 +40,8 @@ impl Camera3D { |
| 40 | 40 | /// Rotate the camera by delta angles |
| 41 | 41 | pub fn rotate(&mut self, d_azimuth: f64, d_elevation: f64) { |
| 42 | 42 | 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()); |
| 45 | 45 | } |
| 46 | 46 | |
| 47 | 47 | /// Zoom by a factor |
@@ -107,7 +107,12 @@ impl Colormap { |
| 107 | 107 | Colormap::Coolwarm => coolwarm(t), |
| 108 | 108 | Colormap::Grayscale => { |
| 109 | 109 | 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 | + } |
| 111 | 116 | } |
| 112 | 117 | } |
| 113 | 118 | } |
@@ -158,9 +163,24 @@ pub struct Plot3DConfig { |
| 158 | 163 | impl Default for Plot3DConfig { |
| 159 | 164 | fn default() -> Self { |
| 160 | 165 | 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 | + }, |
| 164 | 184 | colormap: Colormap::Viridis, |
| 165 | 185 | render_mode: RenderMode::FilledWithWireframe, |
| 166 | 186 | grid_lines: 40, |
@@ -256,7 +276,11 @@ impl Graph3D { |
| 256 | 276 | forward.0 * world_up.1 - forward.1 * world_up.0, |
| 257 | 277 | ); |
| 258 | 278 | 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 | + ); |
| 260 | 284 | |
| 261 | 285 | // Actual up = right x forward |
| 262 | 286 | let up = ( |
@@ -361,9 +385,17 @@ impl Graph3D { |
| 361 | 385 | Surface3D::Explicit { expr, x_var, y_var } => { |
| 362 | 386 | self.draw_explicit_surface(ctx, expr, x_var, y_var, width, height); |
| 363 | 387 | } |
| 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 | + } => { |
| 365 | 397 | 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, |
| 367 | 399 | ); |
| 368 | 400 | } |
| 369 | 401 | } |
@@ -446,8 +478,8 @@ impl Graph3D { |
| 446 | 478 | let cy = (p00.1 + p10.1 + p11.1 + p01.1) / 4.0; |
| 447 | 479 | let cz = (p00.2 + p10.2 + p11.2 + p01.2) / 4.0; |
| 448 | 480 | 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); |
| 451 | 483 | |
| 452 | 484 | quads.push(Quad { |
| 453 | 485 | corners: [p00, p10, p11, p01], |
@@ -459,11 +491,16 @@ impl Graph3D { |
| 459 | 491 | } |
| 460 | 492 | |
| 461 | 493 | // 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 | + }); |
| 463 | 499 | |
| 464 | 500 | // Draw quads |
| 465 | 501 | for quad in &quads { |
| 466 | | - let corners: Vec<(f64, f64)> = quad.corners |
| 502 | + let corners: Vec<(f64, f64)> = quad |
| 503 | + .corners |
| 467 | 504 | .iter() |
| 468 | 505 | .map(|p| self.project(p.0, p.1, p.2, width, height)) |
| 469 | 506 | .collect(); |
@@ -532,7 +569,9 @@ impl Graph3D { |
| 532 | 569 | let z_result = evaluator.eval(z_expr); |
| 533 | 570 | |
| 534 | 571 | 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 | + { |
| 536 | 575 | if x.is_finite() && y.is_finite() && z.is_finite() { |
| 537 | 576 | z_min = z_min.min(z); |
| 538 | 577 | z_max = z_max.max(z); |
@@ -574,8 +613,8 @@ impl Graph3D { |
| 574 | 613 | let cy = (p00.1 + p10.1 + p11.1 + p01.1) / 4.0; |
| 575 | 614 | let cz = (p00.2 + p10.2 + p11.2 + p01.2) / 4.0; |
| 576 | 615 | 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); |
| 579 | 618 | |
| 580 | 619 | quads.push(Quad { |
| 581 | 620 | corners: [p00, p10, p11, p01], |
@@ -586,10 +625,15 @@ impl Graph3D { |
| 586 | 625 | } |
| 587 | 626 | } |
| 588 | 627 | |
| 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 | + }); |
| 590 | 633 | |
| 591 | 634 | for quad in &quads { |
| 592 | | - let corners: Vec<(f64, f64)> = quad.corners |
| 635 | + let corners: Vec<(f64, f64)> = quad |
| 636 | + .corners |
| 593 | 637 | .iter() |
| 594 | 638 | .map(|p| self.project(p.0, p.1, p.2, width, height)) |
| 595 | 639 | .collect(); |
@@ -675,21 +719,13 @@ fn plasma(t: f64) -> Color { |
| 675 | 719 | |
| 676 | 720 | fn coolwarm(t: f64) -> Color { |
| 677 | 721 | // 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 }; |
| 683 | 723 | let g = if t < 0.5 { |
| 684 | 724 | 0.2 + t * 1.2 |
| 685 | 725 | } else { |
| 686 | 726 | 0.8 - (t - 0.5) * 1.6 |
| 687 | 727 | }; |
| 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 }; |
| 693 | 729 | Color { |
| 694 | 730 | r: (r.clamp(0.0, 1.0) * 255.0) as u8, |
| 695 | 731 | g: (g.clamp(0.0, 1.0) * 255.0) as u8, |