#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.Volumes.PointGenerators {
/// Point generator for cylinder volumes
public static class CylinderPointGenerator {
/// Returns a random point on the surface of a cylinder
/// Random number generator that will be used
/// Orientation of the cylinder
/// Radius of the cylinder
/// Length of the cylinder
/// A random point on the volume's surface
public static Vector3 GenerateRandomPointOnSurface(
IRandom randomNumberGenerator,
Matrix orientation, float radius, float length
) {
// Calculate the surface areas of the three sections our cylinder has:
// Upper cap, side and lower cap
float capArea = MathHelper.Pi * (radius * radius);
float sideArea = 2.0f * MathHelper.Pi * radius * length;
float capAndSideArea = capArea + sideArea;
// We need a phi value (angle of the random point) in any of the cases
float phi = (float)randomNumberGenerator.NextDouble() * MathHelper.TwoPi;
// Choose the section that the random point will be generated on in relation
// to its surface area so the probability is constant on the entire surface
float section = (float)randomNumberGenerator.NextDouble() * (capArea * 2.0f + sideArea);
// Depending on the section, these two values are calculated differently
float randomRadius;
float randomZ;
// Upper cap: Generate a random radius
if(section < capArea) {
randomZ = length / 2.0f;
randomRadius = (float)Math.Sqrt(randomNumberGenerator.NextDouble()) * radius;
// Side: Generate a random height
} else if(section < capAndSideArea) {
randomZ = ((float)randomNumberGenerator.NextDouble() - 0.5f) * length;
randomRadius = radius;
// Lower cap: Generate a random radius
} else {
randomZ = -length / 2.0f;
randomRadius = (float)Math.Sqrt(randomNumberGenerator.NextDouble()) * radius;
}
// Now transform the point to cartesian coordinates and rotate it into
// the global coordinate frame
return Vector3.Transform(
new Vector3(
randomRadius * (float)Math.Cos(phi),
randomRadius * (float)Math.Sin(phi),
randomZ
),
orientation
);
}
/// Returns a random point within a cylinder
/// Random number generator that will be used
/// Orientation of the cylinder
/// Radius of the cylinder
/// Length of the cylinder
/// A random point within the cylinder
public static Vector3 GenerateRandomPointWithin(
IRandom randomNumberGenerator,
Matrix orientation, float radius, float length
) {
Vector2 randomPoint = Areas.PointGenerators.Disc2PointGenerator.GenerateRandomPointWithin(
randomNumberGenerator, radius
);
float z = (float)randomNumberGenerator.NextDouble() * 2.0f - 1.0f;
return Vector3.Transform(
new Vector3(randomPoint.X, randomPoint.Y, z * length),
orientation
);
}
}
} // namespace Nuclex.Geometry.Volumes.Generators