use crate::{distance::Distance, unit::Radius, FromProto, IntoProto};
use sc2_proto::common::{Point, Point2D};
use std::{
hash::{Hash, Hasher},
iter::Sum,
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};
#[allow(missing_docs)]
#[derive(Debug, Default, Copy, Clone)]
pub struct Size {
pub x: usize,
pub y: usize,
}
impl Size {
pub fn new(x: usize, y: usize) -> Self {
Self { x, y }
}
}
#[allow(missing_docs)]
#[derive(Debug, Default, Copy, Clone)]
pub struct Rect {
pub x0: usize,
pub y0: usize,
pub x1: usize,
pub y1: usize,
}
impl Rect {
pub fn new(x0: usize, y0: usize, x1: usize, y1: usize) -> Self {
Self { x0, y0, x1, y1 }
}
}
#[allow(missing_docs)]
#[derive(Debug, Default, Copy, Clone)]
pub struct Point2 {
pub x: f32,
pub y: f32,
}
#[allow(clippy::len_without_is_empty)]
impl Point2 {
pub fn new(x: f32, y: f32) -> Self {
Self { x, y }
}
pub fn towards(self, other: Self, offset: f32) -> Self {
self + (other - self) / self.distance(other) * offset
}
pub fn towards_angle(self, angle: f32, offset: f32) -> Self {
self.offset(offset * angle.cos(), offset * angle.sin())
}
pub fn offset(self, x: f32, y: f32) -> Self {
Self {
x: self.x + x,
y: self.y + y,
}
}
pub fn circle_intersection(self, other: Self, radius: f32) -> Option<[Self; 2]> {
if self == other {
return None;
}
let vec_to_center = (other - self) / 2.0;
let half_distance = vec_to_center.len();
if radius < half_distance {
return None;
}
let remaining_distance = (radius * radius - half_distance * half_distance).sqrt();
let stretch_factor = remaining_distance / half_distance;
let center = self + vec_to_center;
let vec_stretched = vec_to_center * stretch_factor;
Some([
center + vec_stretched.rotate90(true),
center + vec_stretched.rotate90(false),
])
}
pub fn len_squared(self) -> f32 {
self.x.powi(2) + self.y.powi(2)
}
pub fn len(self) -> f32 {
self.len_squared().sqrt()
}
pub fn normalize(self) -> Self {
self / self.len()
}
pub fn rotate(self, angle: f32) -> Self {
let (s, c) = angle.sin_cos();
let (x, y) = (self.x, self.y);
Self {
x: c * x - s * y,
y: s * x + c * y,
}
}
pub fn rotate90(self, clockwise: bool) -> Self {
if clockwise {
Self::new(self.y, -self.x)
} else {
Self::new(-self.y, self.x)
}
}
pub fn dot(self, other: Self) -> f32 {
self.x * other.x + self.y * other.y
}
pub fn round(self) -> Self {
Self {
x: (self.x + 0.5) as i32 as f32,
y: (self.y + 0.5) as i32 as f32,
}
}
pub fn floor(self) -> Self {
Self {
x: self.x as i32 as f32,
y: self.y as i32 as f32,
}
}
pub fn ceil(self) -> Self {
Self {
x: (self.x + 0.999999) as i32 as f32,
y: (self.y + 0.999999) as i32 as f32,
}
}
pub fn abs(self) -> Self {
Self {
x: self.x.abs(),
y: self.y.abs(),
}
}
pub fn neighbors4(self) -> [Self; 4] {
[
self.offset(1.0, 0.0),
self.offset(-1.0, 0.0),
self.offset(0.0, 1.0),
self.offset(0.0, -1.0),
]
}
pub fn neighbors4diagonal(self) -> [Self; 4] {
[
self.offset(1.0, 1.0),
self.offset(-1.0, -1.0),
self.offset(1.0, -1.0),
self.offset(-1.0, 1.0),
]
}
pub fn neighbors8(self) -> [Self; 8] {
[
self.offset(1.0, 0.0),
self.offset(-1.0, 0.0),
self.offset(0.0, 1.0),
self.offset(0.0, -1.0),
self.offset(1.0, 1.0),
self.offset(-1.0, -1.0),
self.offset(1.0, -1.0),
self.offset(-1.0, 1.0),
]
}
pub fn as_tuple(self) -> (f32, f32) {
(self.x, self.y)
}
pub fn to3(self, z: f32) -> Point3 {
Point3 {
x: self.x,
y: self.y,
z,
}
}
}
impl PartialEq for Point2 {
fn eq(&self, other: &Self) -> bool {
self.x as i32 == other.x as i32 && self.y as i32 == other.y as i32
}
}
impl Eq for Point2 {}
impl Hash for Point2 {
fn hash<H: Hasher>(&self, state: &mut H) {
(self.x as i32).hash(state);
(self.y as i32).hash(state);
}
}
impl From<&Point2> for Point2 {
#[inline]
fn from(p: &Point2) -> Self {
*p
}
}
impl From<Point2> for (usize, usize) {
#[inline]
fn from(p: Point2) -> Self {
(p.x as usize, p.y as usize)
}
}
impl From<(usize, usize)> for Point2 {
#[inline]
fn from((x, y): (usize, usize)) -> Self {
Self {
x: x as f32 + 0.5,
y: y as f32 + 0.5,
}
}
}
impl From<(f32, f32)> for Point2 {
#[inline]
fn from((x, y): (f32, f32)) -> Self {
Self { x, y }
}
}
impl From<Point2> for (f32, f32) {
#[inline]
fn from(p: Point2) -> Self {
p.as_tuple()
}
}
impl Add for Point2 {
type Output = Self;
fn add(self, other: Self) -> Self {
Self {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
impl Sub for Point2 {
type Output = Self;
fn sub(self, other: Self) -> Self {
Self {
x: self.x - other.x,
y: self.y - other.y,
}
}
}
impl Mul for Point2 {
type Output = Self;
fn mul(self, other: Self) -> Self {
Self {
x: self.x * other.x,
y: self.y * other.y,
}
}
}
impl Div for Point2 {
type Output = Self;
fn div(self, other: Self) -> Self {
Self {
x: self.x / other.x,
y: self.y / other.y,
}
}
}
impl AddAssign for Point2 {
fn add_assign(&mut self, other: Self) {
self.x += other.x;
self.y += other.y;
}
}
impl SubAssign for Point2 {
fn sub_assign(&mut self, other: Self) {
self.x -= other.x;
self.y -= other.y;
}
}
impl MulAssign for Point2 {
fn mul_assign(&mut self, other: Self) {
self.x *= other.x;
self.y *= other.y;
}
}
impl DivAssign for Point2 {
fn div_assign(&mut self, other: Self) {
self.x /= other.x;
self.y /= other.y;
}
}
impl Add<f32> for Point2 {
type Output = Self;
fn add(self, other: f32) -> Self {
Self {
x: self.x + other,
y: self.y + other,
}
}
}
impl Sub<f32> for Point2 {
type Output = Self;
fn sub(self, other: f32) -> Self {
Self {
x: self.x - other,
y: self.y - other,
}
}
}
impl Mul<f32> for Point2 {
type Output = Self;
fn mul(self, other: f32) -> Self {
Self {
x: self.x * other,
y: self.y * other,
}
}
}
impl Div<f32> for Point2 {
type Output = Self;
fn div(self, other: f32) -> Self {
Self {
x: self.x / other,
y: self.y / other,
}
}
}
impl AddAssign<f32> for Point2 {
fn add_assign(&mut self, other: f32) {
self.x += other;
self.y += other;
}
}
impl SubAssign<f32> for Point2 {
fn sub_assign(&mut self, other: f32) {
self.x -= other;
self.y -= other;
}
}
impl MulAssign<f32> for Point2 {
fn mul_assign(&mut self, other: f32) {
self.x *= other;
self.y *= other;
}
}
impl DivAssign<f32> for Point2 {
fn div_assign(&mut self, other: f32) {
self.x /= other;
self.y /= other;
}
}
impl Neg for Point2 {
type Output = Self;
fn neg(self) -> Self {
Self {
x: -self.x,
y: -self.y,
}
}
}
impl Sum for Point2 {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Default::default(), Add::add)
}
}
impl FromProto<&Point2D> for Point2 {
fn from_proto(p: &Point2D) -> Self {
Self {
x: p.get_x(),
y: p.get_y(),
}
}
}
impl FromProto<&Point> for Point2 {
fn from_proto(p: &Point) -> Self {
Self {
x: p.get_x(),
y: p.get_y(),
}
}
}
impl IntoProto<Point2D> for Point2 {
fn into_proto(self) -> Point2D {
let mut pos = Point2D::new();
pos.set_x(self.x);
pos.set_y(self.y);
pos
}
}
#[allow(missing_docs)]
#[derive(Debug, Default, Copy, Clone)]
pub struct Point3 {
pub x: f32,
pub y: f32,
pub z: f32,
}
impl Point3 {
pub fn new(x: f32, y: f32, z: f32) -> Self {
Self { x, y, z }
}
pub fn offset(self, x: f32, y: f32, z: f32) -> Self {
Self {
x: self.x + x,
y: self.y + y,
z: self.z + z,
}
}
pub fn round(self) -> Self {
Self {
x: (self.x + 0.5) as i32 as f32,
y: (self.y + 0.5) as i32 as f32,
z: (self.z + 0.5) as i32 as f32,
}
}
pub fn as_tuple(self) -> (f32, f32, f32) {
(self.x, self.y, self.z)
}
pub fn to2(self) -> Point2 {
Point2 { x: self.x, y: self.y }
}
}
impl From<Point3> for Point2 {
#[inline]
fn from(p3: Point3) -> Self {
p3.to2()
}
}
impl From<(f32, f32, f32)> for Point3 {
#[inline]
fn from((x, y, z): (f32, f32, f32)) -> Self {
Self { x, y, z }
}
}
impl From<Point3> for (f32, f32, f32) {
#[inline]
fn from(p3: Point3) -> Self {
p3.as_tuple()
}
}
impl Add for Point3 {
type Output = Self;
fn add(self, other: Self) -> Self {
Self {
x: self.x + other.x,
y: self.y + other.y,
z: self.z + other.z,
}
}
}
impl Sub for Point3 {
type Output = Self;
fn sub(self, other: Self) -> Self {
Self {
x: self.x - other.x,
y: self.y - other.y,
z: self.z - other.z,
}
}
}
impl Mul for Point3 {
type Output = Self;
fn mul(self, other: Self) -> Self {
Self {
x: self.x * other.x,
y: self.y * other.y,
z: self.z * other.z,
}
}
}
impl Div for Point3 {
type Output = Self;
fn div(self, other: Self) -> Self {
Self {
x: self.x / other.x,
y: self.y / other.y,
z: self.z / other.z,
}
}
}
impl Add<f32> for Point3 {
type Output = Self;
fn add(self, other: f32) -> Self {
Self {
x: self.x + other,
y: self.y + other,
z: self.z + other,
}
}
}
impl Sub<f32> for Point3 {
type Output = Self;
fn sub(self, other: f32) -> Self {
Self {
x: self.x - other,
y: self.y - other,
z: self.z - other,
}
}
}
impl Mul<f32> for Point3 {
type Output = Self;
fn mul(self, other: f32) -> Self {
Self {
x: self.x * other,
y: self.y * other,
z: self.z * other,
}
}
}
impl Div<f32> for Point3 {
type Output = Self;
fn div(self, other: f32) -> Self {
Self {
x: self.x / other,
y: self.y / other,
z: self.z / other,
}
}
}
impl Sum for Point3 {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Default::default(), Add::add)
}
}
impl FromProto<&Point> for Point3 {
fn from_proto(p: &Point) -> Self {
Self {
x: p.get_x(),
y: p.get_y(),
z: p.get_z(),
}
}
}
impl IntoProto<Point> for Point3 {
fn into_proto(self) -> Point {
let mut pos = Point::new();
pos.set_x(self.x);
pos.set_y(self.y);
pos.set_z(self.z);
pos
}
}
impl Radius for Point2 {}
impl Radius for &Point2 {}
impl Radius for Point3 {}
impl Radius for &Point3 {}