1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-01-20 20:31:06 +00:00

feat(core/rust): introduce f32 angles for sector drawing

[no changelog]
This commit is contained in:
cepetr 2024-05-16 16:12:03 +02:00 committed by cepetr
parent e3a383526b
commit f03e4c8d9c
4 changed files with 25 additions and 40 deletions

View File

@ -4,7 +4,7 @@ use crate::ui::{
}; };
use super::super::{ use super::super::{
utils::{circle_points, line_points, sin_i16, PI4}, utils::{circle_points, line_points, sin_f32},
BitmapView, Viewport, BitmapView, Viewport,
}; };
@ -576,12 +576,12 @@ pub trait Canvas: BasicCanvas {
&mut self, &mut self,
center: Point, center: Point,
radius: i16, radius: i16,
mut start: i16, mut start: f32,
mut end: i16, mut end: f32,
color: Color, color: Color,
) { ) {
start = (PI4 * 8 + start % (PI4 * 8)) % (PI4 * 8); start = (360.0 + start % 360.0) % 360.0;
end = (PI4 * 8 + end % (PI4 * 8)) % (PI4 * 8); end = (360.0 + end % 360.0) % 360.0;
let alpha = 255; let alpha = 255;
let alpha_mul = |a: u8| -> u8 { ((a as u16 * alpha as u16) / 255) as u8 }; let alpha_mul = |a: u8| -> u8 { ((a as u16 * alpha as u16) / 255) as u8 };
@ -591,12 +591,14 @@ pub trait Canvas: BasicCanvas {
self.draw_pixel(center, color); self.draw_pixel(center, color);
} }
const PI4: f32 = 45.0;
for octant in 0..8 { for octant in 0..8 {
let angle = octant * PI4; let angle = PI4 * octant as f32;
// Function for calculation of 'u' coordinate inside the circle octant // Function for calculation of 'u' coordinate inside the circle octant
// radius * sin(angle) // radius * sin(angle)
let sin = |angle: i16| -> i16 { sin_i16(angle, radius) }; let sin = |angle: f32| -> i16 { (sin_f32(angle) * radius as f32 + 0.5) as i16 };
// Calculate the octant's bounding rectangle // Calculate the octant's bounding rectangle
let p = Point::new(sin(PI4) + 1, -radius - 1).rot(octant); let p = Point::new(sin(PI4) + 1, -radius - 1).rot(octant);
@ -660,7 +662,7 @@ pub trait Canvas: BasicCanvas {
} else { } else {
// Partial fill // Partial fill
let u1 = if start <= angle { let u1 = if start <= angle {
sin(corr(0)) sin(corr(0.0))
} else { } else {
sin(corr(start - angle)) sin(corr(start - angle))
}; };
@ -682,7 +684,7 @@ pub trait Canvas: BasicCanvas {
// Partial fill // Partial fill
if (end > angle) && (end < angle + PI4) { if (end > angle) && (end < angle + PI4) {
// Fill up to `end` // Fill up to `end`
fill_octant(radius, sin(corr(0)), sin(corr(end - angle)), filler); fill_octant(radius, sin(corr(0.0)), sin(corr(end - angle)), filler);
} }
if start < angle + PI4 { if start < angle + PI4 {
// Fill all from `start` // Fill all from `start`

View File

@ -15,8 +15,8 @@ pub struct Circle {
bg_color: Option<Color>, bg_color: Option<Color>,
thickness: i16, thickness: i16,
alpha: u8, alpha: u8,
start_angle: Option<i16>, start_angle: Option<f32>,
end_angle: Option<i16>, end_angle: Option<f32>,
} }
impl Circle { impl Circle {
@ -55,14 +55,14 @@ impl Circle {
Self { alpha, ..self } Self { alpha, ..self }
} }
pub fn with_start_angle(self, from_angle: i16) -> Self { pub fn with_start_angle(self, from_angle: f32) -> Self {
Self { Self {
start_angle: Some(from_angle), start_angle: Some(from_angle),
..self ..self
} }
} }
pub fn with_end_angle(self, to_angle: i16) -> Self { pub fn with_end_angle(self, to_angle: f32) -> Self {
Self { Self {
end_angle: Some(to_angle), end_angle: Some(to_angle),
..self ..self
@ -119,8 +119,8 @@ impl Shape<'_> for Circle {
} }
} }
} else { } else {
let start = self.start_angle.unwrap_or(0); let start = self.start_angle.unwrap_or(0.0);
let end = self.end_angle.unwrap_or(360); let end = self.end_angle.unwrap_or(360.0);
if let Some(color) = self.fg_color { if let Some(color) = self.fg_color {
if th > 0 { if th > 0 {

View File

@ -6,4 +6,4 @@ mod trigo;
pub use blur::{BlurAlgorithm, BlurBuff}; pub use blur::{BlurAlgorithm, BlurBuff};
pub use circle::circle_points; pub use circle::circle_points;
pub use line::line_points; pub use line::line_points;
pub use trigo::{sin_i16, PI4}; pub use trigo::sin_f32;

View File

@ -1,29 +1,12 @@
/// Integer representing an angle of 45 degress (PI/4).
//
// Changing this constant requires revisiting isin() algorithm
// (for higher values consider changing T type to i64 or f32)
pub const PI4: i16 = 45;
/// Fast sine approximation. /// Fast sine approximation.
/// ///
/// Returns mult * sin(angle). /// Returns sin(angle).
/// ///
/// Angle must be in range <0..PI4>. /// Angle must be in range <0..45>.
/// This function provides an error within +-1 for multiplier up to 500 pub fn sin_f32(angle: f32) -> f32 {
pub fn sin_i16(angle: i16, mult: i16) -> i16 { assert!((0.0..=45.0).contains(&angle));
assert!((0..=PI4).contains(&angle));
assert!(mult <= 2500);
type T = i32; // Applying the approximation x - x^3 / 6
let x = (angle / 180.0) * core::f32::consts::PI;
// Based on polynomial x - x^3 / 6 x - x * x * x / 6.0
let x = angle as T;
// Constants for the approximation
const K: f32 = (PI4 as f32) * 4.0 / core::f32::consts::PI;
const M: T = (6.0 * K * K + 0.5) as T;
const N: T = (6.0 * K * K * K + 0.5) as T;
// Applying the approximation
(((M * x - x * x * x) * mult as T + N / 2) / N) as i16
} }