///|
pub fn BoundingBox::empty() -> BoundingBox {
{
min: { x: 0.0, y: 0.0, z: 0.0 },
max: { x: 0.0, y: 0.0, z: 0.0 },
empty: true,
}
}
///|
pub fn BoundingBox::from_points(points : Array[Point3]) -> BoundingBox {
if points.length() == 0 {
return BoundingBox::empty()
}
let first = points[0]
let mut min_x = first.x
let mut min_y = first.y
let mut min_z = first.z
let mut max_x = first.x
let mut max_y = first.y
let mut max_z = first.z
for point in points[1:] {
if point.x < min_x {
min_x = point.x
}
if point.y < min_y {
min_y = point.y
}
if point.z < min_z {
min_z = point.z
}
if point.x > max_x {
max_x = point.x
}
if point.y > max_y {
max_y = point.y
}
if point.z > max_z {
max_z = point.z
}
}
{
min: { x: min_x, y: min_y, z: min_z },
max: { x: max_x, y: max_y, z: max_z },
empty: false,
}
}
///|
pub fn BoundingBox::width(self : BoundingBox) -> Double {
if self.empty {
0.0
} else {
self.max.x - self.min.x
}
}
///|
pub fn BoundingBox::height(self : BoundingBox) -> Double {
if self.empty {
0.0
} else {
self.max.y - self.min.y
}
}
///|
pub fn BoundingBox::depth(self : BoundingBox) -> Double {
if self.empty {
0.0
} else {
self.max.z - self.min.z
}
}
///|
pub fn BoundingBox::volume(self : BoundingBox) -> Double {
self.width() * self.height() * self.depth()
}
///|
pub fn BoundingBox::center(self : BoundingBox) -> Point3 {
{
x: (self.min.x + self.max.x) / 2.0,
y: (self.min.y + self.max.y) / 2.0,
z: (self.min.z + self.max.z) / 2.0,
}
}
///|
pub fn bounds_of_mesh(mesh : Mesh) -> BoundingBox {
BoundingBox::from_points(mesh.points)
}
///|
pub fn bounds_of_geometry(geometry : Geometry) -> BoundingBox {
BoundingBox::from_points(geometry.points)
}
///|
pub fn merge_bounds(left : BoundingBox, right : BoundingBox) -> BoundingBox {
if left.empty {
return right
}
if right.empty {
return left
}
BoundingBox::{
min: {
x: if left.min.x < right.min.x {
left.min.x
} else {
right.min.x
},
y: if left.min.y < right.min.y {
left.min.y
} else {
right.min.y
},
z: if left.min.z < right.min.z {
left.min.z
} else {
right.min.z
},
},
max: {
x: if left.max.x > right.max.x {
left.max.x
} else {
right.max.x
},
y: if left.max.y > right.max.y {
left.max.y
} else {
right.max.y
},
z: if left.max.z > right.max.z {
left.max.z
} else {
right.max.z
},
},
empty: false,
}
}
///|
pub fn transform_mesh(transform : Transform3, mesh : Mesh) -> Mesh {
{
points: mesh.points.map(point => transform.apply(point)),
triangles: mesh.triangles,
}
}
///|
pub fn merge_meshes(meshes : Array[Mesh]) -> Mesh {
let points : Array[Point3] = []
let triangles : Array[(Int, Int, Int)] = []
for mesh in meshes {
let offset = points.length()
points.append(mesh.points)
for triangle in mesh.triangles {
let (a, b, c) = triangle
triangles.push((a + offset, b + offset, c + offset))
}
}
{ points, triangles }
}
///|
pub fn estimated_volume(geometry : Geometry) -> Double? {
match (geometry.profile_width, geometry.profile_height, geometry.depth) {
(Some(width), Some(height), Some(depth)) => Some(width * height * depth)
(Some(radius), _, Some(depth)) if geometry.profile_radius is Some(_) =>
Some(3.141592653589793 * radius * radius * depth)
_ => None
}
}
///|
pub fn model_bounds(
index : ModelIndex,
products : Array[Product],
) -> BoundingBox {
products.fold(init=BoundingBox::empty(), (result, product) => {
let product_bounds = geometries_for_product(index, product).fold(
init=BoundingBox::empty(),
(geometry_result, geometry) => {
merge_bounds(geometry_result, bounds_of_geometry(geometry))
},
)
merge_bounds(result, product_bounds)
})
}