Skip to content

Commit

Permalink
More angles
Browse files Browse the repository at this point in the history
  • Loading branch information
dfkeenan committed Dec 2, 2023
1 parent 2765624 commit a675423
Showing 1 changed file with 43 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,27 @@ Proposal API for additional math types to bring it up to feature parity with oth
- Text herein marked **INFORMATIVE** does not form a normative part of this proposal, and is for background only.
- Within this proposal, the key words **must**, **required**, **shall**, **should**, **recommended**, **may**, **could**, and **optional** are to be interpreted as described in [RFC 2119 - Key words for use in RFCs to Indicate Requirement Levels](https://www.ietf.org/rfc/rfc2119.txt). The additional key word **optionally** is an alternate form of **optional**, for use where grammatically appropriate. These key words are highlighted in the proposal for clarity.

# **INFORMATIVE** Integer and Floating Point Types
While investigating the use of generic math it was decided to provide both an integer and floating point variant for each vector type and every type built from them. See [Generic Math](Proposal%20-%20Generic%20Math.md) proposal for more details.

# I types versus F Types
Where it is appropriate for a type in this proposal to have both integer and floating point variants they will have a name that ends in I or F, defining whether it is an integer type or floating point type. Integer types **must** use a generic type argument `T` with the constraint of `IBinaryInteger<T>`. On the other hand, floating point types **must** use a generic type argument `T` with the constraint of `IFloatingPointIeee754<T>`.

# Proposed API

## Angle

* `IParsable<TSelf>`, `ISpanParsable<TSelf>`, `IUtf8SpanParsable<TSelf>`
* must parse angle in degrees using `IParsable<TScalar>`, `ISpanParsable<TScalar>`, `IUtf8SpanParsable<TSelf>`
* optional handle `°` character

* `IFormattable`, `IUtf8SpanFormattable`
* must produce text in degrees with default format of 2 decimal places. i.e. format string `0.##`
* optional include `°` character. i.e. format string `0.##°`

Interface implementations not included for brevity.

```csharp
/// <summary>
/// Represents a unit independant angle using a floating-point
/// internal representation.
/// </summary>
public readonly struct Angle<TScalar>
: IEquatable<Angle<TScalar>>
, IEqualityOperators<Angle<TScalar>,Angle<TScalar>, bool>
Expand All @@ -48,131 +56,76 @@ public readonly struct Angle<TScalar>
, IUtf8SpanFormattable
where TScalar : IFloatingPointIeee754<TScalar>
{

public readonly TScalar TotalRadians;

public Angle(TScalar totalRadians) { }
public Angle(TScalar radians) { }

/// <summary>Angle in degrees in the range [0, 360].</summary>
public TScalar Degrees { get; }
/// <summary>Total angle in degrees.</summary>
public TScalar TotalDegrees { get; }

/// <summary>Angle in radians in range [π, -π].</summary>
public TScalar Radians { get; }

public TScalar Hours { get; }
/// <summary>Angle in radians in range [0, 2π].</summary>
public TScalar PositiveRadians { get; }

/// <summary>Gets or sets the minutes component of the degrees this Silk.NET.Maths.Angle<TScalar> represents.</summary>
public TScalar Minutes { get; }

/// <summary>Gets or sets the seconds of the degrees this Silk.NET.Maths.Angle<TScalar> represents.</summary>
public TScalar Seconds { get; }


/// <summary>
/// Gets a System.Boolean that determines whether this Angle<TScalar>
/// Gets a System.Boolean that determines whether this Silk.NET.Maths.Angle<TScalar>
/// is a right angle (i.e. 90° or π/2).
/// </summary>
public bool IsRight { get; }

/// <summary>
/// Gets a System.Boolean that determines whether this Angle<TScalar>
/// Gets a System.Boolean that determines whether this Silk.NET.Maths.Angle<TScalar>
/// is a straight angle (i.e. 180° or π).
/// </summary>
public bool IsStraight { get; }

/// <summary>
/// Gets a System.Boolean that determines whether this Angle<TScalar>
/// Gets a System.Boolean that determines whether this Silk.NET.Maths.Angle<TScalar>
/// is a full rotation angle (i.e. 360° or 2π).
/// </summary>
public bool IsFullRotation { get; }

/// <summary>
/// Gets a System.Boolean that determines whether this Angle<TScalar>
/// Gets a System.Boolean that determines whether this Silk.NET.Maths.Angle<TScalar>
/// is an oblique angle (i.e. is not 90° or a multiple of 90°).
/// </summary>
public bool IsOblique { get; }

/// <summary>
/// Gets a System.Boolean that determines whether this Angle<TScalar>
/// Gets a System.Boolean that determines whether this Silk.NET.Maths.Angle<TScalar>
/// is an acute angle (i.e. less than 90° but greater than 0°).
/// </summary>
public bool IsAcute { get; }

/// <summary>
/// Gets a System.Boolean that determines whether this Angle<TScalar>
/// Gets a System.Boolean that determines whether this Silk.NET.Maths.Angle<TScalar>
/// is an obtuse angle (i.e. greater than 90° but less than 180°).
/// </summary>
public bool IsObtuse { get; }

/// <summary>
/// Gets a System.Boolean that determines whether this Angle<TScalar>
/// Gets a System.Boolean that determines whether this Silk.NET.Maths.Angle<TScalar>
/// is a reflex angle (i.e. greater than 180° but less than 360°).
/// </summary>
public bool IsReflex { get; }

/// <summary>
/// Gets a Angle<TScalar> instance that complements this angle (i.e. the two angles add to 90°).
/// Gets a Silk.NET.Maths.Angle<TScalar> instance that complements this angle (i.e. the two angles add to 90°).
/// </summary>
public Angle<TScalar> Complement { get; }

/// <summary>
/// Gets a Angle<TScalar> instance that supplements this angle (i.e. the two angles add to 180°).
/// Gets a Silk.NET.Maths.Angle<TScalar> instance that supplements this angle (i.e. the two angles add to 180°).
/// </summary>
public Angle<TScalar> Supplement { get; }

/// <summary>
/// Wraps this Angle<TScalar> to be in the range [π, -π].
/// </summary>
public Angle<TScalar> Wrap() => default;

/// <summary>
/// Wraps this Angle<TScalar> to be in the range [0, 2π).
/// </summary>
public Angle<TScalar> WrapPositive() => default;


/// <summary>Computes the arc-cosine of a value.</summary>
public TScalar Acos() => default;

/// <summary>Computes the arc-cosine of a value and divides the result by <c>pi</c>.</summary>
public TScalar AcosPi() => default;

/// <summary>Computes the arc-sine of a value.</summary>
public TScalar Asin() => default;

/// <summary>Computes the arc-sine of a value and divides the result by <c>pi</c>.</summary>
public TScalar AsinPi() => default;

/// <summary>Computes the arc-tangent of a value.</summary>
public TScalar Atan() => default;

/// <summary>Computes the arc-tangent of a value and divides the result by pi.</summary>
public TScalar AtanPi() => default;

/// <summary>Computes the cosine of a value.</summary>
public TScalar Cos() => default;

/// <summary>Computes the cosine of a value that has been multipled by <c>pi</c>.</summary>
public TScalar CosPi() => default;

/// <summary>Computes the sine of a value.</summary>
/// <param name="x">The value, in radians, whose sine is to be computed.</param>
/// <returns>The sine of <paramref name="x" />.</returns>
/// <remarks>This computes <c>sin(x)</c>.</remarks>
public TScalar Sin() => default;

/// <summary>Computes the sine and cosine of a value.</summary>
public (TScalar Sin, TScalar Cos) SinCos() => default;

/// <summary>Computes the sine and cosine of a value that has been multiplied by <c>pi</c>.</summary>
public (TScalar SinPi, TScalar CosPi) SinCosPi() => default;

/// <summary>Computes the sine of a value that has been multiplied by <c>pi</c>.</summary>
public TScalar SinPi() => default;

/// <summary>Computes the tangent of a value.</summary>
public TScalar Tan() => default;

/// <summary>Computes the tangent of a value that has been multipled by <c>pi</c>.</summary>
public TScalar TanPi() => default;

/// <summary>Implicit cast in radians</summary>
public static implicit operator TScalar(Angle<TScalar> angle) => default;
}
Expand All @@ -188,20 +141,16 @@ public static class Angle
public static Angle<TScalar> FromRadians<TScalar>(TScalar radians)
where TScalar : IFloatingPointIeee754<TScalar>
=> default;

public static Angle<TScalar> FromDegrees<TScalar>(TScalar degrees)
where TScalar : IFloatingPointIeee754<TScalar>
=> default;
public static Angle<TScalar> FromHours<TScalar>(TScalar hours)
where TScalar : IFloatingPointIeee754<TScalar>
=> default;

public static Angle<TScalar> FromMinutes<TScalar>(TScalar minutes)
where TScalar : IFloatingPointIeee754<TScalar>
=> default;
public static Angle<TScalar> FromSeconds<TScalar>(TScalar seconds)
where TScalar : IFloatingPointIeee754<TScalar>
=> default;

public static Angle<TScalar> FromTimeSpan<TScalar>(TimeSpan timeSpan)
public static Angle<TScalar> FromSeconds<TScalar>(TScalar seconds)
where TScalar : IFloatingPointIeee754<TScalar>
=> default;

Expand All @@ -213,15 +162,23 @@ public static class Angle
where TScalar : IFloatingPointIeee754<TScalar>
=> default;

public static Angle<TScalar> Clamp<TScalar>(Angle<TScalar> value, Angle<TScalar> min, Angle<TScalar> max)
public static Angle<TScalar> Add<TScalar>(Angle<TScalar> left, Angle<TScalar> right)
where TScalar : IFloatingPointIeee754<TScalar>
=> default;

public static Angle<TScalar> Subtract<TScalar>(Angle<TScalar> left, Angle<TScalar> right)
where TScalar : IFloatingPointIeee754<TScalar>
=> default;

public static Angle<TScalar> Lerp<TScalar>(Angle<TScalar> start, Angle<TScalar> end, TScalar amount)
public static Angle<TScalar> Multiply<TScalar>(Angle<TScalar> left, TScalar right)
where TScalar : IFloatingPointIeee754<TScalar>
=> default;

public static Angle<TScalar> SmoothStep<TScalar>(Angle<TScalar> start, Angle<TScalar> end, TScalar amount)
public static Angle<TScalar> Divide<TScalar>(Angle<TScalar> left, TScalar right)
where TScalar : IFloatingPointIeee754<TScalar>
=> default;

public static Angle<TScalar> Clamp<TScalar>(Angle<TScalar> value, Angle<TScalar> min, Angle<TScalar> max)
where TScalar : IFloatingPointIeee754<TScalar>
=> default;

Expand Down

0 comments on commit a675423

Please sign in to comment.