Ejemplo n.º 1
0
  protected static boolean isSectorVisible(
      DrawContext dc, Sector sector, double minDistanceSquared, double maxDistanceSquared) {

    View view = dc.getView();
    Position eyePos = view.getEyePosition();
    if (eyePos == null) return false;

    Angle lat = clampAngle(eyePos.getLatitude(), sector.getMinLatitude(), sector.getMaxLatitude());
    Angle lon =
        clampAngle(eyePos.getLongitude(), sector.getMinLongitude(), sector.getMaxLongitude());
    Vec4 p = dc.getGlobe().computePointFromPosition(lat, lon, 0d);
    double distSquared = dc.getView().getEyePoint().distanceToSquared3(p);
    //noinspection RedundantIfStatement
    if (minDistanceSquared > distSquared || maxDistanceSquared < distSquared) return false;

    return true;
  }
    public URL getURL(Tile tile, String altImageFormat) throws MalformedURLException {
      StringBuffer sb;
      if (this.URLTemplate == null) {
        sb = new StringBuffer(WWXML.fixGetMapString(tile.getLevel().getService()));

        if (!sb.toString().toLowerCase().contains("service=wms")) sb.append("service=WMS");
        sb.append("&request=GetMap");
        sb.append("&version=").append(this.wmsVersion);
        sb.append(this.crs);
        sb.append("&layers=").append(this.layerNames);
        sb.append("&styles=").append(this.styleNames != null ? this.styleNames : "");
        sb.append("&transparent=TRUE");
        if (this.backgroundColor != null) sb.append("&bgcolor=").append(this.backgroundColor);

        this.URLTemplate = sb.toString();
      } else {
        sb = new StringBuffer(this.URLTemplate);
      }

      String format = (altImageFormat != null) ? altImageFormat : this.imageFormat;
      if (null != format) sb.append("&format=").append(format);

      sb.append("&width=").append(tile.getWidth());
      sb.append("&height=").append(tile.getHeight());

      Sector s = tile.getSector();
      sb.append("&bbox=");
      sb.append(s.getMinLongitude().getDegrees());
      sb.append(",");
      sb.append(s.getMinLatitude().getDegrees());
      sb.append(",");
      sb.append(s.getMaxLongitude().getDegrees());
      sb.append(",");
      sb.append(s.getMaxLatitude().getDegrees());
      //            sb.append("&"); // terminate the query string

      return new java.net.URL(sb.toString().replace(" ", "%20"));
    }
Ejemplo n.º 3
0
    protected boolean isNavSectorVisible(
        DrawContext dc, double minDistanceSquared, double maxDistanceSquared) {
      if (!navSector.intersects(dc.getVisibleSector())) return false;

      View view = dc.getView();
      Position eyePos = view.getEyePosition();
      if (eyePos == null) return false;

      // check for eyePos over globe
      if (Double.isNaN(eyePos.getLatitude().getDegrees())
          || Double.isNaN(eyePos.getLongitude().getDegrees())) return false;

      Angle lat =
          clampAngle(eyePos.getLatitude(), navSector.getMinLatitude(), navSector.getMaxLatitude());
      Angle lon =
          clampAngle(
              eyePos.getLongitude(), navSector.getMinLongitude(), navSector.getMaxLongitude());
      Vec4 p = dc.getGlobe().computePointFromPosition(lat, lon, 0d);
      double distSquared = dc.getView().getEyePoint().distanceToSquared3(p);
      //noinspection RedundantIfStatement
      if (minDistanceSquared > distSquared || maxDistanceSquared < distSquared) return false;

      return true;
    }
  protected static void legacyWmsRestoreStateToParams(
      RestorableSupport rs, RestorableSupport.StateObject context, AVList params) {
    // WMSTiledImageLayer has historically used a different format for storing LatLon and Sector
    // properties
    // in the restorable state XML documents. Although WMSTiledImageLayer no longer writes these
    // properties,
    // we must provide support for reading them here.
    Double lat = rs.getStateValueAsDouble(context, AVKey.LEVEL_ZERO_TILE_DELTA + ".Latitude");
    Double lon = rs.getStateValueAsDouble(context, AVKey.LEVEL_ZERO_TILE_DELTA + ".Longitude");
    if (lat != null && lon != null)
      params.setValue(AVKey.LEVEL_ZERO_TILE_DELTA, LatLon.fromDegrees(lat, lon));

    Double minLat = rs.getStateValueAsDouble(context, AVKey.SECTOR + ".MinLatitude");
    Double minLon = rs.getStateValueAsDouble(context, AVKey.SECTOR + ".MinLongitude");
    Double maxLat = rs.getStateValueAsDouble(context, AVKey.SECTOR + ".MaxLatitude");
    Double maxLon = rs.getStateValueAsDouble(context, AVKey.SECTOR + ".MaxLongitude");
    if (minLat != null && minLon != null && maxLat != null && maxLon != null)
      params.setValue(AVKey.SECTOR, Sector.fromDegrees(minLat, maxLat, minLon, maxLon));
  }
Ejemplo n.º 5
0
  public static DataRaster wrapAsGeoreferencedRaster(BufferedImage image, AVList params) {
    if (null == image) {
      String message = Logging.getMessage("nullValue.ImageIsNull");
      Logging.logger().severe(message);
      throw new IllegalArgumentException(message);
    }

    if (null == params) {
      String msg = Logging.getMessage("nullValue.AVListIsNull");
      Logging.logger().finest(msg);
      throw new IllegalArgumentException(msg);
    }

    if (params.hasKey(AVKey.WIDTH)) {
      int width = (Integer) params.getValue(AVKey.WIDTH);
      if (width != image.getWidth()) {
        String msg =
            Logging.getMessage("generic.InvalidWidth", "" + width + "!=" + image.getWidth());
        Logging.logger().finest(msg);
        throw new IllegalArgumentException(msg);
      }
    }

    if (params.hasKey(AVKey.HEIGHT)) {
      int height = (Integer) params.getValue(AVKey.HEIGHT);
      if (height != image.getHeight()) {
        String msg =
            Logging.getMessage("generic.InvalidHeight", "" + height + "!=" + image.getHeight());
        Logging.logger().finest(msg);
        throw new IllegalArgumentException(msg);
      }
    }

    if (!params.hasKey(AVKey.SECTOR)) {
      String msg = Logging.getMessage("generic.MissingRequiredParameter", AVKey.SECTOR);
      Logging.logger().finest(msg);
      throw new IllegalArgumentException(msg);
    }

    Sector sector = (Sector) params.getValue(AVKey.SECTOR);
    if (null == sector) {
      String msg = Logging.getMessage("nullValue.SectorIsNull");
      Logging.logger().severe(msg);
      throw new IllegalArgumentException(msg);
    }

    if (!params.hasKey(AVKey.COORDINATE_SYSTEM)) {
      // assume Geodetic Coordinate System
      params.setValue(AVKey.COORDINATE_SYSTEM, AVKey.COORDINATE_SYSTEM_GEOGRAPHIC);
    }

    String cs = params.getStringValue(AVKey.COORDINATE_SYSTEM);
    if (!params.hasKey(AVKey.PROJECTION_EPSG_CODE)) {
      if (AVKey.COORDINATE_SYSTEM_GEOGRAPHIC.equals(cs)) {
        // assume WGS84
        params.setValue(AVKey.PROJECTION_EPSG_CODE, GeoTiff.GCS.WGS_84);
      } else {
        String msg =
            Logging.getMessage("generic.MissingRequiredParameter", AVKey.PROJECTION_EPSG_CODE);
        Logging.logger().finest(msg);
        throw new IllegalArgumentException(msg);
      }
    }

    // if PIXEL_WIDTH is specified, we are not overriding it because UTM images
    // will have different pixel size
    if (!params.hasKey(AVKey.PIXEL_WIDTH)) {
      if (AVKey.COORDINATE_SYSTEM_GEOGRAPHIC.equals(cs)) {
        double pixelWidth = sector.getDeltaLonDegrees() / (double) image.getWidth();
        params.setValue(AVKey.PIXEL_WIDTH, pixelWidth);
      } else {
        String msg = Logging.getMessage("generic.MissingRequiredParameter", AVKey.PIXEL_WIDTH);
        Logging.logger().finest(msg);
        throw new IllegalArgumentException(msg);
      }
    }

    // if PIXEL_HEIGHT is specified, we are not overriding it
    // because UTM images will have different pixel size
    if (!params.hasKey(AVKey.PIXEL_HEIGHT)) {
      if (AVKey.COORDINATE_SYSTEM_GEOGRAPHIC.equals(cs)) {
        double pixelHeight = sector.getDeltaLatDegrees() / (double) image.getHeight();
        params.setValue(AVKey.PIXEL_HEIGHT, pixelHeight);
      } else {
        String msg = Logging.getMessage("generic.MissingRequiredParameter", AVKey.PIXEL_HEIGHT);
        Logging.logger().finest(msg);
        throw new IllegalArgumentException(msg);
      }
    }

    if (!params.hasKey(AVKey.PIXEL_FORMAT)) {
      params.setValue(AVKey.PIXEL_FORMAT, AVKey.IMAGE);
    } else if (!AVKey.IMAGE.equals(params.getStringValue(AVKey.PIXEL_FORMAT))) {
      String msg =
          Logging.getMessage(
              "generic.UnknownValueForKey",
              params.getStringValue(AVKey.PIXEL_FORMAT),
              AVKey.PIXEL_FORMAT);
      Logging.logger().severe(msg);
      throw new IllegalArgumentException(msg);
    }

    if (!params.hasKey(AVKey.ORIGIN) && AVKey.COORDINATE_SYSTEM_GEOGRAPHIC.equals(cs)) {
      // set UpperLeft corner as the origin, if not specified
      LatLon origin = new LatLon(sector.getMaxLatitude(), sector.getMinLongitude());
      params.setValue(AVKey.ORIGIN, origin);
    }

    if (!params.hasKey(AVKey.DATE_TIME)) {
      // add NUL (\0) termination as required by TIFF v6 spec (20 bytes length)
      String timestamp = String.format("%1$tY:%1$tm:%1$td %tT\0", Calendar.getInstance());
      params.setValue(AVKey.DATE_TIME, timestamp);
    }

    if (!params.hasKey(AVKey.VERSION)) {
      params.setValue(AVKey.VERSION, Version.getVersion());
    }

    boolean hasAlpha = (null != image.getColorModel() && image.getColorModel().hasAlpha());
    params.setValue(AVKey.RASTER_HAS_ALPHA, hasAlpha);

    return new BufferedImageRaster(sector, image, params);
  }
Ejemplo n.º 6
0
  protected void doDrawOnTo(BufferedImageRaster canvas) {
    Sector sector = this.getSector();
    if (null == sector) {
      String message = Logging.getMessage("nullValue.SectorIsNull");
      Logging.logger().severe(message);
      throw new IllegalArgumentException(message);
    }

    if (!sector.intersects(canvas.getSector())) {
      return;
    }

    java.awt.Graphics2D g2d = null;
    java.awt.Shape prevClip = null;
    java.awt.Composite prevComposite = null;
    java.lang.Object prevInterpolation = null, prevAntialiasing = null;

    try {
      int canvasWidth = canvas.getWidth();
      int canvasHeight = canvas.getHeight();

      // Apply the transform that correctly maps the image onto the canvas.
      java.awt.geom.AffineTransform transform =
          this.computeSourceToDestTransform(
              this.getWidth(),
              this.getHeight(),
              this.getSector(),
              canvasWidth,
              canvasHeight,
              canvas.getSector());

      AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
      Rectangle2D rect = op.getBounds2D(this.getBufferedImage());

      int clipWidth =
          (int) Math.ceil((rect.getMaxX() >= canvasWidth) ? canvasWidth : rect.getMaxX());
      int clipHeight =
          (int) Math.ceil((rect.getMaxY() >= canvasHeight) ? canvasHeight : rect.getMaxY());

      if (clipWidth <= 0 || clipHeight <= 0) {
        return;
      }

      g2d = canvas.getGraphics();

      prevClip = g2d.getClip();
      prevComposite = g2d.getComposite();
      prevInterpolation = g2d.getRenderingHint(RenderingHints.KEY_INTERPOLATION);
      prevAntialiasing = g2d.getRenderingHint(RenderingHints.KEY_ANTIALIASING);

      // Set the alpha composite for appropriate alpha blending.
      g2d.setComposite(java.awt.AlphaComposite.SrcOver);
      g2d.setRenderingHint(
          RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
      g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

      g2d.drawImage(this.getBufferedImage(), transform, null);
    }
    //        catch (java.awt.image.ImagingOpException ioe)
    //        {
    //            // If we catch a ImagingOpException, then the transformed image has a width or
    // height of 0.
    //            // This indicates that there is no intersection between the source image and the
    // canvas,
    //            // or the intersection is smaller than one pixel.
    //        }
    //        catch (java.awt.image.RasterFormatException rfe)
    //        {
    //            // If we catch a RasterFormatException, then the transformed image has a width or
    // height of 0.
    //            // This indicates that there is no intersection between the source image and the
    // canvas,
    //            // or the intersection is smaller than one pixel.
    //        }
    catch (Throwable t) {
      String reason = WWUtil.extractExceptionReason(t);
      Logging.logger().log(java.util.logging.Level.SEVERE, reason, t);
    } finally {
      // Restore the previous clip, composite, and transform.
      try {
        if (null != g2d) {
          if (null != prevClip) g2d.setClip(prevClip);

          if (null != prevComposite) g2d.setComposite(prevComposite);

          if (null != prevInterpolation)
            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, prevInterpolation);

          if (null != prevAntialiasing)
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, prevAntialiasing);
        }
      } catch (Throwable t) {
        Logging.logger().log(java.util.logging.Level.FINEST, WWUtil.extractExceptionReason(t), t);
      }
    }
  }
  protected void validateParameters(AVList list, int srcWidth, int srcHeight)
      throws IllegalArgumentException {
    if (null == list || 0 == list.getValues().size()) {
      String reason = Logging.getMessage("nullValue.AVListIsNull");
      String msg = Logging.getMessage("GeotiffWriter.GeoKeysMissing", reason);
      Logging.logger().finest(msg);
      throw new IllegalArgumentException(msg);
    }

    if (!(srcWidth > 0 && srcHeight > 0)) {
      String msg = Logging.getMessage("generic.InvalidImageSize", srcWidth, srcHeight);
      Logging.logger().finest(msg);
      throw new IllegalArgumentException(msg);
    }

    if (list.hasKey(AVKey.WIDTH)) {
      int width = (Integer) list.getValue(AVKey.WIDTH);
      if (width != srcWidth) {
        String msg = Logging.getMessage("GeotiffWriter.ImageWidthMismatch", width, srcWidth);
        Logging.logger().severe(msg);
        throw new IllegalArgumentException(msg);
      }
    } else list.setValue(AVKey.WIDTH, srcWidth);

    if (list.hasKey(AVKey.HEIGHT)) {
      int height = (Integer) list.getValue(AVKey.HEIGHT);
      if (height != srcHeight) {
        String msg = Logging.getMessage("GeotiffWriter.ImageHeightMismatch", height, srcHeight);
        Logging.logger().severe(msg);
        throw new IllegalArgumentException(msg);
      }
    } else list.setValue(AVKey.HEIGHT, srcHeight);

    Sector sector = null;

    if (list.hasKey(AVKey.SECTOR)) sector = (Sector) list.getValue(AVKey.SECTOR);

    if (null == sector) {
      String msg = Logging.getMessage("GeotiffWriter.NoSectorSpecified");
      Logging.logger().severe(msg);
      throw new IllegalArgumentException(msg);
    }

    if (!list.hasKey(AVKey.COORDINATE_SYSTEM)) {
      String msg = Logging.getMessage("GeotiffWriter.GeoKeysMissing", AVKey.COORDINATE_SYSTEM);
      Logging.logger().finest(msg);
      //            throw new IllegalArgumentException(msg);

      // assume Geodetic Coordinate System
      list.setValue(AVKey.COORDINATE_SYSTEM, AVKey.COORDINATE_SYSTEM_GEOGRAPHIC);
    }

    if (!list.hasKey(AVKey.PROJECTION_EPSG_CODE)) {
      if (isGeographic(list)) {
        // assume WGS84
        list.setValue(AVKey.PROJECTION_EPSG_CODE, GeoTiff.GCS.WGS_84);
      } else {
        String msg = Logging.getMessage("GeotiffWriter.GeoKeysMissing", AVKey.PROJECTION_EPSG_CODE);
        Logging.logger().finest(msg);
        throw new IllegalArgumentException(msg);
      }
    }

    // if PIXEL_WIDTH is specified, we are not overriding it because UTM images
    // will have different pixel size
    if (!list.hasKey(AVKey.PIXEL_WIDTH)) {
      if (isGeographic(list)) {
        double pixelWidth = sector.getDeltaLonDegrees() / (double) srcWidth;
        list.setValue(AVKey.PIXEL_WIDTH, pixelWidth);
      } else {
        String msg = Logging.getMessage("GeotiffWriter.GeoKeysMissing", AVKey.PIXEL_WIDTH);
        Logging.logger().finest(msg);
        throw new IllegalArgumentException(msg);
      }
    }

    // if PIXEL_HEIGHT is specified, we are not overriding it
    // because UTM images will have different pixel size
    if (!list.hasKey(AVKey.PIXEL_HEIGHT)) {
      if (isGeographic(list)) {
        double pixelHeight = sector.getDeltaLatDegrees() / (double) srcHeight;
        list.setValue(AVKey.PIXEL_HEIGHT, pixelHeight);
      } else {
        String msg = Logging.getMessage("GeotiffWriter.GeoKeysMissing", AVKey.PIXEL_HEIGHT);
        Logging.logger().finest(msg);
        throw new IllegalArgumentException(msg);
      }
    }

    if (!list.hasKey(AVKey.PIXEL_FORMAT)) {
      String msg = Logging.getMessage("GeotiffWriter.GeoKeysMissing", AVKey.PIXEL_FORMAT);
      Logging.logger().finest(msg);
      throw new IllegalArgumentException(msg);
    } else {
      String pixelFormat = list.getStringValue(AVKey.PIXEL_FORMAT);
      if (!AVKey.ELEVATION.equals(pixelFormat) && !AVKey.IMAGE.equals(pixelFormat)) {
        String msg =
            Logging.getMessage("Geotiff.UnknownGeoKeyValue", pixelFormat, AVKey.PIXEL_FORMAT);
        Logging.logger().severe(msg);
        throw new IllegalArgumentException(msg);
      }
    }

    // validate elevation parameters
    if (AVKey.ELEVATION.equals(list.getValue(AVKey.PIXEL_FORMAT))) {
      if (!list.hasKey(AVKey.DATA_TYPE)) {
        String msg = Logging.getMessage("GeotiffWriter.GeoKeysMissing", AVKey.DATA_TYPE);
        Logging.logger().finest(msg);
        throw new IllegalArgumentException(msg);
      }

      String type = list.getStringValue(AVKey.DATA_TYPE);
      if (!AVKey.FLOAT32.equals(type) && !AVKey.INT16.equals(type)) {
        String msg = Logging.getMessage("Geotiff.UnknownGeoKeyValue", type, AVKey.DATA_TYPE);
        Logging.logger().severe(msg);
        throw new IllegalArgumentException(msg);
      }
    }

    if (!list.hasKey(AVKey.ORIGIN)) {
      // set UpperLeft corner as the origin, if not specified
      LatLon origin = new LatLon(sector.getMaxLatitude(), sector.getMinLongitude());
      list.setValue(AVKey.ORIGIN, origin);
    }

    if (list.hasKey(AVKey.BYTE_ORDER)
        && !AVKey.BIG_ENDIAN.equals(list.getStringValue(AVKey.BYTE_ORDER))) {
      String msg =
          Logging.getMessage(
              "generic.UnrecognizedByteOrder", list.getStringValue(AVKey.BYTE_ORDER));
      Logging.logger().severe(msg);
      throw new IllegalArgumentException(msg);
    }

    if (!list.hasKey(AVKey.DATE_TIME)) {
      // add NUL (\0) termination as required by TIFF v6 spec (20 bytes length)
      String timestamp = String.format("%1$tY:%1$tm:%1$td %tT\0", Calendar.getInstance());
      list.setValue(AVKey.DATE_TIME, timestamp);
    }

    if (!list.hasKey(AVKey.VERSION)) {
      list.setValue(AVKey.VERSION, Version.getVersion());
    }
  }
  private void appendGeoTiff(ArrayList<TiffIFDEntry> ifds, AVList params)
      throws IOException, IllegalArgumentException {
    if (null == params || 0 == params.getEntries().size()) {
      String reason = Logging.getMessage("nullValue.AVListIsNull");
      Logging.logger().finest(Logging.getMessage("GeotiffWriter.GeoKeysMissing", reason));
      return;
    }

    long offset = this.theChannel.position();

    if (params.hasKey(AVKey.DISPLAY_NAME)) {
      String value = params.getStringValue(AVKey.DISPLAY_NAME);
      if (null != value && 0 < value.trim().length()) {
        offset = this.theChannel.position();
        byte[] bytes = value.trim().getBytes();
        this.theChannel.write(ByteBuffer.wrap(bytes));
        ifds.add(new TiffIFDEntry(Tiff.Tag.DOCUMENT_NAME, Tiff.Type.ASCII, bytes.length, offset));
      }
    }

    if (params.hasKey(AVKey.DESCRIPTION)) {
      String value = params.getStringValue(AVKey.DESCRIPTION);
      if (null != value && 0 < value.trim().length()) {
        offset = this.theChannel.position();
        byte[] bytes = value.trim().getBytes();
        this.theChannel.write(ByteBuffer.wrap(bytes));
        ifds.add(
            new TiffIFDEntry(Tiff.Tag.IMAGE_DESCRIPTION, Tiff.Type.ASCII, bytes.length, offset));
      }
    }

    if (params.hasKey(AVKey.VERSION)) {
      String value = params.getStringValue(AVKey.VERSION);
      if (null != value && 0 < value.trim().length()) {
        offset = this.theChannel.position();
        byte[] bytes = value.trim().getBytes();
        this.theChannel.write(ByteBuffer.wrap(bytes));
        ifds.add(
            new TiffIFDEntry(Tiff.Tag.SOFTWARE_VERSION, Tiff.Type.ASCII, bytes.length, offset));
      }
    }

    if (params.hasKey(AVKey.DATE_TIME)) {
      String value = params.getStringValue(AVKey.DATE_TIME);
      if (null != value && 0 < value.trim().length()) {
        offset = this.theChannel.position();
        byte[] bytes = value.getBytes();
        this.theChannel.write(ByteBuffer.wrap(bytes));
        ifds.add(new TiffIFDEntry(Tiff.Tag.DATE_TIME, Tiff.Type.ASCII, bytes.length, offset));
      }
    }

    if (params.hasKey(AVKey.SECTOR)) {
      if (params.hasKey(AVKey.PIXEL_WIDTH) && params.hasKey(AVKey.PIXEL_HEIGHT)) {
        offset = this.theChannel.position();
        double[] values =
            new double[] {
              (Double) params.getValue(AVKey.PIXEL_WIDTH),
              (Double) params.getValue(AVKey.PIXEL_HEIGHT),
              isElevation(params) ? 1d : 0d
            };
        byte[] bytes = this.getBytes(values);
        this.theChannel.write(ByteBuffer.wrap(bytes));
        ifds.add(
            new TiffIFDEntry(
                GeoTiff.Tag.MODEL_PIXELSCALE, Tiff.Type.DOUBLE, values.length, offset));
      }

      if (params.hasKey(AVKey.WIDTH) && params.hasKey(AVKey.HEIGHT)) {
        offset = this.theChannel.position();

        double w = (Integer) params.getValue(AVKey.WIDTH);
        double h = (Integer) params.getValue(AVKey.HEIGHT);

        Sector sec = (Sector) params.getValue(AVKey.SECTOR);

        double[] values =
            new double[] { // i ,  j, k=0, x, y, z=0
              0d,
              0d,
              0d,
              sec.getMinLongitude().degrees,
              sec.getMaxLatitude().degrees,
              0d,
              w - 1,
              0d,
              0d,
              sec.getMaxLongitude().degrees,
              sec.getMaxLatitude().degrees,
              0d,
              w - 1,
              h - 1,
              0d,
              sec.getMaxLongitude().degrees,
              sec.getMinLatitude().degrees,
              0d,
              0d,
              h - 1,
              0d,
              sec.getMinLongitude().degrees,
              sec.getMinLatitude().degrees,
              0d,
            };

        byte[] bytes = this.getBytes(values);
        this.theChannel.write(ByteBuffer.wrap(bytes));
        ifds.add(
            new TiffIFDEntry(GeoTiff.Tag.MODEL_TIEPOINT, Tiff.Type.DOUBLE, values.length, offset));
      }

      // Tiff.Tag.MODEL_TRANSFORMATION excludes Tiff.Tag.MODEL_TIEPOINT & Tiff.Tag.MODEL_PIXELSCALE

      if (params.hasKey(AVKey.MISSING_DATA_SIGNAL)
          || params.hasKey(AVKey.MISSING_DATA_REPLACEMENT)) {
        offset = this.theChannel.position();

        Object nodata =
            params.hasKey(AVKey.MISSING_DATA_SIGNAL)
                ? params.getValue(AVKey.MISSING_DATA_SIGNAL)
                : params.getValue(AVKey.MISSING_DATA_REPLACEMENT);

        String value = "" + nodata + "\0";
        byte[] bytes = value.getBytes();
        this.theChannel.write(ByteBuffer.wrap(bytes));
        ifds.add(new TiffIFDEntry(GeoTiff.Tag.GDAL_NODATA, Tiff.Type.ASCII, bytes.length, offset));
      }

      if (params.hasKey(AVKey.COORDINATE_SYSTEM)) {
        String cs = params.getStringValue(AVKey.COORDINATE_SYSTEM);

        if (AVKey.COORDINATE_SYSTEM_GEOGRAPHIC.equals(cs)) {
          if (isElevation(params)) this.writeGeographicElevationGeoKeys(ifds, params);
          else this.writeGeographicImageGeoKeys(ifds, params);
        } else if (AVKey.COORDINATE_SYSTEM_PROJECTED.equals(cs)) {
          String msg = Logging.getMessage("GeotiffWriter.FeatureNotImplementedd", cs);
          Logging.logger().severe(msg);
          throw new IllegalArgumentException(msg);
          // TODO extract PCS (Projection Coordinate System)
        } else {
          String msg = Logging.getMessage("GeotiffWriter.UnknownCoordinateSystem", cs);
          Logging.logger().severe(msg);
          throw new IllegalArgumentException(msg);
        }
      }
    }
  }