// Copyright (c) 2010-2014 SharpDX - Alexandre Mutel // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // ----------------------------------------------------------------------------- // Original code from SlimMath project. http://code.google.com/p/slimmath/ // Greetings to SlimDX Group. Original code published with the following license: // ----------------------------------------------------------------------------- /* * Copyright (c) 2007-2011 SlimDX Group * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ using System; using System.Globalization; using System.Runtime.InteropServices; namespace SharpDX { /// /// Represents a unit independent angle using a single-precision floating-point /// internal representation. /// [StructLayout(LayoutKind.Explicit)] public struct AngleSingle : IComparable, IComparable, IEquatable, IFormattable { /// /// A value that specifies the size of a single degree. /// public const float Degree = 0.002777777777777778f; /// /// A value that specifies the size of a single minute. /// public const float Minute = 0.000046296296296296f; /// /// A value that specifies the size of a single second. /// public const float Second = 0.000000771604938272f; /// /// A value that specifies the size of a single radian. /// public const float Radian = 0.159154943091895336f; /// /// A value that specifies the size of a single milliradian. /// public const float Milliradian = 0.0001591549431f; /// /// A value that specifies the size of a single gradian. /// public const float Gradian = 0.0025f; /// /// The internal representation of the angle. /// [FieldOffset(0)] float radians; [FieldOffset(0)] private int radiansInt; /// /// Initializes a new instance of the SharpDX.AngleSingle structure with the /// given unit dependant angle and unit type. /// /// A unit dependant measure of the angle. /// The type of unit the angle argument is. public AngleSingle(float angle, AngleType type) { radiansInt = 0; switch (type) { case AngleType.Revolution: radians = MathUtil.RevolutionsToRadians(angle); break; case AngleType.Degree: radians = MathUtil.DegreesToRadians(angle); break; case AngleType.Radian: radians = angle; break; case AngleType.Gradian: radians = MathUtil.GradiansToRadians(angle); break; default: radians = 0.0f; break; } } /// /// Initializes a new instance of the SharpDX.AngleSingle structure using the /// arc length formula (θ = s/r). /// /// The measure of the arc. /// The radius of the circle. public AngleSingle(float arcLength, float radius) { radiansInt = 0; radians = arcLength / radius; } /// /// Wraps this SharpDX.AngleSingle to be in the range [π, -π]. /// public void Wrap() { float newangle = (float)Math.IEEERemainder(radians, MathUtil.TwoPi); if (newangle <= -MathUtil.Pi) newangle += MathUtil.TwoPi; else if (newangle > MathUtil.Pi) newangle -= MathUtil.TwoPi; radians = newangle; } /// /// Wraps this SharpDX.AngleSingle to be in the range [0, 2π). /// public void WrapPositive() { float newangle = radians % MathUtil.TwoPi; if (newangle < 0.0) newangle += MathUtil.TwoPi; radians = newangle; } /// /// Gets or sets the total number of revolutions this SharpDX.AngleSingle represents. /// public float Revolutions { get { return MathUtil.RadiansToRevolutions(radians); } set { radians = MathUtil.RevolutionsToRadians(value); } } /// /// Gets or sets the total number of degrees this SharpDX.AngleSingle represents. /// public float Degrees { get { return MathUtil.RadiansToDegrees(radians); } set { radians = MathUtil.DegreesToRadians(value); } } /// /// Gets or sets the minutes component of the degrees this SharpDX.AngleSingle represents. /// When setting the minutes, if the value is in the range (-60, 60) the whole degrees are /// not changed; otherwise, the whole degrees may be changed. Fractional values may set /// the seconds component. /// public float Minutes { get { float degrees = MathUtil.RadiansToDegrees(radians); if (degrees < 0) { float degreesfloor = (float)Math.Ceiling(degrees); return (degrees - degreesfloor) * 60.0f; } else { float degreesfloor = (float)Math.Floor(degrees); return (degrees - degreesfloor) * 60.0f; } } set { float degrees = MathUtil.RadiansToDegrees(radians); float degreesfloor = (float)Math.Floor(degrees); degreesfloor += value / 60.0f; radians = MathUtil.DegreesToRadians(degreesfloor); } } /// /// Gets or sets the seconds of the degrees this SharpDX.AngleSingle represents. /// When setting the seconds, if the value is in the range (-60, 60) the whole minutes /// or whole degrees are not changed; otherwise, the whole minutes or whole degrees /// may be changed. /// public float Seconds { get { float degrees = MathUtil.RadiansToDegrees(radians); if (degrees < 0) { float degreesfloor = (float)Math.Ceiling(degrees); float minutes = (degrees - degreesfloor) * 60.0f; float minutesfloor = (float)Math.Ceiling(minutes); return (minutes - minutesfloor) * 60.0f; } else { float degreesfloor = (float)Math.Floor(degrees); float minutes = (degrees - degreesfloor) * 60.0f; float minutesfloor = (float)Math.Floor(minutes); return (minutes - minutesfloor) * 60.0f; } } set { float degrees = MathUtil.RadiansToDegrees(radians); float degreesfloor = (float)Math.Floor(degrees); float minutes = (degrees - degreesfloor) * 60.0f; float minutesfloor = (float)Math.Floor(minutes); minutesfloor += value / 60.0f; degreesfloor += minutesfloor / 60.0f; radians = MathUtil.DegreesToRadians(degreesfloor); } } /// /// Gets or sets the total number of radians this SharpDX.AngleSingle represents. /// public float Radians { get { return radians; } set { radians = value; } } /// /// Gets or sets the total number of milliradians this SharpDX.AngleSingle represents. /// One milliradian is equal to 1/(2000π). /// public float Milliradians { get { return radians / (Milliradian * MathUtil.TwoPi); } set { radians = value * (Milliradian * MathUtil.TwoPi); } } /// /// Gets or sets the total number of gradians this SharpDX.AngleSingle represents. /// public float Gradians { get { return MathUtil.RadiansToGradians(radians); } set { radians = MathUtil.RadiansToGradians(value); } } /// /// Gets a System.Boolean that determines whether this SharpDX.Angle /// is a right angle (i.e. 90° or π/2). /// public bool IsRight { get { return radians == MathUtil.PiOverTwo; } } /// /// Gets a System.Boolean that determines whether this SharpDX.Angle /// is a straight angle (i.e. 180° or π). /// public bool IsStraight { get { return radians == MathUtil.Pi; } } /// /// Gets a System.Boolean that determines whether this SharpDX.Angle /// is a full rotation angle (i.e. 360° or 2π). /// public bool IsFullRotation { get { return radians == MathUtil.TwoPi; } } /// /// Gets a System.Boolean that determines whether this SharpDX.Angle /// is an oblique angle (i.e. is not 90° or a multiple of 90°). /// public bool IsOblique { get { return WrapPositive(this).radians != MathUtil.PiOverTwo; } } /// /// Gets a System.Boolean that determines whether this SharpDX.Angle /// is an acute angle (i.e. less than 90° but greater than 0°). /// public bool IsAcute { get { return radians > 0.0 && radians < MathUtil.PiOverTwo; } } /// /// Gets a System.Boolean that determines whether this SharpDX.Angle /// is an obtuse angle (i.e. greater than 90° but less than 180°). /// public bool IsObtuse { get { return radians > MathUtil.PiOverTwo && radians < MathUtil.Pi; } } /// /// Gets a System.Boolean that determines whether this SharpDX.Angle /// is a reflex angle (i.e. greater than 180° but less than 360°). /// public bool IsReflex { get { return radians > MathUtil.Pi && radians < MathUtil.TwoPi; } } /// /// Gets a SharpDX.AngleSingle instance that complements this angle (i.e. the two angles add to 90°). /// public AngleSingle Complement { get { return new AngleSingle(MathUtil.PiOverTwo - radians, AngleType.Radian); } } /// /// Gets a SharpDX.AngleSingle instance that supplements this angle (i.e. the two angles add to 180°). /// public AngleSingle Supplement { get { return new AngleSingle(MathUtil.Pi - radians, AngleType.Radian); } } /// /// Wraps the SharpDX.AngleSingle given in the value argument to be in the range [π, -π]. /// /// A SharpDX.AngleSingle to wrap. /// The SharpDX.AngleSingle that is wrapped. public static AngleSingle Wrap(AngleSingle value) { value.Wrap(); return value; } /// /// Wraps the SharpDX.AngleSingle given in the value argument to be in the range [0, 2π). /// /// A SharpDX.AngleSingle to wrap. /// The SharpDX.AngleSingle that is wrapped. public static AngleSingle WrapPositive(AngleSingle value) { value.WrapPositive(); return value; } /// /// Compares two SharpDX.AngleSingle instances and returns the smaller angle. /// /// The first SharpDX.AngleSingle instance to compare. /// The second SharpDX.AngleSingle instance to compare. /// The smaller of the two given SharpDX.AngleSingle instances. public static AngleSingle Min(AngleSingle left, AngleSingle right) { if (left.radians < right.radians) return left; return right; } /// /// Compares two SharpDX.AngleSingle instances and returns the greater angle. /// /// The first SharpDX.AngleSingle instance to compare. /// The second SharpDX.AngleSingle instance to compare. /// The greater of the two given SharpDX.AngleSingle instances. public static AngleSingle Max(AngleSingle left, AngleSingle right) { if (left.radians > right.radians) return left; return right; } /// /// Adds two SharpDX.AngleSingle objects and returns the result. /// /// The first object to add. /// The second object to add. /// The value of the two objects added together. public static AngleSingle Add(AngleSingle left, AngleSingle right) { return new AngleSingle(left.radians + right.radians, AngleType.Radian); } /// /// Subtracts two SharpDX.AngleSingle objects and returns the result. /// /// The first object to subtract. /// The second object to subtract. /// The value of the two objects subtracted. public static AngleSingle Subtract(AngleSingle left, AngleSingle right) { return new AngleSingle(left.radians - right.radians, AngleType.Radian); } /// /// Multiplies two SharpDX.AngleSingle objects and returns the result. /// /// The first object to multiply. /// The second object to multiply. /// The value of the two objects multiplied together. public static AngleSingle Multiply(AngleSingle left, AngleSingle right) { return new AngleSingle(left.radians * right.radians, AngleType.Radian); } /// /// Divides two SharpDX.AngleSingle objects and returns the result. /// /// The numerator object. /// The denominator object. /// The value of the two objects divided. public static AngleSingle Divide(AngleSingle left, AngleSingle right) { return new AngleSingle(left.radians / right.radians, AngleType.Radian); } /// /// Gets a new SharpDX.AngleSingle instance that represents the zero angle (i.e. 0°). /// public static AngleSingle ZeroAngle { get { return new AngleSingle(0.0f, AngleType.Radian); } } /// /// Gets a new SharpDX.AngleSingle instance that represents the right angle (i.e. 90° or π/2). /// public static AngleSingle RightAngle { get { return new AngleSingle(MathUtil.PiOverTwo, AngleType.Radian); } } /// /// Gets a new SharpDX.AngleSingle instance that represents the straight angle (i.e. 180° or π). /// public static AngleSingle StraightAngle { get { return new AngleSingle(MathUtil.Pi, AngleType.Radian); } } /// /// Gets a new SharpDX.AngleSingle instance that represents the full rotation angle (i.e. 360° or 2π). /// public static AngleSingle FullRotationAngle { get { return new AngleSingle(MathUtil.TwoPi, AngleType.Radian); } } /// /// Returns a System.Boolean that indicates whether the values of two SharpDX.Angle /// objects are equal. /// /// The first object to compare. /// The second object to compare. /// True if the left and right parameters have the same value; otherwise, false. public static bool operator ==(AngleSingle left, AngleSingle right) { return left.radians == right.radians; } /// /// Returns a System.Boolean that indicates whether the values of two SharpDX.Angle /// objects are not equal. /// /// The first object to compare. /// The second object to compare. /// True if the left and right parameters do not have the same value; otherwise, false. public static bool operator !=(AngleSingle left, AngleSingle right) { return left.radians != right.radians; } /// /// Returns a System.Boolean that indicates whether a SharpDX.Angle /// object is less than another SharpDX.AngleSingle object. /// /// The first object to compare. /// The second object to compare. /// True if left is less than right; otherwise, false. public static bool operator <(AngleSingle left, AngleSingle right) { return left.radians < right.radians; } /// /// Returns a System.Boolean that indicates whether a SharpDX.Angle /// object is greater than another SharpDX.AngleSingle object. /// /// The first object to compare. /// The second object to compare. /// True if left is greater than right; otherwise, false. public static bool operator >(AngleSingle left, AngleSingle right) { return left.radians > right.radians; } /// /// Returns a System.Boolean that indicates whether a SharpDX.Angle /// object is less than or equal to another SharpDX.AngleSingle object. /// /// The first object to compare. /// The second object to compare. /// True if left is less than or equal to right; otherwise, false. public static bool operator <=(AngleSingle left, AngleSingle right) { return left.radians <= right.radians; } /// /// Returns a System.Boolean that indicates whether a SharpDX.Angle /// object is greater than or equal to another SharpDX.AngleSingle object. /// /// The first object to compare. /// The second object to compare. /// True if left is greater than or equal to right; otherwise, false. public static bool operator >=(AngleSingle left, AngleSingle right) { return left.radians >= right.radians; } /// /// Returns the value of the SharpDX.AngleSingle operand. (The sign of /// the operand is unchanged.) /// /// A SharpDX.AngleSingle object. /// The value of the value parameter. public static AngleSingle operator +(AngleSingle value) { return value; } /// /// Returns the the negated value of the SharpDX.AngleSingle operand. /// /// A SharpDX.AngleSingle object. /// The negated value of the value parameter. public static AngleSingle operator -(AngleSingle value) { return new AngleSingle(-value.radians, AngleType.Radian); } /// /// Adds two SharpDX.AngleSingle objects and returns the result. /// /// The first object to add. /// The second object to add. /// The value of the two objects added together. public static AngleSingle operator +(AngleSingle left, AngleSingle right) { return new AngleSingle(left.radians + right.radians, AngleType.Radian); } /// /// Subtracts two SharpDX.AngleSingle objects and returns the result. /// /// The first object to subtract /// The second object to subtract. /// The value of the two objects subtracted. public static AngleSingle operator -(AngleSingle left, AngleSingle right) { return new AngleSingle(left.radians - right.radians, AngleType.Radian); } /// /// Multiplies two SharpDX.AngleSingle objects and returns the result. /// /// The first object to multiply. /// The second object to multiply. /// The value of the two objects multiplied together. public static AngleSingle operator *(AngleSingle left, AngleSingle right) { return new AngleSingle(left.radians * right.radians, AngleType.Radian); } /// /// Divides two SharpDX.AngleSingle objects and returns the result. /// /// The numerator object. /// The denominator object. /// The value of the two objects divided. public static AngleSingle operator /(AngleSingle left, AngleSingle right) { return new AngleSingle(left.radians / right.radians, AngleType.Radian); } /// /// Compares this instance to a specified object and returns an integer that /// indicates whether the value of this instance is less than, equal to, or greater /// than the value of the specified object. /// /// The object to compare. /// /// A signed integer that indicates the relationship of the current instance /// to the obj parameter. If the value is less than zero, the current instance /// is less than the other. If the value is zero, the current instance is equal /// to the other. If the value is greater than zero, the current instance is /// greater than the other. /// public int CompareTo(object other) { if (other == null) return 1; if (!(other is AngleSingle)) throw new ArgumentException("Argument must be of type Angle.", "other"); float radians = ((AngleSingle)other).radians; if (this.radians > radians) return 1; if (this.radians < radians) return -1; return 0; } /// /// Compares this instance to a second SharpDX.AngleSingle and returns /// an integer that indicates whether the value of this instance is less than, /// equal to, or greater than the value of the specified object. /// /// The object to compare. /// /// A signed integer that indicates the relationship of the current instance /// to the obj parameter. If the value is less than zero, the current instance /// is less than the other. If the value is zero, the current instance is equal /// to the other. If the value is greater than zero, the current instance is /// greater than the other. /// public int CompareTo(AngleSingle other) { if (this.radians > other.radians) return 1; if (this.radians < other.radians) return -1; return 0; } /// /// Returns a value that indicates whether the current instance and a specified /// SharpDX.AngleSingle object have the same value. /// /// The object to compare. /// /// Returns true if this SharpDX.AngleSingle object and another have the same value; /// otherwise, false. /// public bool Equals(AngleSingle other) { return this == other; } /// /// Returns a that represents this instance. /// /// /// A that represents this instance. /// public override string ToString() { return string.Format(CultureInfo.CurrentCulture, MathUtil.RadiansToDegrees(radians).ToString("0.##°")); } /// /// Returns a that represents this instance. /// /// The format. /// /// A that represents this instance. /// public string ToString(string format) { if (format == null) return ToString(); return string.Format(CultureInfo.CurrentCulture, "{0}°", MathUtil.RadiansToDegrees(radians).ToString(format, CultureInfo.CurrentCulture)); } /// /// Returns a that represents this instance. /// /// The format provider. /// /// A that represents this instance. /// public string ToString(IFormatProvider formatProvider) { return string.Format(formatProvider, MathUtil.RadiansToDegrees(radians).ToString("0.##°")); } /// /// Returns a that represents this instance. /// /// The format. /// The format provider. /// /// A that represents this instance. /// public string ToString(string format, IFormatProvider formatProvider) { if (format == null) return ToString(formatProvider); return string.Format(formatProvider, "{0}°", MathUtil.RadiansToDegrees(radians).ToString(format, CultureInfo.CurrentCulture)); } /// /// Returns a hash code for this SharpDX.AngleSingle instance. /// /// A 32-bit signed integer hash code. public override int GetHashCode() { return radiansInt; } /// /// Returns a value that indicates whether the current instance and a specified /// object have the same value. /// /// The object to compare. /// /// Returns true if the obj parameter is a SharpDX.AngleSingle object or a type /// capable of implicit conversion to a SharpDX.AngleSingle value, and /// its value is equal to the value of the current SharpDX.Angle /// object; otherwise, false. /// public override bool Equals(object obj) { return (obj is AngleSingle) && (this == (AngleSingle)obj); } } }