private void scheduleTileForRendering(final Tile tile) {
   //        System.out.println("Scheduling tile for rendering: " + tile.getX() + ", " +
   // tile.getY());
   if (SwingUtilities.isEventDispatchThread()) {
     Rectangle visibleArea = ((JViewport) getParent()).getViewRect();
     Rectangle tileBounds = zoom(getTileBounds(tile.getX(), tile.getY()));
     if (tileBounds.intersects(visibleArea)) {
       // The tile is (partially) visible, so it should be repainted
       // immediately
       switch (refreshMode) {
         case IMMEDIATE:
           threeDeeRenderManager.renderTile(tile);
           break;
         case DELAYED:
           tilesWaitingToBeRendered.add(tile);
           lastTileChange = System.currentTimeMillis();
           break;
         case MANUAL:
           // Do nothing
           break;
         default:
           throw new InternalError();
       }
     } else {
       // The tile is not visible, so repaint it when it becomes visible
       tilesWaitingToBeRendered.remove(tile);
       renderedTiles.remove(tile);
     }
   } else {
     SwingUtilities.invokeLater(
         () -> {
           Rectangle visibleArea = ((JViewport) getParent()).getViewRect();
           Rectangle tileBounds = zoom(getTileBounds(tile.getX(), tile.getY()));
           if (tileBounds.intersects(visibleArea)) {
             // The tile is (partially) visible, so it should be repainted
             // immediately
             switch (refreshMode) {
               case IMMEDIATE:
                 threeDeeRenderManager.renderTile(tile);
                 break;
               case DELAYED:
                 tilesWaitingToBeRendered.add(tile);
                 lastTileChange = System.currentTimeMillis();
                 break;
               case MANUAL:
                 // Do nothing
                 break;
               default:
                 throw new InternalError();
             }
           } else {
             // The tile is not visible, so repaint it when it becomes visible
             tilesWaitingToBeRendered.remove(tile);
             renderedTiles.remove(tile);
           }
         });
   }
 }
  @Override
  public void actionPerformed(ActionEvent e) {
    // Send tiles to be rendered
    if ((!tilesWaitingToBeRendered.isEmpty())
        && ((System.currentTimeMillis() - lastTileChange) > 250)) {
      tilesWaitingToBeRendered.forEach(threeDeeRenderManager::renderTile);
      tilesWaitingToBeRendered.clear();
    }

    // Collect rendered tiles
    Set<RenderResult> renderResults = threeDeeRenderManager.getRenderedTiles();
    Rectangle repaintArea = null;
    for (RenderResult renderResult : renderResults) {
      Tile tile = renderResult.getTile();
      int x = tile.getX(), y = tile.getY();
      renderedTiles.put(tile, renderResult.getImage());
      Rectangle tileBounds = zoom(getTileBounds(x, y));
      if (repaintArea == null) {
        repaintArea = tileBounds;
      } else {
        repaintArea = repaintArea.union(tileBounds);
      }
    }
    if (repaintArea != null) {
      //            System.out.println("Repainting " + repaintArea);
      repaint(repaintArea);
    }
  }