Skip to content

Commit

Permalink
Merge pull request #150 from hannobraun/approximation
Browse files Browse the repository at this point in the history
Add test for approximation of an edge
  • Loading branch information
hannobraun authored Feb 8, 2022
2 parents 8c4dfe7 + 72c1552 commit bf8fe8d
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 36 deletions.
87 changes: 87 additions & 0 deletions src/kernel/approximation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ use parry3d_f64::shape::Segment;

use crate::math::Point;

use super::topology::edges::Edge;

/// An approximation of an edge, multiple edges, or a face
#[derive(Debug, PartialEq)]
pub struct Approximation {
/// All points that make up the approximation
///
Expand All @@ -25,6 +28,39 @@ pub struct Approximation {
}

impl Approximation {
/// Compute an approximate for an edge
///
/// `tolerance` defines how far the approximation is allowed to deviate from
/// the actual edge.
pub fn for_edge(edge: &Edge, tolerance: f64) -> Self {
let mut points = Vec::new();
edge.curve.approx(tolerance, &mut points);

if edge.reverse {
points.reverse()
}

let mut segment_points = points.clone();
if edge.vertices.is_none() {
// The edge has no vertices, which means it connects to itself. We
// need to reflect that in the approximation.

if let Some(&point) = points.first() {
segment_points.push(point);
}
}

let mut segments = Vec::new();
for segment in segment_points.windows(2) {
let p0 = segment[0];
let p1 = segment[1];

segments.push([p0, p1].into());
}

Self { points, segments }
}

/// Validate the approximation
///
/// Returns an `Err(ValidationError)`, if the validation is not valid. See
Expand Down Expand Up @@ -111,8 +147,59 @@ mod tests {
use nalgebra::point;
use parry3d_f64::shape::Segment;

use crate::kernel::{geometry::Curve, topology::edges::Edge};

use super::Approximation;

#[test]
fn test_for_edge() {
let tolerance = 1.;

let a = point![1., 2., 3.];
let b = point![3., 5., 8.];

let curve = Curve::Mock { approx: vec![a, b] };

let edge_regular = Edge {
curve: curve.clone(),
vertices: Some([(), ()]),
reverse: false,
};
assert_eq!(
Approximation::for_edge(&edge_regular, tolerance),
Approximation {
points: vec![a, b],
segments: vec![Segment { a, b }],
}
);

let edge_self_connected = Edge {
curve: curve.clone(),
vertices: None,
reverse: false,
};
assert_eq!(
Approximation::for_edge(&edge_self_connected, tolerance),
Approximation {
points: vec![a, b],
segments: vec![Segment { a, b }, Segment { a: b, b: a }],
}
);

let edge_reversed = Edge {
curve: curve.clone(),
vertices: Some([(), ()]),
reverse: true,
};
assert_eq!(
Approximation::for_edge(&edge_reversed, tolerance),
Approximation {
points: vec![b, a],
segments: vec![Segment { a: b, b: a }],
}
);
}

#[test]
fn test_validate() {
let a = point![0., 1., 2.];
Expand Down
12 changes: 11 additions & 1 deletion src/kernel/geometry/curves/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,17 @@ use crate::math::Point;
///
/// This distinction is not observed here, but moving things into that direction
/// is the intention.
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Debug)]
pub enum Curve {
/// A circle
Circle(Circle),

/// A line
Line(Line),

/// A mock curve used for testing
#[cfg(test)]
Mock { approx: Vec<Point<3>> },
}

impl Curve {
Expand All @@ -34,6 +38,9 @@ impl Curve {
match self {
Self::Circle(circle) => Self::Circle(circle.transform(transform)),
Self::Line(line) => Self::Line(line.transform(transform)),

#[cfg(test)]
Self::Mock { .. } => todo!(),
}
}

Expand All @@ -57,6 +64,9 @@ impl Curve {
match self {
Self::Circle(circle) => circle.approx(tolerance, out),
Self::Line(Line { a, b }) => out.extend([*a, *b]),

#[cfg(test)]
Self::Mock { approx } => out.extend(approx),
}
}
}
37 changes: 2 additions & 35 deletions src/kernel/topology/edges.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl Edges {
pub fn transform(mut self, transform: &Isometry<f64>) -> Self {
for cycle in &mut self.cycles {
for edge in &mut cycle.edges {
edge.curve = edge.curve.transform(transform);
edge.curve = edge.curve.clone().transform(transform);
}
}

Expand Down Expand Up @@ -100,7 +100,7 @@ impl Cycle {
let mut segments = Vec::new();

for edge in &self.edges {
let approx = edge.approx(tolerance);
let approx = Approximation::for_edge(&edge, tolerance);

points.extend(approx.points);
segments.extend(approx.segments);
Expand Down Expand Up @@ -170,37 +170,4 @@ impl Edge {
pub fn reverse(&mut self) {
self.reverse = !self.reverse;
}

/// Compute an approximation of the edge
///
/// `tolerance` defines how far the approximation is allowed to deviate from
/// the actual edge.
pub fn approx(&self, tolerance: f64) -> Approximation {
let mut points = Vec::new();
self.curve.approx(tolerance, &mut points);

if self.reverse {
points.reverse()
}

let mut segment_vertices = points.clone();
if self.vertices.is_none() {
// The edge has no vertices, which means it connects to itself. We
// need to reflect that in the approximation.

if let Some(&vertex) = points.first() {
segment_vertices.push(vertex);
}
}

let mut segments = Vec::new();
for segment in segment_vertices.windows(2) {
let v0 = segment[0];
let v1 = segment[1];

segments.push([v0, v1].into());
}

Approximation { points, segments }
}
}

0 comments on commit bf8fe8d

Please sign in to comment.