Skip to main content

polygon_unionfind/
combinators.rs

1// SPDX-FileCopyrightText: 2026 polygon_unionfind contributors
2//
3// SPDX-License-Identifier: MIT OR Apache-2.0
4
5use alloc::vec::Vec;
6
7use maplike::{Container, Get};
8
9use crate::{Add, Clip, Inflate, PolygonId, Sub};
10#[cfg(feature = "undoredo")]
11use crate::{Polygon, RecordingPolygonSet, RecordingPolygonUnionFind};
12
13#[cfg(feature = "undoredo")]
14use core::marker::PhantomData;
15#[cfg(feature = "undoredo")]
16use undoredo::{ApplyDelta, Delta, FlushDelta};
17
18#[derive(Clone, Debug)]
19pub struct Inflated<I, K> {
20    inflatee: I,
21    offset: K,
22}
23
24impl<I, K> Inflated<I, K> {
25    #[inline]
26    pub fn inflatee(&self) -> &I {
27        &self.inflatee
28    }
29
30    #[inline]
31    pub fn offset(&self) -> &K {
32        &self.offset
33    }
34}
35
36impl<I: Default, K> Inflated<I, K> {
37    #[inline]
38    pub fn new(offset: K) -> Self {
39        Self {
40            inflatee: I::default(),
41            offset,
42        }
43    }
44}
45
46impl<K: Clone, P: Clone + Inflate<K>, S: Add<P, Output = PolygonId>> Add<P> for Inflated<S, K> {
47    type Output = PolygonId;
48
49    fn add(&mut self, polygon: P) -> PolygonId {
50        self.inflatee.add(polygon.inflate(self.offset.clone()))
51    }
52}
53
54impl<K: Clone, P: Clone + Inflate<K>, S: Sub<P>> Sub<P> for Inflated<S, K> {
55    type Output = S::Output;
56
57    fn sub(&mut self, polygon: P) -> S::Output {
58        self.inflatee.sub(polygon.inflate(self.offset.clone()))
59    }
60}
61
62impl<I: Container, K> Container for Inflated<I, K> {
63    type Key = I::Key;
64    type Value = I::Value;
65}
66
67impl<I: Get<K2>, K, K2> Get<K2> for Inflated<I, K> {
68    #[inline]
69    fn get(&self, key: &K2) -> Option<&Self::Value> {
70        self.inflatee.get(key)
71    }
72}
73
74#[derive(Clone, Debug)]
75pub struct Negated<M, S> {
76    minuend: M,
77    subtrahend: S,
78}
79
80impl<M, S> Negated<M, S> {
81    #[inline]
82    pub fn minuend(&self) -> &M {
83        &self.minuend
84    }
85
86    #[inline]
87    pub fn subtrahend(&self) -> &S {
88        &self.subtrahend
89    }
90
91    #[inline]
92    pub fn new(minuend: M, subtrahend: S) -> Self {
93        Self {
94            minuend,
95            subtrahend,
96        }
97    }
98}
99
100impl<M: Default, S: Default> Default for Negated<M, S> {
101    #[inline]
102    fn default() -> Self {
103        Self {
104            minuend: M::default(),
105            subtrahend: S::default(),
106        }
107    }
108}
109
110impl<
111    P: Clone,
112    M: Sub<P, Output = (Vec<PolygonId>, Vec<P>)>,
113    S: Add<P, Output = PolygonId> + Get<PolygonId, Value = P>,
114> Add<P> for Negated<M, S>
115{
116    type Output = (Vec<PolygonId>, Vec<P>);
117
118    fn add(&mut self, polygon: P) -> (Vec<PolygonId>, Vec<P>) {
119        let id = self.subtrahend.add(polygon.clone());
120
121        self.minuend.sub(self.subtrahend.get(&id).unwrap().clone())
122    }
123}
124
125#[derive(Clone, Debug)]
126pub struct Paralleled<S> {
127    primary: S,
128    parallels: Vec<S>,
129}
130
131impl<S> Paralleled<S> {
132    #[inline]
133    pub fn primary(&self) -> &S {
134        &self.primary
135    }
136
137    #[inline]
138    pub fn parallels(&self) -> &Vec<S> {
139        &self.parallels
140    }
141
142    #[inline]
143    pub fn row(&self, row: usize) -> &S {
144        if row >= 1 {
145            &self.parallels[row - 1]
146        } else {
147            &self.primary
148        }
149    }
150}
151
152impl<S> Paralleled<S> {
153    #[inline]
154    pub fn new(primary: S, parallels: Vec<S>) -> Self {
155        Self { primary, parallels }
156    }
157}
158
159impl<P: Clone, S: Add<P>> Add<P> for Paralleled<S> {
160    type Output = (S::Output, Vec<S::Output>);
161
162    fn add(&mut self, polygon: P) -> (S::Output, Vec<S::Output>) {
163        let mut parallel_outputs = Vec::with_capacity(self.parallels.len());
164
165        for parallel in &mut self.parallels {
166            parallel_outputs.push(parallel.add(polygon.clone()));
167        }
168
169        let primary_output = self.primary.add(polygon);
170        (primary_output, parallel_outputs)
171    }
172}
173
174impl<P: Clone, S: Sub<P>> Sub<P> for Paralleled<S> {
175    type Output = (S::Output, Vec<S::Output>);
176
177    fn sub(&mut self, polygon: P) -> (S::Output, Vec<S::Output>) {
178        let mut parallel_outputs = Vec::with_capacity(self.parallels.len());
179
180        for parallel in &mut self.parallels {
181            parallel_outputs.push(parallel.sub(polygon.clone()));
182        }
183
184        let primary_output = self.primary.sub(polygon);
185        (primary_output, parallel_outputs)
186    }
187}
188
189impl<P: Clone, S: Clip<P>> Clip<P> for Paralleled<S> {
190    type Output = S::Output;
191
192    fn clip(&mut self, polygon: P) -> S::Output {
193        for parallel in &mut self.parallels {
194            parallel.clip(polygon.clone());
195        }
196
197        self.primary.clip(polygon)
198    }
199}
200
201#[cfg(feature = "undoredo")]
202/// `Inflated` that records changes for delta-based Undo/Redo.
203pub type RecordingInflated<K, P = Polygon<K>> = Inflated<RecordingPolygonUnionFind<K, P>, K>;
204
205#[cfg(feature = "undoredo")]
206/// Half-delta of `Inflated`.
207pub type InflatedHalfDelta<IE, K> = Inflated<IE, PhantomData<K>>;
208
209#[cfg(feature = "undoredo")]
210/// Delta of `Inflated` for delta-based Undo/Redo.
211pub type InflatedDelta<IE, K> = Delta<InflatedHalfDelta<IE, K>>;
212
213#[cfg(feature = "undoredo")]
214impl<IE: Clone, IC: Clone + ApplyDelta<IE>, K> ApplyDelta<InflatedHalfDelta<IE, K>>
215    for Inflated<IC, K>
216{
217    fn apply_delta(&mut self, delta: InflatedDelta<IE, K>) {
218        let (removed, inserted) = delta.dissolve();
219
220        let inflatee_delta = Delta::with_removed_inserted(removed.inflatee, inserted.inflatee);
221        self.inflatee.apply_delta(inflatee_delta);
222    }
223}
224
225#[cfg(feature = "undoredo")]
226impl<IE: Clone, IC: FlushDelta<IE>, K> FlushDelta<InflatedHalfDelta<IE, K>> for Inflated<IC, K> {
227    fn flush_delta(&mut self) -> InflatedDelta<IE, K> {
228        let (removed_inflatee, inserted_inflatee) = self.inflatee.flush_delta().dissolve();
229
230        Delta::with_removed_inserted(
231            Inflated {
232                inflatee: removed_inflatee,
233                offset: PhantomData,
234            },
235            Inflated {
236                inflatee: inserted_inflatee,
237                offset: PhantomData,
238            },
239        )
240    }
241}
242
243#[cfg(feature = "undoredo")]
244/// `Negated` that records changes for delta-based Undo/Redo.
245pub type RecordingNegated<K, P = Polygon<K>> =
246    Negated<RecordingPolygonSet<K, P>, RecordingInflated<K, P>>;
247
248#[cfg(feature = "undoredo")]
249/// Half-delta of `Negated`.
250pub type NegatedHalfDelta<ME, SE> = Negated<ME, SE>;
251
252#[cfg(feature = "undoredo")]
253/// Delta of `Negated` for delta-based Undo/Redo.
254pub type NegatedDelta<ME, SE> = Delta<NegatedHalfDelta<ME, SE>>;
255
256#[cfg(feature = "undoredo")]
257impl<ME: Clone, M: Clone + ApplyDelta<ME>, SE: Clone, S: Clone + ApplyDelta<SE>>
258    ApplyDelta<NegatedHalfDelta<ME, SE>> for Negated<M, S>
259{
260    fn apply_delta(&mut self, delta: NegatedDelta<ME, SE>) {
261        let (removed, inserted) = delta.dissolve();
262
263        let minuend_delta = Delta::with_removed_inserted(removed.minuend, inserted.minuend);
264        self.minuend.apply_delta(minuend_delta);
265
266        let subtrahend_delta =
267            Delta::with_removed_inserted(removed.subtrahend, inserted.subtrahend);
268        self.subtrahend.apply_delta(subtrahend_delta);
269    }
270}
271
272#[cfg(feature = "undoredo")]
273impl<ME: Clone, M: FlushDelta<ME>, SE: Clone, S: FlushDelta<SE>>
274    FlushDelta<NegatedHalfDelta<ME, SE>> for Negated<M, S>
275{
276    fn flush_delta(&mut self) -> NegatedDelta<ME, SE> {
277        let (removed_minuend, inserted_minuend) = self.minuend.flush_delta().dissolve();
278        let (removed_subtrahend, inserted_subtrahend) = self.subtrahend.flush_delta().dissolve();
279
280        Delta::with_removed_inserted(
281            Negated {
282                minuend: removed_minuend,
283                subtrahend: removed_subtrahend,
284            },
285            Negated {
286                minuend: inserted_minuend,
287                subtrahend: inserted_subtrahend,
288            },
289        )
290    }
291}
292
293#[cfg(feature = "undoredo")]
294/// `Paralleled` that records changes for delta-based Undo/Redo.
295pub type RecordingParalleled<K, P = Polygon<K>> = Paralleled<RecordingNegated<K, P>>;
296
297#[cfg(feature = "undoredo")]
298/// Half-delta of `Paralleled`.
299pub type ParalleledHalfDelta<SE> = Paralleled<SE>;
300
301#[cfg(feature = "undoredo")]
302/// Delta of `Paralleled` for delta-based Undo/Redo.
303pub type ParalleledDelta<SE> = Delta<ParalleledHalfDelta<SE>>;
304
305#[cfg(feature = "undoredo")]
306impl<SE: Clone, S: Clone + ApplyDelta<SE>> ApplyDelta<ParalleledHalfDelta<SE>> for Paralleled<S> {
307    fn apply_delta(&mut self, delta: ParalleledDelta<SE>) {
308        let (removed, inserted) = delta.dissolve();
309
310        let primary_delta = Delta::with_removed_inserted(removed.primary, inserted.primary);
311        self.primary.apply_delta(primary_delta);
312
313        for (parallel, (removed_parallel, inserted_parallel)) in self.parallels.iter_mut().zip(
314            removed
315                .parallels
316                .into_iter()
317                .zip(inserted.parallels.into_iter()),
318        ) {
319            parallel.apply_delta(Delta::with_removed_inserted(
320                removed_parallel,
321                inserted_parallel,
322            ));
323        }
324    }
325}
326
327#[cfg(feature = "undoredo")]
328impl<SE: Clone, S: FlushDelta<SE>> FlushDelta<ParalleledHalfDelta<SE>> for Paralleled<S> {
329    fn flush_delta(&mut self) -> ParalleledDelta<SE> {
330        let (removed_primary, inserted_primary) = self.primary.flush_delta().dissolve();
331
332        let mut removed_parallels = Vec::with_capacity(self.parallels.len());
333        let mut inserted_parallels = Vec::with_capacity(self.parallels.len());
334
335        for parallel in &mut self.parallels {
336            let (removed_parallel, inserted_parallel) = parallel.flush_delta().dissolve();
337            removed_parallels.push(removed_parallel);
338            inserted_parallels.push(inserted_parallel);
339        }
340
341        Delta::with_removed_inserted(
342            Paralleled {
343                primary: removed_primary,
344                parallels: removed_parallels,
345            },
346            Paralleled {
347                primary: inserted_primary,
348                parallels: inserted_parallels,
349            },
350        )
351    }
352}