コメントで述べたように、度と回転は、特にAPI間でdouble値を混同しないようにするための良い例です。
現在使用しているクラスRadians
とクラスを取り出しました。Degrees
今(久しぶりに)それらを見て、それらをクリーンアップして(特にコメント/ドキュメント)、適切にテストされていることを確認したいと思います。ありがたいことに、私はそうするためにスケジュールに時間をかけることができました。いずれにせよ、これらは自己責任で使用してください。ここでのすべての計算が正しいかどうかは保証できません。私たちが書いたすべての機能を実際に使用/テストしたわけではないからです。
ラジアン
/// <summary>
/// Defines an angle in Radians
/// </summary>
public struct Radians
{
public static readonly Radians ZERO_PI = 0;
public static readonly Radians ONE_PI = System.Math.PI;
public static readonly Radians TWO_PI = ONE_PI * 2;
public static readonly Radians HALF_PI = ONE_PI * 0.5;
public static readonly Radians QUARTER_PI = ONE_PI * 0.25;
#region Public Members
/// <summary>
/// Angle value
/// </summary>
public double Value;
/// <summary>
/// Finds the Cosine of the angle
/// </summary>
public double Cos
{
get
{
return System.Math.Cos(this);
}
}
/// <summary>
/// Finds the Sine of the angle
/// </summary>
public double Sin
{
get
{
return System.Math.Sin(this);
}
}
#endregion
/// <summary>
/// Constructor
/// </summary>
/// <param name="value">angle value in radians</param>
public Radians(double value)
{
this.Value = value;
}
/// <summary>
/// Gets the angle in degrees
/// </summary>
/// <returns>Returns the angle in degrees</returns>
public Degrees GetDegrees()
{
return this;
}
public Radians Reduce()
{
double radian = this.Value;
bool IsNegative = radian < 0;
radian = System.Math.Abs(radian);
while (radian >= System.Math.PI * 2)
{
radian -= System.Math.PI * 2;
}
if (IsNegative && radian != 0)
{
radian = System.Math.PI * 2 - radian;
}
return radian;
}
#region operator overloading
/// <summary>
/// Conversion of Degrees to Radians
/// </summary>
/// <param name="deg"></param>
/// <returns></returns>
public static implicit operator Radians(Degrees deg)
{
return new Radians(deg.Value * System.Math.PI / 180);
}
/// <summary>
/// Conversion of integer to Radians
/// </summary>
/// <param name="i"></param>
/// <returns></returns>
public static implicit operator Radians(int i)
{
return new Radians((double)i);
}
/// <summary>
/// Conversion of float to Radians
/// </summary>
/// <param name="f"></param>
/// <returns></returns>
public static implicit operator Radians(float f)
{
return new Radians((double)f);
}
/// <summary>
/// Conversion of double to Radians
/// </summary>
/// <param name="dbl"></param>
/// <returns></returns>
public static implicit operator Radians(double dbl)
{
return new Radians(dbl);
}
/// <summary>
/// Conversion of Radians to double
/// </summary>
/// <param name="rad"></param>
/// <returns></returns>
public static implicit operator double(Radians rad)
{
return rad.Value;
}
/// <summary>
/// Add Radians and a double
/// </summary>
/// <param name="rad"></param>
/// <param name="dbl"></param>
/// <returns></returns>
public static Radians operator +(Radians rad, double dbl)
{
return new Radians(rad.Value + dbl);
}
/// <summary>
/// Add Radians to Radians
/// </summary>
/// <param name="rad1"></param>
/// <param name="rad2"></param>
/// <returns></returns>
public static Radians operator +(Radians rad1, Radians rad2)
{
return new Radians(rad1.Value + rad2.Value);
}
/// <summary>
/// Add Radians and Degrees
/// </summary>
/// <param name="rad"></param>
/// <param name="deg"></param>
/// <returns></returns>
public static Radians operator +(Radians rad, Degrees deg)
{
return new Radians(rad.Value + deg.GetRadians().Value);
}
/// <summary>
/// Sets Radians value negative
/// </summary>
/// <param name="rad"></param>
/// <returns></returns>
public static Radians operator -(Radians rad)
{
return new Radians(-rad.Value);
}
/// <summary>
/// Subtracts a double from Radians
/// </summary>
/// <param name="rad"></param>
/// <param name="dbl"></param>
/// <returns></returns>
public static Radians operator -(Radians rad, double dbl)
{
return new Radians(rad.Value - dbl);
}
/// <summary>
/// Subtracts Radians from Radians
/// </summary>
/// <param name="rad1"></param>
/// <param name="rad2"></param>
/// <returns></returns>
public static Radians operator -(Radians rad1, Radians rad2)
{
return new Radians(rad1.Value - rad2.Value);
}
/// <summary>
/// Subtracts Degrees from Radians
/// </summary>
/// <param name="rad"></param>
/// <param name="deg"></param>
/// <returns></returns>
public static Radians operator -(Radians rad, Degrees deg)
{
return new Radians(rad.Value - deg.GetRadians().Value);
}
#endregion
public override string ToString()
{
return String.Format("{0}", this.Value);
}
public static Radians Convert(object value)
{
if (value is Radians)
return (Radians)value;
if (value is Degrees)
return (Degrees)value;
return System.Convert.ToDouble(value);
}
}
度
public struct Degrees
{
public double Value;
public Degrees(double value) { this.Value = value; }
public Radians GetRadians()
{
return this;
}
public Degrees Reduce()
{
return this.GetRadians().Reduce();
}
public double Cos
{
get
{
return System.Math.Cos(this.GetRadians());
}
}
public double Sin
{
get
{
return System.Math.Sin(this.GetRadians());
}
}
#region operator overloading
public static implicit operator Degrees(Radians rad)
{
return new Degrees(rad.Value * 180 / System.Math.PI);
}
public static implicit operator Degrees(int i)
{
return new Degrees((double)i);
}
public static implicit operator Degrees(float f)
{
return new Degrees((double)f);
}
public static implicit operator Degrees(double d)
{
return new Degrees(d);
}
public static implicit operator double(Degrees deg)
{
return deg.Value;
}
public static Degrees operator +(Degrees deg, int i)
{
return new Degrees(deg.Value + i);
}
public static Degrees operator +(Degrees deg, double dbl)
{
return new Degrees(deg.Value + dbl);
}
public static Degrees operator +(Degrees deg1, Degrees deg2)
{
return new Degrees(deg1.Value + deg2.Value);
}
public static Degrees operator +(Degrees deg, Radians rad)
{
return new Degrees(deg.Value + rad.GetDegrees().Value);
}
public static Degrees operator -(Degrees deg)
{
return new Degrees(-deg.Value);
}
public static Degrees operator -(Degrees deg, int i)
{
return new Degrees(deg.Value - i);
}
public static Degrees operator -(Degrees deg, double dbl)
{
return new Degrees(deg.Value - dbl);
}
public static Degrees operator -(Degrees deg1, Degrees deg2)
{
return new Degrees(deg1.Value - deg2.Value);
}
public static Degrees operator -(Degrees deg, Radians rad)
{
return new Degrees(deg.Value - rad.GetDegrees().Value);
}
#endregion
public override string ToString()
{
return String.Format("{0}", this.Value);
}
public static Degrees Convert(object value)
{
if (value is Degrees)
return (Degrees)value;
if (value is Radians)
return (Radians)value;
return System.Convert.ToDouble(value);
}
}
いくつかの使用例
これらは、APIを使用するときに本当に役立ちます。内部的には、組織は混乱を避けるために度またはラジアンに厳密に固執することを決定する場合がありますが、少なくともこれらのクラスでは、最も意味のあるタイプを使用できます。たとえば、公的に消費されているAPIまたはGUI APIを使用できますDegrees
が、大量の数学/トリガーまたは内部使用ではを使用する場合がありますRadians
。次のクラス/印刷機能を検討します。
public class MyRadiansShape
{
public Radians Rotation { get; set; }
}
public class MyDegreesShape
{
public Degrees Rotation { get; set; }
}
public static void PrintRotation(Degrees degrees, Radians radians)
{
Console.WriteLine(String.Format("Degrees: {0}, Radians: {1}", degrees.Value, radians.Value));
}
ええ、コードはかなり工夫されています(そしてひどく曖昧です)が、それは大丈夫です!偶発的な取り違えを減らすのにどのように役立つかを示します。
var radiansShape = new MyRadiansShape() { Rotation = Math.PI / 2}; //prefer "Radians.HALF_PI" instead, but just as an example
var degreesShape = new MyDegreesShape() { Rotation = 90 };
PrintRotation(radiansShape.Rotation, radiansShape.Rotation);
PrintRotation(degreesShape.Rotation, degreesShape.Rotation);
PrintRotation(radiansShape.Rotation + degreesShape.Rotation, radiansShape.Rotation + degreesShape.Rotation);
//Degrees: 90, Radians: 1.5707963267949
//Degrees: 90, Radians: 1.5707963267949
//Degrees: 180, Radians: 3.14159265358979
次に、極座標など、角度に基づく他の数学的概念を実装するのに非常に役立ちます。
double distance = 5;
Polar polarCoordinate = new Polar(distance, (degreesShape.Rotation - radiansShape.Rotation) + Radians.QUARTER_PI);
Console.WriteLine("Polar Coordinate Angle: " + (Degrees)polarCoordinate.Angle); //because it's easier to read degrees!
//Polar Coordinate Angle: 45
そして最後に、Point2D
以下への/からの暗黙的な変換を使用してクラスを実装(またはSystem.Windows.Pointを使用)することができPolar
ます。
Point2D cartesianCoordinate = polarCoordinate;
Console.WriteLine(cartesianCoordinate.X + ", " + cartesianCoordinate.Y);
//3.53553390593274, 3.53553390593274
私が言ったように、私はこれらのクラスで別のパスを取り、おそらくいくつかのコーナーケースの取り違えやコンパイラのあいまいさを避けるためにdouble
暗黙の変換を排除したいと思います。これらは、静的フィールド(など)Radians
を作成する前に実際に存在し、 doubleの倍数から変換していました。ONE_PI
HALF_PI
Math.PI
編集:Polar
これは、追加の暗黙的な変換のデモンストレーションとしてのクラスです。Radians
クラス(およびその暗黙の変換)と、クラスおよびクラスのヘルパーメソッドを利用しPoint2D
ます。ここには含めていませんが、Polar
クラスはクラスと対話する演算子を簡単に実装できますPoint2D
が、これらはこの説明には関係ありません。
public struct Polar
{
public double Radius;
public Radians Angle;
public double X { get { return Radius * Angle.Cos; } }
public double Y { get { return Radius * Angle.Sin; } }
public Polar(double radius, Radians angle)
{
this.Radius = radius;
this.Angle = angle;
}
public Polar(Point2D point)
: this(point.Magnitude(), point.GetAngleFromOrigin())
{
}
public Polar(Point2D point, double radius)
: this(radius, point.GetAngleFromOrigin())
{
}
public Polar(Point2D point, Point2D origin)
: this(point - origin)
{
}
public Point2D ToCartesian()
{
return new Point2D(X, Y);
}
public static implicit operator Point2D(Polar polar)
{
return polar.ToCartesian();
}
public static implicit operator Polar(Point2D vector)
{
return new Polar(vector);
}
}