use derive_more::derive::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
use rand::{
distr::{
StandardUniform,
uniform::{SampleRange, SampleUniform},
},
prelude::*,
};
use std::{
cmp::Ordering,
num::NonZeroU16,
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};
#[derive(
Copy,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
AddAssign,
Add,
Mul,
MulAssign,
Sub,
SubAssign,
Div,
DivAssign,
Default,
)]
#[mul(forward)]
#[div(forward)]
#[mul_assign(forward)]
#[div_assign(forward)]
pub struct Point2d<T = i64> {
pub x: T,
pub y: T,
}
#[derive(PartialEq, Debug, Copy, Clone)]
pub struct Line<T = i64> {
pub start: Point2d<T>,
pub end: Point2d<T>,
}
impl Line {
pub fn get_intersection(self, other: Self) -> Option<Point2d> {
let s10 = self.end - self.start;
let s32 = other.end - other.start;
let denom = s10.x * s32.y - s32.x * s10.y;
if denom == 0 {
return None; }
let denom_positive = denom > 0;
let s02 = self.start - other.start;
let s_numer = s10.x * s02.y - s10.y * s02.x;
if (s_numer < 0) == denom_positive {
return None; }
let t_numer = s32.x * s02.y - s32.y * s02.x;
if (t_numer < 0) == denom_positive {
return None; }
if (s_numer > denom) == denom_positive || (t_numer > denom) == denom_positive {
return None; }
let t = t_numer / denom;
Some(self.start + s10 * t)
}
pub fn bounds(&self) -> Bounds {
Bounds {
min: self.start,
max: self.end,
}
}
pub fn with_manhattan_length(self, len: i64) -> Self {
assert!(len > 0);
let dir = self.end - self.start;
let old_len = dir.x.abs() + dir.y.abs();
let new_dir = dir * len / old_len;
Self {
start: self.start,
end: self.start + new_dir,
}
}
pub fn flip(self) -> Self {
Self {
start: self.end,
end: self.start,
}
}
pub fn len_squared(&self) -> i64 {
(self.end - self.start).len_squared()
}
}
impl<T: Num> Line<T> {
pub fn iter_all_touched_pixels(mut self, mut pnt: impl FnMut(Point2d<T>)) {
let mut k = Point2d::splat(T::ZERO);
self.end -= self.start;
match self.end.x.cmp(&T::ZERO) {
Ordering::Greater => k.x = T::ONE,
Ordering::Equal => {}
Ordering::Less => {
k.x = -T::ONE;
self.end.x = -self.end.x;
}
}
self.end.x += T::ONE;
match self.end.y.cmp(&T::ZERO) {
Ordering::Less => k.y = T::ONE,
Ordering::Equal => {}
Ordering::Greater => {
k.y = -T::ONE;
self.end.y = -self.end.y;
}
}
self.end.y += T::ONE;
let flip = self.end.x >= self.end.y;
if flip {
self.end = self.end.flip();
self.start = self.start.flip();
k = k.flip();
}
let mut pnt = |p: Point2d<T>| if flip { pnt(p.flip()) } else { pnt(p) };
let mut c = self.end.y;
for i in T::iter_range(T::ZERO..self.end.y) {
pnt(self.start); c -= self.end.x;
if c <= T::ZERO {
if i != self.end.y - T::ONE {
pnt(self.start + Point2d::new(T::ZERO, k.y));
}
c += self.end.y;
self.start.x += k.x;
if i != self.end.y - T::ONE {
pnt(self.start);
}
}
self.start.y += k.y
}
}
}
impl<T: std::fmt::Debug> std::fmt::Debug for Point2d<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(&self.x, &self.y).fmt(f)
}
}
impl<T> Distribution<Point2d<T>> for StandardUniform
where
StandardUniform: Distribution<T>,
{
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Point2d<T> {
Point2d {
x: self.sample(rng),
y: self.sample(rng),
}
}
}
impl<T: Copy> Point2d<T> {
pub const fn splat(arg: T) -> Self {
Self::new(arg, arg)
}
pub const fn new(x: T, y: T) -> Self {
Self { x, y }
}
pub fn map<U>(&self, f: impl Fn(T) -> U) -> Point2d<U> {
Point2d {
x: f(self.x),
y: f(self.y),
}
}
pub fn to(self, other: Self) -> Line<T> {
Line {
start: self,
end: other,
}
}
fn flip(self) -> Point2d<T> {
Point2d {
x: self.y,
y: self.x,
}
}
}
impl<T: Neg<Output = T>> Point2d<T> {
pub fn perp(self) -> Self {
Self {
x: -self.y,
y: self.x,
}
}
}
pub trait Abs {
fn abs(self) -> Self;
}
impl Abs for i64 {
fn abs(self) -> Self {
i64::abs(self)
}
}
impl<T: Copy + Sub<Output = T> + Mul<Output = T> + Add<Output = T> + Abs> Point2d<T> {
pub fn dist_squared(self, center: Point2d<T>) -> T {
(self - center).len_squared()
}
pub fn len_squared(self) -> T {
let Self { x, y } = self;
x * x + y * y
}
pub fn manhattan_dist(self, city: Point2d<T>) -> T {
let diff = city - self;
diff.manhattan_len()
}
pub fn manhattan_len(&self) -> T {
self.x.abs() + self.y.abs()
}
}
impl From<Point2d<NonZeroU16>> for Point2d {
fn from(value: Point2d<NonZeroU16>) -> Self {
Self {
x: value.x.get().into(),
y: value.y.get().into(),
}
}
}
impl Point2d<i64> {
pub const fn sub(mut self, rhs: Point2d) -> Point2d {
self.x -= rhs.x;
self.y -= rhs.y;
self
}
pub const fn mul(mut self, rhs: Point2d) -> Point2d {
self.x *= rhs.x;
self.y *= rhs.y;
self
}
pub fn to_ne_bytes(&self) -> [u8; 16] {
let mut array = [0; 16];
for (dest, src) in array
.iter_mut()
.zip(self.x.to_ne_bytes().into_iter().chain(self.y.to_ne_bytes()))
{
*dest = src;
}
array
}
}
impl<T: DivAssign + Copy> Div<T> for Point2d<T> {
type Output = Self;
fn div(mut self, rhs: T) -> Self::Output {
self /= rhs;
self
}
}
impl<T: DivAssign + Copy> DivAssign<T> for Point2d<T> {
fn div_assign(&mut self, rhs: T) {
self.x /= rhs;
self.y /= rhs;
}
}
impl<T: MulAssign + Copy> Mul<T> for Point2d<T> {
type Output = Self;
fn mul(mut self, rhs: T) -> Self::Output {
self *= rhs;
self
}
}
impl<T: MulAssign + Copy> MulAssign<T> for Point2d<T> {
fn mul_assign(&mut self, rhs: T) {
self.x *= rhs;
self.y *= rhs;
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Bounds<T = i64> {
pub min: Point2d<T>,
pub max: Point2d<T>,
}
impl<T: std::fmt::Debug> std::fmt::Debug for Bounds<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}..={:?}", self.min, self.max)
}
}
impl<T: Copy + PartialEq + PartialOrd + SampleUniform> Bounds<T> {
pub fn sample<R: RngCore + ?Sized>(self, rng: &mut R) -> Point2d<T> {
Point2d {
x: (self.min.x..self.max.x).sample_single(rng).unwrap(),
y: (self.min.y..self.max.y).sample_single(rng).unwrap(),
}
}
pub fn map<U>(&self, f: impl Fn(Point2d<T>) -> Point2d<U>) -> Bounds<U> {
Bounds {
min: f(self.min),
max: f(self.max),
}
}
}
impl<T: Copy> Bounds<T> {
pub fn point(point: Point2d<T>) -> Self {
Self {
min: point,
max: point,
}
}
}
impl<T: PartialOrd + Num + Copy + AddAssign> Bounds<T> {
pub fn iter(self) -> impl Iterator<Item = Point2d<T>> {
let mut current = self.min;
std::iter::from_fn(move || {
if current.y > self.max.y {
None
} else {
let item = current;
current.x += T::ONE;
if current.x > self.max.x {
current.x = self.min.x;
current.y += T::ONE;
}
Some(item)
}
})
}
}
impl<T: Copy + Num + Add<Output = T> + Sub<Output = T> + DivAssign<T>> Bounds<T> {
pub fn center(&self) -> Point2d<T> {
(self.max - self.min) / T::TWO + self.min
}
}
impl<T: Copy + Add<Output = T> + Sub<Output = T>> Bounds<T> {
pub fn pad(&self, padding: Point2d<T>) -> Self {
Self {
min: self.min - padding,
max: self.max + padding,
}
}
}
#[cfg(test)]
#[test]
fn iter() {
let grid = Bounds {
min: Point2d::new(10, 42),
max: Point2d::new(12, 43),
};
let mut iter = grid.iter();
assert_eq!(iter.next(), Some(grid.min));
assert_eq!(iter.next(), Some(Point2d::new(11, 42)));
assert_eq!(iter.next(), Some(Point2d::new(12, 42)));
assert_eq!(iter.next(), Some(Point2d::new(10, 43)));
assert_eq!(iter.next(), Some(Point2d::new(11, 43)));
assert_eq!(iter.next(), Some(Point2d::new(12, 43)));
assert_eq!(iter.next(), None);
assert_eq!(iter.next(), None);
}
#[cfg(test)]
#[test]
fn iter_point() {
let grid = Bounds::point(Point2d::new(10, 42));
let mut iter = grid.iter();
assert_eq!(iter.next(), Some(grid.min));
assert_eq!(iter.next(), None);
assert_eq!(iter.next(), None);
}
impl<T: DivAssign + Copy> Div<Point2d<T>> for Bounds<T> {
type Output = Self;
fn div(mut self, rhs: Point2d<T>) -> Self::Output {
self.min /= rhs;
self.max /= rhs;
self
}
}
pub trait Num:
Sized
+ Copy
+ AddAssign
+ SubAssign
+ Ord
+ Sub<Output = Self>
+ Neg<Output = Self>
+ Eq
+ Add<Output = Self>
{
const ZERO: Self;
const ONE: Self;
const TWO: Self;
fn iter_range(range: std::ops::Range<Self>) -> impl Iterator<Item = Self>;
fn as_u64(self) -> u64;
}
impl Num for i64 {
const ZERO: i64 = 0;
const ONE: i64 = 1;
const TWO: i64 = 2;
fn iter_range(range: std::ops::Range<Self>) -> impl Iterator<Item = Self> {
range
}
fn as_u64(self) -> u64 {
self as u64
}
}