///|
pub(all) struct PointCloud {
points : Array[Point3]
} derive(Debug, Eq)
///|
pub fn PointCloud::from_points(points : ArrayView[Point3]) -> PointCloud {
{ points: points.to_owned() }
}
///|
pub fn PointCloud::length(cloud : PointCloud) -> Int {
cloud.points.length()
}
///|
pub fn PointCloud::is_empty(cloud : PointCloud) -> Bool {
cloud.points.length() == 0
}
///|
pub fn PointCloud::centroid(cloud : PointCloud) -> Point3 raise GeometryError {
centroid3(cloud.points)
}
///|
pub fn PointCloud::valid_depth_count(cloud : PointCloud) -> Int {
let mut result = 0
for point in cloud.points {
if point.z > 0.0 {
result += 1
}
}
result
}
///|
pub fn PointCloud::positive_depth_ratio(cloud : PointCloud) -> Double {
if cloud.is_empty() {
0.0
} else {
Double::from_int(cloud.valid_depth_count()) /
Double::from_int(cloud.length())
}
}
///|
pub fn PointCloud::depth_range(
cloud : PointCloud,
) -> (Double, Double) raise GeometryError {
if cloud.is_empty() {
raise GeometryError::NotEnoughPoints("point cloud has no points")
}
let mut minimum = cloud.points[0].z
let mut maximum = cloud.points[0].z
for point in cloud.points {
if point.z < minimum {
minimum = point.z
}
if point.z > maximum {
maximum = point.z
}
}
(minimum, maximum)
}
///|
pub fn PointCloud::filter_depth(
cloud : PointCloud,
minimum~ : Double,
maximum~ : Double,
) -> PointCloud raise GeometryError {
if maximum < minimum {
raise GeometryError::DegenerateInput("depth filter bounds are reversed")
}
let result : Array[Point3] = []
for point in cloud.points {
if point.z >= minimum && point.z <= maximum {
result.push(point)
}
}
PointCloud::from_points(result)
}
///|
pub fn PointCloud::bounds(cloud : PointCloud) -> Aabb3 raise GeometryError {
Aabb3::from_points(cloud.points)
}
///|
pub fn PointCloud::rms_radius(cloud : PointCloud) -> Double raise GeometryError {
let center = cloud.centroid()
if cloud.is_empty() {
raise GeometryError::NotEnoughPoints("point cloud has no points")
}
let mut sum = 0.0
for point in cloud.points {
let distance = distance3(point, center)
sum += distance * distance
}
(sum / Double::from_int(cloud.length())).sqrt()
}
///|
pub fn merge_point_clouds(left : PointCloud, right : PointCloud) -> PointCloud {
let result = left.points.copy()
for point in right.points {
result.push(point)
}
PointCloud::from_points(result)
}