Original javascript on http://williams.best.vwh.net/gccalc.htm
    Translated into python by Thomas Lecocq
    This function is a black box, because trigonometry is difficult
516936
def _gccalc(lon, lat, azimuth, maxdist=None):
    
    glat1 = lat * np.pi / 180.
    glon1 = lon * np.pi / 180.
    s = maxdist / 1.852243
    faz = azimuth * np.pi / 180.
 
    EPS = 0.00000000005
    if ((np.abs(np.cos(glat1)) < EPS) and not (np.abs(np.sin(faz)) < EPS)):
        raise CourseException("Only North-South courses are meaningful")

    a = 6378.137 / 1.852243
    f = 1 / 298.257223563
    r = 1 - f
    tu = r * np.tan(glat1)
    sf = np.sin(faz)
    cf = np.cos(faz)
    if (cf == 0):
        b = 0.
    else:
        b = 2. * np.arctan2 (tu, cf)

    cu = 1. / np.sqrt(1 + tu * tu)
    su = tu * cu
    sa = cu * sf
    c2a = 1 - sa * sa
    x = 1. + np.sqrt(1. + c2a * (1. / (r * r) - 1.))
    x = (x - 2.) / x
    c = 1. - x
    c = (x * x / 4. + 1.) / c
    d = (0.375 * x * x - 1.) * x
    tu = s / (r * a * c)
    y = tu
    c = y + 1
    while (np.abs (y - c) > EPS):
        sy = np.sin(y)
        cy = np.cos(y)
        cz = np.cos(b + y)
        e = 2. * cz * cz - 1.
        c = y
        x = e * cy
        y = e + e - 1.
        y = (((sy * sy * 4. - 3.) * y * cz * d / 6. + x) *
            d / 4. - cz) * sy * d + tu

    b = cu * cy * cf - su * sy
    c = r * np.sqrt(sa * sa + b * b)
    d = su * cy + cu * sy * cf
    glat2 = (np.arctan2(d, c) + np.pi) % (2*np.pi) - np.pi
    c = cu * cy - su * sy * cf
    x = np.arctan2(sy * sf, c)
    c = ((-3. * c2a + 4.) * f + 4.) * c2a * f / 16.
    d = ((e * cy * c + cz) * sy * c + y) * sa
    glon2 = ((glon1 + x - (1. - c) * d * f + np.pi) % (2*np.pi)) - np.pi

    baz = (np.arctan2(sa, b) + np.pi) % (2 * np.pi)

    glon2 *= 180./np.pi
    glat2 *= 180./np.pi
    baz *= 180./np.pi
    return (glon2, glat2, baz)
1372530
function gradientBox(angle, rect) {
  const [x, y, w, h] = rect;

  angle %= 360;
  if(angle < 0) {
    angle += 360;
  }

  let ret = [x, y, x + w, y + h];
  if(angle >= 0 && angle < 90) {
    const tan = Math.tan((Math.PI * angle) / 180);

    let d = tan * w;

    if(d <= h) {
      ret = [x, y, x + w, y + d];
    } else {
      d = h / tan;
      ret = [x, y, x + d, y + h];
    }
  } else if(angle >= 90 && angle < 180) {
    const tan = Math.tan((Math.PI * (angle - 90)) / 180);

    let d = tan * h;

    if(d <= w) {
      ret = [x + w, y, x + w - d, y + h];
    } else {
      d = w / tan;
      ret = [x + w, y, x, y + d];
    }
  } else if(angle >= 180 && angle < 270) {
    const tan = Math.tan((Math.PI * (angle - 180)) / 180);

    let d = tan * w;

    if(d <= h) {
      ret = [x + w, y + h, x, y + h - d];
    } else {
      d = h / tan;
      ret = [x + w, y + h, x + w - d, y];
    }
  } else if(angle >= 270 && angle < 360) {
    const tan = Math.tan((Math.PI * (angle - 270)) / 180);

    let d = tan * h;

    if(d <= w) {
      ret = [x, y + h, x + d, y];
    } else {
      d = w / tan;
      ret = [x, y + h, x + w, y + h - d];
    }
  }

  return ret;
}
1053644
function g(){Array.isArray||(Array.isArray=function(a){return"[object Array]"===Object.prototype.toString.call(a)});var d={MAX_CODEPOINT:1114111,encodeUTF8:function(a,b){var c=null;"number"===typeof a&&(c=a,a=function(){return null});for(;null!==c||null!==(c=a());)128>c?b(c&127):(2048>c?b(c>>6&31|192):(65536>c?b(c>>12&15|224):(b(c>>18&7|240),b(c>>12&63|128)),b(c>>6&63|128)),b(c&63|128)),c=null},decodeUTF8:function(a,b){function c(a){a=a.slice(0,a.indexOf(null));var b=Error(a.toString());b.name="TruncatedError";
b.bytes=a;throw b;}for(var e,d,f,h;null!==(e=a());)if(0===(e&128))b(e);else if(192===(e&224))null===(d=a())&&c([e,d]),b((e&31)<<6|d&63);else if(224===(e&240))null!==(d=a())&&null!==(f=a())||c([e,d,f]),b((e&15)<<12|(d&63)<<6|f&63);else if(240===(e&248))null!==(d=a())&&null!==(f=a())&&null!==(h=a())||c([e,d,f,h]),b((e&7)<<18|(d&63)<<12|(f&63)<<6|h&63);else throw RangeError("Illegal starting byte: "+e);},UTF16toUTF8:function(a,b){for(var c,e=null;null!==(c=null!==e?e:a());)55296<=c&&57343>=c&&null!==
(e=a())&&56320<=e&&57343>=e?(b(1024*(c-55296)+e-56320+65536),e=null):b(c);null!==e&&b(e)},UTF8toUTF16:function(a,b){var c=null;"number"===typeof a&&(c=a,a=function(){return null});for(;null!==c||null!==(c=a());)65535>=c?b(c):(c-=65536,b((c>>10)+55296),b(c%1024+56320)),c=null},encodeUTF16toUTF8:function(a,b){d.UTF16toUTF8(a,function(a){d.encodeUTF8(a,b)})},decodeUTF8toUTF16:function(a,b){d.decodeUTF8(a,function(a){d.UTF8toUTF16(a,b)})},calculateCodePoint:function(a){return 128>a?1:2048>a?2:65536>a?
3:4},calculateUTF8:function(a){for(var b,c=0;null!==(b=a());)c+=128>b?1:2048>b?2:65536>b?3:4;return c},calculateUTF16asUTF8:function(a){var b=0,c=0;d.UTF16toUTF8(a,function(a){++b;c+=128>a?1:2048>a?2:65536>a?3:4});return[b,c]}},k=String.fromCharCode;d.arraySource=function(a){if(!Array.isArray(a))throw TypeError("Illegal argument: "+typeof a);var b=0;return function(){return b>=a.length?null:a[b++]}};d.arrayDestination=function(a){if(!Array.isArray(a))throw TypeError("Illegal argument: "+typeof a);
return Array.prototype.push.bind(a)};d.stringSource=function(a){if("string"!==typeof a)throw TypeError("Illegal argument: "+typeof a);var b=0;return function(){return b>=a.length?null:a.charCodeAt(b++)}};d.stringDestination=function(){var a=[],b=[];return function(){if(0===arguments.length)return b.join("")+k.apply(String,a);1024<a.length+arguments.length&&(b.push(k.apply(String,a)),a.length=0);Array.prototype.push.apply(a,arguments)}};d.assertCharCode=function(a){if("number"!==typeof a||a!==a)throw TypeError("Illegal char code: "+
typeof a);if(0>a||65535<a)throw RangeError("Illegal char code: "+a);return a};d.assertCodePoint=function(a){if("number"!==typeof a||a!==a)throw TypeError("Illegal code point: "+typeof a);if(0>a||a>d.MAX_CODEPOINT)throw RangeError("Illegal code point: "+a);return a};d.fromCodePoint=function(a){var b,c=0,e=arguments,l=e.length;d.UTF8toUTF16(function(){return c<l?d.assertCodePoint(e[c++]):null},b=d.stringDestination());return b()};d.codePointAt=function(a,b){if("string"!==typeof a&&!(a&&a instanceof
String)||"number"!==typeof b)throw TypeError("Illegal arguments: "+typeof a+", "+typeof b);var c,e;if(!(0>b||b>=(c=a.length)))return d.UTF16toUTF8(function(){return"undefined"===typeof e&&b<c?a.charCodeAt(b++):null},function(a){e=a}),e};d.polyfill=function(a){if(!String.fromCodePoint||a)String.fromCodePoint=d.fromCodePoint;if(!String.prototype.codePointAt||a)String.prototype.codePointAt=function(a){return d.codePointAt(this,a)};return d};return d}
56763
def tanh(x):
    
    if isinstance(x, UncertainFunction):
        mcpts = np.tanh(x._mcpts)
        return UncertainFunction(mcpts)
    else:
        return np.tanh(x)
520442
function findx0BigA(a, p, q) {
      var w, s, D, B, u, z, zbar, logpg;

      // snTerm -- see formula 34
      logpg = Math.log(p * gamma(a + 1));
      function snTerm(x) {
         return function(n, v) {
            return n === 0 ? 1 : v * x / (a + n);
         };
      }
      // See formula 34, where `n` is off by 1
      function f(x, n) {
         return Math.exp((logpg + x - Math.log(series(snTerm(x), n + 1))) / a);
      }
      B = q * gamma(a);
      D = Math.max(2, a * (a - 1));
      s = funS(p, q);
      w = a + s * Math.sqrt(a) + (s * s - 1) / 3 +
         (s * s * s - 7 * s) / (36 * Math.sqrt(a)) -
         (3 * s * s * s * s + 7 * s * s - 16) / (810 * a) +
         (9 * s * s * s * s * s + 256 * s * s * s - 433 * s) /
            (38880 * a * Math.sqrt(a));
      if (a >= 500 && Math.abs(1 - w / a) < 1e-6) { return w; }
      if (p > 0.5) {
         if (w < 3 * a) { return w; }
         if (B < Math.pow(10, -D)) { return findx0TinyB(a, -Math.log(B)); }
         u = -Math.log(B) + (a - 1) * Math.log(w) -
               Math.log(1 + (1 - a) / (1 + w));
         // formula 33
         return -Math.log(B) + (a - 1) * Math.log(u) -
               Math.log(1 + (1 - a) / (1 + u));
      }
      // handle p <= 0.5
      z = w > 0.15 * (a + 1) ? w : f(f(f(f(w, 1), 3), 3), 4);
      if (z <= 0.01 * (a + 1) || z > 0.7 * (a + 1)) { return z; }
      /* eslint-disable no-extra-parens */
      return (function() {
         // find N for formula 36
         var N, term;

         N = 0;
         term = 1;
         do {
            N += 1;
            term = snTerm(z)(N, term);
         } while (term > 1e-4);
         zbar = f(z, N + 1);
         return zbar * (1 - (a * Math.log(zbar) - zbar - logpg +
                  Math.log(series(snTerm(z), N + 1))) / (a - zbar));
      }());
      /* eslint-enable no-extra-parens */
   }
680423
function(x, y) {
        this.rho = Math.sqrt(x * x + y * y);
        this.theta = Math.atan2(y, x);
        if(this.theta < 0) this.theta += Math.PI * 2;
    }
131787
def getcosIm(alat):
    

    alat = np.float64(alat)

    return np.cos(np.radians(alat))/np.sqrt(4 - 3*np.cos(np.radians(alat))**2)
605282
function() {

      var w = this['w'];
      var x = this['x'];
      var y = this['y'];
      var z = this['z'];

      var vNorm = Math.sqrt(x * x + y * y + z * z);
      var wExp = Math.exp(w);
      var scale = wExp / vNorm * Math.sin(vNorm);

      if (vNorm === 0) {
        //return new Quaternion(wExp * Math.cos(vNorm), 0, 0, 0);
        return new Quaternion(wExp, 0, 0, 0);
      }

      return new Quaternion(
              wExp * Math.cos(vNorm),
              x * scale,
              y * scale,
              z * scale);
    }
966788
def _function(self, x, a, b, c, d, s):
        
        return c/(np.pi*self._g_a(x, a, b, s)*(1.0+((x-a)/(self._g_a(x, a, b, s)))**2))+d
1008607
function(d2) {

      var w = this['w'];
      var x = this['x'];
      var y = this['y'];
      var z = this['z'];

      var n = w * w + x * x + y * y + z * z;
      var s = n === 0 ? 0 : 2 / n;
      var wx = s * w * x, wy = s * w * y, wz = s * w * z;
      var xx = s * x * x, xy = s * x * y, xz = s * x * z;
      var yy = s * y * y, yz = s * y * z, zz = s * z * z;

      if (d2) {
        return [
          [1 - (yy + zz), xy - wz, xz + wy],
          [xy + wz, 1 - (xx + zz), yz - wx],
          [xz - wy, yz + wx, 1 - (xx + yy)]];
      }

      return [
        1 - (yy + zz), xy - wz, xz + wy,
        xy + wz, 1 - (xx + zz), yz - wx,
        xz - wy, yz + wx, 1 - (xx + yy)];
    }
1287508
function() {
      var coords = this.oCoords,
          theta = degreesToRadians(45 - this.getAngle()),
          cornerHypotenuse = Math.sqrt(2 * Math.pow(this.cornersize, 2)) / 2,
          cosHalfOffset = cornerHypotenuse * Math.cos(theta),
          sinHalfOffset = cornerHypotenuse * Math.sin(theta),
          sinTh = Math.sin(this._theta),
          cosTh = Math.cos(this._theta);

      coords.tl.corner = {
        tl: {
          x: coords.tl.x - sinHalfOffset,
          y: coords.tl.y - cosHalfOffset
        },
        tr: {
          x: coords.tl.x + cosHalfOffset,
          y: coords.tl.y - sinHalfOffset
        },
        bl: {
          x: coords.tl.x - cosHalfOffset,
          y: coords.tl.y + sinHalfOffset
        },
        br: {
          x: coords.tl.x + sinHalfOffset,
          y: coords.tl.y + cosHalfOffset
        }
      };

      coords.tr.corner = {
        tl: {
          x: coords.tr.x - sinHalfOffset,
          y: coords.tr.y - cosHalfOffset
        },
        tr: {
          x: coords.tr.x + cosHalfOffset,
          y: coords.tr.y - sinHalfOffset
        },
        br: {
          x: coords.tr.x + sinHalfOffset,
          y: coords.tr.y + cosHalfOffset
        },
        bl: {
          x: coords.tr.x - cosHalfOffset,
          y: coords.tr.y + sinHalfOffset
        }
      };

      coords.bl.corner = {
        tl: {
          x: coords.bl.x - sinHalfOffset,
          y: coords.bl.y - cosHalfOffset
        },
        bl: {
          x: coords.bl.x - cosHalfOffset,
          y: coords.bl.y + sinHalfOffset
        },
        br: {
          x: coords.bl.x + sinHalfOffset,
          y: coords.bl.y + cosHalfOffset
        },
        tr: {
          x: coords.bl.x + cosHalfOffset,
          y: coords.bl.y - sinHalfOffset
        }
      };

      coords.br.corner = {
        tr: {
          x: coords.br.x + cosHalfOffset,
          y: coords.br.y - sinHalfOffset
        },
        bl: {
          x: coords.br.x - cosHalfOffset,
          y: coords.br.y + sinHalfOffset
        },
        br: {
          x: coords.br.x + sinHalfOffset,
          y: coords.br.y + cosHalfOffset
        },
        tl: {
          x: coords.br.x - sinHalfOffset,
          y: coords.br.y - cosHalfOffset
        }
      };

      coords.ml.corner = {
        tl: {
          x: coords.ml.x - sinHalfOffset,
          y: coords.ml.y - cosHalfOffset
        },
        tr: {
          x: coords.ml.x + cosHalfOffset,
          y: coords.ml.y - sinHalfOffset
        },
        bl: {
          x: coords.ml.x - cosHalfOffset,
          y: coords.ml.y + sinHalfOffset
        },
        br: {
          x: coords.ml.x + sinHalfOffset,
          y: coords.ml.y + cosHalfOffset
        }
      };

      coords.mt.corner = {
        tl: {
          x: coords.mt.x - sinHalfOffset,
          y: coords.mt.y - cosHalfOffset
        },
        tr: {
          x: coords.mt.x + cosHalfOffset,
          y: coords.mt.y - sinHalfOffset
        },
        bl: {
          x: coords.mt.x - cosHalfOffset,
          y: coords.mt.y + sinHalfOffset
        },
        br: {
          x: coords.mt.x + sinHalfOffset,
          y: coords.mt.y + cosHalfOffset
        }
      };

      coords.mr.corner = {
        tl: {
          x: coords.mr.x - sinHalfOffset,
          y: coords.mr.y - cosHalfOffset
        },
        tr: {
          x: coords.mr.x + cosHalfOffset,
          y: coords.mr.y - sinHalfOffset
        },
        bl: {
          x: coords.mr.x - cosHalfOffset,
          y: coords.mr.y + sinHalfOffset
        },
        br: {
          x: coords.mr.x + sinHalfOffset,
          y: coords.mr.y + cosHalfOffset
        }
      };

      coords.mb.corner = {
        tl: {
          x: coords.mb.x - sinHalfOffset,
          y: coords.mb.y - cosHalfOffset
        },
        tr: {
          x: coords.mb.x + cosHalfOffset,
          y: coords.mb.y - sinHalfOffset
        },
        bl: {
          x: coords.mb.x - cosHalfOffset,
          y: coords.mb.y + sinHalfOffset
        },
        br: {
          x: coords.mb.x + sinHalfOffset,
          y: coords.mb.y + cosHalfOffset
        }
      };

      coords.mtr.corner = {
        tl: {
          x: coords.mtr.x - sinHalfOffset + (sinTh * this.rotatingPointOffset),
          y: coords.mtr.y - cosHalfOffset - (cosTh * this.rotatingPointOffset)
        },
        tr: {
          x: coords.mtr.x + cosHalfOffset + (sinTh * this.rotatingPointOffset),
          y: coords.mtr.y - sinHalfOffset - (cosTh * this.rotatingPointOffset)
        },
        bl: {
          x: coords.mtr.x - cosHalfOffset + (sinTh * this.rotatingPointOffset),
          y: coords.mtr.y + sinHalfOffset - (cosTh * this.rotatingPointOffset)
        },
        br: {
          x: coords.mtr.x + sinHalfOffset + (sinTh * this.rotatingPointOffset),
          y: coords.mtr.y + cosHalfOffset - (cosTh * this.rotatingPointOffset)
        }
      };
    }
705593
def funTransEdgeX(theta, rho):
    
    return np.matrix([[1, 0], [np.tan(theta) / rho, 1]], dtype=np.double)
825502
def bounding_box(self):
        

        # We use the solution described in http://stackoverflow.com/a/88020
        # which is to use the parametric equation of an ellipse and to find
        # when dx/dt or dy/dt=0.

        cos_angle = np.cos(self.angle)
        sin_angle = np.sin(self.angle)
        tan_angle = np.tan(self.angle)

        t1 = np.arctan(-self.height * tan_angle / self.width)
        t2 = t1 + np.pi * u.rad

        dx1 = 0.5 * self.width * cos_angle * np.cos(t1) - 0.5 * self.height * sin_angle * np.sin(t1)
        dx2 = 0.5 * self.width * cos_angle * np.cos(t2) - 0.5 * self.height * sin_angle * np.sin(t2)

        if dx1 > dx2:
            dx1, dx2 = dx2, dx1

        t1 = np.arctan(self.height / tan_angle / self.width)
        t2 = t1 + np.pi * u.rad

        dy1 = 0.5 * self.height * cos_angle * np.sin(t1) + 0.5 * self.width * sin_angle * np.cos(t1)
        dy2 = 0.5 * self.height * cos_angle * np.sin(t2) + 0.5 * self.width * sin_angle * np.cos(t2)

        if dy1 > dy2:
            dy1, dy2 = dy2, dy1

        xmin = self.center.x + dx1
        xmax = self.center.x + dx2
        ymin = self.center.y + dy1
        ymax = self.center.y + dy2

        return BoundingBox.from_float(xmin, xmax, ymin, ymax)
613762
function DEGtoSEC(angle) {

  // Extract DMS
  const deg = parseInt(angle, 10);
  let min = parseInt((angle - deg) * 100, 10);
  let sec = (((angle - deg) * 100) - min) * 100;

  // Avoid rounding problems with seconds=0
  const parts = String(angle).split('.');
  if (parts.length == 2 && parts[1].length == 2) {
    min = Number(parts[1]);
    sec = 0;
  }

  // Result in degrees sex (dd.mmss)
  return sec + min * 60 + deg * 3600;

}
589668
function() {

      // acot(c) = i / 2 log((c - i) / (c + i))

      var a = this['re'];
      var b = this['im'];

      if (b === 0) {
        return new Complex(Math.atan2(1, a), 0);
      }

      var d = a * a + b * b;
      return (d !== 0)
              ? new Complex(
                      a / d,
                      -b / d).atan()
              : new Complex(
                      (a !== 0) ? a / 0 : 0,
                      (b !== 0) ? -b / 0 : 0).atan();
    }
1320099
def bounding_boxes(self):
        

        w2 = self.w_out / 2.
        h2 = self.h_out / 2.
        cos_theta = math.cos(self.theta)
        sin_theta = math.sin(self.theta)
        dx1 = abs(w2 * cos_theta - h2 * sin_theta)
        dy1 = abs(w2 * sin_theta + h2 * cos_theta)
        dx2 = abs(w2 * cos_theta + h2 * sin_theta)
        dy2 = abs(w2 * sin_theta - h2 * cos_theta)
        dx = max(dx1, dx2)
        dy = max(dy1, dy2)

        xmin = self.positions[:, 0] - dx
        xmax = self.positions[:, 0] + dx
        ymin = self.positions[:, 1] - dy
        ymax = self.positions[:, 1] + dy

        return [BoundingBox._from_float(x0, x1, y0, y1)
                for x0, x1, y0, y1 in zip(xmin, xmax, ymin, ymax)]
489470
def _sin(x):
    ''''''
    return 0. if np.isclose(np.mod(x, np.pi), 0.) else np.sin(x)