One problem with the .NET library is the inconsistent use of radians and degrees to represent angles: System.Math angle functions assume angle are expressed in radian while WPF assumes angles are expressed in degrees. Trouble arises when you try to mix both APIs. While you can convert between degrees and radians using a couple simple equations (that I was forget and are not provided in System.Math as they are in java.lang.Math), a better way has to exist.

In Bling WPF, I’ve defined the struct Bling.Signals.Angle that abstracts the underlying angle representation. Assuming “using Bling.Signals,” you can go from a double or int to an Angle using three extensions methods: Degrees(), Radians(), or PI(). E.g., 90.Degrees() is an angle that is equivalent to .5.PI() and (.5 * Math.PI).Radians(). The Angle struct itself then has standard trigonometric functions on Angles that are otherwise in Math (e.g., Cos(), Sin(), Tan()) and some that Math left out that are useful in graphics programming; e.g., SinCos() that returns a unit vector pointing in the direction of the angle. Since there is no point in an Angle struct if no APIs will ever use it, I’ve wrapped all the angle-like dependency properties to return Angle signals (AngleSg) rather than double signals. Example of Rotate:

public static AngleSg Rotate(this UIElement source, PointSg center) { RotateTransform rotate = source.Transform<RotateTransform>(); rotate.Center().Bind = center; return rotate.Angle(); }

public static AngleSg Angle(this RotateTransform source) { return source.Signal<double>(RotateTransform.AngleProperty).Lft().Degrees(); }

Basically, double signal (DoubleSg) has a function Degrees() that transforms it into a read/write angle signal. Rotation can now be expressed in angles or radians:

  • rectangle.Rotate(rectangle.Center()).Value = 45.Degrees();
  • rectangle.Rotate(rectangle.Center()).Value = .25.PI();

These can also be combined with trig functions:

  • rectangle.Rotate(rectangle.Center()).Value = x.ASin();
  • rectangle.Rotate(rectangle.Center()).Value = x.ACos();

This becomes really convenient when you are doing lots of geometric graphics programming.