///|
/// Finds the nearest point in a set, returning its index and distance.
pub fn nearest_point(points : Array[Vec2], target : Vec2) -> (Int, Double)? {
if points.length() == 0 {
None
} else {
let mut index = 0
let mut distance = points[0].distance(target)
for i in 1.. (Int, Double)? {
if points.length() == 0 {
None
} else {
let mut index = 0
let mut distance = points[0].distance(target)
for i in 1.. distance {
distance = candidate
index = i
}
}
Some((index, distance))
}
}
///|
/// Rotates a point cloud around its centroid.
pub fn rotate_around_centroid(
points : Array[Vec2],
angle : Double,
) -> Array[Vec2] {
let box_ = bounds_of_points(points)
let center = box_.center()
let result = []
for point in points {
result.push(point.rotate(angle, center~))
}
result
}
///|
/// Reflects points across a line defined by an origin and a unit direction.
pub fn reflect_points(
points : Array[Vec2],
origin : Vec2,
direction : Vec2,
) -> Array[Vec2] {
let axis = direction.normalized()
let result = []
for point in points {
let relative = point.sub(origin)
let projection = axis.scale(relative.dot(axis))
result.push(origin.add(projection.scale(2.0).sub(relative)))
}
result
}
///|
pub fn convex_hull(points : Array[Vec2]) -> Array[Vec2] {
if points.length() <= 1 {
points
} else {
let sorted = points.copy()
for i in 0..= 2 &&
lower[lower.length() - 1]
.sub(lower[lower.length() - 2])
.cross(point.sub(lower[lower.length() - 1])) <=
0.0 {
let _ = lower.pop()
}
lower.push(point)
}
let upper : Array[Vec2] = []
for offset in 1..<=sorted.length() {
let point = sorted[sorted.length() - offset]
while upper.length() >= 2 &&
upper[upper.length() - 1]
.sub(upper[upper.length() - 2])
.cross(point.sub(upper[upper.length() - 1])) <=
0.0 {
let _ = upper.pop()
}
upper.push(point)
}
let _ = lower.pop()
let _ = upper.pop()
for point in upper {
lower.push(point)
}
lower
}
}
///|
/// Calculates the signed angle between two vectors.
pub fn signed_angle(left : Vec2, right : Vec2) -> Double {
@math.atan2(left.cross(right), left.dot(right))
}
///|
pub fn is_convex_polygon(points : Array[Vec2]) -> Bool {
if points.length() < 3 {
false
} else {
let mut sign = 0
for i in 0.. 0.000000001 {
if sign < 0 {
return false
}
sign = 1
}
if cross < -0.000000001 {
if sign > 0 {
return false
}
sign = -1
}
}
true
}
}