fj_kernel/algorithms/transform/
mod.rs

1//! API for transforming objects
2
3mod cycle;
4mod edge;
5mod face;
6mod shell;
7mod sketch;
8mod solid;
9mod surface;
10mod vertex;
11
12use std::collections::BTreeMap;
13
14use fj_math::{Transform, Vector};
15use type_map::TypeMap;
16
17use crate::{
18    operations::Insert,
19    services::Services,
20    storage::{Handle, ObjectId},
21};
22
23/// Transform an object
24///
25/// # Implementation Note
26///
27/// So far, a general `transform` method is available, along some convenience
28/// methods for more specific transformations.
29///
30/// More convenience methods can be added as required. The only reason this
31/// hasn't been done so far, is that no one has put in the work yet.
32pub trait TransformObject: Sized {
33    /// Transform the object
34    fn transform(self, transform: &Transform, services: &mut Services) -> Self {
35        let mut cache = TransformCache::default();
36        self.transform_with_cache(transform, services, &mut cache)
37    }
38
39    /// Transform the object using the provided cache
40    fn transform_with_cache(
41        self,
42        transform: &Transform,
43        services: &mut Services,
44        cache: &mut TransformCache,
45    ) -> Self;
46
47    /// Translate the object
48    ///
49    /// Convenience wrapper around [`TransformObject::transform`].
50    fn translate(
51        self,
52        offset: impl Into<Vector<3>>,
53        services: &mut Services,
54    ) -> Self {
55        self.transform(&Transform::translation(offset), services)
56    }
57
58    /// Rotate the object
59    ///
60    /// Convenience wrapper around [`TransformObject::transform`].
61    fn rotate(
62        self,
63        axis_angle: impl Into<Vector<3>>,
64        services: &mut Services,
65    ) -> Self {
66        self.transform(&Transform::rotation(axis_angle), services)
67    }
68}
69
70impl<T> TransformObject for Handle<T>
71where
72    T: Clone + Insert<Inserted = Handle<T>> + TransformObject + 'static,
73{
74    fn transform_with_cache(
75        self,
76        transform: &Transform,
77        services: &mut Services,
78        cache: &mut TransformCache,
79    ) -> Self {
80        if let Some(object) = cache.get(&self) {
81            return object.clone();
82        }
83
84        let transformed = self
85            .clone_object()
86            .transform_with_cache(transform, services, cache)
87            .insert(services);
88
89        cache.insert(self.clone(), transformed.clone());
90
91        transformed
92    }
93}
94
95/// A cache for transformed objects
96///
97/// See [`TransformObject`].
98#[derive(Default)]
99pub struct TransformCache(TypeMap);
100
101impl TransformCache {
102    fn get<T: 'static>(&mut self, key: &Handle<T>) -> Option<&Handle<T>> {
103        let map = self
104            .0
105            .entry::<BTreeMap<ObjectId, Handle<T>>>()
106            .or_insert_with(BTreeMap::new);
107
108        map.get(&key.id())
109    }
110
111    fn insert<T: 'static>(&mut self, key: Handle<T>, value: Handle<T>) {
112        let map = self
113            .0
114            .entry::<BTreeMap<ObjectId, Handle<T>>>()
115            .or_insert_with(BTreeMap::new);
116
117        map.insert(key.id(), value);
118    }
119}