using System;
using Chernobyl.Mathematics.Movement;
using Chernobyl.Mathematics.Vectors;
namespace Chernobyl.Mathematics.Geometry
{
///
/// A class that makes for the creation of new s easier.
/// This ties the ,
/// , and to the
/// scale of the so that the length of the
/// axis' (i.e. the scale of those axis') also
/// represents the , ,
/// and of the .
///
public abstract class Shape : MatrixTransform, IShape
{
///
/// The largest width of the object in the object's X axis. This should
/// be the world width and not the local width.
///
public virtual float Width
{
get
{
// ensure the width cache is up to date
Update();
return _widthCache;
}
set
{
if (value < 0)
throw new ArgumentException("The width of the IShape cannot be negative. You specified: " + value, "value");
// grab the local matrix and set its row 0 (the first row, which
// holds the scale in the X axis) to unit vector scaled by our
// new width.
Matrix4 local = LocalMatrix;
local.Row0 = Vector4.UnitX * value;
SetTransformation(ref local);
}
}
///
/// The largest height of the object in the object's Y axis. This should
/// be the world height and not the local height
///
public virtual float Height
{
get
{
// ensure the height cache is up to date
Update();
return _heightCache;
}
set
{
if (value < 0)
throw new ArgumentException("The height of the IShape cannot be negative. You specified: " + value, "value");
// grab the local matrix and set its row 1 (the second row, which
// holds the scale in the Y axis) to unit vector scaled by our
// new height.
Matrix4 local = LocalMatrix;
local.Row1 = Vector4.UnitY * value;
SetTransformation(ref local);
}
}
///
/// The largest depth of the object in the object's Z axis. If the depth
/// is zero, the object is 2D. This should be the world depth and not
/// the local depth.
///
public float Depth
{
get
{
// ensure the depth cache is up to date
Update();
return _depthCache;
}
set
{
if (value < 0)
throw new ArgumentException("The depth of the IShape cannot be negative. You specified: " + value, "value");
// grab the local matrix and set its row 2 (the third row, which
// holds the scale in the Z axis) to unit vector scaled by our
// new depth.
Matrix4 local = LocalMatrix;
local.Row2 = Vector4.UnitZ * value;
SetTransformation(ref local);
}
}
///
/// Sets the width and height of the . This method
/// is both a helper method and more optimal than using the
/// and properties if you want
/// to set both the width and the height at the same time.
///
/// The new width (specified by
/// ) and height (specified by
/// ) of the .
public void SetWidthHeight(Vector2 widthHeight)
{
SetWidthHeight(widthHeight.X, widthHeight.Y);
}
///
/// Sets the width and height of the . This method
/// is both a helper method and more optimal than using the
/// and properties if you want
/// to set both the width and the height at the same time.
///
/// The new width of the .
/// The new height of the .
public void SetWidthHeight(float width, float height)
{
if (width < 0)
throw new ArgumentException("The width of the IShape cannot be negative. You specified: " + width, "width");
if (height < 0)
throw new ArgumentException("The height of the IShape cannot be negative. You specified: " + height, "height");
// grab the local matrix and set its row 0 (the first row, which
// holds the scale in the X axis) to unit vector scaled by our
// new width.
Matrix4 local = LocalMatrix;
local.Row0 = Vector4.UnitX * width;
local.Row1 = Vector4.UnitY * height;
SetTransformation(ref local);
}
///
/// Sets the width, height, and depth of the . This
/// method is both a helper method and more optimal than using the
/// , ,
/// properties if you want to set all three at the same time.
///
/// The new width (specified by
/// )m height (specified by
/// ), and depth (specified by
/// ) of the .
public void SetWidthHeightDepth(Vector3 widthHeightDepth)
{
SetWidthHeightDepth(widthHeightDepth.X, widthHeightDepth.Y, widthHeightDepth.Z);
}
///
/// Sets the width, height, and depth of the . This
/// method is both a helper method and more optimal than using the
/// , ,
/// properties if you want to set all three at the same time.
///
/// The new width of the .
/// The new height of the .
/// The new depth of the .
public void SetWidthHeightDepth(float width, float height, float depth)
{
if (width < 0)
throw new ArgumentException("The width of the IShape cannot be negative. You specified: " + width, "width");
if (height < 0)
throw new ArgumentException("The height of the IShape cannot be negative. You specified: " + height, "height");
if (depth < 0)
throw new ArgumentException("The depth of the IShape cannot be negative. You specified: " + depth, "depth");
// grab the local matrix and set its row 0 (the first row, which
// holds the scale in the X axis) to unit vector scaled by our
// new width.
Matrix4 local = LocalMatrix;
local.Row0 = Vector4.UnitX * width;
local.Row1 = Vector4.UnitY * height;
local.Row2 = Vector4.UnitZ * depth;
SetTransformation(ref local);
}
///
/// True if this is convex, false if it is concave
/// or has 0 (such as a point). A
/// is convex if for every pair of points within
/// the object, every point on the straight line segment that joins them
/// is also within the object. A concave is the
/// opposite of this.
///
public abstract bool IsConvex { get; }
///
/// The amount of space taken up by an object on a flat plane in
/// square metres (m^2).
///
public abstract float Area { get; }
///
/// The amount of 3D space this object consumes in cubic metres (m^3).
/// If this object is 2D, then the value of this property is zero.
///
public abstract float Volume { get; }
///
/// The length of the path that surrounds a shape specified in metres (m).
/// in the case of a closed curve such as a circle, this value represents
/// the circumference of the object.
///
public abstract float Perimeter { get; }
///
/// The minimum number of coordinates needed to specify each point
/// within this object. For example: a point has 0 dimensions, a
/// line has 1 dimension, a circle or rectangle has 2 dimensions, a
/// cube or sphere has 3 dimensions, and a moving cube or sphere has 4.
///
public abstract uint Dimensions { get; }
///
/// This method is invoked during the update of the
/// right after the
/// has been updated. This method
/// recalculates the width, height, and depth of this .
///
/// The new value of the
/// .
protected override void PostUpdate(ref Matrix4 world)
{
base.PostUpdate(ref world);
// store the with, height, and depth for faster performance
_widthCache = WorldMatrix.Right.Length;
_heightCache = WorldMatrix.Up.Length;
_depthCache = WorldMatrix.Forward.Length;
}
///
/// The width of this held for speed of access.
///
float _widthCache;
///
/// The height of this held for speed of access.
///
float _heightCache;
///
/// The depth of this held for speed of access.
///
float _depthCache;
}
}