Class CachedRendererJFX

java.lang.Object
org.jorigin.geotools.CachedRendererJFX
All Implemented Interfaces:
GTRendererJFX

public class CachedRendererJFX extends Object implements GTRendererJFX
A GeoTools map renderer that draws directly onto a JavaFX Canvas using the JavaFX GraphicsContext API, with a built-in caching layer to reduce display latency during pan and zoom interactions.

Rendering pipeline

Iterates over the MapContent layers and handles each type:

  • FeatureLayer — vector layers with SLD-based symbolization (polygon, line, point symbolizers); geometries are converted to JavaFX path commands via JTS CoordinateSequence traversal.
  • FXTiledWMSLayer — preferred WMS fast path: for WMS-R endpoints (tile-cached WMS), the buffer envelope is split into PM-grid-aligned tiles and one GetMap is issued per tile. Server returns cached bytes per tile; responses load in parallel via JavaFX async Image; the URL cache is shared with WMTS tiles. Requires EPSG:3857; falls back to the single-request path otherwise.
  • WMSLayer — raster layers fetched from a WMS server via a GetMap request; the response image is loaded asynchronously and drawn onto the canvas when available.
  • FXWMTSMapLayer — preferred WMTS fast path: each tile is fetched independently via JavaFX async Image loading (parallel HTTP) and drawn on arrival; per-tile URL cache (see wmsImageCache) makes repeated pans hit memory only.
  • WMTSMapLayer — fallback WMTS path for stock layers that don't expose their server: the GridCoverage2DReader is read on a background thread (sequential tile fetch inside the reader) and the resulting image is drawn when available.

Overpaint buffer

Each render request paints a larger world area than strictly needed (controlled by OVERPAINT_FACTOR): the rendered region extends 0.5×width and 0.5×height beyond the visible envelope on every side. A WritableImage snapshot of this buffer is retained after each render.

Subsequent paint(org.geotools.map.MapContent, double, double, org.geotools.geometry.jts.ReferencedEnvelope) calls whose target area falls entirely within the buffered region are served instantly by cropping and scaling the snapshot. A buffer refresh is only triggered when the view has consumed more than half of the overpaint margin in any direction (see needsBufferRefresh(org.geotools.geometry.jts.ReferencedEnvelope)).

Tile cache (two tiers)

WMS GetMap and WMTS GetTile responses are cached by request URL across two layers:

Because tile URLs include dimensions and bbox parameters, the key is already dimension-specific.

Thread model

paint(org.geotools.map.MapContent, double, double, org.geotools.geometry.jts.ReferencedEnvelope) must be called on the JavaFX application thread. stopRendering() may be called from any thread.

Usage


   CachedRendererJFX renderer = new CachedRendererJFX();
   pane.getChildren().add(renderer.getCanvas());
   renderer.paint(mapContent, 800, 600, envelope);
   // call renderer.dispose() when the pane is discarded
 
Author:
Julien SEINTURIER - Université de Toulon / CNRS LIS umr 7020
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final Path
    Default location of the persistent (disk) tile cache: <java.io.tmpdir>/.geotools/cache.
    static final long
    Default decoded-byte budget for the WMS/WMTS tile image cache: 128 MB, which holds ~500 PM tiles at 256×256 RGBA once decoded.
    static final int
    Deprecated.
    Dimensioning in entry count drifts with tile content density.
    static final double
    Fraction of the view width/height added on each side when rendering the overpaint buffer. 0.5 means the buffer covers 2× the visible width and 2× the visible height, giving a full "screen" of margin in every direction before a re-render is needed.
    static final String
    Name of the system property that overrides the persistent cache directory.
    static final String
    Name of the system property that controls whether the persistent disk cache is enabled by default in newly-constructed renderers.
  • Constructor Summary

    Constructors
    Constructor
    Description
    Creates a renderer using the default 134217728L-byte tile cache.
    CachedRendererJFX(int wmsCacheSize)
    Deprecated.
    Dimensioning in entry count makes real memory use unpredictable.
    CachedRendererJFX(long wmsCacheBytes)
    Creates a renderer with a custom tile cache byte budget.
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    Removes every file under getPersistentCacheDirectory() asynchronously, so the FX thread is never blocked on disk I/O.
    void
    Clears the WMS image URL cache.
    void
    Releases resources held by this renderer.
    double
    Get the rolling average wall-clock load time across all successfully-completed async image loads, in milliseconds.
    long
    Get the number of completed buffer refresh cycles since construction (or last reset).
    long
    Get the current cumulative decoded footprint of the tile cache, in bytes.
    double
    Get the fraction of user-visible cache lookups served from cache, in [0.0, 1.0].
    long
    Get the number of tile cache lookups that returned a ready image (user-visible render paths only — prefetch and adjacent-level placeholder lookups are excluded to keep the metric reflective of actual render latency).
    long
    Get the configured maximum cumulative decoded footprint of the tile cache, in bytes.
    long
    Get the number of tile cache lookups that missed and triggered an async fetch.
    javafx.scene.canvas.Canvas
    Returns the display Canvas.
    Get the filesystem directory where persistent cache entries are stored.
    int
    Get the current number of async image loads in flight (includes both main-render and prefetch loads).
    void
    Discards the overpaint buffer, forcing a full re-render on the next paint(org.geotools.map.MapContent, double, double, org.geotools.geometry.jts.ReferencedEnvelope) call.
    boolean
    Get whether the persistent disk cache is currently active.
    void
    paint(org.geotools.map.MapContent content, double w, double h, org.geotools.geometry.jts.ReferencedEnvelope area)
    Renders the map content onto the display canvas at the given size and world envelope.
    Returns a one-line human-readable summary of all perf counters, suitable for logging, a status-bar overlay, or ad-hoc debugging.
    void
    Resets all performance counters to zero.
    void
    setPersistentCacheActive(boolean active)
    Enables or disables the persistent (on-disk) tile cache.
    void
    Overrides the persistent cache directory for this renderer.
    void
    Signals the current render to stop after the current feature.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

    • OVERPAINT_FACTOR

      public static final double OVERPAINT_FACTOR
      Fraction of the view width/height added on each side when rendering the overpaint buffer. 0.5 means the buffer covers 2× the visible width and 2× the visible height, giving a full "screen" of margin in every direction before a re-render is needed.
      See Also:
    • DEFAULT_WMS_CACHE_BYTES

      public static final long DEFAULT_WMS_CACHE_BYTES
      Default decoded-byte budget for the WMS/WMTS tile image cache: 128 MB, which holds ~500 PM tiles at 256×256 RGBA once decoded. Generous enough to cover the current view, its overpaint margin, and several zoom levels worth of prefetched (prefetchTimer) neighbors without evicting still-relevant entries.

      Dimensioning in bytes rather than entry count prevents the cache's real memory footprint from drifting with tile content density. A PNG of an urban tile decodes to the same 256 KB in RGBA as an ocean tile, even though their compressed sizes differ wildly.

      See Also:
    • DEFAULT_WMS_CACHE_SIZE

      @Deprecated public static final int DEFAULT_WMS_CACHE_SIZE
      Deprecated.
      Dimensioning in entry count drifts with tile content density. Prefer DEFAULT_WMS_CACHE_BYTES and the byte-budget constructor CachedRendererJFX(long).
      Number of WMS response images kept in the LRU URL cache.
      See Also:
    • DEFAULT_PERSISTENT_CACHE_DIR

      public static final Path DEFAULT_PERSISTENT_CACHE_DIR
      Default location of the persistent (disk) tile cache: <java.io.tmpdir>/.geotools/cache. Survives JVM restarts so the second launch of an application finds previously-fetched tiles already available. Cleared via clearPersistentCache().
    • PERSISTENT_CACHE_PROPERTY

      public static final String PERSISTENT_CACHE_PROPERTY
      Name of the system property that controls whether the persistent disk cache is enabled by default in newly-constructed renderers.
      • -Dorg.geotools.renderer.cached.persistant=true — enable (same as default).
      • -Dorg.geotools.renderer.cached.persistant=false — disable globally.
      • property not set — enabled (default behavior).
      Read once per renderer at construction time; runtime overrides via setPersistentCacheActive(boolean) take precedence afterward.
      See Also:
    • PERSISTENT_CACHE_DIR_PROPERTY

      public static final String PERSISTENT_CACHE_DIR_PROPERTY
      Name of the system property that overrides the persistent cache directory. When set to a usable filesystem path (existing directory or a path that can be created), the renderer stores its disk cache there instead of DEFAULT_PERSISTENT_CACHE_DIR. When unset, blank, pointing at a non-directory, or otherwise unusable, the default applies and a warning is logged.

      Read once per renderer at construction time.

      See Also:
  • Constructor Details

    • CachedRendererJFX

      public CachedRendererJFX()
      Creates a renderer using the default 134217728L-byte tile cache.
    • CachedRendererJFX

      public CachedRendererJFX(long wmsCacheBytes)
      Creates a renderer with a custom tile cache byte budget.
      Parameters:
      wmsCacheBytes - maximum cumulative decoded size of cached tile images, in bytes; pass 0 to disable caching. Typical values range from 32 MB (very light use) to 512 MB (heavy pan/zoom sessions).
    • CachedRendererJFX

      @Deprecated public CachedRendererJFX(int wmsCacheSize)
      Deprecated.
      Dimensioning in entry count makes real memory use unpredictable. Prefer CachedRendererJFX(long).
      Creates a renderer with an entry-count cache budget.
      Parameters:
      wmsCacheSize - maximum number of WMS response images to keep in the LRU cache; pass 0 to disable caching. Translated internally to a byte budget via ESTIMATED_TILE_BYTES.
  • Method Details

    • getCanvas

      public javafx.scene.canvas.Canvas getCanvas()
      Returns the display Canvas. Add it to the JavaFX scene graph to show the rendered map.
      Specified by:
      getCanvas in interface GTRendererJFX
      Returns:
      the display canvas
    • paint

      public void paint(org.geotools.map.MapContent content, double w, double h, org.geotools.geometry.jts.ReferencedEnvelope area)
      Renders the map content onto the display canvas at the given size and world envelope.
      • If the requested area is fully covered by the overpaint buffer, the display is updated immediately from the cached snapshot (zero latency — no WMS request, no vector pass). A buffer refresh is only scheduled when the view has consumed more than half the overpaint margin in any direction.
      • On a buffer miss, a full buffer render is performed synchronously for vector layers, then the display is updated from the fresh buffer.

      Must be called on the JavaFX application thread.

      Specified by:
      paint in interface GTRendererJFX
      Parameters:
      content - the map content to render
      w - target width in pixels
      h - target height in pixels
      area - the world-coordinate envelope to display
    • stopRendering

      public void stopRendering()
      Signals the current render to stop after the current feature. Safe to call from any thread.
      Specified by:
      stopRendering in interface GTRendererJFX
    • invalidateBuffer

      public void invalidateBuffer()
      Discards the overpaint buffer, forcing a full re-render on the next paint(org.geotools.map.MapContent, double, double, org.geotools.geometry.jts.ReferencedEnvelope) call. Call this when the map content changes in a way that makes the buffer invalid (layer added / removed, style change, etc.).
    • clearWmsCache

      public void clearWmsCache()
      Clears the WMS image URL cache. Subsequent WMS requests will fetch fresh images from the server. No-op if WMS caching was disabled at construction time.
    • setPersistentCacheActive

      public void setPersistentCacheActive(boolean active)
      Enables or disables the persistent (on-disk) tile cache. When enabled, every successful HTTP tile fetch is also written to DEFAULT_PERSISTENT_CACHE_DIR as a PNG, and memory-cache misses probe the disk before issuing an HTTP request — so the second launch of the application finds previously-rendered tiles instantly.

      The renderer's initial state is governed by the system property PERSISTENT_CACHE_PROPERTY; this setter overrides that default for the lifetime of this instance.

      Disabling does not delete existing files on disk; for that, call clearPersistentCache(). In-flight async loads are unaffected.

      Parameters:
      active - true if the persistent caching has to be activated and false otherwise
    • isPersistentCacheActive

      public boolean isPersistentCacheActive()
      Get whether the persistent disk cache is currently active.
      Returns:
      true if the persistent cache is active and false otherwise
    • getPersistentCacheDirectory

      public Path getPersistentCacheDirectory()
      Get the filesystem directory where persistent cache entries are stored.
      Returns:
      the persistent cache directory
    • setPersistentCacheDirectory

      public void setPersistentCacheDirectory(Path dir)
      Overrides the persistent cache directory for this renderer. Subsequent disk reads and writes target dir instead of the previous location; pre-existing files at the old directory are not migrated and remain accessible only after another override or clearPersistentCache() on the old path.

      The directory itself is not created here — that happens lazily on the first write so this setter is filesystem-side-effect free.

      Parameters:
      dir - the new cache directory; must not be null
      Throws:
      IllegalArgumentException - if dir is null or points at an existing entry that is not a directory
    • clearPersistentCache

      public void clearPersistentCache()
      Removes every file under getPersistentCacheDirectory() asynchronously, so the FX thread is never blocked on disk I/O. The directory itself is preserved. No-op if the directory doesn't exist.
    • getCacheHits

      public long getCacheHits()
      Get the number of tile cache lookups that returned a ready image (user-visible render paths only — prefetch and adjacent-level placeholder lookups are excluded to keep the metric reflective of actual render latency).
      Returns:
      the number of tile cache lookups
    • getCacheMisses

      public long getCacheMisses()
      Get the number of tile cache lookups that missed and triggered an async fetch.
      Returns:
      the number of tile cache lookups that missed
    • getCacheHitRate

      public double getCacheHitRate()
      Get the fraction of user-visible cache lookups served from cache, in [0.0, 1.0]. Returns 0.0 before the first lookup. A steady-state value above ~0.7 indicates the cache is well-sized and the prefetch / placeholder optimizations are pulling their weight.
      Returns:
      The fraction of user-visible cache lookups served from cache
    • getBufferRefreshCount

      public long getBufferRefreshCount()
      Get the number of completed buffer refresh cycles since construction (or last reset).
      Returns:
      The number of completed buffer refresh cycles since construction
    • getTilesInFlight

      public int getTilesInFlight()
      Get the current number of async image loads in flight (includes both main-render and prefetch loads). Drops to 0 between renders when the network catches up; a persistently high value suggests the server is too slow or the prefetch cap is too aggressive.
      Returns:
      the current number of async image loads in flight
    • getAverageTileLoadMs

      public double getAverageTileLoadMs()
      Get the rolling average wall-clock load time across all successfully-completed async image loads, in milliseconds. Excludes canceled/errored/stale loads so it reflects the server's effective response time, not client churn. Returns 0.0 before the first successful load.
      Returns:
      the rolling average wall-clock load time across all successfully-complete async image loads
    • getCacheBytes

      public long getCacheBytes()
      Get the current cumulative decoded footprint of the tile cache, in bytes.
      Returns:
      the current cumulative decoded footprint of the tile cache, in bytes
    • getCacheMaxBytes

      public long getCacheMaxBytes()
      Get the configured maximum cumulative decoded footprint of the tile cache, in bytes.
      Returns:
      the configured maximum cumulative decoded footprint of the tile cache, in bytes
    • resetCounters

      public void resetCounters()
      Resets all performance counters to zero. Useful for measuring a specific operation (e.g. "how many tiles and buffer refreshes did this zoom-out consume?") without the noise of prior activity.
    • perfSummary

      public String perfSummary()
      Returns a one-line human-readable summary of all perf counters, suitable for logging, a status-bar overlay, or ad-hoc debugging. Example output:
      hits=142 misses=18 hitRate=88.7% refreshes=9 inFlight=0 avgLoad=76.3ms cache=34.2/128.0MB
      Returns:
      a one-line human-readable summary of all perf counters
    • dispose

      public void dispose()
      Releases resources held by this renderer. After calling this method the renderer must not be used.