mirror of https://codeberg.org/topola/topola.git
Add method to calculate polygon centroid
This commit is contained in:
parent
603160f660
commit
2f52c1e236
|
|
@ -2,9 +2,33 @@
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
|
||||||
use derive_more::{Add, Constructor, From, Into, Sub};
|
use derive_more::{
|
||||||
|
Add, AddAssign, Constructor, Div, DivAssign, From, Into, Mul, MulAssign, Sub, SubAssign,
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Add, Clone, Constructor, Copy, Debug, Eq, From, Into, PartialEq, Sub)]
|
#[derive(
|
||||||
|
Add,
|
||||||
|
AddAssign,
|
||||||
|
Clone,
|
||||||
|
Constructor,
|
||||||
|
Copy,
|
||||||
|
Debug,
|
||||||
|
Deserialize,
|
||||||
|
Div,
|
||||||
|
DivAssign,
|
||||||
|
Eq,
|
||||||
|
From,
|
||||||
|
Into,
|
||||||
|
Mul,
|
||||||
|
MulAssign,
|
||||||
|
Ord,
|
||||||
|
PartialEq,
|
||||||
|
PartialOrd,
|
||||||
|
Serialize,
|
||||||
|
Sub,
|
||||||
|
SubAssign,
|
||||||
|
)]
|
||||||
pub struct Vector2<T> {
|
pub struct Vector2<T> {
|
||||||
pub x: T,
|
pub x: T,
|
||||||
pub y: T,
|
pub y: T,
|
||||||
|
|
@ -25,27 +49,27 @@ impl<T: Copy> From<Vector2<T>> for [T; 2] {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if the point (px, py) is inside a polygon using the ray-casting
|
|
||||||
// algorithm. Division is not used to avoid integer truncation errors.
|
|
||||||
macro_rules! impl_inside_polygon {
|
macro_rules! impl_inside_polygon {
|
||||||
($type:ty) => {
|
($type:ty) => {
|
||||||
impl Vector2<$type> {
|
impl Vector2<$type> {
|
||||||
|
// Checks if the point (px, py) is inside a polygon using the ray-casting
|
||||||
|
// algorithm. Division is not used to avoid integer truncation errors.
|
||||||
pub fn inside_polygon(&self, polygon: &[Vector2<$type>]) -> bool {
|
pub fn inside_polygon(&self, polygon: &[Vector2<$type>]) -> bool {
|
||||||
let mut inside = false;
|
let mut inside = false;
|
||||||
let n = polygon.len();
|
let n = polygon.len();
|
||||||
let px = self.x;
|
let px = self.x;
|
||||||
let py = self.y;
|
let py = self.y;
|
||||||
|
|
||||||
let mut p1 = &polygon[n - 1];
|
let mut v1 = &polygon[n - 1];
|
||||||
|
|
||||||
for p2 in polygon.iter() {
|
for v2 in polygon.iter() {
|
||||||
let dy = p2.y - p1.y;
|
let dy = v2.y - v1.y;
|
||||||
let zero = 0 as $type;
|
let zero = 0 as $type;
|
||||||
|
|
||||||
if dy != zero && (py > p1.y) != (py > p2.y) {
|
if dy != zero && (py > v1.y) != (py > v2.y) {
|
||||||
let dx = p2.x - p1.x;
|
let dx = v2.x - v1.x;
|
||||||
let t = py - p1.y;
|
let t = py - v1.y;
|
||||||
let s = px - p1.x;
|
let s = px - v1.x;
|
||||||
|
|
||||||
let crosses = if dy > zero {
|
let crosses = if dy > zero {
|
||||||
s * dy < dx * t
|
s * dy < dx * t
|
||||||
|
|
@ -57,7 +81,7 @@ macro_rules! impl_inside_polygon {
|
||||||
inside = !inside;
|
inside = !inside;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p1 = p2;
|
v1 = v2;
|
||||||
}
|
}
|
||||||
|
|
||||||
inside
|
inside
|
||||||
|
|
@ -92,9 +116,9 @@ pub fn inflated_segment(x1: i64, y1: i64, x2: i64, y2: i64, half_width: u64) ->
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_rotate_around_point {
|
macro_rules! impl_rotate_around_point {
|
||||||
($t:ty) => {
|
($type:ty) => {
|
||||||
impl Vector2<$t> {
|
impl Vector2<$type> {
|
||||||
pub fn rotate_around_point(&mut self, angle: $t, origin: Vector2<$t>) -> Self {
|
pub fn rotate_around_point(&mut self, angle: $type, origin: Vector2<$type>) -> Self {
|
||||||
let sin = angle.sin();
|
let sin = angle.sin();
|
||||||
let cos = angle.cos();
|
let cos = angle.cos();
|
||||||
|
|
||||||
|
|
@ -110,7 +134,11 @@ macro_rules! impl_rotate_around_point {
|
||||||
*self
|
*self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rotate_around_point_degrees(&mut self, angle: $t, origin: Vector2<$t>) -> Self {
|
pub fn rotate_around_point_degrees(
|
||||||
|
&mut self,
|
||||||
|
angle: $type,
|
||||||
|
origin: Vector2<$type>,
|
||||||
|
) -> Self {
|
||||||
self.rotate_around_point(angle.to_radians(), origin)
|
self.rotate_around_point(angle.to_radians(), origin)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -119,3 +147,24 @@ macro_rules! impl_rotate_around_point {
|
||||||
|
|
||||||
impl_rotate_around_point!(f32);
|
impl_rotate_around_point!(f32);
|
||||||
impl_rotate_around_point!(f64);
|
impl_rotate_around_point!(f64);
|
||||||
|
|
||||||
|
macro_rules! impl_polygon_centroid {
|
||||||
|
($type:ty) => {
|
||||||
|
impl Vector2<$type> {
|
||||||
|
pub fn polygon_centroid(polygon: &[Vector2<$type>]) -> Self {
|
||||||
|
let mut sum = Vector2::new(0 as $type, 0 as $type);
|
||||||
|
|
||||||
|
for vertex in polygon.iter() {
|
||||||
|
sum += *vertex;
|
||||||
|
}
|
||||||
|
|
||||||
|
sum / polygon.len() as $type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_polygon_centroid!(f32);
|
||||||
|
impl_polygon_centroid!(f64);
|
||||||
|
impl_polygon_centroid!(i32);
|
||||||
|
impl_polygon_centroid!(i64);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue