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; } }