Merge pull request #1953 from hannobraun/approx

Make some cleanups in edge approximation code
This commit is contained in:
Hanno Braun 2023-07-20 10:08:30 +02:00 committed by GitHub
commit 40b364814a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -12,7 +12,7 @@ use fj_math::Point;
use crate::{ use crate::{
geometry::{BoundaryOnCurve, GlobalPath, SurfacePath}, geometry::{BoundaryOnCurve, GlobalPath, SurfacePath},
objects::{GlobalEdge, HalfEdge, Surface, Vertex}, objects::{GlobalEdge, HalfEdge, Surface, Vertex},
storage::{Handle, ObjectId}, storage::{Handle, HandleWrapper},
}; };
use super::{Approx, ApproxPoint, Tolerance}; use super::{Approx, ApproxPoint, Tolerance};
@ -54,8 +54,8 @@ impl Approx for (&HalfEdge, &Surface) {
// approximations. // approximations.
// //
// Caching works like this: We check whether there already is a // Caching works like this: We check whether there already is a
// cache entry for the `GlobalEdge`. If there isn't we create the 3D // cache entry for the `GlobalEdge`. If there isn't, we create the
// approximation from the 2D `HalfEdge`. Next time we check for a // 3D approximation from the 2D `HalfEdge`. Next time we check for a
// coincident `HalfEdge`, we'll find the cache and use that, getting // coincident `HalfEdge`, we'll find the cache and use that, getting
// the exact same 3D approximation, instead of generating a slightly // the exact same 3D approximation, instead of generating a slightly
// different one from the different 2D `HalfEdge`. // different one from the different 2D `HalfEdge`.
@ -74,16 +74,10 @@ impl Approx for (&HalfEdge, &Surface) {
// forward, as it is, well, too limiting. This means things here // forward, as it is, well, too limiting. This means things here
// will need to change. // will need to change.
// //
// Basically, we're missing two things: // What we need here, is more intelligent caching based on `Curve`
// // and the edge boundaries, instead of `GlobalEdge`. The cache needs
// 1. A "global curve" object that is referenced by `HalfEdge`s and // to be able to deliver partial results for a given boundary, then
// can be used as the cache key, in combination with the range. // generating (and caching) the rest of it on the fly.
// 2. More intelligent caching, that can deliver partial results for
// the range given, while generating (and then caching) any
// unavailable parts of the range on the fly.
//
// Only item 2. is something we can do right here. Item 1. requires
// a change to the object graph.
let cached_approx = cache.get_edge( let cached_approx = cache.get_edge(
half_edge.global_form().clone(), half_edge.global_form().clone(),
half_edge.boundary(), half_edge.boundary(),
@ -223,8 +217,11 @@ fn approx_edge(
/// A cache for results of an approximation /// A cache for results of an approximation
#[derive(Default)] #[derive(Default)]
pub struct EdgeCache { pub struct EdgeCache {
edge_approx: BTreeMap<(ObjectId, BoundaryOnCurve), GlobalEdgeApprox>, edge_approx: BTreeMap<
vertex_approx: BTreeMap<ObjectId, Point<3>>, (HandleWrapper<GlobalEdge>, BoundaryOnCurve),
GlobalEdgeApprox,
>,
vertex_approx: BTreeMap<HandleWrapper<Vertex>, Point<3>>,
} }
impl EdgeCache { impl EdgeCache {
@ -234,16 +231,18 @@ impl EdgeCache {
} }
/// Access the approximation for the given [`GlobalEdge`], if available /// Access the approximation for the given [`GlobalEdge`], if available
pub fn get_edge( fn get_edge(
&self, &self,
handle: Handle<GlobalEdge>, handle: Handle<GlobalEdge>,
boundary: BoundaryOnCurve, boundary: BoundaryOnCurve,
) -> Option<GlobalEdgeApprox> { ) -> Option<GlobalEdgeApprox> {
if let Some(approx) = self.edge_approx.get(&(handle.id(), boundary)) { if let Some(approx) =
self.edge_approx.get(&(handle.clone().into(), boundary))
{
return Some(approx.clone()); return Some(approx.clone());
} }
if let Some(approx) = if let Some(approx) =
self.edge_approx.get(&(handle.id(), boundary.reverse())) self.edge_approx.get(&(handle.into(), boundary.reverse()))
{ {
// If we have a cache entry for the reverse boundary, we need to use // If we have a cache entry for the reverse boundary, we need to use
// that too! // that too!
@ -254,19 +253,19 @@ impl EdgeCache {
} }
/// Insert the approximation of a [`GlobalEdge`] /// Insert the approximation of a [`GlobalEdge`]
pub fn insert_edge( fn insert_edge(
&mut self, &mut self,
handle: Handle<GlobalEdge>, handle: Handle<GlobalEdge>,
boundary: BoundaryOnCurve, boundary: BoundaryOnCurve,
approx: GlobalEdgeApprox, approx: GlobalEdgeApprox,
) -> GlobalEdgeApprox { ) -> GlobalEdgeApprox {
self.edge_approx self.edge_approx
.insert((handle.id(), boundary), approx.clone()) .insert((handle.into(), boundary), approx.clone())
.unwrap_or(approx) .unwrap_or(approx)
} }
fn get_position(&self, handle: &Handle<Vertex>) -> Option<Point<3>> { fn get_position(&self, handle: &Handle<Vertex>) -> Option<Point<3>> {
self.vertex_approx.get(&handle.id()).cloned() self.vertex_approx.get(&handle.clone().into()).cloned()
} }
fn insert_position( fn insert_position(
@ -275,21 +274,21 @@ impl EdgeCache {
position: Point<3>, position: Point<3>,
) -> Point<3> { ) -> Point<3> {
self.vertex_approx self.vertex_approx
.insert(handle.id(), position) .insert(handle.clone().into(), position)
.unwrap_or(position) .unwrap_or(position)
} }
} }
/// An approximation of a [`GlobalEdge`] /// An approximation of a [`GlobalEdge`]
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] #[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct GlobalEdgeApprox { struct GlobalEdgeApprox {
/// The points that approximate the edge /// The points that approximate the edge
pub points: Vec<ApproxPoint<1>>, points: Vec<ApproxPoint<1>>,
} }
impl GlobalEdgeApprox { impl GlobalEdgeApprox {
/// Reverse the order of the approximation /// Reverse the order of the approximation
pub fn reverse(mut self) -> Self { fn reverse(mut self) -> Self {
self.points.reverse(); self.points.reverse();
self self
} }