Skip to content

Commit

Permalink
Merge pull request #46 from mattatz/develop
Browse files Browse the repository at this point in the history
0.1.46
  • Loading branch information
mattatz authored Jan 20, 2025
2 parents 3a4eeaf + 74df5f6 commit 2ebca66
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 32 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "curvo"
version = "0.1.45"
version = "0.1.46"
authors = ["Masatatsu Nakamura <masatatsu.nakamura@gmail.com"]
edition = "2021"
keywords = ["nurbs", "modeling", "graphics", "3d"]
Expand Down Expand Up @@ -42,7 +42,7 @@ serde_json = "1.0.135"

[features]
default = []
# default = ["bevy"] # for debugging example
# default = ["bevy", "serde"] # for debugging example
bevy = [
"dep:easer",
"dep:rand_distr",
Expand Down
11 changes: 3 additions & 8 deletions examples/constrained_surface_tessellation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ use bevy_points::{
};
use itertools::Itertools;
use materials::*;
use misc::{add_surface, add_surface_normals};
use nalgebra::{Point3, Rotation3, Translation3, Vector3};

use curvo::prelude::*;
Expand Down Expand Up @@ -70,13 +69,9 @@ fn setup(

let surface = NurbsSurface::try_loft(&[front, back], Some(3)).unwrap();

let u_parameters = vec![
umin,
(umin + umax) * 0.25,
(umin + umax) * 0.5,
(umin + umax) * 0.75,
umax,
];
let u_parameters = (0..=8)
.map(|i| umin + (umax - umin) * i as f64 / 8.)
.collect_vec();
let vmin = surface.v_knots_domain().0;

let boundary = BoundaryConstraints::default().with_u_parameters_at_v_min(u_parameters.clone());
Expand Down
12 changes: 4 additions & 8 deletions src/tessellation/tessellation_curve.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use nalgebra::{
allocator::Allocator, DefaultAllocator, DimName, DimNameDiff, DimNameSub, OPoint, U1,
};
use rand::{rngs::ThreadRng, Rng};

use crate::{
curve::NurbsCurve,
Expand All @@ -25,10 +24,9 @@ where
return self.dehomogenized_control_points();
}

let mut rng = rand::thread_rng();
let tol = tolerance.unwrap_or(T::from_f64(1e-3).unwrap());
let (start, end) = self.knots_domain();
tessellate_adaptive(self, start, end, tol, &mut rng)
tessellate_adaptive(self, start, end, tol)
}
}

Expand All @@ -39,7 +37,6 @@ fn tessellate_adaptive<T: FloatingPoint, D>(
start: T,
end: T,
tol: T,
rng: &mut ThreadRng,
) -> Vec<OPoint<T, DimNameDiff<D, U1>>>
where
D: DimName + DimNameSub<U1>,
Expand All @@ -54,8 +51,7 @@ where

let p3 = curve.point_at(end);

let t = 0.5_f64 + 0.2_f64 * rng.gen::<f64>();
let mid = start + delta * T::from_f64(t).unwrap();
let mid = start + delta * T::from_f64(0.5).unwrap();
let p2 = curve.point_at(mid);

let diff = &p1 - &p3;
Expand All @@ -64,8 +60,8 @@ where
|| !three_points_are_flat(&p1, &p2, &p3, tol)
{
let exact_mid = start + (end - start) * T::from_f64(0.5).unwrap();
let mut left_pts = tessellate_adaptive(curve, start, exact_mid, tol, rng);
let right_pts = tessellate_adaptive(curve, exact_mid, end, tol, rng);
let mut left_pts = tessellate_adaptive(curve, start, exact_mid, tol);
let right_pts = tessellate_adaptive(curve, exact_mid, end, tol);
left_pts.pop();
[left_pts, right_pts].concat()
} else {
Expand Down
83 changes: 70 additions & 13 deletions src/tessellation/trimmed_surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ impl<T: FloatingPoint> Vertex<T> {
pub fn new(point: Point3<T>, normal: Vector3<T>, uv: Vector2<T>) -> Self {
Self { point, normal, uv }
}

pub fn point(&self) -> Point3<T> {
self.point
}
}

impl<T: FloatingPoint + SpadeNum> HasPosition for Vertex<T> {
Expand Down Expand Up @@ -151,7 +155,22 @@ fn trimmed_surface_adaptive_tessellate<T: FloatingPoint + SpadeNum>(
});

let insert_constraint = |t: &mut Tri<T>, vertices: &[Vertex<T>]| {
let handles = vertices.iter().map(|v| t.insert(*v)).collect_vec();
let skip = if let (Some(first), Some(last)) = (vertices.first(), vertices.last()) {
// if the input vertices are closed, skip the first vertex to avoid adding a duplicate constraint
if first.point() == last.point() {
1
} else {
0
}
} else {
0
};

let handles = vertices
.iter()
.skip(skip)
.map(|v| t.insert(*v))
.collect_vec();
handles
.into_iter()
.circular_tuple_windows()
Expand Down Expand Up @@ -250,15 +269,48 @@ fn tessellate_uv_curve_adaptive<T: FloatingPoint>(
surface: &NurbsSurface3D<T>,
tolerance: T,
) -> Vec<Vertex<T>> {
let (start, end) = curve.knots_domain();
let pts = iterate_uv_curve_tessellation(curve, surface, start, end, tolerance);
pts.into_iter()
.map(|uv| {
let p = surface.point_at(uv.x, uv.y);
let n = surface.normal_at(uv.x, uv.y);
Vertex::new(p, n, uv.coords)
})
.collect_vec()
let degree = curve.degree();
match degree {
1 => {
// if the curve is a linear curve, should start tessellation from the knots
let knots = curve.knots();
let n = knots.len();

let pts = (1..n - 2).flat_map(|i| {
let evaluated = iterate_uv_curve_tessellation(
curve,
surface,
knots[i],
knots[i + 1],
tolerance,
);
#[allow(clippy::iter_skip_zero)]
if i == 1 {
evaluated.into_iter().skip(0)
} else {
evaluated.into_iter().skip(1)
}
});

pts.map(|uv| {
let p = surface.point_at(uv.x, uv.y);
let n = surface.normal_at(uv.x, uv.y);
Vertex::new(p, n, uv.coords)
})
.collect_vec()
}
_ => {
let (start, end) = curve.knots_domain();
let pts = iterate_uv_curve_tessellation(curve, surface, start, end, tolerance);
pts.into_iter()
.map(|uv| {
let p = surface.point_at(uv.x, uv.y);
let n = surface.normal_at(uv.x, uv.y);
Vertex::new(p, n, uv.coords)
})
.collect_vec()
}
}
}

fn iterate_uv_curve_tessellation<T: FloatingPoint>(
Expand All @@ -279,9 +331,14 @@ fn iterate_uv_curve_tessellation<T: FloatingPoint>(
let (p3, n3) = curve.point_tangent_at(end);

let flag = {
let diff = n2 - n1;
let diff2 = n3 - n2;
(diff - diff2).norm() > normal_tolerance
if curve.degree() == 1 {
// if the curve is a linear curve, we don't need to tessellate it by normal
false
} else {
let diff = n2 - n1;
let diff2 = n3 - n2;
(diff - diff2).norm() > normal_tolerance
}
} || {
let sn1 = surface.normal_at(p1.x, p1.y);
let sn2 = surface.normal_at(p2.x, p2.y);
Expand Down

0 comments on commit 2ebca66

Please sign in to comment.