Skip to content

Instantly share code, notes, and snippets.

@haxtibal
Created January 27, 2019 18:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save haxtibal/799f028f0c7113422194118e7c2518d4 to your computer and use it in GitHub Desktop.
Save haxtibal/799f028f0c7113422194118e7c2518d4 to your computer and use it in GitHub Desktop.
Use crate lyon_tessellation to triangulate a 3D volume
extern crate lyon_tessellation;
#[cfg(test)]
mod tests {
use lyon_tessellation::{FillError, FillOptions, FillTessellator, FillVertex};
use lyon_tessellation::path::builder::{FlatPathBuilder,PolygonBuilder};
use lyon_tessellation::path::default::Path;
use lyon_tessellation::geometry_builder::{BuffersBuilder,VertexBuffers};
use lyon_tessellation::geom::euclid::{Point2D, Point3D};
struct Mesh3D {
positions: Vec<Point3D<f32>>,
faces: Vec<Vec<usize>>
}
impl Mesh3D {
fn get_face<'a>(&'a self, faceidx: usize) -> Face3D<'a> {
Face3D {mesh: self, faceidx: faceidx}
}
}
struct Face3D<'a> {
mesh: &'a Mesh3D,
faceidx: usize
}
impl<'a> Face3D<'a> {
fn get_point(&self, index: usize) -> Point3D<f32> {
let idx = self.mesh.faces[self.faceidx as usize][index as usize];
self.mesh.positions[idx]
}
fn get_len(&self) -> usize {
self.mesh.faces[self.faceidx].len()
}
fn to2d(&self) -> ProjectedFace<'a> {
let mut polygon2d = Vec::new();
let v0 = self.get_point(0).to_vector();
let loc_x = self.get_point(1).to_vector() - v0;
let n = loc_x.cross(self.get_point(2).to_vector() - v0);
let loc_y = n.cross(loc_x);
let x_n = loc_x.normalize();
let y_n = loc_y.normalize();
for idx in 0..self.get_len() {
let to_p = self.get_point(idx).to_vector() - v0;
polygon2d.push(Point2D::new(to_p.dot(x_n), to_p.dot(y_n)));
}
ProjectedFace {
mesh: self.mesh,
faceidx: self.faceidx,
points: polygon2d
}
}
}
struct ProjectedFace<'a> {
mesh: &'a Mesh3D,
faceidx: usize,
points: Vec<Point2D<f32>>
}
impl<'a> ProjectedFace<'a> {
fn get_mesh_idx(&self, point_index: usize) -> usize {
self.mesh.faces[self.faceidx as usize][point_index as usize]
}
fn to_path(&self) -> Path {
let mut builder = Path::builder();
builder.polygon(&self.points);
builder.build()
}
fn tesselate(&self) -> Result<Vec<usize>, FillError> {
let delta = 0.00001;
let mut tess = FillTessellator::new();
let mut outbuf: VertexBuffers<usize, u16> = VertexBuffers::new();
tess.tessellate_path(
self.to_path().path_iter(),
&FillOptions::default().with_tolerance(0.5),
&mut BuffersBuilder::new(&mut outbuf,
|vertex: FillVertex| {
let point_index_search = self.points.iter().position(
|&point| (point.x - vertex.position.x).abs() < delta &&
(point.y - vertex.position.y).abs() < delta);
match point_index_search {
Some(point_index) => self.get_mesh_idx(point_index),
None => {println!("Error: Vertex {:?} is not part of input polygon {:?}", vertex, self.points); 0}
}
}
),
)?;
Ok(outbuf.indices.iter().map(|item: &u16| {outbuf.vertices[*item as usize]}).collect())
}
}
#[test]
fn test_tessellate_3dmesh() {
let mesh = Mesh3D {
positions: vec![
Point3D::new(0., 0., 0.), Point3D::new(10., 0., 0.), Point3D::new(10., 10., 0.), Point3D::new(5., 5., 0.), Point3D::new(0., 10., 0.),
Point3D::new(0., 0., 10.), Point3D::new(10., 0., 10.), Point3D::new(10., 10., 10.), Point3D::new(5., 5., 10.), Point3D::new(0., 10., 10.)
],
faces: vec![
vec![0, 1, 2, 3, 4], // bottom face
vec![5, 6, 7, 8, 9], // top face
vec![0, 1, 6, 5], // side
vec![1, 2, 7, 6], // side
vec![2, 3, 8, 7], // side
vec![3, 4, 9, 8], // side
vec![4, 0, 5, 9], // side
]
};
assert_eq!(mesh.get_face(0).to2d().tesselate().unwrap(), [3, 0, 4, 1, 0, 3, 1, 3, 2]);
assert_eq!(mesh.get_face(1).to2d().tesselate().unwrap(), [8, 5, 9, 6, 5, 8, 6, 8, 7]);
assert_eq!(mesh.get_face(2).to2d().tesselate().unwrap(), [1, 0, 5, 1, 5, 6]);
assert_eq!(mesh.get_face(3).to2d().tesselate().unwrap(), [2, 1, 6, 2, 6, 7]);
assert_eq!(mesh.get_face(4).to2d().tesselate().unwrap(), [3, 2, 7, 3, 7, 8]);
assert_eq!(mesh.get_face(5).to2d().tesselate().unwrap(), [4, 3, 8, 4, 8, 9]);
assert_eq!(mesh.get_face(6).to2d().tesselate().unwrap(), [0, 4, 9, 0, 9, 5]);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment