private void renderNotRenderedTiles(
      Graphics2D destination,
      IProgressMonitor monitor,
      WMTRenderJob renderJob,
      TileRange range,
      RasterSymbolizer style,
      int tileWorth,
      int thisid,
      Set<String> notRenderedTiles,
      Set<String> renderedTiles)
      throws Exception {
    checkCancelState(monitor, thisid, false);

    // set the listener on the tile range
    range.addListener(listener);

    // load the missing tiles by sending requests for them
    range.loadTiles(monitor);

    // block until all the missing tiles have come through (and draw them
    // as they are added to the blocking queue
    while (!notRenderedTiles.isEmpty()) {
      // check that the rendering is not canceled
      checkCancelState(monitor, thisid, true);

      if (testing) {
        System.out.println("BLOCKED: " + thisid); // $NON-NLS-1$
        System.out.println(
            "waiting on: " + notRenderedTiles.size() + " tiles"); // $NON-NLS-1$ //$NON-NLS-2$
      }

      Tile tile = null;
      try {
        Object element = null;

        /* get the next tile that is ready to render,
         * check after 1 sec if the rendering was canceled
         */
        while ((element = tilesToDraw_queue.poll(1000, TimeUnit.MILLISECONDS)) == null) {
          checkCancelState(monitor, thisid, true);
        }

        tile = (Tile) element;

        if (testing) {
          System.out.println("removed from queue: " + tile.getId()); // $NON-NLS-1$
        }
      } catch (InterruptedException ex) {
        if (testing) {
          System.out.println("InterruptedException trying to take: " + ex); // $NON-NLS-1$
        }
      }

      if (testing) {
        System.out.println("UNBLOCKED!!!: " + thisid); // $NON-NLS-1$
      }

      // check that the rendering is not canceled again after block
      checkCancelState(monitor, thisid, true);

      // check that the tile's bounds are within the current
      // context's bounds (if it's not, don't bother drawing it) and also
      // only draw tiles that haven't already been drawn (panning fast
      // can result in listeners being notified the same tile is ready multiple
      // times but we don't want to draw it more than once per render cycle)
      // ReferencedEnvelope viewbounds = getContext().getViewportModel().getBounds();

      ReferencedEnvelope viewbounds =
          renderJob.projectMapToTileCrs(context.getViewportModel().getBounds());

      if (tile != null
          && tile.getBufferedImage() != null
          && viewbounds != null
          && viewbounds.intersects(tile.getBounds())
          && !renderedTiles.contains(tile.getId())
          && notRenderedTiles.contains(tile.getId())) {
        try {
          renderedTiles.add(tile.getId());
          renderTile(destination, (WMTTile) tile, style, renderJob);

        } catch (Exception exc) {
          WMTPlugin.log(
              "[BasicWMTRender.render] renderTile failed (2): " + tile.getId(), exc); // $NON-NLS-1$
        }
        monitor.worked(tileWorth); // inc the monitor work by 1 tile
        setState(RENDERING); // tell renderer new data is ready
      }

      // remove the tile from the not rendered list regardless
      // of whether it was actually drawn (this is to prevent
      // this render cycle from blocking endlessly waiting for tiles
      // that either didn't return or had some error)
      notRenderedTiles.remove(tile.getId());
    }
  }