#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