Esempio n. 1
0
 def Astroid(x, y):
     """Private: solve astroid equation."""
     # Solve k^4+2*k^3-(x^2+y^2-1)*k^2-2*y^2*k-y^2 = 0 for positive root k.
     # This solution is adapted from Geocentric::Reverse.
     p = Math.sq(x)
     q = Math.sq(y)
     r = (p + q - 1) / 6
     if not (q == 0 and r <= 0):
         # Avoid possible division by zero when r = 0 by multiplying equations
         # for s and t by r^3 and r, resp.
         S = p * q / 4  # S = r^3 * s
         r2 = Math.sq(r)
         r3 = r * r2
         # The discrimant of the quadratic equation for T3.  This is zero on
         # the evolute curve p^(1/3)+q^(1/3) = 1
         disc = S * (S + 2 * r3)
         u = r
         if (disc >= 0):
             T3 = S + r3
             # Pick the sign on the sqrt to maximize abs(T3).  This minimizes loss
             # of precision due to cancellation.  The result is unchanged because
             # of the way the T is used in definition of u.
             T3 += -math.sqrt(disc) if T3 < 0 else math.sqrt(
                 disc)  # T3 = (r * t)^3
             # N.B. cbrt always returns the real root.  cbrt(-8) = -2.
             T = Math.cbrt(T3)  # T = r * t
             # T can be zero; but then r2 / T -> 0.
             u += T + (r2 / T if T != 0 else 0)
         else:
             # T is complex, but the way u is defined the result is real.
             ang = math.atan2(math.sqrt(-disc), -(S + r3))
             # There are three possible cube roots.  We choose the root which
             # avoids cancellation.  Note that disc < 0 implies that r < 0.
             u += 2 * r * math.cos(ang / 3)
         v = math.sqrt(Math.sq(u) + q)  # guaranteed positive
         # Avoid loss of accuracy when u < 0.
         uv = q / (v - u) if u < 0 else u + v  # u+v, guaranteed positive
         w = (uv - q) / (2 * v)  # positive?
         # Rearrange expression for k to avoid loss of accuracy due to
         # subtraction.  Division by 0 not possible because uv > 0, w >= 0.
         k = uv / (math.sqrt(uv + Math.sq(w)) + w)  # guaranteed positive
     else:  # q == 0 && r <= 0
         # y = 0 with |x| <= 1.  Handle this case directly.
         # for y small, positive root is k = abs(y)/sqrt(1-x^2)
         k = 0
     return k
Esempio n. 2
0
 def Astroid(x, y):
   """Private: solve astroid equation."""
   # Solve k^4+2*k^3-(x^2+y^2-1)*k^2-2*y^2*k-y^2 = 0 for positive root k.
   # This solution is adapted from Geocentric::Reverse.
   p = Math.sq(x)
   q = Math.sq(y)
   r = (p + q - 1) / 6
   if not(q == 0 and r <= 0):
     # Avoid possible division by zero when r = 0 by multiplying equations
     # for s and t by r^3 and r, resp.
     S = p * q / 4            # S = r^3 * s
     r2 = Math.sq(r)
     r3 = r * r2
     # The discrimant of the quadratic equation for T3.  This is zero on
     # the evolute curve p^(1/3)+q^(1/3) = 1
     disc = S * (S + 2 * r3)
     u = r
     if (disc >= 0):
       T3 = S + r3
       # Pick the sign on the sqrt to maximize abs(T3).  This minimizes loss
       # of precision due to cancellation.  The result is unchanged because
       # of the way the T is used in definition of u.
       T3 += -math.sqrt(disc) if T3 < 0 else math.sqrt(disc) # T3 = (r * t)^3
       # N.B. cbrt always returns the real root.  cbrt(-8) = -2.
       T = Math.cbrt(T3)       # T = r * t
       # T can be zero; but then r2 / T -> 0.
       u += T + (r2 / T if T != 0 else 0)
     else:
       # T is complex, but the way u is defined the result is real.
       ang = math.atan2(math.sqrt(-disc), -(S + r3))
       # There are three possible cube roots.  We choose the root which
       # avoids cancellation.  Note that disc < 0 implies that r < 0.
       u += 2 * r * math.cos(ang / 3)
     v = math.sqrt(Math.sq(u) + q) # guaranteed positive
     # Avoid loss of accuracy when u < 0.
     uv = q / (v - u) if u < 0 else u + v # u+v, guaranteed positive
     w = (uv - q) / (2 * v)               # positive?
     # Rearrange expression for k to avoid loss of accuracy due to
     # subtraction.  Division by 0 not possible because uv > 0, w >= 0.
     k = uv / (math.sqrt(uv + Math.sq(w)) + w) # guaranteed positive
   else:                                       # q == 0 && r <= 0
     # y = 0 with |x| <= 1.  Handle this case directly.
     # for y small, positive root is k = abs(y)/sqrt(1-x^2)
     k = 0
   return k