#pragma region CPL License
/*
Nuclex Native Framework
Copyright (C) 2002-2015 Nuclex Development Labs
This library is free software; you can redistribute it and/or
modify it under the terms of the IBM Common Public License as
published by the IBM Corporation; either version 1.0 of the
License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
IBM Common Public License for more details.
You should have received a copy of the IBM Common Public
License along with this library
*/
#pragma endregion // CPL License
#ifndef NUCLEX_GEOMETRY_VOLUMES_GENERATORS_BOX3GENERATOR_H
#define NUCLEX_GEOMETRY_VOLUMES_GENERATORS_BOX3GENERATOR_H
#include "Nuclex/Geometry/Config.h"
#include "Nuclex/Geometry/Volumes/Box3.h"
#include "Nuclex/Geometry/Volumes/Sphere3.h"
namespace Nuclex { namespace Geometry { namespace Volumes { namespace Generators {
// ------------------------------------------------------------------------------------------- //
/// Point and volume generation methods for 3D boxes
template
class Box3Generator {
/// Generates a random point within a box
/// Box in which a random point will be generated
/// Random number generator that will be used
/// A random point inside the box
public: template Point3
static GetRandomPointInside(const Box3 &box, TRandomNumberEngine &random) {
box.EnforceNotFlipped();
return Point3(
Math::Random(random, box.Min.X, box.Max.X),
Math::Random(random, box.Min.Y, box.Max.Y),
Math::Random(random, box.Min.Z, box.Max.Z)
);
}
/// Generates a random point on the hull of the box
/// Box on which a random point will be generated
/// Random number generator that will be used
/// A random point on the hull of the box
public: template Point3
static GetRandomPointOnHull(const Box3 &box, TRandomNumberEngine &random) {
box.EnforceNotFlipped();
TScalar capDepth = (box.Max.Y - box.Min.Y);
TScalar doubleCapDepth = capDepth * 2;
TScalar sideWidth = (box.Max.X - box.Min.X);
TScalar quadrupleSideWidth = sideWidth * 4;
TScalar x = Math::Random(random, doubleCapDepth + quadrupleSideWidth);
if(x < quadrupleSideWidth) {
TScalar doubleSideWidth = sideWidth * 2;
if(x < doubleSideWidth) {
float z = Math::Random(random, box.Min.Z, box.Max.Z);
if(x < sideWidth) {
return Point3(x, box.Min.Y, z); // Front face
} else {
return Point3(x - sideWidth, box.Max.Y, z); // Back face
}
} else {
TScalar thirdSideStart = doubleSideWidth + sideWidth;
float y = Math::Random(random, capDepth) + box.Min.Y;
if(x < thirdSideStart) {
return Point3(x - doubleSideWidth, y, box.Min.Z); // Bottom face
} else {
return Point3(x - thirdSideStart, y, box.Max.Z); // Top face
}
}
} else {
float secondCapStart = quadrupleSideWidth + capDepth;
float z = Math::Random(random, box.Min.Z, box.Max.Z);
if(x < secondCapStart) {
return Point3(box.Min.X, x - quadrupleSideWidth, z); // Left cap
} else {
return Point3(box.Max.X, x - secondCapStart, z); // Right cap
}
}
}
/// Returns the closest point to another point within the box
/// Box within which the closest point will be determined
/// Point to which the closest point will be determined
/// The closest point within the box to the provided point
public: static Point3 GetClosestPointInside(
const Box3 &box, const Point3 &point
) {
box.EnforceNotFlipped();
return Point3(
Math::Clamp(point.X, box.Min.X, box.Max.X),
Math::Clamp(point.Y, box.Min.Y, box.Max.Y),
Math::Clamp(point.Z, box.Min.Z, box.Max.Z)
);
}
/// Returns the closest point to another point on the box' hull
/// Box on whose hull the closest point will be determined
/// Point to which the closest point will be determined
/// The closest point on the box' hull to the provided point
public: static Point3 GetClosestPointOnHull(
const Box3 &box, const Point3 &point
) {
box.EnforceNotFlipped();
Point3 closest;
if(point.X - box.Min.X < box.Max.X - point.X) {
closest.X = box.Min.X;
} else {
closest.X = box.Max.X;
}
if(point.Y - box.Min.Y < box.Max.Y - point.Y) {
closest.Y = box.Min.Y;
} else {
closest.Y = box.Max.Y;
}
if(point.Z - box.Min.Z < box.Max.Z - point.Z) {
closest.Z = box.Min.Z;
} else {
closest.Z = box.Max.Z;
}
return closest;
}
/// Calculates the bounding box of the specified box
/// Box of which the bounding box will be calculated
/// The bounding box of the specified box
///
/// This is a no-op, but provided for completeness so templated algorithms
/// can assume this member to be there in any generator type.
///
public: static Box3 GetBoundingBox(const Box3 &box) {
box.EnforceNotFlipped();
return box;
}
/// Calculates the bounding sphere of the specified box
/// Box of which the bounding sphere will be calculated
/// The bounding sphere of the specified box
public: static Sphere3 GetBoundingSphere(const Box3 &box) {
box.EnforceNotFlipped();
TScalar width = box.Max.X - box.Min.X;
TScalar depth = box.Max.Y - box.Min.Y;
TScalar height = box.Max.Z - box.Min.Z;
TScalar diameter = Math::Max(width, depth, height);
return Sphere3(box.GetCenter(), diameter / 2);
}
};
// ------------------------------------------------------------------------------------------- //
}}}} // namespace Nuclex::Geometry::Volumes::Generators
#endif // NUCLEX_GEOMETRY_VOLUMES_GENERATORS_BOX3GENERATOR_H