]> git.donarmstrong.com Git - lilypond.git/commitdiff
Issue 4961/2: Add offset_directed (Real)
authorDavid Kastrup <dak@gnu.org>
Sun, 28 Aug 2016 23:13:15 +0000 (01:13 +0200)
committerDavid Kastrup <dak@gnu.org>
Mon, 5 Sep 2016 17:07:09 +0000 (19:07 +0200)
This converts an angle in degrees into a unit vector.

flower/include/offset.hh
flower/offset.cc

index 8f395398b75e2768d31f476737142502c3a7eedd..c6c166cc428037cb1883363a5601a90d2ff68785 100644 (file)
@@ -126,6 +126,7 @@ IMPLEMENT_ARITHMETIC_OPERATOR (Offset, *);
 Offset complex_multiply (Offset, Offset);
 Offset complex_divide (Offset, Offset);
 Offset complex_exp (Offset);
+Offset offset_directed (Real);
 
 inline Offset
 Offset::operator *= (Offset z2)
index b7f5df40262c7b67e1fbea794142401c558eba7a..cdb63f3f865cddc192e4cd8d1a92b0ad53fc8870 100644 (file)
@@ -182,3 +182,39 @@ Offset::swapped () const
 {
   return Offset (coordinate_a_[Y_AXIS], coordinate_a_[X_AXIS]);
 }
+
+Offset
+offset_directed (Real angle)
+{
+  if (angle <= -360.0 || angle >= 360.0)
+    angle = fmod (angle, 360.0);
+  // Now |angle| < 360.0, and the absolute size is not larger than
+  // before, so we haven't lost precision.
+  if (angle <= -180.0)
+    angle += 360.0;
+  else if (angle > 180.0)
+    angle -= 360.0;
+  // Now -180.0 < angle <= 180.0 and we still haven't lost precision.
+  // We don't work with angles greater than 45 degrees absolute in
+  // order to minimize how rounding errors of M_PI/180 affect the
+  // result.  That way, at least angles that are a multiple of 90
+  // degree deliver the expected results.
+  //
+  // Sign of the sine is chosen to avoid -0.0 in results.  This
+  // version delivers exactly equal magnitude on x/y for odd multiples
+  // of 45 degrees at the cost of losing some less obvious invariants.
+
+  if (angle > 0)
+    if (angle > 90)
+      return Offset (sin ((90 - angle) * M_PI/180.0),
+                     sin ((180 - angle) * M_PI/180.0));
+    else
+      return Offset (sin ((90 - angle) * M_PI/180.0),
+                     sin (angle * M_PI/180.0));
+  else if (angle < -90)
+    return Offset (sin ((90 + angle) * M_PI/180.0),
+                   sin ((-180 - angle) * M_PI/180.0));
+  else
+    return Offset (sin ((90 + angle) * M_PI/180.0),
+                   sin (angle * M_PI/180.0));
+}