topola/crates/specctra-core/src/math.rs

92 lines
2.2 KiB
Rust

// SPDX-FileCopyrightText: 2024 Topola contributors
//
// SPDX-License-Identifier: MIT
use core::{fmt, ops::Sub};
use geo_types::geometry::Point;
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct Circle {
pub pos: Point,
pub r: f64,
}
#[derive(Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct PointWithRotation {
pub pos: Point,
pub rot: f64,
}
impl fmt::Debug for Circle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Circle")
.field("x", &self.pos.0.x)
.field("y", &self.pos.0.y)
.field("r", &self.r)
.finish()
}
}
impl Circle {
/// Calculate the point that lies on the circle at angle `phi`,
/// relative to coordinate axes.
///
/// `phi` is the angle given in radians starting at `(r, 0)`.
pub fn position_at_angle(&self, phi: f64) -> Point {
geo_types::point! {
x: self.pos.0.x + self.r * phi.cos(),
y: self.pos.0.y + self.r * phi.sin()
}
}
/// The (x,y) axis aligned bounding box for this circle.
#[cfg(feature = "rstar")]
pub fn bbox(&self, margin: f64) -> rstar::AABB<[f64; 2]> {
let r = self.r + margin;
rstar::AABB::from_corners(
[self.pos.0.x - r, self.pos.0.y - r],
[self.pos.0.x + r, self.pos.0.y + r],
)
}
}
impl Sub for Circle {
type Output = Self;
fn sub(self, other: Self) -> Self {
Self {
pos: self.pos - other.pos,
r: self.r,
}
}
}
impl fmt::Debug for PointWithRotation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PointWithRotation")
.field("x", &self.pos.0.x)
.field("y", &self.pos.0.y)
.field("rot", &self.rot)
.finish()
}
}
impl Default for PointWithRotation {
fn default() -> Self {
Self {
pos: (0.0, 0.0).into(),
rot: 0.0,
}
}
}
impl PointWithRotation {
pub fn from_xy(x: f64, y: f64) -> Self {
Self {
pos: (x, y).into(),
rot: 0.0,
}
}
}