#region CPL License /* Nuclex Framework Copyright (C) 2002-2009 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 */ #endregion using System; using Microsoft.Xna.Framework; namespace Nuclex.Geometry.Areas.PointGenerators { /// Point generator for planes public static class Plane3PointGenerator { /// Returns a random point on a plane's perimeter /// Random number generator that will be used /// Normal of the plane around which to create a random point /// A random point on the plane's perimeter public static Vector3 RandomPointOnPerimeter(IRandom randomNumberGenerator, Vector3 normal) { return generateRandomPlanePoint(randomNumberGenerator, normal); } /// Returns a random point within a plane /// Random number generator that will be used /// Normal of the plane in which to create a random point /// A random point inside the area public static Vector3 RandomPointWithin(IRandom randomNumberGenerator, Vector3 normal) { return generateRandomPlanePoint(randomNumberGenerator, normal); } /// Returns a random point around or within the plane /// Random number generator that will be used /// Normal of the plane /// A random point around or within the plane /// /// /// Since the plane extends to infinity in each direction, the chance of hitting /// a value outside of what can be expressed with a meager float (and actually, /// any finite numbering system) is infinitely larger than being within the range /// we can express, so we can assume the chance of the result being infinity is /// about 1. /// /// /// The same applies to both, finding a point on the plane's perimeter as well as /// finding a point within the plane, so this method is used for both cases. /// /// private static Vector3 generateRandomPlanePoint( IRandom randomNumberGenerator, Vector3 normal ) { // Randomly select a corner of the plane int side = randomNumberGenerator.Next(4); // Depending on the randomly selected corner, get the normalized coordinates // of that corner of the plane (if we involved infinity here, the result would // be NaN as soon as a multiplication by negative infinity took place) Vector2 corner; switch(side) { case 0: { corner.X = -1.0f; corner.Y = -1.0f; break; } case 1: { corner.X = +1.0f; corner.Y = -1.0f; break; } case 2: { corner.X = +1.0f; corner.Y = +1.0f; break; } case 3: { corner.X = -1.0f; corner.Y = +1.0f; break; } default: { throw new InvalidOperationException("Random number generator malfunctioned"); } } // Determine an up and a right vector from the plane's normal Vector3 right = VectorHelper.GetPerpendicularVector(normal); Vector3 up = Vector3.Cross(normal, right); // Now transform the corner from plane coordinates into the world coordinate frame Vector3 unitPerimeterPoint = (up * corner.X) + (right * corner.Y); // The randomly chosen corner now is zero in one dimension and infinity in all the // others if the plane was exactly aligned to one of the three unit vectors, or // infinity in all dimensions if the plane was arbitrary. return new Vector3( infinitize(unitPerimeterPoint.X), infinitize(unitPerimeterPoint.Y), infinitize(unitPerimeterPoint.Z) ); } /// Scales any value but zero to positive or negative infinity /// Value that will be scaled to infinity if not zero /// The input value scaled to infinity if it wasn't zero private static float infinitize(float value) { if(value < 0.0f) { return float.NegativeInfinity; } else if(value > 0.0f) { return float.PositiveInfinity; } else { return 0.0f; } } } } // namespace Nuclex.Geometry.Volumes.Generators