Skip to content

Commit

Permalink
WIP Make more of sweep operation triangle-less
Browse files Browse the repository at this point in the history
Generate b-rep geometry for the side faces of a sweep, when sweeping
non-continuous edges. Continuous edges are still handled using the old
code, for the reasons explained in the comment this commit adds.
  • Loading branch information
hannobraun committed Feb 24, 2022
1 parent 8623787 commit 6d1f8cf
Showing 1 changed file with 112 additions and 28 deletions.
140 changes: 112 additions & 28 deletions src/kernel/shapes/sweep.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::f64::consts::PI;
use std::{collections::HashMap, f64::consts::PI};

use nalgebra::vector;
use parry3d_f64::math::Isometry;
Expand All @@ -7,14 +7,15 @@ use crate::{
debug::DebugInfo,
kernel::{
approximation::Approximation,
geometry::{surfaces::Swept, Curve, Line, Surface},
topology::{
edges::Edges,
edges::{self, Edge, Edges},
faces::{Face, Faces},
vertices::Vertices,
vertices::{Vertex, Vertices},
},
Shape,
},
math::{Aabb, Scalar, Transform},
math::{Aabb, Scalar, Transform, Vector},
};

impl Shape for fj::Sweep {
Expand All @@ -25,6 +26,8 @@ impl Shape for fj::Sweep {
}

fn faces(&self, tolerance: Scalar, debug_info: &mut DebugInfo) -> Faces {
let path = Vector::from([0., 0., self.length]);

let rotation = Isometry::rotation(vector![PI, 0., 0.]).into();
let translation = Isometry::translation(0.0, 0.0, self.length).into();

Expand All @@ -44,31 +47,112 @@ impl Shape for fj::Sweep {
}

for cycle in self.shape.edges().cycles {
let approx = Approximation::for_cycle(&cycle, tolerance);

// This will only work correctly, if the cycle consists of one edge.
// If there are more, this will create some kind of weird face
// chimera, a single face to represent all the side faces.

let mut quads = Vec::new();
for segment in approx.segments {
let [v0, v1] = segment.points();
let [v3, v2] = {
let segment = Transform::translation(0., 0., self.length)
.transform_segment(&segment);
segment.points()
};

quads.push([v0, v1, v2, v3]);
}

let mut side_face = Vec::new();
for [v0, v1, v2, v3] in quads {
side_face.push([v0, v1, v2].into());
side_face.push([v0, v2, v3].into());
if cycle.edges.len() == 1 {
// If there's only one edge, it must be a continuous edge that
// connects to itself. By sweeping that, we create a continuous
// face.
//
// Continuous faces aren't currently supported by the
// approximation code, and hence can't be triangulated. To
// address that, we fall back to the old and almost obsolete
// triangle representation to create the face.
//
// This is the last piece of code that still uses the triangle
// representation.

let approx = Approximation::for_cycle(&cycle, tolerance);

let mut quads = Vec::new();
for segment in approx.segments {
let [v0, v1] = segment.points();
let [v3, v2] = {
let segment =
Transform::translation(0., 0., self.length)
.transform_segment(&segment);
segment.points()
};

quads.push([v0, v1, v2, v3]);
}

let mut side_face = Vec::new();
for [v0, v1, v2, v3] in quads {
side_face.push([v0, v1, v2].into());
side_face.push([v0, v2, v3].into());
}

side_faces.push(Face::Triangles(side_face));
} else {
// If there's no continuous edge, we can create the non-
// continuous faces using boundary representation.

let mut side_edges = HashMap::new();

for bottom_edge in cycle.edges {
let top_edge = bottom_edge.clone().transform(&translation);

let surface = Surface::Swept(Swept {
curve: bottom_edge.curve.clone(),
path,
});

let side_edges = bottom_edge.vertices.map(|vertices| {
vertices.map(|vertex| {
let edge =
side_edges.entry(vertex).or_insert_with(|| {
let line = Line {
origin: *vertex
.to_canonical()
.location(),
direction: path,
};

let a = vertex;
// TASK: This is wrong. The vertex created
// here already exists in `top_edges`.
let b = Vertex::create_at(
line.origin + line.direction,
);

let curve = Curve::Line(line);

let vertices = Some([a.to_canonical(), b]);

Edge::new(curve, vertices)
});

edge.clone()
})
});

let face = match side_edges {
Some([a, b]) => Face::Face {
surface,
edges: Edges::single_cycle([
bottom_edge,
top_edge,
a,
b,
]),
},
None => Face::Face {
surface,
edges: Edges {
cycles: vec![
edges::Cycle {
edges: vec![bottom_edge],
},
edges::Cycle {
edges: vec![top_edge],
},
],
},
},
};

side_faces.push(face);
}
}

side_faces.push(Face::Triangles(side_face));
}

let mut faces = Vec::new();
Expand Down

0 comments on commit 6d1f8cf

Please sign in to comment.