use std::fmt;
use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Point {
pub x: i32,
pub y: i32,
}
impl Point {
pub fn new(x: i32, y: i32) -> Self {
Self { x, y }
}
pub fn origin() -> Self {
Self::new(0, 0)
}
pub fn distance_to(&self, other: &Point) -> f64 {
let dx = (self.x - other.x) as f64;
let dy = (self.y - other.y) as f64;
(dx * dx + dy * dy).sqrt()
}
pub fn dot(&self, other: &Point) -> i32 {
self.x * other.x + self.y * other.y
}
}
impl Default for Point {
fn default() -> Self {
Self::origin()
}
}
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
impl From<(i32, i32)> for Point {
fn from((x, y): (i32, i32)) -> Self {
Self::new(x, y)
}
}
impl From<Point> for (i32, i32) {
fn from(point: Point) -> Self {
(point.x, point.y)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Point2f {
pub x: f32,
pub y: f32,
}
impl Point2f {
pub fn new(x: f32, y: f32) -> Self {
Self { x, y }
}
pub fn origin() -> Self {
Self::new(0.0, 0.0)
}
pub fn distance_to(&self, other: &Point2f) -> f32 {
let dx = self.x - other.x;
let dy = self.y - other.y;
(dx * dx + dy * dy).sqrt()
}
pub fn dot(&self, other: &Point2f) -> f32 {
self.x * other.x + self.y * other.y
}
pub fn normalize(&self) -> Point2f {
let len = (self.x * self.x + self.y * self.y).sqrt();
if len > 0.0 {
Point2f::new(self.x / len, self.y / len)
} else {
*self
}
}
}
impl Default for Point2f {
fn default() -> Self {
Self::origin()
}
}
impl fmt::Display for Point2f {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({:.2}, {:.2})", self.x, self.y)
}
}
impl From<(f32, f32)> for Point2f {
fn from((x, y): (f32, f32)) -> Self {
Self::new(x, y)
}
}
impl From<Point2f> for (f32, f32) {
fn from(point: Point2f) -> Self {
(point.x, point.y)
}
}
impl From<Point> for Point2f {
fn from(point: Point) -> Self {
Self::new(point.x as f32, point.y as f32)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Point2d {
pub x: f64,
pub y: f64,
}
impl Point2d {
pub fn new(x: f64, y: f64) -> Self {
Self { x, y }
}
pub fn origin() -> Self {
Self::new(0.0, 0.0)
}
pub fn distance_to(&self, other: &Point2d) -> f64 {
let dx = self.x - other.x;
let dy = self.y - other.y;
(dx * dx + dy * dy).sqrt()
}
pub fn dot(&self, other: &Point2d) -> f64 {
self.x * other.x + self.y * other.y
}
pub fn normalize(&self) -> Point2d {
let len = (self.x * self.x + self.y * self.y).sqrt();
if len > 0.0 {
Point2d::new(self.x / len, self.y / len)
} else {
*self
}
}
}
impl Default for Point2d {
fn default() -> Self {
Self::origin()
}
}
impl fmt::Display for Point2d {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({:.6}, {:.6})", self.x, self.y)
}
}
impl From<(f64, f64)> for Point2d {
fn from((x, y): (f64, f64)) -> Self {
Self::new(x, y)
}
}
impl From<Point2d> for (f64, f64) {
fn from(point: Point2d) -> Self {
(point.x, point.y)
}
}
impl From<Point2f> for Point2d {
fn from(point: Point2f) -> Self {
Self::new(point.x as f64, point.y as f64)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Point3f {
pub x: f32,
pub y: f32,
pub z: f32,
}
impl Point3f {
pub fn new(x: f32, y: f32, z: f32) -> Self {
Self { x, y, z }
}
pub fn origin() -> Self {
Self::new(0.0, 0.0, 0.0)
}
pub fn distance_to(&self, other: &Point3f) -> f32 {
let dx = self.x - other.x;
let dy = self.y - other.y;
let dz = self.z - other.z;
(dx * dx + dy * dy + dz * dz).sqrt()
}
pub fn dot(&self, other: &Point3f) -> f32 {
self.x * other.x + self.y * other.y + self.z * other.z
}
pub fn cross(&self, other: &Point3f) -> Point3f {
Point3f::new(
self.y * other.z - self.z * other.y,
self.z * other.x - self.x * other.z,
self.x * other.y - self.y * other.x,
)
}
pub fn normalize(&self) -> Point3f {
let len = (self.x * self.x + self.y * self.y + self.z * self.z).sqrt();
if len > 0.0 {
Point3f::new(self.x / len, self.y / len, self.z / len)
} else {
*self
}
}
}
impl Default for Point3f {
fn default() -> Self {
Self::origin()
}
}
impl fmt::Display for Point3f {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({:.2}, {:.2}, {:.2})", self.x, self.y, self.z)
}
}
impl From<(f32, f32, f32)> for Point3f {
fn from((x, y, z): (f32, f32, f32)) -> Self {
Self::new(x, y, z)
}
}
impl From<Point3f> for (f32, f32, f32) {
fn from(point: Point3f) -> Self {
(point.x, point.y, point.z)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Point3d {
pub x: f64,
pub y: f64,
pub z: f64,
}
impl Point3d {
pub fn new(x: f64, y: f64, z: f64) -> Self {
Self { x, y, z }
}
pub fn origin() -> Self {
Self::new(0.0, 0.0, 0.0)
}
pub fn distance_to(&self, other: &Point3d) -> f64 {
let dx = self.x - other.x;
let dy = self.y - other.y;
let dz = self.z - other.z;
(dx * dx + dy * dy + dz * dz).sqrt()
}
pub fn dot(&self, other: &Point3d) -> f64 {
self.x * other.x + self.y * other.y + self.z * other.z
}
pub fn cross(&self, other: &Point3d) -> Point3d {
Point3d::new(
self.y * other.z - self.z * other.y,
self.z * other.x - self.x * other.z,
self.x * other.y - self.y * other.x,
)
}
pub fn normalize(&self) -> Point3d {
let len = (self.x * self.x + self.y * self.y + self.z * self.z).sqrt();
if len > 0.0 {
Point3d::new(self.x / len, self.y / len, self.z / len)
} else {
*self
}
}
}
impl Default for Point3d {
fn default() -> Self {
Self::origin()
}
}
impl fmt::Display for Point3d {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({:.6}, {:.6}, {:.6})", self.x, self.y, self.z)
}
}
impl From<(f64, f64, f64)> for Point3d {
fn from((x, y, z): (f64, f64, f64)) -> Self {
Self::new(x, y, z)
}
}
impl From<Point3d> for (f64, f64, f64) {
fn from(point: Point3d) -> Self {
(point.x, point.y, point.z)
}
}
impl From<Point3f> for Point3d {
fn from(point: Point3f) -> Self {
Self::new(point.x as f64, point.y as f64, point.z as f64)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_point_creation() {
let p = Point::new(10, 20);
assert_eq!(p.x, 10);
assert_eq!(p.y, 20);
}
#[test]
fn test_point_distance() {
let p1 = Point::new(0, 0);
let p2 = Point::new(3, 4);
assert_eq!(p1.distance_to(&p2), 5.0);
}
#[test]
fn test_point3d_cross_product() {
let p1 = Point3d::new(1.0, 0.0, 0.0);
let p2 = Point3d::new(0.0, 1.0, 0.0);
let cross = p1.cross(&p2);
assert_eq!(cross, Point3d::new(0.0, 0.0, 1.0));
}
}