///|
pub fn centroid_of_points(points : Array[Point]) -> Point {
polygon_centroid(points)
}
///|
pub fn bounding_box_of_points(points : Array[Point]) -> Bounds {
polygon_bounds(points)
}
///|
pub fn translate_points(
points : Array[Point],
dx : Double,
dy : Double,
) -> Array[Point] {
points.map(fn(point) { Point::Point(x=point.x + dx, y=point.y + dy) })
}
///|
pub fn scale_points(
points : Array[Point],
center : Point,
factor : Double,
) -> Array[Point] {
points.map(fn(point) {
Point::Point(
x=center.x + (point.x - center.x) * factor,
y=center.y + (point.y - center.y) * factor,
)
})
}
///|
pub fn reflect_points(points : Array[Point], line : Line) -> Array[Point] {
points.map(fn(point) { reflect_point(point, line) })
}
///|
pub fn point_at_distance(
start : Point,
finish : Point,
distance_from_start : Double,
) -> Point {
let length = distance(start, finish)
if length <= 0.0000001 {
start
} else {
let t = distance_from_start / length
Point::Point(x=lerp(start.x, finish.x, t), y=lerp(start.y, finish.y, t))
}
}
///|
pub fn interpolate_points(points : Array[Point], count : Int) -> Array[Point] {
if points.length() < 2 || count <= 0 {
[]
} else {
let result : Array[Point] = []
let total = line_length(points)
for i in 0..= target {
selected = point_at_distance(
points[j - 1],
points[j],
target - accumulated,
)
break
}
accumulated += segment
selected = points[j]
}
result.push(selected)
}
result
}
}
///|
pub fn polyline_length(points : Array[Point], closed? : Bool = false) -> Double {
let length = line_length(points)
if closed && points.length() > 1 {
length + distance(points[0], points[points.length() - 1])
} else {
length
}
}
///|
pub fn polyline_tangent(points : Array[Point], index : Int) -> Vector2 {
if points.length() < 2 {
Vector2::Vector2(x=0.0, y=0.0)
} else {
let i = index.clamp(min=0, max=points.length() - 1)
let first = points[(i - 1).max(0)]
let last = points[(i + 1).min(points.length() - 1)]
Vector2::Vector2(x=last.x - first.x, y=last.y - first.y).normalized()
}
}
///|
pub fn polyline_normal(points : Array[Point], index : Int) -> Vector2 {
let tangent = polyline_tangent(points, index)
Vector2::Vector2(x=-tangent.y, y=tangent.x)
}
///|
pub fn point_line_distance(
first : Point,
second : Point,
point : Point,
) -> Double {
line_from_points(first, second).distance_to(point)
}
///|
pub fn segment_projection(
first : Point,
second : Point,
point : Point,
) -> Point {
let direction = Vector2::Vector2(x=second.x - first.x, y=second.y - first.y)
let denominator = direction.dot(direction)
if denominator <= 0.0000001 {
first
} else {
let relative = Vector2::Vector2(x=point.x - first.x, y=point.y - first.y)
let t = clamp_double(relative.dot(direction) / denominator, 0.0, 1.0)
Point::Point(x=first.x + direction.x * t, y=first.y + direction.y * t)
}
}
///|
pub fn segment_distance(first : Point, second : Point, point : Point) -> Double {
distance(segment_projection(first, second, point), point)
}
///|
pub fn triangle_area(first : Point, second : Point, third : Point) -> Double {
(second.x - first.x) * (third.y - first.y) -
(second.y - first.y) * (third.x - first.x)
}
///|
pub fn triangle_orientation(
first : Point,
second : Point,
third : Point,
) -> Int {
let area = triangle_area(first, second, third)
if area > 0.0 {
1
} else if area < 0.0 {
-1
} else {
0
}
}
///|
pub fn point_inside_polygon(point : Point, polygon : Array[Point]) -> Bool {
if polygon.length() < 3 {
false
} else {
let mut inside = false
let mut j = polygon.length() - 1
for i in 0.. point.y) != (b.y > point.y) &&
point.x <
(b.x - a.x) * (point.y - a.y) / (b.y - a.y + 0.0000000001) + a.x {
inside = !inside
}
j = i
}
inside
}
}
///|
pub fn polygon_distance(point : Point, polygon : Array[Point]) -> Double {
if polygon.is_empty() {
0.0
} else {
let mut result = distance(point, polygon[0])
for i in 1.. Point {
Point::Point(
x=Double::from_int(bounds.min_x + bounds.max_x) / 2.0,
y=Double::from_int(bounds.min_y + bounds.max_y) / 2.0,
)
}
///|
pub fn line_angle_from_points(first : Point, second : Point) -> Double {
measure_angle(first, second)
}
///|
pub fn angle_difference(first : Double, second : Double) -> Double {
normalize_angle(first - second).abs()
}
///|
pub fn point_set_spread(points : Array[Point]) -> Double {
if points.is_empty() {
0.0
} else {
let center = polygon_centroid(points)
maximum_value(points.map(fn(point) { distance(point, center) }))
}
}