mirror of https://codeberg.org/topola/topola.git
Revert "feat(math): introduce dedicated data type for normalized angles"
This reverts commit b4fe7006b7.
The reverted commit introduced an autorouter regression, observable
in 4x_3rd_order_smd_lc_filters test using egui (see Matrix chat).
This commit is contained in:
parent
c52db50e29
commit
3201df50bd
|
|
@ -266,7 +266,8 @@ impl BendShape {
|
|||
}
|
||||
|
||||
pub fn start_angle(&self) -> f64 {
|
||||
*math::NormalizedAngle::atan2(self.from - self.inner_circle.pos)
|
||||
let r = self.from - self.inner_circle.pos;
|
||||
math::vector_angle(r)
|
||||
}
|
||||
|
||||
pub fn spanned_angle(&self) -> f64 {
|
||||
|
|
@ -279,7 +280,11 @@ impl BendShape {
|
|||
|
||||
// atan2 returns values normalized into the range (-pi, pi]
|
||||
// so for angles below 0 we add 1 winding to get a nonnegative angle
|
||||
angle.non_negative()
|
||||
if angle < 0.0 {
|
||||
angle + TAU
|
||||
} else {
|
||||
angle
|
||||
}
|
||||
}
|
||||
|
||||
/// Render this bend as a list of points on its circle.
|
||||
|
|
|
|||
136
src/math/mod.rs
136
src/math/mod.rs
|
|
@ -2,7 +2,6 @@
|
|||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use core::{cmp, ops};
|
||||
use geo::algorithm::line_measures::{Distance, Euclidean};
|
||||
use geo::{geometry::Point, point, Line};
|
||||
pub use specctra_core::math::{Circle, PointWithRotation};
|
||||
|
|
@ -98,139 +97,18 @@ pub fn between_vectors(p: Point, from: Point, to: Point) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
/// An angle that is measured counterclockwise and normalized into range (-pi, pi] (like atan2).
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct NormalizedAngle(f64);
|
||||
|
||||
impl cmp::PartialOrd for NormalizedAngle {
|
||||
#[inline(always)]
|
||||
fn partial_cmp(&self, oth: &Self) -> Option<cmp::Ordering> {
|
||||
Some(self.cmp(oth))
|
||||
}
|
||||
}
|
||||
|
||||
impl cmp::Ord for NormalizedAngle {
|
||||
#[inline(always)]
|
||||
fn cmp(&self, oth: &Self) -> cmp::Ordering {
|
||||
self.0.total_cmp(&oth.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl cmp::PartialEq for NormalizedAngle {
|
||||
fn eq(&self, oth: &Self) -> bool {
|
||||
self.cmp(oth) == cmp::Ordering::Equal
|
||||
}
|
||||
}
|
||||
|
||||
impl cmp::Eq for NormalizedAngle {}
|
||||
|
||||
impl NormalizedAngle {
|
||||
pub const ZERO: Self = Self(0.0);
|
||||
|
||||
fn normalize_single_step(mut angle: f64) -> Self {
|
||||
use core::f64::consts::{PI, TAU};
|
||||
if !(angle.is_nan() || angle.is_infinite()) {
|
||||
if angle <= -PI {
|
||||
angle += TAU;
|
||||
}
|
||||
if angle > PI {
|
||||
angle -= TAU;
|
||||
}
|
||||
assert!((-PI..PI).contains(&(-angle)));
|
||||
}
|
||||
Self(angle)
|
||||
}
|
||||
|
||||
/// Computes the (directed) angle between the positive X axis and the vector.
|
||||
#[inline]
|
||||
pub fn atan2(pt: Point) -> Self {
|
||||
NormalizedAngle(pt.0.x.atan2(pt.0.y))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn non_negative(self) -> f64 {
|
||||
let mut angle = self.0;
|
||||
if angle < 0.0 {
|
||||
angle + core::f64::consts::TAU
|
||||
} else {
|
||||
angle
|
||||
}
|
||||
}
|
||||
|
||||
/// Rotate this angle by 180°
|
||||
#[must_use]
|
||||
pub fn flip(self) -> Self {
|
||||
Self::normalize_single_step(self.0 + core::f64::consts::PI)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for NormalizedAngle {
|
||||
fn from(mut angle: f64) -> Self {
|
||||
use core::f64::consts::{PI, TAU};
|
||||
if !(angle.is_nan() || angle.is_infinite()) {
|
||||
while angle <= -PI {
|
||||
angle += TAU;
|
||||
}
|
||||
while angle > PI {
|
||||
angle -= TAU;
|
||||
}
|
||||
debug_assert!((-PI..PI).contains(&(-angle)));
|
||||
}
|
||||
Self(angle)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Deref for NormalizedAngle {
|
||||
type Target = f64;
|
||||
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &f64 {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Add for NormalizedAngle {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, oth: Self) -> Self {
|
||||
Self::normalize_single_step(self.0 + oth.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::AddAssign for NormalizedAngle {
|
||||
fn add_assign(&mut self, oth: Self) {
|
||||
*self = Self::normalize_single_step(self.0 + oth.0);
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Sub for NormalizedAngle {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, oth: Self) -> Self {
|
||||
Self::normalize_single_step(self.0 - oth.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::SubAssign for NormalizedAngle {
|
||||
fn sub_assign(&mut self, oth: Self) {
|
||||
*self = Self::normalize_single_step(self.0 - oth.0);
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::MulAssign<f64> for NormalizedAngle {
|
||||
fn mul_assign(&mut self, oth: f64) {
|
||||
*self = (self.0 * oth).into();
|
||||
}
|
||||
/// Computes the (directed) angle between the positive X axis and the vector.
|
||||
///
|
||||
/// The result is measured counterclockwise and normalized into range (-pi, pi] (like atan2).
|
||||
pub fn vector_angle(vector: Point) -> f64 {
|
||||
vector.y().atan2(vector.x())
|
||||
}
|
||||
|
||||
/// Computes the (directed) angle between two vectors.
|
||||
///
|
||||
/// The result is measured counterclockwise and normalized into range (-pi, pi] (like atan2).
|
||||
pub fn angle_between(v1: Point, v2: Point) -> NormalizedAngle {
|
||||
NormalizedAngle::atan2(geo::point! {
|
||||
x: dot_product(v1, v2),
|
||||
y: perp_dot_product(v1, v2)
|
||||
})
|
||||
pub fn angle_between(v1: Point, v2: Point) -> f64 {
|
||||
perp_dot_product(v1, v2).atan2(dot_product(v1, v2))
|
||||
}
|
||||
|
||||
pub fn seq_perp_dot_product(start: Point, stop: Point, reference: Point) -> f64 {
|
||||
|
|
|
|||
Loading…
Reference in New Issue