You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
158: Make `Take` iterator for gradient inclusive of both end colors, add tests r=Ogeon a=okaneco
As mentioned in the third point of #156, this PR includes the bounds of the gradient along with more equal distribution of colors returned from the iterator.
In the current version of the iterator, `(self.from_head) / (self.len)` will approach 1 but never equal 1 which results in the upper gradient bound being excluded. The current behavior of `take()` is surprising if one expects the last color step to be the max color of the gradient. This PR increases step distance so the user receives an iterator of colors that evenly traverses from the minimum bound of the gradient to the maximum. The step is increased by subtracting 1 from `self.len` in the calculation of `i`. The calculation for `i` will then include
- `0` when `self.from_head` is `0`
- `1` when `self.from_head == self.len - 1`.
The assignment of `i` has a conditional for when `self.len` is `1`. This avoids division by 0 which results in NaN parameters for the iterator color returned in the case of `take(1)`. The check needed to be added to the `DoubleEndedIterator`, otherwise it would NaN on `1` as well. The behavior of `take(1)` before this PR is to supply the minimum color in the gradient.
Pictured below is an example of the difference between current behavior and this PR in 3 sets of Lch gradients. The 1st, 3rd, and 5th rows are the current implementation of the iterator and the others are from the PR with the final step being inclusive of the maximum gradient color specified. The gradients are no longer skewed towards the beginning. The penultimate steps are very close to the current behavior's final step.

---
`gradient::test::simple_slice` fails as a result of this PR.
```
---- gradient::test::simple_slice stdout ----
thread 'gradient::test::simple_slice' panicked at 'assert_relative_eq!(t1, t2)
left = Rgb { red: 0.8888888888888888, green: 0.0, blue: 0.1111111111111111, standard: PhantomData }
right = Rgb { red: 0.875, green: 0.0, blue: 0.125, standard: PhantomData }
', palette/src/gradient.rs:453:13
```
```rust
#[test]
fn simple_slice() {
let g1 = Gradient::new(vec![
LinSrgb::new(1.0, 0.0, 0.0),
LinSrgb::new(0.0, 0.0, 1.0),
]);
let g2 = g1.slice(..0.5);
let v1: Vec<_> = g1.take(10).take(5).collect();
let v2: Vec<_> = g2.take(5).collect();
for (t1, t2) in v1.iter().zip(v2.iter()) {
assert_relative_eq!(t1, t2);
}
}
```
Co-authored-by: okaneco <47607823+okaneco@users.noreply.github.com>
Copy file name to clipboardexpand all lines: README.md
+2-2
Original file line number
Diff line number
Diff line change
@@ -99,7 +99,7 @@ This results in the following three colors:
99
99
100
100
There is also a linear gradient type which makes it easy to interpolate between a series of colors. This gradient can be used in any color space and it can be used to make color sequence iterators.
101
101
102
-
The following example shows two gradients between the same two endpoints, but one is in RGB and the other in is HSV space.
102
+
The following example shows three gradients between the same two endpoints, but the top is in RGB space while the middle and bottom are in HSV space. The bottom gradient is an example of using the color sequence iterator.
103
103
104
104
```Rust
105
105
externcrate palette;
@@ -116,7 +116,7 @@ let grad2 = Gradient::new(vec![
116
116
]);
117
117
```
118
118
119
-
The RGB gradient goes through gray, while the HSV gradients changes only the hue:
119
+
The RGB gradient goes through gray, while the HSV gradients only change hue:
0 commit comments