Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use radians type in arc and ellipse #2029

Merged
merged 2 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Update `wgpu` to `0.17`. [#2065](https://github.com/iced-rs/iced/pull/2065)
- Support automatic style type casting for `Button`. [#2046](https://github.com/iced-rs/iced/pull/2046)
- `with_clip` and `with_save` in `Frame` can now return the data of the provided closure. [#1994](https://github.com/iced-rs/iced/pull/1994)
- `Arc` and `arc::Elliptical` now use `Radians` for angle fields. [#2027](https://github.com/iced-rs/iced/pull/2027)

### Fixed
- Clipping of `TextInput` selection. [#2199](https://github.com/iced-rs/iced/pull/2199)
Expand Down
97 changes: 83 additions & 14 deletions core/src/angle.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{Point, Rectangle, Vector};

use std::f32::consts::{FRAC_PI_2, PI};
use std::ops::RangeInclusive;
use std::ops::{Add, AddAssign, Div, Mul, RangeInclusive, Sub, SubAssign};

/// Degrees
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
Expand All @@ -13,7 +13,26 @@ pub struct Radians(pub f32);

impl Radians {
/// The range of radians of a circle.
pub const RANGE: RangeInclusive<Radians> = Radians(0.0)..=Radians(2.0 * PI);
pub const RANGE: RangeInclusive<Self> = Self(0.0)..=Self(2.0 * PI);

/// The amount of radians in half a circle.
pub const PI: Self = Self(PI);

/// Calculates the line in which the angle intercepts the `bounds`.
pub fn to_distance(&self, bounds: &Rectangle) -> (Point, Point) {
let angle = self.0 - FRAC_PI_2;
let r = Vector::new(f32::cos(angle), f32::sin(angle));

let distance_to_rect = f32::max(
f32::abs(r.x * bounds.width / 2.0),
f32::abs(r.y * bounds.height / 2.0),
);

let start = bounds.center() - r * distance_to_rect;
let end = bounds.center() + r * distance_to_rect;

(start, end)
}
}

impl From<Degrees> for Radians {
Expand Down Expand Up @@ -54,20 +73,70 @@ impl num_traits::FromPrimitive for Radians {
}
}

impl Radians {
/// Calculates the line in which the angle intercepts the `bounds`.
pub fn to_distance(&self, bounds: &Rectangle) -> (Point, Point) {
let angle = self.0 - FRAC_PI_2;
let r = Vector::new(f32::cos(angle), f32::sin(angle));
impl Sub for Radians {
type Output = Self;

let distance_to_rect = f32::max(
f32::abs(r.x * bounds.width / 2.0),
f32::abs(r.y * bounds.height / 2.0),
);
fn sub(self, rhs: Self) -> Self::Output {
Self(self.0 - rhs.0)
}
}

let start = bounds.center() - r * distance_to_rect;
let end = bounds.center() + r * distance_to_rect;
impl SubAssign for Radians {
fn sub_assign(&mut self, rhs: Self) {
self.0 = self.0 - rhs.0;
}
}

(start, end)
impl Add for Radians {
type Output = Self;

fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0)
}
}

impl AddAssign for Radians {
fn add_assign(&mut self, rhs: Radians) {
self.0 = self.0 + rhs.0;
}
}

impl Mul for Radians {
type Output = Self;

fn mul(self, rhs: Radians) -> Self::Output {
Radians(self.0 * rhs.0)
}
}

impl Mul<f32> for Radians {
type Output = Self;

fn mul(self, rhs: f32) -> Self::Output {
Self(self.0 * rhs)
}
}

impl Mul<Radians> for f32 {
type Output = Radians;

fn mul(self, rhs: Radians) -> Self::Output {
Radians(self * rhs.0)
}
}

impl Div<f32> for Radians {
type Output = Self;

fn div(self, rhs: f32) -> Self::Output {
Radians(self.0 / rhs)
}
}

impl Div for Radians {
type Output = Self;

fn div(self, rhs: Self) -> Self::Output {
Self(self.0 / rhs.0)
}
}
21 changes: 11 additions & 10 deletions examples/loading_spinners/src/circular.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,17 @@ use iced::time::Instant;
use iced::widget::canvas;
use iced::window::{self, RedrawRequest};
use iced::{
Background, Color, Element, Event, Length, Rectangle, Renderer, Size,
Vector,
Background, Color, Element, Event, Length, Radians, Rectangle, Renderer,
Size, Vector,
};

use super::easing::{self, Easing};

use std::f32::consts::PI;
use std::time::Duration;

const MIN_RADIANS: f32 = PI / 8.0;
const WRAP_RADIANS: f32 = 2.0 * PI - PI / 4.0;
const MIN_ANGLE: Radians = Radians(PI / 8.0);
const WRAP_ANGLE: Radians = Radians(2.0 * PI - PI / 4.0);
const BASE_ROTATION_SPEED: u32 = u32::MAX / 80;

#[allow(missing_debug_implementations)]
Expand Down Expand Up @@ -139,7 +139,8 @@ impl Animation {
progress: 0.0,
rotation: rotation.wrapping_add(
BASE_ROTATION_SPEED.wrapping_add(
((WRAP_RADIANS / (2.0 * PI)) * u32::MAX as f32) as u32,
(f64::from(WRAP_ANGLE / (2.0 * Radians::PI)) * f64::MAX)
as u32,
),
),
last: now,
Expand Down Expand Up @@ -318,7 +319,7 @@ where

let mut builder = canvas::path::Builder::new();

let start = state.animation.rotation() * 2.0 * PI;
let start = Radians(state.animation.rotation() * 2.0 * PI);

match state.animation {
Animation::Expanding { progress, .. } => {
Expand All @@ -327,17 +328,17 @@ where
radius: track_radius,
start_angle: start,
end_angle: start
+ MIN_RADIANS
+ WRAP_RADIANS * (self.easing.y_at_x(progress)),
+ MIN_ANGLE
+ WRAP_ANGLE * (self.easing.y_at_x(progress)),
});
}
Animation::Contracting { progress, .. } => {
builder.arc(canvas::path::Arc {
center: frame.center(),
radius: track_radius,
start_angle: start
+ WRAP_RADIANS * (self.easing.y_at_x(progress)),
end_angle: start + MIN_RADIANS + WRAP_RADIANS,
+ WRAP_ANGLE * (self.easing.y_at_x(progress)),
end_angle: start + MIN_ANGLE + WRAP_ANGLE,
});
}
}
Expand Down
22 changes: 11 additions & 11 deletions graphics/src/geometry/path/arc.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! Build and draw curves.
use iced_core::{Point, Vector};
use iced_core::{Point, Radians, Vector};

/// A segment of a differentiable curve.
#[derive(Debug, Clone, Copy)]
Expand All @@ -8,10 +8,10 @@ pub struct Arc {
pub center: Point,
/// The radius of the arc.
pub radius: f32,
/// The start of the segment's angle in radians, clockwise rotation from positive x-axis.
pub start_angle: f32,
/// The end of the segment's angle in radians, clockwise rotation from positive x-axis.
pub end_angle: f32,
/// The start of the segment's angle, clockwise rotation from positive x-axis.
pub start_angle: Radians,
/// The end of the segment's angle, clockwise rotation from positive x-axis.
pub end_angle: Radians,
}

/// An elliptical [`Arc`].
Expand All @@ -22,19 +22,19 @@ pub struct Elliptical {
/// The radii of the arc's ellipse. The horizontal and vertical half-dimensions of the ellipse will match the x and y values of the radii vector.
pub radii: Vector,
/// The clockwise rotation of the arc's ellipse.
pub rotation: f32,
/// The start of the segment's angle in radians, clockwise rotation from positive x-axis.
pub start_angle: f32,
/// The end of the segment's angle in radians, clockwise rotation from positive x-axis.
pub end_angle: f32,
pub rotation: Radians,
/// The start of the segment's angle, clockwise rotation from positive x-axis.
pub start_angle: Radians,
/// The end of the segment's angle, clockwise rotation from positive x-axis.
pub end_angle: Radians,
}

impl From<Arc> for Elliptical {
fn from(arc: Arc) -> Elliptical {
Elliptical {
center: arc.center,
radii: Vector::new(arc.radius, arc.radius),
rotation: 0.0,
rotation: Radians(0.0),
start_angle: arc.start_angle,
end_angle: arc.end_angle,
}
Expand Down
14 changes: 8 additions & 6 deletions graphics/src/geometry/path/builder.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::geometry::path::{arc, Arc, Path};

use iced_core::{Point, Size};
use iced_core::{Point, Radians, Size};

use lyon_path::builder::{self, SvgPathBuilder};
use lyon_path::geom;
Expand Down Expand Up @@ -106,9 +106,11 @@ impl Builder {
let arc = geom::Arc {
center: math::Point::new(arc.center.x, arc.center.y),
radii: math::Vector::new(arc.radii.x, arc.radii.y),
x_rotation: math::Angle::radians(arc.rotation),
start_angle: math::Angle::radians(arc.start_angle),
sweep_angle: math::Angle::radians(arc.end_angle - arc.start_angle),
x_rotation: math::Angle::radians(arc.rotation.0),
start_angle: math::Angle::radians(arc.start_angle.0),
sweep_angle: math::Angle::radians(
(arc.end_angle - arc.start_angle).0,
),
};

let _ = self.raw.move_to(arc.sample(0.0));
Expand Down Expand Up @@ -165,8 +167,8 @@ impl Builder {
self.arc(Arc {
center,
radius,
start_angle: 0.0,
end_angle: 2.0 * std::f32::consts::PI,
start_angle: Radians(0.0),
end_angle: Radians(2.0 * std::f32::consts::PI),
});
}

Expand Down
Loading