Skip to content

Commit

Permalink
Convert z_slice to generalized slice
Browse files Browse the repository at this point in the history
  • Loading branch information
lbirkert committed Aug 8, 2023
1 parent 67588b8 commit d0df880
Show file tree
Hide file tree
Showing 17 changed files with 144 additions and 70 deletions.
1 change: 1 addition & 0 deletions src/core/axis.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use nalgebra::{UnitVector3, Vector3};

#[derive(Debug)]
pub enum Axis {
X,
Y,
Expand Down
43 changes: 43 additions & 0 deletions src/core/line.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use nalgebra::Vector3;

use super::Plane;

#[derive(Debug)]
pub struct Line {
pub a: Vector3<f32>,
pub b: Vector3<f32>,
}

impl Line {
pub fn new(a: Vector3<f32>, b: Vector3<f32>) -> Self {
Self { a, b }
}

/// Returns the intersection of this line with a plane (if any).
pub fn intersect_plane(&self, plane: &Plane) -> Option<Vector3<f32>> {
Self::intersect_plane_raw(&self.a, &self.b, plane)
}

/// Returns the intersection of a line with start and endpoints on a plane (if any).
pub fn intersect_plane_raw(
a: &Vector3<f32>,
b: &Vector3<f32>,
plane: &Plane,
) -> Option<Vector3<f32>> {
let s = (a - b).dot(&plane.normal);

// => line and plane parallel
if s == 0.0 {
return None;
}

let t = (plane.origin - b).dot(&plane.normal) / s;

// => point not on line
if !(0.0..1.0).contains(&t) {
return None;
}

Some(b.lerp(a, t))
}
}
53 changes: 21 additions & 32 deletions src/core/mesh.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use std::io::Cursor;

use nalgebra::{Matrix4, UnitVector3, Vector2, Vector3};
use nalgebra::{Matrix4, UnitVector3, Vector3};

use super::{Path2, Ray, Triangle};
use crate::core::Line;

#[derive(Clone)]
use super::{Path3, Plane, Ray, Triangle};

#[derive(Debug, Clone)]
pub struct Mesh {
pub triangles: Vec<Triangle>,
}
Expand Down Expand Up @@ -44,39 +46,26 @@ impl Mesh {
intersection_point
}

/// Z-Slice a model. Creates a path representing the outline of this Mesh at this z height.
pub fn z_slice(&self, z: f32) -> Vec<Path2> {
Self::z_slice_raw(&self.triangles, z)
/// Slice a model using a plane. This returns the outline of the cross section.
pub fn slice(&self, plane: Plane) -> Vec<Path3> {
Self::slice_raw(&self.triangles, plane)
}

/// TODO: Rewrite
/// Z-Slice a model. Creates a path representing the outline of this Mesh at this z height.
pub fn z_slice_raw(triangles: &[Triangle], z: f32) -> Vec<Path2> {
/// Slice a model using a plane. This returns the outline of the cross section.
pub fn slice_raw(triangles: &[Triangle], plane: Plane) -> Vec<Path3> {
// Used for connecting the polygons properly
let mut points: Vec<Vector2<f32>> = Vec::new();
let mut points: Vec<Vector3<f32>> = Vec::new();
let mut indicies: Vec<Vec<usize>> = Vec::new();

for triangle in triangles.iter() {
let a = triangle.a;
let b = triangle.b;
let c = triangle.c;
let pa = if (a.z > z) != (b.z > z) {
Some(a.xy().lerp(&b.xy(), 1.0 - (z - b.z) / (a.z - b.z)))
} else {
None
};
let pb = if (b.z > z) != (c.z > z) {
Some(b.xy().lerp(&c.xy(), 1.0 - (z - c.z) / (b.z - c.z)))
} else {
None
};
let pc = if (c.z > z) != (a.z > z) {
Some(c.xy().lerp(&a.xy(), 1.0 - (z - a.z) / (c.z - a.z)))
} else {
None
};
let pa = Line::intersect_plane_raw(&a, &b, &plane);
let pb = Line::intersect_plane_raw(&b, &c, &plane);
let pc = Line::intersect_plane_raw(&c, &a, &plane);

let segment = match (pa, pb, pc) {
let seg = match (pa, pb, pc) {
(Some(pa), Some(pb), _) => (pa, pb),
(_, Some(pb), Some(pc)) => (pb, pc),
(Some(pa), _, Some(pc)) => (pc, pa),
Expand All @@ -86,15 +75,15 @@ impl Mesh {
const EPSILON: f32 = 1e-9;

// Skip 'zero' length segments
if (segment.0 - segment.1).magnitude_squared() < EPSILON {
if (seg.0 - seg.1).magnitude_squared() < EPSILON {
continue;
}

let delta = Vector3::z_axis().cross(&triangle.normal).xy();
let (a, b) = if (segment.1 - segment.0).dot(&delta) > 0.0 {
(segment.0, segment.1)
let delta = plane.normal.cross(&triangle.normal);
let (a, b) = if (seg.1 - seg.0).dot(&delta) > 0.0 {
(seg.0, seg.1)
} else {
(segment.1, segment.0)
(seg.1, seg.0)
};

let mut ai = None;
Expand Down Expand Up @@ -138,7 +127,7 @@ impl Mesh {
let mut pointer = 0;
loop {
if indicies[pointer].is_empty() {
paths.push(Path2::new(path));
paths.push(Path3::new_sanitize(path));

let mut found = None;
for (i, index) in indicies.iter().enumerate() {
Expand Down
2 changes: 2 additions & 0 deletions src/core/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod axis;
pub mod line;
pub mod mesh;
pub mod path;
pub mod plane;
Expand All @@ -9,6 +10,7 @@ pub mod square;
pub mod triangle;

pub use axis::Axis;
pub use line::Line;
pub use mesh::Mesh;
pub use path::Path2;
pub use path::Path3;
Expand Down
38 changes: 36 additions & 2 deletions src/core/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@ use nalgebra::{UnitVector2, UnitVector3, Vector2, Vector3};

use super::sdf;

#[derive(Debug)]
pub struct Path2 {
points: Vec<Vector2<f32>>,
}

impl Path2 {
/// Creates a new sanitized path instance.
pub fn new(points: Vec<Vector2<f32>>) -> Self {
let mut path = Self { points };
Self { points }
}

/// Creates a new sanitized 2D path
pub fn new_sanitize(points: Vec<Vector2<f32>>) -> Self {
let mut path = Self::new(points);
path.sanitize();
path
}
Expand Down Expand Up @@ -122,6 +127,7 @@ impl Path2 {
}
}

#[derive(Debug)]
pub struct Path3 {
pub points: Vec<Vector3<f32>>,
}
Expand All @@ -130,4 +136,32 @@ impl Path3 {
pub fn new(points: Vec<Vector3<f32>>) -> Self {
Self { points }
}

/// Creates a new sanitized 3D path
pub fn new_sanitize(points: Vec<Vector3<f32>>) -> Self {
let mut path = Self::new(points);
path.sanitize();
path
}

/// Sanitize this path. This will delete all points whose left and right edge have the
/// same normal vector rounded to EPSILON (~ 1e-3)
pub fn sanitize(&mut self) {
let mut i = 0;
while i < self.points.len() {
let len = self.points.len();

let a = &self.points[if i > 0 { i } else { len } - 1];
let b = &self.points[i];
let c = &self.points[(i + 1) % len];

const EPSILON: f32 = 1e-3;

if ((a - b).normalize() - (b - c).normalize()).magnitude_squared() < EPSILON {
self.points.remove(i);
} else {
i += 1;
}
}
}
}
1 change: 1 addition & 0 deletions src/core/plane.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use nalgebra::{UnitVector3, Vector3};

use super::ray::Ray;

#[derive(Debug)]
pub struct Plane {
pub origin: Vector3<f32>,
pub normal: UnitVector3<f32>,
Expand Down
1 change: 1 addition & 0 deletions src/core/ray.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use nalgebra::{UnitVector3, Vector3};

use super::plane::Plane;

#[derive(Debug)]
pub struct Ray {
pub normal: Vector3<f32>,
pub origin: Vector3<f32>,
Expand Down
1 change: 1 addition & 0 deletions src/core/sdf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use nalgebra::Vector2;
use super::Path2;

// Is the contour of a SDF (sign distance field) of some object at a certain distance.
#[derive(Debug)]
pub struct Contour {
segments: Vec<Segment>,
distance: f32,
Expand Down
1 change: 1 addition & 0 deletions src/core/sphere.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use nalgebra::Vector3;

#[derive(Debug)]
pub struct Sphere {
pub origin: Vector3<f32>,
pub radius: f32,
Expand Down
1 change: 1 addition & 0 deletions src/core/square.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use nalgebra::{UnitVector3, Vector3};

use super::{plane::Plane, ray::Ray};

#[derive(Debug)]
pub struct Square {
pub a: Vector3<f32>,
pub ab: Vector3<f32>,
Expand Down
2 changes: 1 addition & 1 deletion src/core/triangle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use nalgebra::{UnitVector3, Vector3};

use super::{plane::Plane, ray::Ray};

#[derive(Clone)]
#[derive(Debug, Clone)]
pub struct Triangle {
pub a: Vector3<f32>,
pub b: Vector3<f32>,
Expand Down
16 changes: 5 additions & 11 deletions src/editor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,18 +276,12 @@ impl Editor {
);
}

for points in object.mesh.z_slice(self.z_slice).iter() {
let slice_plane = Plane::new(Vector3::new(0.0, 0.0, self.z_slice), Vector3::z_axis());

for path in object.mesh.slice(slice_plane).iter() {
renderer::path::generate_closed(
&points
.sdf_contour(self.factor)
.path()
.extend3(
&Vector3::new(0.0, 0.0, self.z_slice),
&Vector3::x_axis(),
&Vector3::y_axis(),
)
.points,
[1.0, 0.0, 1.0],
&path.points,
[1.0, 0.0, 1.0, 1.0],
0.01,
&mut path_verticies,
&mut path_indicies,
Expand Down
18 changes: 12 additions & 6 deletions src/editor/tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,20 @@ impl Tool {
path_indicies: &mut Vec<renderer::path::Index>,
entity_verticies: &mut Vec<renderer::entity::Vertex>,
) {
let mut xcolor = [1.0, 0.0, 0.0];
let mut ycolor = [0.0, 1.0, 0.0];
let mut zcolor = [0.0, 0.0, 1.0];
let mut xcolor = [1.0, 0.0, 0.0, 1.0];
let mut ycolor = [0.0, 1.0, 0.0, 1.0];
let mut zcolor = [0.0, 0.0, 1.0, 1.0];
if let Some(action) = action {
match action {
Action::Hover(Axis::X) | Action::Transform(Axis::X) => xcolor = [1.0, 0.6, 0.6],
Action::Hover(Axis::Y) | Action::Transform(Axis::Y) => ycolor = [0.6, 1.0, 0.6],
Action::Hover(Axis::Z) | Action::Transform(Axis::Z) => zcolor = [0.6, 0.6, 1.0],
Action::Hover(Axis::X) | Action::Transform(Axis::X) => {
xcolor = [1.0, 0.6, 0.6, 1.0]
}
Action::Hover(Axis::Y) | Action::Transform(Axis::Y) => {
ycolor = [0.6, 1.0, 0.6, 1.0]
}
Action::Hover(Axis::Z) | Action::Transform(Axis::Z) => {
zcolor = [0.6, 0.6, 1.0, 1.0]
}
};
}

Expand Down
8 changes: 4 additions & 4 deletions src/renderer/entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub const VERTEX_BUFFER_LAYOUT: wgpu::VertexBufferLayout<'static> = wgpu::Vertex
},
// Normal vector
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x3,
format: wgpu::VertexFormat::Float32x4,
offset: 4 * 3,
shader_location: 1,
},
Expand All @@ -26,15 +26,15 @@ pub const VERTEX_BUFFER_LAYOUT: wgpu::VertexBufferLayout<'static> = wgpu::Vertex
#[derive(Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)]
pub struct Vertex {
pos: [f32; 3],
color: [f32; 3],
color: [f32; 4],
}

/// Generates a cube entity
#[rustfmt::skip]
pub fn generate_cube(
scale: f32,
origin: &Vector3<f32>,
color: [f32; 3],
color: [f32; 4],
verticies: &mut Vec<Vertex>,
) {
let a = Vector3::new(scale * 0.5, scale * 0.5, scale * 0.5);
Expand Down Expand Up @@ -91,7 +91,7 @@ pub fn generate_arrow(
scale: f32,
origin: &Vector3<f32>,
direction: &UnitVector3<f32>,
color: [f32; 3],
color: [f32; 4],
verticies: &mut Vec<Vertex>,
) {
let mut na = direction.cross(&Vector3::new(-direction.z, direction.x, direction.y));
Expand Down
Loading

0 comments on commit d0df880

Please sign in to comment.