/** Get the scaling when it is described as a matrix */
  private boolean extractScaler2(double crpix1, double crpix2) throws TransformationException {

    // Look for the CD matrix...
    //
    double m11 = h.getDoubleValue("CD" + lonAxis + "_" + lonAxis, NaN);
    double m12 = h.getDoubleValue("CD" + lonAxis + "_" + latAxis, NaN);
    double m21 = h.getDoubleValue("CD" + latAxis + "_" + lonAxis, NaN);
    double m22 = h.getDoubleValue("CD" + latAxis + "_" + latAxis, NaN);

    boolean matrix = !isNaN(m11 + m12 + m21 + m22);
    if (!matrix) {
      return false;
    }
    wcsKeys.put("CD1_1", m11);
    wcsKeys.put("CD1_2", m12);
    wcsKeys.put("CD2_1", m21);
    wcsKeys.put("CD2_2", m22);

    m11 = toRadians(m11);
    m12 = toRadians(m12);
    m21 = toRadians(m21);
    m22 = toRadians(m22);

    // we have
    //   t = a11 (x-x0) + a12 (y-y0); u = a21(x-x0) + a22(y-y0)
    //       t = a11x + a12y - a11 x0 - a12 y0;
    //
    Scaler s =
        new Scaler(-m11 * crpix1 - m12 * crpix2, -m21 * crpix1 - m22 * crpix2, m11, m12, m21, m22);

    s = s.inverse();

    // Are longitude and latitude in unusual order?
    if (lonAxis > latAxis) {
      s.interchangeAxes();
    }
    this.scale = s;
    add(s);
    setWCSScale(s);
    return true;
  }
  /** Get the scaling when CDELT is specified */
  private boolean extractScaler1(double crpix1, double crpix2) throws TransformationException {

    boolean matrix = false;

    double cdelt1 = h.getDoubleValue("CDELT" + lonAxis, NaN);
    double cdelt2 = h.getDoubleValue("CDELT" + latAxis, NaN);
    wcsKeys.put("CDELT1", cdelt1);
    wcsKeys.put("CDELT2", cdelt2);
    if (isNaN(cdelt1) || isNaN(cdelt2)) {
      return false;
    }

    // We use 1 indexing to match better with the FITS files.
    double m11, m12, m21, m22;

    // We've got minimal information...  We might have more.
    double crota = h.getDoubleValue("CROTA" + latAxis, NaN);
    if (!isNaN(crota) && crota != 0) {
      wcsKeys.put("CROTA2", crota);
      crota = toRadians(crota);

      m11 = cos(crota);
      m12 = sin(crota);
      m21 = -sin(crota);
      m22 = cos(crota);
      matrix = true;

    } else {

      m11 = h.getDoubleValue("PC" + lonAxis + "_" + lonAxis, NaN);
      m12 = h.getDoubleValue("PC" + lonAxis + "_" + latAxis, NaN);
      m21 = h.getDoubleValue("PC" + latAxis + "_" + lonAxis, NaN);
      m22 = h.getDoubleValue("PC" + latAxis + "_" + latAxis, NaN);
      matrix = !isNaN(m11 + m12 + m21 + m22);
      if (matrix) {
        wcsKeys.put("PC1_1", m11);
        wcsKeys.put("PC1_2", m12);
        wcsKeys.put("PC2_1", m21);
        wcsKeys.put("PC2_2", m22);
      }
    }

    // Note that Scaler is defined with parameters t = x0 + a00 x + a01 y; u = y0 + a10 x + a11 y
    // which is different from what we have here...
    //    t = scalex (x-x0),  u = scaley (y-y0)
    //    t = scalex x - scalex x0; u = scaley y - scaley y0
    // or
    //    t = scalex [a11 (x-x0) + a12 (y-y0)], u = scaley [a21 (x-x0) + a22 (y-y0)] ->
    //       t = scalex a11 x - scalex a11 x0 + scalex a12 y + scalex a12 y0         ->
    //       t = - scalex (a11 x0 + a12 y0) + scalex a11 x + scalex a12 y (and similarly for u)

    Scaler s;
    cdelt1 = toRadians(cdelt1);
    cdelt2 = toRadians(cdelt2);
    if (!matrix) {
      s = new Scaler(-cdelt1 * crpix1, -cdelt2 * crpix2, cdelt1, 0, 0, cdelt2);
    } else {
      s =
          new Scaler(
              -cdelt1 * (m11 * crpix1 + m12 * crpix2),
              -cdelt2 * (m21 * crpix1 + m22 * crpix2),
              cdelt1 * m11,
              cdelt1 * m12,
              cdelt2 * m21,
              cdelt2 * m22);
    }

    // Note that this scaler transforms from pixel coordinates to standard projection
    // plane coordinates.  We want the inverse transformation as the scaler.
    s = s.inverse();

    // Are lon and lat in unusual order?
    if (lonAxis > latAxis) {
      s.interchangeAxes();
    }

    this.scale = s;
    add(s);
    setWCSScale(s);

    return true;
  }