Skip to content

Commit

Permalink
Merge pull request #2221 from hannobraun/presentation
Browse files Browse the repository at this point in the history
Use color from presentation layer during approximation
  • Loading branch information
hannobraun authored Feb 16, 2024
2 parents f079566 + 0d80cee commit 2b8f9fa
Show file tree
Hide file tree
Showing 12 changed files with 148 additions and 90 deletions.
131 changes: 71 additions & 60 deletions crates/fj-core/src/algorithms/approx/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{
geometry::{CurveBoundary, GlobalPath, SurfacePath},
objects::{Curve, Surface},
storage::{Handle, HandleWrapper},
Core,
};

use super::{Approx, ApproxPoint, Tolerance};
Expand All @@ -27,14 +28,20 @@ impl Approx
self,
tolerance: impl Into<Tolerance>,
cache: &mut Self::Cache,
core: &mut Core,
) -> Self::Approximation {
let (curve, surface_path, surface, boundary) = self;

match cache.get(curve, boundary) {
Some(approx) => approx,
None => {
let approx =
approx_curve(&surface_path, surface, boundary, tolerance);
let approx = approx_curve(
&surface_path,
surface,
boundary,
tolerance,
core,
);

cache.insert(curve.clone(), boundary, approx)
}
Expand All @@ -47,67 +54,71 @@ fn approx_curve(
surface: &Surface,
boundary: CurveBoundary<Point<1>>,
tolerance: impl Into<Tolerance>,
core: &mut Core,
) -> CurveApprox {
// There are different cases of varying complexity. Circles are the hard
// part here, as they need to be approximated, while lines don't need to be.
//
// This will probably all be unified eventually, as `SurfacePath` and
// `GlobalPath` grow APIs that are better suited to implementing this code
// in a more abstract way.
let points = match (path, surface.geometry().u) {
(SurfacePath::Circle(_), GlobalPath::Circle(_)) => {
todo!(
let points =
match (path, surface.geometry().u) {
(SurfacePath::Circle(_), GlobalPath::Circle(_)) => {
todo!(
"Approximating a circle on a curved surface not supported yet."
)
}
(SurfacePath::Circle(_), GlobalPath::Line(_)) => {
(path, boundary)
.approx_with_cache(tolerance, &mut ())
.into_iter()
.map(|(point_curve, point_surface)| {
// We're throwing away `point_surface` here, which is a bit
// weird, as we're recomputing it later (outside of this
// function).
//
// It should be fine though:
//
// 1. We're throwing this version away, so there's no danger
// of inconsistency between this and the later version.
// 2. This version should have been computed using the same
// path and parameters and the later version will be, so
// they should be the same anyway.
// 3. Not all other cases handled in this function have a
// surface point available, so it needs to be computed
// later anyway, in the general case.

}
(SurfacePath::Circle(_), GlobalPath::Line(_)) => {
(path, boundary)
.approx_with_cache(tolerance, &mut (), core)
.into_iter()
.map(|(point_curve, point_surface)| {
// We're throwing away `point_surface` here, which is a
// bit weird, as we're recomputing it later (outside of
// this function).
//
// It should be fine though:
//
// 1. We're throwing this version away, so there's no
// danger of inconsistency between this and the later
// version.
// 2. This version should have been computed using the
// same path and parameters and the later version
// will be, so they should be the same anyway.
// 3. Not all other cases handled in this function have
// a surface point available, so it needs to be
// computed later anyway, in the general case.

let point_global = surface
.geometry()
.point_from_surface_coords(point_surface);
(point_curve, point_global)
})
.collect()
}
(SurfacePath::Line(line), _) => {
let range_u =
CurveBoundary::from(boundary.inner.map(|point_curve| {
[path.point_from_path_coords(point_curve).u]
}));

let approx_u = (surface.geometry().u, range_u)
.approx_with_cache(tolerance, &mut (), core);

let mut points = Vec::new();
for (u, _) in approx_u {
let t = (u.t - line.origin().u) / line.direction().u;
let point_surface = path.point_from_path_coords([t]);
let point_global = surface
.geometry()
.point_from_surface_coords(point_surface);
(point_curve, point_global)
})
.collect()
}
(SurfacePath::Line(line), _) => {
let range_u =
CurveBoundary::from(boundary.inner.map(|point_curve| {
[path.point_from_path_coords(point_curve).u]
}));

let approx_u = (surface.geometry().u, range_u)
.approx_with_cache(tolerance, &mut ());

let mut points = Vec::new();
for (u, _) in approx_u {
let t = (u.t - line.origin().u) / line.direction().u;
let point_surface = path.point_from_path_coords([t]);
let point_global =
surface.geometry().point_from_surface_coords(point_surface);
points.push((u, point_global));
}
points.push((u, point_global));
}

points
}
};
points
}
};

let points = points
.into_iter()
Expand Down Expand Up @@ -195,8 +206,8 @@ mod tests {
let surface = core.layers.objects.surfaces.xz_plane();

let tolerance = 1.;
let approx =
(&curve, surface_path, surface.deref(), boundary).approx(tolerance);
let approx = (&curve, surface_path, surface.deref(), boundary)
.approx(tolerance, &mut core);

assert_eq!(approx.points, vec![]);
}
Expand All @@ -215,8 +226,8 @@ mod tests {
});

let tolerance = 1.;
let approx =
(&curve, surface_path, &surface, boundary).approx(tolerance);
let approx = (&curve, surface_path, &surface, boundary)
.approx(tolerance, &mut core);

assert_eq!(approx.points, vec![]);
}
Expand All @@ -238,11 +249,11 @@ mod tests {
});

let tolerance = 1.;
let approx =
(&curve, surface_path, &surface, boundary).approx(tolerance);
let approx = (&curve, surface_path, &surface, boundary)
.approx(tolerance, &mut core);

let expected_approx = (global_path, boundary)
.approx(tolerance)
.approx(tolerance, &mut core)
.into_iter()
.map(|(point_local, _)| {
let point_surface =
Expand All @@ -266,11 +277,11 @@ mod tests {
let surface = core.layers.objects.surfaces.xz_plane();

let tolerance = 1.;
let approx =
(&curve, surface_path, surface.deref(), boundary).approx(tolerance);
let approx = (&curve, surface_path, surface.deref(), boundary)
.approx(tolerance, &mut core);

let expected_approx = (&surface_path, boundary)
.approx(tolerance)
.approx(tolerance, &mut core)
.into_iter()
.map(|(point_local, _)| {
let point_surface =
Expand Down
9 changes: 7 additions & 2 deletions crates/fj-core/src/algorithms/approx/cycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ use std::ops::Deref;

use fj_math::Segment;

use crate::objects::{Cycle, Surface};
use crate::{
objects::{Cycle, Surface},
Core,
};

use super::{
edge::{HalfEdgeApprox, HalfEdgeApproxCache},
Expand All @@ -21,6 +24,7 @@ impl Approx for (&Cycle, &Surface) {
self,
tolerance: impl Into<Tolerance>,
cache: &mut Self::Cache,
core: &mut Core,
) -> Self::Approximation {
let (cycle, surface) = self;
let tolerance = tolerance.into();
Expand All @@ -29,7 +33,8 @@ impl Approx for (&Cycle, &Surface) {
.half_edges()
.iter()
.map(|edge| {
(edge.deref(), surface).approx_with_cache(tolerance, cache)
(edge.deref(), surface)
.approx_with_cache(tolerance, cache, core)
})
.collect();

Expand Down
8 changes: 6 additions & 2 deletions crates/fj-core/src/algorithms/approx/edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
//! approximations are usually used to build cycle approximations, and this way,
//! the caller doesn't have to deal with duplicate vertices.
use crate::objects::{HalfEdge, Surface};
use crate::{
objects::{HalfEdge, Surface},
Core,
};

use super::{
curve::CurveApproxCache, vertex::VertexApproxCache, Approx, ApproxPoint,
Expand All @@ -20,6 +23,7 @@ impl Approx for (&HalfEdge, &Surface) {
self,
tolerance: impl Into<Tolerance>,
cache: &mut Self::Cache,
core: &mut Core,
) -> Self::Approximation {
let (edge, surface) = self;
let tolerance = tolerance.into();
Expand All @@ -42,7 +46,7 @@ impl Approx for (&HalfEdge, &Surface) {

let rest = {
let approx = (edge.curve(), edge.path(), surface, edge.boundary())
.approx_with_cache(tolerance, &mut cache.curve);
.approx_with_cache(tolerance, &mut cache.curve, core);

approx.points.into_iter().map(|point| {
let point_surface =
Expand Down
12 changes: 8 additions & 4 deletions crates/fj-core/src/algorithms/approx/face.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ use fj_interop::Color;

use crate::{
objects::{Face, Handedness, ObjectSet},
operations::presentation::GetColor,
validate::ValidationConfig,
Core,
};

use super::{
Expand All @@ -24,12 +26,13 @@ impl Approx for &ObjectSet<Face> {
self,
tolerance: impl Into<Tolerance>,
cache: &mut Self::Cache,
core: &mut Core,
) -> Self::Approximation {
let tolerance = tolerance.into();

let approx = self
.into_iter()
.map(|face| face.approx_with_cache(tolerance, cache))
.map(|face| face.approx_with_cache(tolerance, cache, core))
.collect();

let min_distance = ValidationConfig::default().distinct_min_distance;
Expand Down Expand Up @@ -70,6 +73,7 @@ impl Approx for &Face {
self,
tolerance: impl Into<Tolerance>,
cache: &mut Self::Cache,
core: &mut Core,
) -> Self::Approximation {
let tolerance = tolerance.into();

Expand All @@ -88,19 +92,19 @@ impl Approx for &Face {

let exterior =
(self.region().exterior().deref(), self.surface().deref())
.approx_with_cache(tolerance, cache);
.approx_with_cache(tolerance, cache, core);

let mut interiors = BTreeSet::new();
for cycle in self.region().interiors() {
let cycle = (cycle.deref(), self.surface().deref())
.approx_with_cache(tolerance, cache);
.approx_with_cache(tolerance, cache, core);
interiors.insert(cycle);
}

FaceApprox {
exterior,
interiors,
color: self.region().color(),
color: self.region().get_color(core),
coord_handedness: self.coord_handedness(),
}
}
Expand Down
11 changes: 8 additions & 3 deletions crates/fj-core/src/algorithms/approx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use std::{

use fj_math::Point;

use crate::objects::Surface;
use crate::{objects::Surface, Core};

pub use self::tolerance::{InvalidTolerance, Tolerance};

Expand All @@ -35,9 +35,13 @@ pub trait Approx: Sized {
///
/// `tolerance` defines how far the approximation is allowed to deviate from
/// the actual object.
fn approx(self, tolerance: impl Into<Tolerance>) -> Self::Approximation {
fn approx(
self,
tolerance: impl Into<Tolerance>,
core: &mut Core,
) -> Self::Approximation {
let mut cache = Self::Cache::default();
self.approx_with_cache(tolerance, &mut cache)
self.approx_with_cache(tolerance, &mut cache, core)
}

/// Approximate the object, using the provided cache
Expand All @@ -48,6 +52,7 @@ pub trait Approx: Sized {
self,
tolerance: impl Into<Tolerance>,
cache: &mut Self::Cache,
core: &mut Core,
) -> Self::Approximation;
}

Expand Down
7 changes: 6 additions & 1 deletion crates/fj-core/src/algorithms/approx/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ use std::iter;

use fj_math::{Circle, Point, Scalar, Sign};

use crate::geometry::{CurveBoundary, GlobalPath, SurfacePath};
use crate::{
geometry::{CurveBoundary, GlobalPath, SurfacePath},
Core,
};

use super::{Approx, Tolerance};

Expand All @@ -44,6 +47,7 @@ impl Approx for (&SurfacePath, CurveBoundary<Point<1>>) {
self,
tolerance: impl Into<Tolerance>,
(): &mut Self::Cache,
_core: &mut Core,
) -> Self::Approximation {
let (path, range) = self;

Expand All @@ -64,6 +68,7 @@ impl Approx for (GlobalPath, CurveBoundary<Point<1>>) {
self,
tolerance: impl Into<Tolerance>,
(): &mut Self::Cache,
_core: &mut Core,
) -> Self::Approximation {
let (path, range) = self;

Expand Down
5 changes: 3 additions & 2 deletions crates/fj-core/src/algorithms/approx/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use std::collections::BTreeSet;

use crate::objects::Shell;
use crate::{objects::Shell, Core};

use super::{edge::HalfEdgeApproxCache, face::FaceApprox, Approx, Tolerance};

Expand All @@ -14,7 +14,8 @@ impl Approx for &Shell {
self,
tolerance: impl Into<Tolerance>,
cache: &mut Self::Cache,
core: &mut Core,
) -> Self::Approximation {
self.faces().approx_with_cache(tolerance, cache)
self.faces().approx_with_cache(tolerance, cache, core)
}
}
Loading

0 comments on commit 2b8f9fa

Please sign in to comment.