4
4
//! default).
5
5
6
6
use std:: cmp:: max;
7
+ use std:: ops:: Index ;
7
8
8
9
use approx:: { AbsDiffEq , RelativeEq , UlpsEq } ;
9
10
use num_traits:: { One , Zero } ;
@@ -12,6 +13,57 @@ use crate::float::Float;
12
13
use crate :: Mix ;
13
14
use crate :: { from_f64, FromF64 } ;
14
15
16
+ #[ cfg( feature = "named_gradients" ) ]
17
+ pub mod named;
18
+
19
+ /// Types which represent an ordered collection of known size
20
+ pub trait ArrayLike : Index < usize > {
21
+ /// Returns the number of elements in the collection, also referred to as its 'length'.
22
+ fn len ( & self ) -> usize ;
23
+ /// Returns a reference to the element at the position i or None if out of bounds.
24
+ fn get ( & self , i : usize ) -> Option < & Self :: Output > ;
25
+ /// Returns a pointer to the first element of the collection, or None if it is empty.
26
+ fn first ( & self ) -> Option < & Self :: Output > {
27
+ self . get ( 0 )
28
+ }
29
+ /// Returns a pointer to the last element of the collection, or None if it is empty.
30
+ fn last ( & self ) -> Option < & Self :: Output > {
31
+ self . get ( self . len ( ) - 1 )
32
+ }
33
+ /// Returns true if the collection contains no elements.
34
+ fn is_empty ( & self ) -> bool {
35
+ self . len ( ) == 0
36
+ }
37
+ }
38
+
39
+ impl < T > ArrayLike for Vec < T > {
40
+ fn len ( & self ) -> usize {
41
+ self . len ( )
42
+ }
43
+ fn get ( & self , i : usize ) -> Option < & T > {
44
+ self . as_slice ( ) . get ( i)
45
+ }
46
+ }
47
+
48
+ impl < T , const N : usize > ArrayLike for [ T ; N ] {
49
+ fn len ( & self ) -> usize {
50
+ <[ T ] >:: len ( self )
51
+ }
52
+ fn get ( & self , i : usize ) -> Option < & T > {
53
+ <[ T ] >:: get ( self , i)
54
+ }
55
+ }
56
+
57
+ impl < C , T > From < T > for Gradient < C , T >
58
+ where
59
+ C : Mix + Clone ,
60
+ T : ArrayLike < Output = ( C :: Scalar , C ) >
61
+ {
62
+ fn from ( col : T ) -> Self {
63
+ Gradient ( col)
64
+ }
65
+ }
66
+
15
67
/// A linear interpolation between colors.
16
68
///
17
69
/// It's used to smoothly transition between a series of colors, that can be
@@ -21,36 +73,16 @@ use crate::{from_f64, FromF64};
21
73
/// the domain of the gradient will have the same color as the closest control
22
74
/// point.
23
75
#[ derive( Clone , Debug ) ]
24
- pub struct Gradient < C : Mix + Clone > ( Vec < ( C :: Scalar , C ) > ) ;
25
-
26
- impl < C : Mix + Clone > Gradient < C > {
27
- /// Create a gradient of evenly spaced colors with the domain [0.0, 1.0].
28
- /// There must be at least one color.
29
- pub fn new < I : IntoIterator < Item = C > > ( colors : I ) -> Gradient < C >
30
- where
31
- C :: Scalar : FromF64 ,
32
- {
33
- let mut points: Vec < _ > = colors. into_iter ( ) . map ( |c| ( C :: Scalar :: zero ( ) , c) ) . collect ( ) ;
34
- assert ! ( !points. is_empty( ) ) ;
35
- let step_size = C :: Scalar :: one ( ) / from_f64 ( max ( points. len ( ) - 1 , 1 ) as f64 ) ;
36
-
37
- for ( i, & mut ( ref mut p, _) ) in points. iter_mut ( ) . enumerate ( ) {
38
- * p = from_f64 :: < C :: Scalar > ( i as f64 ) * step_size;
39
- }
40
-
41
- Gradient ( points)
42
- }
43
-
44
- /// Create a gradient of colors with custom spacing and domain. There must
45
- /// be at least one color and they are expected to be ordered by their
46
- /// position value.
47
- pub fn with_domain ( colors : Vec < ( C :: Scalar , C ) > ) -> Gradient < C > {
48
- assert ! ( !colors. is_empty( ) ) ;
49
-
50
- //Maybe sort the colors?
51
- Gradient ( colors)
52
- }
76
+ pub struct Gradient < C , T = Vec < ( <C as Mix >:: Scalar , C ) > > ( T )
77
+ where
78
+ C : Mix + Clone ,
79
+ T : ArrayLike < Output = ( C :: Scalar , C ) > ;
53
80
81
+ impl < C , T > Gradient < C , T >
82
+ where
83
+ C : Mix + Clone ,
84
+ T : ArrayLike < Output = ( C :: Scalar , C ) >
85
+ {
54
86
/// Get a color from the gradient. The color of the closest control point
55
87
/// will be returned if `i` is outside the domain.
56
88
pub fn get ( & self , i : C :: Scalar ) -> C {
@@ -97,6 +129,16 @@ impl<C: Mix + Clone> Gradient<C> {
97
129
min_color. mix ( max_color, factor)
98
130
}
99
131
132
+ /// Create a gradient of colors with custom spacing and domain. There must
133
+ /// be at least one color and they are expected to be ordered by their
134
+ /// position value.
135
+ pub fn with_domain ( colors : T ) -> Gradient < C , T > {
136
+ assert ! ( !colors. is_empty( ) ) ;
137
+
138
+ //Maybe sort the colors?
139
+ Gradient ( colors)
140
+ }
141
+
100
142
/// Take `n` evenly spaced colors from the gradient, as an iterator. The
101
143
/// iterator includes both ends of the gradient, for `n > 1`, or just
102
144
/// the lower end of the gradient for `n = 0`.
@@ -125,7 +167,7 @@ impl<C: Mix + Clone> Gradient<C> {
125
167
/// assert_relative_eq!(c1, c2);
126
168
/// }
127
169
/// ```
128
- pub fn take ( & self , n : usize ) -> Take < C > {
170
+ pub fn take ( & self , n : usize ) -> Take < C , T > {
129
171
let ( min, max) = self . domain ( ) ;
130
172
131
173
Take {
@@ -139,7 +181,7 @@ impl<C: Mix + Clone> Gradient<C> {
139
181
}
140
182
141
183
/// Slice this gradient to limit its domain.
142
- pub fn slice < R : Into < Range < C :: Scalar > > > ( & self , range : R ) -> Slice < C > {
184
+ pub fn slice < R : Into < Range < C :: Scalar > > > ( & self , range : R ) -> Slice < C , T > {
143
185
Slice {
144
186
gradient : self ,
145
187
range : range. into ( ) ,
@@ -160,20 +202,45 @@ impl<C: Mix + Clone> Gradient<C> {
160
202
}
161
203
}
162
204
205
+ impl < C : Mix + Clone > Gradient < C > {
206
+ /// Create a gradient of evenly spaced colors with the domain [0.0, 1.0].
207
+ /// There must be at least one color.
208
+ pub fn new < I : IntoIterator < Item = C > > ( colors : I ) -> Gradient < C >
209
+ where
210
+ C :: Scalar : FromF64 ,
211
+ {
212
+ let mut points: Vec < _ > = colors. into_iter ( ) . map ( |c| ( C :: Scalar :: zero ( ) , c) ) . collect ( ) ;
213
+ assert ! ( !points. is_empty( ) ) ;
214
+ let step_size = C :: Scalar :: one ( ) / from_f64 ( max ( points. len ( ) - 1 , 1 ) as f64 ) ;
215
+
216
+ for ( i, & mut ( ref mut p, _) ) in points. iter_mut ( ) . enumerate ( ) {
217
+ * p = from_f64 :: < C :: Scalar > ( i as f64 ) * step_size;
218
+ }
219
+
220
+ Gradient ( points)
221
+ }
222
+ }
223
+
163
224
/// An iterator over interpolated colors.
164
225
#[ derive( Clone ) ]
165
- pub struct Take < ' a , C : Mix + Clone + ' a > {
166
- gradient : MaybeSlice < ' a , C > ,
226
+ pub struct Take < ' a , C , T = Vec < ( <C as Mix >:: Scalar , C ) > >
227
+ where
228
+ C : Mix + Clone + ' a ,
229
+ T : ArrayLike < Output = ( C :: Scalar , C ) >
230
+ {
231
+ gradient : MaybeSlice < ' a , C , T > ,
167
232
from : C :: Scalar ,
168
233
diff : C :: Scalar ,
169
234
len : usize ,
170
235
from_head : usize ,
171
236
from_end : usize ,
172
237
}
173
238
174
- impl < ' a , C : Mix + Clone > Iterator for Take < ' a , C >
239
+ impl < ' a , C , T > Iterator for Take < ' a , C , T >
175
240
where
176
241
C :: Scalar : FromF64 ,
242
+ C : Mix + Clone ,
243
+ T : ArrayLike < Output = ( C :: Scalar , C ) >
177
244
{
178
245
type Item = C ;
179
246
@@ -202,11 +269,18 @@ where
202
269
}
203
270
}
204
271
205
- impl < ' a , C : Mix + Clone > ExactSizeIterator for Take < ' a , C > where C :: Scalar : FromF64 { }
272
+ impl < ' a , C , T > ExactSizeIterator for Take < ' a , C , T >
273
+ where
274
+ C :: Scalar : FromF64 ,
275
+ C : Mix + Clone ,
276
+ T : ArrayLike < Output = ( C :: Scalar , C ) >
277
+ { }
206
278
207
- impl < ' a , C : Mix + Clone > DoubleEndedIterator for Take < ' a , C >
279
+ impl < ' a , C , T > DoubleEndedIterator for Take < ' a , C , T >
208
280
where
209
281
C :: Scalar : FromF64 ,
282
+ C : Mix + Clone ,
283
+ T : ArrayLike < Output = ( C :: Scalar , C ) >
210
284
{
211
285
fn next_back ( & mut self ) -> Option < Self :: Item > {
212
286
if self . from_head + self . from_end < self . len {
@@ -228,35 +302,29 @@ where
228
302
229
303
/// A slice of a Gradient that limits its domain.
230
304
#[ derive( Clone , Debug ) ]
231
- pub struct Slice < ' a , C : Mix + Clone + ' a > {
232
- gradient : & ' a Gradient < C > ,
305
+ pub struct Slice < ' a , C , T = Vec < ( <C as Mix >:: Scalar , C ) > >
306
+ where
307
+ C : Mix + Clone + ' a ,
308
+ T : ArrayLike < Output = ( C :: Scalar , C ) >
309
+ {
310
+ gradient : & ' a Gradient < C , T > ,
233
311
range : Range < C :: Scalar > ,
234
312
}
235
313
236
- impl < ' a , C : Mix + Clone > Slice < ' a , C > {
314
+ impl < ' a , C , T > Slice < ' a , C , T >
315
+ where
316
+ C : Mix + Clone + ' a ,
317
+ T : ArrayLike < Output = ( C :: Scalar , C ) >
318
+ {
237
319
/// Get a color from the gradient slice. The color of the closest domain
238
320
/// limit will be returned if `i` is outside the domain.
239
321
pub fn get ( & self , i : C :: Scalar ) -> C {
240
322
self . gradient . get ( self . range . clamp ( i) )
241
323
}
242
324
243
- /// Take `n` evenly spaced colors from the gradient slice, as an iterator.
244
- pub fn take ( & self , n : usize ) -> Take < C > {
245
- let ( min, max) = self . domain ( ) ;
246
-
247
- Take {
248
- gradient : MaybeSlice :: Slice ( self . clone ( ) ) ,
249
- from : min,
250
- diff : max - min,
251
- len : n,
252
- from_head : 0 ,
253
- from_end : 0 ,
254
- }
255
- }
256
-
257
325
/// Slice this gradient slice to further limit its domain. Ranges outside
258
326
/// the domain will be clamped to the nearest domain limit.
259
- pub fn slice < R : Into < Range < C :: Scalar > > > ( & self , range : R ) -> Slice < C > {
327
+ pub fn slice < R : Into < Range < C :: Scalar > > > ( & self , range : R ) -> Slice < C , T > {
260
328
Slice {
261
329
gradient : self . gradient ,
262
330
range : self . range . constrain ( & range. into ( ) ) ,
@@ -278,6 +346,26 @@ impl<'a, C: Mix + Clone> Slice<'a, C> {
278
346
}
279
347
}
280
348
349
+ impl < ' a , C , T > Slice < ' a , C , T >
350
+ where
351
+ C : Mix + Clone + ' a ,
352
+ T : ArrayLike < Output = ( C :: Scalar , C ) > + Clone
353
+ {
354
+ /// Take `n` evenly spaced colors from the gradient slice, as an iterator.
355
+ pub fn take ( & self , n : usize ) -> Take < C , T > {
356
+ let ( min, max) = self . domain ( ) ;
357
+
358
+ Take {
359
+ gradient : MaybeSlice :: Slice ( self . clone ( ) ) ,
360
+ from : min,
361
+ diff : max - min,
362
+ len : n,
363
+ from_head : 0 ,
364
+ from_end : 0 ,
365
+ }
366
+ }
367
+ }
368
+
281
369
/// A domain range for gradient slices.
282
370
#[ derive( Clone , Debug , PartialEq ) ]
283
371
pub struct Range < T : Float > {
@@ -449,12 +537,20 @@ where
449
537
}
450
538
451
539
#[ derive( Clone ) ]
452
- enum MaybeSlice < ' a , C : Mix + Clone + ' a > {
453
- NotSlice ( & ' a Gradient < C > ) ,
454
- Slice ( Slice < ' a , C > ) ,
540
+ enum MaybeSlice < ' a , C , T = Vec < ( <C as Mix >:: Scalar , C ) > >
541
+ where
542
+ C : Mix + Clone + ' a ,
543
+ T : ArrayLike < Output = ( C :: Scalar , C ) >
544
+ {
545
+ NotSlice ( & ' a Gradient < C , T > ) ,
546
+ Slice ( Slice < ' a , C , T > ) ,
455
547
}
456
548
457
- impl < ' a , C : Mix + Clone > MaybeSlice < ' a , C > {
549
+ impl < ' a , C , T > MaybeSlice < ' a , C , T >
550
+ where
551
+ C : Mix + Clone + ' a ,
552
+ T : ArrayLike < Output = ( C :: Scalar , C ) >
553
+ {
458
554
fn get ( & self , i : C :: Scalar ) -> C {
459
555
match * self {
460
556
MaybeSlice :: NotSlice ( g) => g. get ( i) ,
0 commit comments