public void initialize() {
   super.initialize();
   if (Math.abs(Math.abs(projectionLatitude) - MapMath.HALFPI) < EPS10) {
     mode = projectionLatitude < 0. ? SOUTH_POLE : NORTH_POLE;
     sinphi0 = projectionLatitude < 0. ? -1. : 1.;
     cosphi0 = 0.;
   } else if (Math.abs(projectionLatitude) < EPS10) {
     mode = EQUATOR;
     sinphi0 = 0.;
     cosphi0 = 1.;
   } else {
     mode = OBLIQUE;
     sinphi0 = Math.sin(projectionLatitude);
     cosphi0 = Math.cos(projectionLatitude);
   }
   if (!spherical) {
     en = MapMath.enfn(es);
     switch (mode) {
       case NORTH_POLE:
         Mp = MapMath.mlfn(MapMath.HALFPI, 1., 0., en);
         break;
       case SOUTH_POLE:
         Mp = MapMath.mlfn(-MapMath.HALFPI, -1., 0., en);
         break;
       case EQUATOR:
       case OBLIQUE:
         N1 = 1. / Math.sqrt(1. - es * sinphi0 * sinphi0);
         G = sinphi0 * (He = e / Math.sqrt(one_es));
         He *= cosphi0;
         break;
     }
   }
 }
  public Coordinate projectInverse(double xyx, double xyy, Coordinate out) {
    double c;

    out.y = MapMath.asin(xyy / C_y);
    out.x = xyx / (C_x * ((c = Math.cos(out.y)) - 0.5));
    out.y = MapMath.asin((out.y + Math.sin(out.y) * (c - 1.)) / C_p);
    return out;
  }
  public void initialize() {
    super.initialize();
    double t = trueScaleLatitude;

    scaleFactor = Math.cos(t);
    if (es != 0) {
      t = Math.sin(t);
      scaleFactor /= Math.sqrt(1. - es * t * t);
      apa = MapMath.authset(es);
      qp = MapMath.qsfn(1., e, one_es);
    }
  }
 public Point2D.Double project(double lam, double phi, Point2D.Double xy) {
   if (spherical) {
     xy.x = scaleFactor * lam;
     xy.y = Math.sin(phi) / scaleFactor;
   } else {
     xy.x = scaleFactor * lam;
     xy.y = .5 * MapMath.qsfn(Math.sin(phi), e, one_es) / scaleFactor;
   }
   return xy;
 }
  public Point2D.Double projectInverse(double x, double y, Point2D.Double lp) {
    if (spherical) {
      y *= scaleFactor;
      double t = Math.abs(y);

      if (t - EPS10 <= 1.) {
        if (t >= 1.) {
          lp.y = y < 0. ? -MapMath.HALFPI : MapMath.HALFPI;
        } else {
          lp.y = Math.asin(y);
        }
        lp.x = x / scaleFactor;
      } else {
        throw new ProjectionException();
      }
    } else {
      lp.y = MapMath.authlat(Math.asin(2. * y * scaleFactor / qp), apa);
      lp.x = x / scaleFactor;
    }
    return lp;
  }
  public Point2D.Double projectInverse(double xyx, double xyy, Point2D.Double out) {
    double rho;

    rho = MapMath.distance(xyx, out.y = rho_0 - xyy);
    if (n < 0.) {
      rho = -rho;
      out.x = -xyx;
      out.y = -xyy;
    }
    out.x = Math.atan2(xyx, xyy) / n;
    switch (type) {
      case PCONIC:
        out.y = Math.atan(c1 - rho / c2) + sig;
        break;
      case MURD2:
        out.y = sig - Math.atan(rho - rho_c);
        break;
      default:
        out.y = rho_c - rho;
    }
    return out;
  }
  public Point2D.Double project(double lam, double phi, Point2D.Double xy) {
    if (spherical) {
      double coslam, cosphi, sinphi;

      sinphi = Math.sin(phi);
      cosphi = Math.cos(phi);
      coslam = Math.cos(lam);
      switch (mode) {
        case EQUATOR:
        case OBLIQUE:
          if (mode == EQUATOR) xy.y = cosphi * coslam;
          else xy.y = sinphi0 * sinphi + cosphi0 * cosphi * coslam;
          if (Math.abs(Math.abs(xy.y) - 1.) < TOL)
            if (xy.y < 0.) throw new ProjectionException();
            else xy.x = xy.y = 0.;
          else {
            xy.y = Math.acos(xy.y);
            xy.y /= Math.sin(xy.y);
            xy.x = xy.y * cosphi * Math.sin(lam);
            xy.y *= (mode == EQUATOR) ? sinphi : cosphi0 * sinphi - sinphi0 * cosphi * coslam;
          }
          break;
        case NORTH_POLE:
          phi = -phi;
          coslam = -coslam;
        case SOUTH_POLE:
          if (Math.abs(phi - MapMath.HALFPI) < EPS10) throw new ProjectionException();
          xy.x = (xy.y = (MapMath.HALFPI + phi)) * Math.sin(lam);
          xy.y *= coslam;
          break;
      }
    } else {
      double coslam, cosphi, sinphi, rho, s, H, H2, c, Az, t, ct, st, cA, sA;

      coslam = Math.cos(lam);
      cosphi = Math.cos(phi);
      sinphi = Math.sin(phi);
      switch (mode) {
        case NORTH_POLE:
          coslam = -coslam;
        case SOUTH_POLE:
          xy.x = (rho = Math.abs(Mp - MapMath.mlfn(phi, sinphi, cosphi, en))) * Math.sin(lam);
          xy.y = rho * coslam;
          break;
        case EQUATOR:
        case OBLIQUE:
          if (Math.abs(lam) < EPS10 && Math.abs(phi - projectionLatitude) < EPS10) {
            xy.x = xy.y = 0.;
            break;
          }
          t =
              Math.atan2(
                  one_es * sinphi + es * N1 * sinphi0 * Math.sqrt(1. - es * sinphi * sinphi),
                  cosphi);
          ct = Math.cos(t);
          st = Math.sin(t);
          Az = Math.atan2(Math.sin(lam) * ct, cosphi0 * st - sinphi0 * coslam * ct);
          cA = Math.cos(Az);
          sA = Math.sin(Az);
          s =
              MapMath.asin(
                  Math.abs(sA) < TOL
                      ? (cosphi0 * st - sinphi0 * coslam * ct) / cA
                      : Math.sin(lam) * ct / sA);
          H = He * cA;
          H2 = H * H;
          c =
              N1
                  * s
                  * (1.
                      + s
                          * s
                          * (-H2 * (1. - H2) / 6.
                              + s
                                  * (G * H * (1. - 2. * H2 * H2) / 8.
                                      + s
                                          * ((H2 * (4. - 7. * H2) - 3. * G * G * (1. - 7. * H2))
                                                  / 120.
                                              - s * G * H / 48.))));
          xy.x = c * sA;
          xy.y = c * cA;
          break;
      }
    }
    return xy;
  }
  public Point2D.Double projectInverse(double x, double y, Point2D.Double lp) {
    if (spherical) {
      double cosc, c_rh, sinc;

      if ((c_rh = MapMath.distance(x, y)) > Math.PI) {
        if (c_rh - EPS10 > Math.PI) throw new ProjectionException();
        c_rh = Math.PI;
      } else if (c_rh < EPS10) {
        lp.y = projectionLatitude;
        lp.x = 0.;
        return lp;
      }
      if (mode == OBLIQUE || mode == EQUATOR) {
        sinc = Math.sin(c_rh);
        cosc = Math.cos(c_rh);
        if (mode == EQUATOR) {
          lp.y = MapMath.asin(y * sinc / c_rh);
          x *= sinc;
          y = cosc * c_rh;
        } else {
          lp.y = MapMath.asin(cosc * sinphi0 + y * sinc * cosphi0 / c_rh);
          y = (cosc - sinphi0 * Math.sin(lp.y)) * c_rh;
          x *= sinc * cosphi0;
        }
        lp.x = y == 0. ? 0. : Math.atan2(x, y);
      } else if (mode == NORTH_POLE) {
        lp.y = MapMath.HALFPI - c_rh;
        lp.x = Math.atan2(x, -y);
      } else {
        lp.y = c_rh - MapMath.HALFPI;
        lp.x = Math.atan2(x, y);
      }
    } else {
      double c, Az, cosAz, A, B, D, E, F, psi, t;
      int i;

      if ((c = MapMath.distance(x, y)) < EPS10) {
        lp.y = projectionLatitude;
        lp.x = 0.;
        return (lp);
      }
      if (mode == OBLIQUE || mode == EQUATOR) {
        cosAz = Math.cos(Az = Math.atan2(x, y));
        t = cosphi0 * cosAz;
        B = es * t / one_es;
        A = -B * t;
        B *= 3. * (1. - A) * sinphi0;
        D = c / N1;
        E = D * (1. - D * D * (A * (1. + A) / 6. + B * (1. + 3. * A) * D / 24.));
        F = 1. - E * E * (A / 2. + B * E / 6.);
        psi = MapMath.asin(sinphi0 * Math.cos(E) + t * Math.sin(E));
        lp.x = MapMath.asin(Math.sin(Az) * Math.sin(E) / Math.cos(psi));
        if ((t = Math.abs(psi)) < EPS10) lp.y = 0.;
        else if (Math.abs(t - MapMath.HALFPI) < 0.) lp.y = MapMath.HALFPI;
        else lp.y = Math.atan((1. - es * F * sinphi0 / Math.sin(psi)) * Math.tan(psi) / one_es);
      } else {
        lp.y = MapMath.inv_mlfn(mode == NORTH_POLE ? Mp - c : Mp + c, es, en);
        lp.x = Math.atan2(x, mode == NORTH_POLE ? -y : y);
      }
    }
    return lp;
  }
 public double getWidth(double y) {
   return MapMath.normalizeLongitude(Math.PI) * Math.cos(y); // FIXME
 }