class RotatedPole extends AbstractProjection {

  @Override
  public LatLonPoint projToLatLon(ProjectionPoint ppt) {
    // "x" and "y" input for rotated pole coords are actually a lon-lat pair
    double lonR = LatLonPoints.range180(ppt.getX()); // LOOK guessing -- shouldn't matter
    double latR = ppt.getY();

    if (Math.abs(latR) > 90.) {
      throw new IllegalArgumentException("ProjectionPoint y must be in range [-90,90].");
    }

    double lonRRad = Math.toRadians(lonR);
    double latRRad = Math.toRadians(latR);

    // Lon-lat pair to xyz coordinates on sphere with radius 1
    double[] p0 = {Math.cos(latRRad) * Math.cos(lonRRad), Math.cos(latRRad) * Math.sin(lonRRad), Math.sin(latRRad)};

    // Inverse rotate around Y-axis (using transpose of Y matrix)
    // final double[] p1 = new double[] {
    // rotY[0][0] * p0[0] + rotY[1][0] * p0[1] + rotY[2][0] * p0[2],
    // rotY[0][1] * p0[0] + rotY[1][1] * p0[1] + rotY[2][1] * p0[2],
    // rotY[0][2] * p0[0] + rotY[1][2] * p0[1] + rotY[2][2] * p0[2]};
    double[] p1 = {rotY[0][0] * p0[0] + rotY[2][0] * p0[2], p0[1], rotY[0][2] * p0[0] + rotY[2][2] * p0[2]};

    // Inverse rotate around Z-axis (using transpose of Z matrix)
    // final double[] p2 = new double[] {
    // rotZ[0][0] * p1[0] + rotZ[1][0] * p1[1] + rotZ[2][0] * p1[2],
    // rotZ[0][1] * p1[0] + rotZ[1][1] * p1[1] + rotZ[2][1] * p1[2],
    // rotZ[0][2] * p1[0] + rotZ[1][2] * p1[1] + rotZ[2][2] * p1[2]};
    double[] p2 = {rotZ[0][0] * p1[0] + rotZ[1][0] * p1[1], rotZ[0][1] * p1[0] + rotZ[1][1] * p1[1], p1[2]};

    double lon = Math.atan2(p2[1], p2[0]) * DEG_PER_RAD;
    double lat = Math.asin(p2[2]) * DEG_PER_RAD;
    return LatLonPoint.create(lat, lon);
  }

  public  RotatedPole();
  public  RotatedPole(double northPoleLat, double northPoleLon);

}