colorutils_rs/
sigmoidal.rs

1/*
2 * // Copyright 2024 (c) the Radzivon Bartoshyk. All rights reserved.
3 * //
4 * // Use of this source code is governed by a BSD-style
5 * // license that can be found in the LICENSE file.
6 */
7use crate::Rgb;
8use std::ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Sub, SubAssign};
9
10#[derive(Debug, PartialOrd, PartialEq, Copy, Clone)]
11/// Represents color as sigmoid function: `y = 1 / (1 + exp(-x))`
12/// and it's inverse
13/// `x = ln(y / (1 - y))`
14pub struct Sigmoidal {
15    pub sr: f32,
16    pub sg: f32,
17    pub sb: f32,
18}
19
20#[inline]
21fn to_sigmoidal(x: f32) -> f32 {
22    let den = 1f32 + (-x).exp();
23    if den == 0f32 {
24        return 0f32;
25    }
26    1f32 / den
27}
28
29#[inline]
30fn inverse_sigmoidal(x: f32) -> f32 {
31    let den = 1f32 - x;
32    if den == 0f32 {
33        return 0f32;
34    }
35    let k = x / den;
36    if k <= 0f32 {
37        return 0f32;
38    }
39    k.ln()
40}
41
42impl Sigmoidal {
43    #[inline]
44    pub fn new(sr: f32, sg: f32, sb: f32) -> Self {
45        Sigmoidal { sr, sg, sb }
46    }
47
48    #[inline]
49    pub fn from_rgb(rgb: Rgb<u8>) -> Self {
50        let normalized = rgb.to_rgb_f32();
51        Sigmoidal::new(
52            to_sigmoidal(normalized.r),
53            to_sigmoidal(normalized.g),
54            to_sigmoidal(normalized.b),
55        )
56    }
57
58    #[inline]
59    pub fn to_rgb(&self) -> Rgb<u8> {
60        let rgb_normalized = Rgb::new(
61            inverse_sigmoidal(self.sr),
62            inverse_sigmoidal(self.sg),
63            inverse_sigmoidal(self.sb),
64        );
65        rgb_normalized.into()
66    }
67}
68
69impl From<Rgb<u8>> for Sigmoidal {
70    #[inline]
71    fn from(value: Rgb<u8>) -> Self {
72        Sigmoidal::from_rgb(value)
73    }
74}
75
76impl From<Rgb<f32>> for Sigmoidal {
77    #[inline]
78    fn from(value: Rgb<f32>) -> Self {
79        Sigmoidal::new(
80            to_sigmoidal(value.r),
81            to_sigmoidal(value.g),
82            to_sigmoidal(value.b),
83        )
84    }
85}
86
87impl Index<usize> for Sigmoidal {
88    type Output = f32;
89
90    fn index(&self, index: usize) -> &f32 {
91        match index {
92            0 => &self.sr,
93            1 => &self.sg,
94            2 => &self.sb,
95            _ => panic!("Index out of bounds for Sigmoidal"),
96        }
97    }
98}
99
100impl IndexMut<usize> for Sigmoidal {
101    fn index_mut(&mut self, index: usize) -> &mut f32 {
102        match index {
103            0 => &mut self.sr,
104            1 => &mut self.sg,
105            2 => &mut self.sb,
106            _ => panic!("Index out of bounds for Sigmoidal"),
107        }
108    }
109}
110
111impl Add<f32> for Sigmoidal {
112    type Output = Sigmoidal;
113
114    #[inline]
115    fn add(self, rhs: f32) -> Self::Output {
116        Sigmoidal::new(self.sr + rhs, self.sg + rhs, self.sb + rhs)
117    }
118}
119
120impl Sub<f32> for Sigmoidal {
121    type Output = Sigmoidal;
122
123    #[inline]
124    fn sub(self, rhs: f32) -> Self::Output {
125        Sigmoidal::new(self.sr - rhs, self.sg - rhs, self.sb - rhs)
126    }
127}
128
129impl Mul<f32> for Sigmoidal {
130    type Output = Sigmoidal;
131
132    #[inline]
133    fn mul(self, rhs: f32) -> Self::Output {
134        Sigmoidal::new(self.sr * rhs, self.sg * rhs, self.sb * rhs)
135    }
136}
137
138impl Div<f32> for Sigmoidal {
139    type Output = Sigmoidal;
140
141    #[inline]
142    fn div(self, rhs: f32) -> Self::Output {
143        Sigmoidal::new(self.sr / rhs, self.sg / rhs, self.sb / rhs)
144    }
145}
146
147impl Add<Sigmoidal> for Sigmoidal {
148    type Output = Sigmoidal;
149
150    #[inline]
151    fn add(self, rhs: Sigmoidal) -> Self::Output {
152        Sigmoidal::new(self.sr + rhs.sr, self.sg + rhs.sg, self.sb + rhs.sb)
153    }
154}
155
156impl Sub<Sigmoidal> for Sigmoidal {
157    type Output = Sigmoidal;
158
159    #[inline]
160    fn sub(self, rhs: Sigmoidal) -> Self::Output {
161        Sigmoidal::new(self.sr - rhs.sr, self.sg - rhs.sg, self.sb - rhs.sb)
162    }
163}
164
165impl Mul<Sigmoidal> for Sigmoidal {
166    type Output = Sigmoidal;
167
168    #[inline]
169    fn mul(self, rhs: Sigmoidal) -> Self::Output {
170        Sigmoidal::new(self.sr * rhs.sr, self.sg * rhs.sg, self.sb * rhs.sb)
171    }
172}
173
174impl Div<Sigmoidal> for Sigmoidal {
175    type Output = Sigmoidal;
176
177    #[inline]
178    fn div(self, rhs: Sigmoidal) -> Self::Output {
179        Sigmoidal::new(self.sr / rhs.sr, self.sg / rhs.sg, self.sb / rhs.sb)
180    }
181}
182
183impl AddAssign<Sigmoidal> for Sigmoidal {
184    #[inline]
185    fn add_assign(&mut self, rhs: Sigmoidal) {
186        self.sr += rhs.sr;
187        self.sg += rhs.sg;
188        self.sb += rhs.sb;
189    }
190}
191
192impl SubAssign<Sigmoidal> for Sigmoidal {
193    #[inline]
194    fn sub_assign(&mut self, rhs: Sigmoidal) {
195        self.sr -= rhs.sr;
196        self.sg -= rhs.sg;
197        self.sb -= rhs.sb;
198    }
199}
200
201impl MulAssign<Sigmoidal> for Sigmoidal {
202    #[inline]
203    fn mul_assign(&mut self, rhs: Sigmoidal) {
204        self.sr *= rhs.sr;
205        self.sg *= rhs.sg;
206        self.sb *= rhs.sb;
207    }
208}
209
210impl DivAssign<Sigmoidal> for Sigmoidal {
211    #[inline]
212    fn div_assign(&mut self, rhs: Sigmoidal) {
213        self.sr /= rhs.sr;
214        self.sg /= rhs.sg;
215        self.sb /= rhs.sb;
216    }
217}
218
219impl AddAssign<f32> for Sigmoidal {
220    #[inline]
221    fn add_assign(&mut self, rhs: f32) {
222        self.sr += rhs;
223        self.sg += rhs;
224        self.sb += rhs;
225    }
226}
227
228impl SubAssign<f32> for Sigmoidal {
229    #[inline]
230    fn sub_assign(&mut self, rhs: f32) {
231        self.sr -= rhs;
232        self.sg -= rhs;
233        self.sb -= rhs;
234    }
235}
236
237impl MulAssign<f32> for Sigmoidal {
238    #[inline]
239    fn mul_assign(&mut self, rhs: f32) {
240        self.sr *= rhs;
241        self.sg *= rhs;
242        self.sb *= rhs;
243    }
244}
245
246impl DivAssign<f32> for Sigmoidal {
247    #[inline]
248    fn div_assign(&mut self, rhs: f32) {
249        self.sr /= rhs;
250        self.sg /= rhs;
251        self.sb /= rhs;
252    }
253}