private void renderGridCoverage(
      Graphics2D graphics,
      Envelope bounds,
      Dimension dimension,
      ReferencedEnvelope requestBBox,
      BufferedImage image)
      throws Exception {
    CoordinateReferenceSystem destinationCRS = getContext().getCRS();

    Envelope envelope = bounds;
    if (envelope == null || envelope.isNull()) {
      // get the bounds from the context
      envelope = getContext().getImageBounds();
    }
    Point upperLeft =
        getContext().worldToPixel(new Coordinate(envelope.getMinX(), envelope.getMinY()));
    Point bottomRight =
        getContext().worldToPixel(new Coordinate(envelope.getMaxX(), envelope.getMaxY()));
    Rectangle screenSize = new Rectangle(upperLeft);
    screenSize.add(bottomRight);

    GridCoverage2D coverage = convertImageToGridCoverage(requestBBox, image);

    AffineTransform worldToScreen =
        RendererUtilities.worldToScreenTransform(envelope, screenSize, destinationCRS);
    GridCoverageRenderer paint =
        new GridCoverageRenderer(destinationCRS, envelope, screenSize, worldToScreen);

    RasterSymbolizer symbolizer =
        CommonFactoryFinder.getStyleFactory(null).createRasterSymbolizer();

    paint.paint(graphics, coverage, symbolizer);
  }
  public void render(Graphics2D g2d, IProgressMonitor monitor) throws RenderException {
    try {
      final IRenderContext currentContext = getContext();
      currentContext.setStatus(ILayer.WAIT);
      CoordinateReferenceSystem destinationCRS = currentContext.getCRS();

      // the bounds of the visible area in world coordinates
      // get the envelope and the screen extent
      Envelope envelope = getRenderBounds();
      if (envelope == null || envelope.isNull()) {
        envelope = context.getImageBounds();
      }

      Point upperLeft =
          currentContext.worldToPixel(new Coordinate(envelope.getMinX(), envelope.getMinY()));
      Point bottomRight =
          currentContext.worldToPixel(new Coordinate(envelope.getMaxX(), envelope.getMaxY()));
      Rectangle screenSize = new Rectangle(upperLeft);
      screenSize.add(bottomRight);

      final IGeoResource resource = getContext().getGeoResource();
      if (resource == null || !resource.canResolve(JGrassMapGeoResource.class)) {
        return;
      }
      JGrassMapGeoResource grassMapGeoResource =
          resource.resolve(JGrassMapGeoResource.class, monitor);

      JGrassRegion fileWindow = new JGrassRegion(grassMapGeoResource.getFileWindow());
      JGrassMapsetGeoResource parent =
          (JGrassMapsetGeoResource) grassMapGeoResource.parent(new NullProgressMonitor());
      CoordinateReferenceSystem grassCrs = parent.getLocationCrs();
      JGrassRegion screenDrawWindow =
          new JGrassRegion(
              envelope.getMinX(),
              envelope.getMaxX(),
              envelope.getMinY(),
              envelope.getMaxY(),
              fileWindow.getRows(),
              fileWindow.getCols());

      // to intersect with the data window, we transform the screen window
      JGrassRegion reprojectedScreenDrawWindow = screenDrawWindow;
      if (!CRS.equalsIgnoreMetadata(destinationCRS, grassCrs)) {
        reprojectedScreenDrawWindow = screenDrawWindow.reproject(destinationCRS, grassCrs, true);
      }

      /*
       * if the map is not visible, do not render it
       */
      // JGrassRegion fileWindow = grassMapGeoResource.getFileWindow();
      Rectangle2D.Double fileRectDouble = fileWindow.getRectangle();
      Double reprojScreenRectangle = reprojectedScreenDrawWindow.getRectangle();
      if (!reprojScreenRectangle.intersects(fileRectDouble)) {
        getContext().setStatus(ILayer.DONE);
        getContext().setStatusMessage(THE_MAP_IS_OUTSIDE_OF_THE_VISIBLE_REGION);
        System.out.println(THE_MAP_IS_OUTSIDE_OF_THE_VISIBLE_REGION);
        return;
      }
      /*
       * we will draw only the intersection of the map in the display system = part of visible map
       */
      Rectangle2D drawMapRectangle =
          reprojectedScreenDrawWindow.getRectangle().createIntersection(fileRectDouble);
      // Rectangle2D drawMapRectangle = fileRectDouble.getBounds2D();
      // resolution is that of the file window
      double ewRes = fileWindow.getWEResolution();
      double nsRes = fileWindow.getNSResolution();
      if (fileRectDouble.getWidth() < ewRes || fileRectDouble.getHeight() < nsRes) {
        getContext().setStatus(ILayer.DONE);
        getContext().setStatusMessage(THE_MAP_IS_OUTSIDE_OF_THE_VISIBLE_REGION);
        System.out.println(THE_MAP_IS_OUTSIDE_OF_THE_VISIBLE_REGION);
        return;
      }
      MathTransform transform = CRS.findMathTransform(destinationCRS, grassCrs, true);
      Coordinate pixelSize = getContext().getPixelSize();

      Coordinate c1 = new Coordinate(envelope.getMinX(), envelope.getMinY());
      Coordinate c2 =
          new Coordinate(envelope.getMinX() + pixelSize.x, envelope.getMinY() + pixelSize.y);
      Envelope envy = new Envelope(c1, c2);
      Envelope envyTrans = JTS.transform(envy, transform);

      pixelSize = new Coordinate(envyTrans.getWidth(), envyTrans.getHeight());
      /*
       * if the resolution is higher of that of the screen, it doesn't make much sense to draw it
       * all. So for visualization we just use the screen resolution to do things faster.
       */
      if (ewRes < pixelSize.x) {
        ewRes = pixelSize.x;
      }
      if (nsRes < pixelSize.y) {
        nsRes = pixelSize.y;
      }
      fileWindow.setNSResolution(nsRes);
      fileWindow.setWEResolution(ewRes);
      nsRes = fileWindow.getNSResolution();
      ewRes = fileWindow.getWEResolution();
      /*
       * redefine the region of the map to be drawn
       */
      /*
       * snap the screen to fit into the active region grid. This is mandatory for the exactness
       * of the query of the pixels (ex. d.what.rast).
       */
      JGrassRegion activeWindow = grassMapGeoResource.getActiveWindow();
      Coordinate minXY =
          JGrassRegion.snapToNextHigherInRegionResolution(
              drawMapRectangle.getMinX(), drawMapRectangle.getMinY(), activeWindow);
      Coordinate maxXY =
          JGrassRegion.snapToNextHigherInRegionResolution(
              drawMapRectangle.getMaxX(), drawMapRectangle.getMaxY(), activeWindow);

      JGrassRegion drawMapRegion =
          new JGrassRegion(minXY.x, maxXY.x, minXY.y, maxXY.y, ewRes, nsRes);
      // JGrassRegion drawMapRegion = new JGrassRegion(drawMapRectangle.getMinX(),
      // drawMapRectangle.getMaxX(), drawMapRectangle.getMinY(), drawMapRectangle
      // .getMaxY(), ewRes, nsRes);
      JGrassMapEnvironment grassMapEnvironment = grassMapGeoResource.getjGrassMapEnvironment();
      GridCoverage2D coverage =
          JGrassCatalogUtilities.getGridcoverageFromGrassraster(grassMapEnvironment, drawMapRegion);
      coverage = coverage.view(ViewType.RENDERED);
      if (coverage != null) {

        // setting rendering hints
        RenderingHints hints = new RenderingHints(Collections.EMPTY_MAP);
        hints.add(
            new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED));
        hints.add(
            new RenderingHints(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE));
        hints.add(
            new RenderingHints(
                RenderingHints.KEY_ALPHA_INTERPOLATION,
                RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED));
        hints.add(
            new RenderingHints(
                RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_SPEED));
        hints.add(
            new RenderingHints(
                RenderingHints.KEY_INTERPOLATION,
                RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR));
        hints.add(
            new RenderingHints(
                RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE));
        hints.add(
            new RenderingHints(
                RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_OFF));
        hints.add(new RenderingHints(JAI.KEY_INTERPOLATION, new InterpolationNearest()));
        g2d.addRenderingHints(hints);
        final TileCache tempCache = JAI.createTileCache();
        tempCache.setMemoryCapacity(16 * 1024 * 1024);
        tempCache.setMemoryThreshold(1.0f);
        hints.add(new RenderingHints(JAI.KEY_TILE_CACHE, tempCache));

        // draw

        AffineTransform worldToScreen =
            RendererUtilities.worldToScreenTransform(envelope, screenSize, destinationCRS);
        final GridCoverageRenderer paint =
            new GridCoverageRenderer(destinationCRS, envelope, screenSize, worldToScreen, hints);
        RasterSymbolizer rasterSymbolizer =
            CommonFactoryFinder.getStyleFactory(null).createRasterSymbolizer();

        paint.paint(g2d, coverage, rasterSymbolizer);

        tempCache.flush();

        // IBlackboard blackboard = context.getMap().getBlackboard();
        // String legendString = coverageReader.getLegendString();
        // String name = grassMapGeoResource.getTitle();
        // blackboard.putString(JGrassMapGeoResource.READERID + "#" + name, legendString);

      }

    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      getContext().setStatus(ILayer.DONE);
      getContext().setStatusMessage(null);
    }
  }
  /**
   * @see net.refractions.udig.render.internal.wmsc.basic#renderTile(Graphics2D graphics, WMTTile
   *     tile, CoordinateReferenceSystem crs, RasterSymbolizer style)
   * @param graphics
   * @param tile
   * @param style
   * @throws FactoryException
   * @throws TransformException
   * @throws RenderException
   */
  private void renderTile(
      Graphics2D graphics, WMTTile tile, RasterSymbolizer style, WMTRenderJob renderJob)
      throws Exception {

    if (tile == null || tile.getBufferedImage() == null) {
      return;
    }

    // create a gridcoverage from the tile image
    GridCoverageFactory factory = new GridCoverageFactory();

    // get the tile bounds in the CRS the tiles were drawn in
    ReferencedEnvelope tileBndsMercatorRef =
        renderJob.projectTileToTileProjectedCrs(tile.getExtent());

    GridCoverage2D coverage =
        (GridCoverage2D)
            factory.create(
                "GridCoverage", tile.getBufferedImage(), tileBndsMercatorRef); // $NON-NLS-1$

    Envelope2D coveragebounds = coverage.getEnvelope2D();

    // bounds of tile
    ReferencedEnvelope bnds =
        new ReferencedEnvelope(
            coveragebounds.getMinX(),
            coveragebounds.getMaxX(),
            coveragebounds.getMinY(),
            coveragebounds.getMaxY(),
            renderJob.getCrsTilesProjected());

    // reproject tile bounds to map CRS
    bnds = renderJob.projectTileProjectedToMapCrs(bnds);

    // determine screen coordinates of tiles
    Point upperLeft = getContext().worldToPixel(new Coordinate(bnds.getMinX(), bnds.getMinY()));
    Point bottomRight = getContext().worldToPixel(new Coordinate(bnds.getMaxX(), bnds.getMaxY()));
    Rectangle tileSize = new Rectangle(upperLeft);
    tileSize.add(bottomRight);

    // render
    try {
      CoordinateReferenceSystem crs = getContext().getCRS();
      AffineTransform worldToScreen = RendererUtilities.worldToScreenTransform(bnds, tileSize, crs);
      GridCoverageRenderer paint = new GridCoverageRenderer(crs, bnds, tileSize, worldToScreen);

      paint.paint(graphics, coverage, style);

      if (TESTING) {
        //            if(true){
        /* for testing draw border around tiles */
        graphics.setColor(Color.BLACK);
        graphics.drawLine(
            (int) tileSize.getMinX(),
            (int) tileSize.getMinY(),
            (int) tileSize.getMinX(),
            (int) tileSize.getMaxY());
        graphics.drawLine(
            (int) tileSize.getMinX(),
            (int) tileSize.getMinY(),
            (int) tileSize.getMaxX(),
            (int) tileSize.getMinY());
        graphics.drawLine(
            (int) tileSize.getMaxX(),
            (int) tileSize.getMinY(),
            (int) tileSize.getMaxX(),
            (int) tileSize.getMaxY());
        graphics.drawLine(
            (int) tileSize.getMinX(),
            (int) tileSize.getMaxY(),
            (int) tileSize.getMaxX(),
            (int) tileSize.getMaxY());
        graphics.drawString(
            tile.getId(), ((int) tileSize.getMaxX() - 113), ((int) tileSize.getMaxY() - 113));
      }
    } catch (Throwable t) {
      WMTPlugin.log("Error Rendering tile. Painting Tile " + tile.getId(), t); // $NON-NLS-1$
    }
  }