Skip to content

Commit

Permalink
Merge pull request #1092 from hannobraun/cache
Browse files Browse the repository at this point in the history
Clean up curve approximation caching code
  • Loading branch information
hannobraun authored Sep 15, 2022
2 parents 4b48e47 + dc5d7b3 commit 6500bb4
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 58 deletions.
47 changes: 41 additions & 6 deletions crates/fj-kernel/src/algorithms/approx/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,30 @@
//! done, to give the caller (who knows the boundary anyway) more options on how
//! to further process the approximation.
use std::collections::BTreeMap;

use crate::objects::{Curve, GlobalCurve};

use super::{path::RangeOnPath, Approx, ApproxCache, ApproxPoint, Tolerance};
use super::{path::RangeOnPath, Approx, ApproxPoint, Tolerance};

impl Approx for (&Curve, RangeOnPath) {
type Approximation = CurveApprox;
type Cache = CurveCache;

fn approx_with_cache(
self,
tolerance: impl Into<Tolerance>,
cache: &mut ApproxCache,
cache: &mut Self::Cache,
) -> Self::Approximation {
let (curve, range) = self;

let cache_key = (*curve.global_form(), range);
let global_curve_approx = match cache.global_curve(cache_key) {
let global_curve_approx = match cache.get(cache_key) {
Some(approx) => approx,
None => {
let approx = (curve.global_form(), range)
.approx_with_cache(tolerance, cache);
cache.insert_global_curve(cache_key, approx)
.approx_with_cache(tolerance, &mut ());
cache.insert(cache_key, approx)
}
};

Expand All @@ -46,11 +49,12 @@ impl Approx for (&Curve, RangeOnPath) {

impl Approx for (&GlobalCurve, RangeOnPath) {
type Approximation = GlobalCurveApprox;
type Cache = ();

fn approx_with_cache(
self,
tolerance: impl Into<Tolerance>,
cache: &mut ApproxCache,
cache: &mut Self::Cache,
) -> Self::Approximation {
let (curve, range) = self;

Expand Down Expand Up @@ -89,6 +93,37 @@ impl CurveApprox {
}
}

/// A cache for results of an approximation
#[derive(Default)]
pub struct CurveCache {
inner: BTreeMap<(GlobalCurve, RangeOnPath), GlobalCurveApprox>,
}

impl CurveCache {
/// Create an empty cache
pub fn new() -> Self {
Self::default()
}

/// Insert the approximation of a [`GlobalCurve`]
pub fn insert(
&mut self,
key: (GlobalCurve, RangeOnPath),
approx: GlobalCurveApprox,
) -> GlobalCurveApprox {
self.inner.insert(key, approx.clone());
approx
}

/// Access the approximation for the given [`GlobalCurve`], if available
pub fn get(
&self,
key: (GlobalCurve, RangeOnPath),
) -> Option<GlobalCurveApprox> {
self.inner.get(&key).cloned()
}
}

/// An approximation of a [`GlobalCurve`]
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct GlobalCurveApprox {
Expand Down
5 changes: 3 additions & 2 deletions crates/fj-kernel/src/algorithms/approx/cycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@ use fj_math::Segment;
use crate::objects::Cycle;

use super::{
edge::HalfEdgeApprox, Approx, ApproxCache, ApproxPoint, Tolerance,
curve::CurveCache, edge::HalfEdgeApprox, Approx, ApproxPoint, Tolerance,
};

impl Approx for &Cycle {
type Approximation = CycleApprox;
type Cache = CurveCache;

fn approx_with_cache(
self,
tolerance: impl Into<Tolerance>,
cache: &mut ApproxCache,
cache: &mut Self::Cache,
) -> Self::Approximation {
let tolerance = tolerance.into();

Expand Down
8 changes: 5 additions & 3 deletions crates/fj-kernel/src/algorithms/approx/edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,19 @@
use crate::objects::HalfEdge;

use super::{
curve::CurveApprox, path::RangeOnPath, Approx, ApproxCache, ApproxPoint,
Tolerance,
curve::{CurveApprox, CurveCache},
path::RangeOnPath,
Approx, ApproxPoint, Tolerance,
};

impl Approx for &HalfEdge {
type Approximation = HalfEdgeApprox;
type Cache = CurveCache;

fn approx_with_cache(
self,
tolerance: impl Into<Tolerance>,
cache: &mut ApproxCache,
cache: &mut Self::Cache,
) -> Self::Approximation {
let &[a, b] = self.vertices();
let range = RangeOnPath::new([a, b].map(|vertex| vertex.position()));
Expand Down
10 changes: 7 additions & 3 deletions crates/fj-kernel/src/algorithms/approx/face.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,18 @@ use crate::{
objects::{Face, Faces, Handedness},
};

use super::{cycle::CycleApprox, Approx, ApproxCache, ApproxPoint, Tolerance};
use super::{
curve::CurveCache, cycle::CycleApprox, Approx, ApproxPoint, Tolerance,
};

impl Approx for &Faces {
type Approximation = BTreeSet<FaceApprox>;
type Cache = CurveCache;

fn approx_with_cache(
self,
tolerance: impl Into<Tolerance>,
cache: &mut ApproxCache,
cache: &mut Self::Cache,
) -> Self::Approximation {
let tolerance = tolerance.into();

Expand Down Expand Up @@ -66,11 +69,12 @@ impl Approx for &Faces {

impl Approx for &Face {
type Approximation = FaceApprox;
type Cache = CurveCache;

fn approx_with_cache(
self,
tolerance: impl Into<Tolerance>,
cache: &mut ApproxCache,
cache: &mut Self::Cache,
) -> Self::Approximation {
let tolerance = tolerance.into();

Expand Down
45 changes: 9 additions & 36 deletions crates/fj-kernel/src/algorithms/approx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,72 +13,45 @@ pub mod tolerance;
use std::{
any::Any,
cmp::Ordering,
collections::BTreeMap,
fmt::Debug,
hash::{Hash, Hasher},
rc::Rc,
};

use fj_math::Point;

use crate::objects::{Curve, GlobalCurve};
use crate::objects::Curve;

pub use self::tolerance::{InvalidTolerance, Tolerance};
use self::{curve::GlobalCurveApprox, path::RangeOnPath};

/// Approximate an object
pub trait Approx: Sized {
/// The approximation of the object
type Approximation;

/// The cache used to cache approximation results
type Cache: Default;

/// Approximate the object
///
/// `tolerance` defines how far the approximation is allowed to deviate from
/// the actual object.
fn approx(self, tolerance: impl Into<Tolerance>) -> Self::Approximation {
let mut cache = ApproxCache::new();
let mut cache = Self::Cache::default();
self.approx_with_cache(tolerance, &mut cache)
}

/// Approximate the object, using the provided cache
///
/// This is a lower-level method that allows some degree of control over
/// caching. Callers might consider using [`Approx::approx`] instead.
fn approx_with_cache(
self,
tolerance: impl Into<Tolerance>,
cache: &mut ApproxCache,
cache: &mut Self::Cache,
) -> Self::Approximation;
}

/// A cache for results of an approximation
#[derive(Default)]
pub struct ApproxCache {
global_curve: BTreeMap<(GlobalCurve, RangeOnPath), GlobalCurveApprox>,
}

impl ApproxCache {
/// Create an empty cache
pub fn new() -> Self {
Self::default()
}

/// Insert the approximation of a [`GlobalCurve`]
pub fn insert_global_curve(
&mut self,
key: (GlobalCurve, RangeOnPath),
approx: GlobalCurveApprox,
) -> GlobalCurveApprox {
self.global_curve.insert(key, approx.clone());
approx
}

/// Access the approximation for the given [`GlobalCurve`], if available
pub fn global_curve(
&self,
key: (GlobalCurve, RangeOnPath),
) -> Option<GlobalCurveApprox> {
self.global_curve.get(&key).cloned()
}
}

/// A point from an approximation, with local and global forms
#[derive(Debug, Clone)]
pub struct ApproxPoint<const D: usize> {
Expand Down
5 changes: 3 additions & 2 deletions crates/fj-kernel/src/algorithms/approx/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,16 @@ use fj_math::{Circle, Point, Scalar};

use crate::path::GlobalPath;

use super::{Approx, ApproxCache, Tolerance};
use super::{Approx, Tolerance};

impl Approx for (GlobalPath, RangeOnPath) {
type Approximation = Vec<(Point<1>, Point<3>)>;
type Cache = ();

fn approx_with_cache(
self,
tolerance: impl Into<Tolerance>,
_: &mut ApproxCache,
(): &mut Self::Cache,
) -> Self::Approximation {
let (path, range) = self;

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

use crate::objects::Shell;

use super::{face::FaceApprox, Approx, ApproxCache, Tolerance};
use super::{curve::CurveCache, face::FaceApprox, Approx, Tolerance};

impl Approx for &Shell {
type Approximation = BTreeSet<FaceApprox>;
type Cache = CurveCache;

fn approx_with_cache(
self,
tolerance: impl Into<Tolerance>,
cache: &mut ApproxCache,
cache: &mut Self::Cache,
) -> Self::Approximation {
self.faces().approx_with_cache(tolerance, cache)
}
Expand Down
5 changes: 3 additions & 2 deletions crates/fj-kernel/src/algorithms/approx/sketch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ use std::collections::BTreeSet;

use crate::objects::Sketch;

use super::{face::FaceApprox, Approx, ApproxCache, Tolerance};
use super::{curve::CurveCache, face::FaceApprox, Approx, Tolerance};

impl Approx for &Sketch {
type Approximation = BTreeSet<FaceApprox>;
type Cache = CurveCache;

fn approx_with_cache(
self,
tolerance: impl Into<Tolerance>,
cache: &mut ApproxCache,
cache: &mut Self::Cache,
) -> Self::Approximation {
self.faces().approx_with_cache(tolerance, cache)
}
Expand Down
5 changes: 3 additions & 2 deletions crates/fj-kernel/src/algorithms/approx/solid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ use std::collections::BTreeSet;

use crate::objects::Solid;

use super::{face::FaceApprox, Approx, ApproxCache, Tolerance};
use super::{curve::CurveCache, face::FaceApprox, Approx, Tolerance};

impl Approx for &Solid {
type Approximation = BTreeSet<FaceApprox>;
type Cache = CurveCache;

fn approx_with_cache(
self,
tolerance: impl Into<Tolerance>,
cache: &mut ApproxCache,
cache: &mut Self::Cache,
) -> Self::Approximation {
let tolerance = tolerance.into();

Expand Down

0 comments on commit 6500bb4

Please sign in to comment.