Problem with resizing a canvas with FXGraphics2D and StreamingRenderer

132 Views Asked by At

I'm in the same situation as here : https://sourceforge.net/p/geotools/mailman/message/35977998/

I am working on a Maps Application using geotools (WMS + WFS for grids) and resizing my JavaFX Canvas works well when I am reducing the size of the canvas, but a part of the image is not rendered when I expend my window (the canvas is expended too).

Is there a solution ?

I'm posting the same example as the one in the link above :

import java.awt.Color;
import java.awt.Rectangle;

import org.geotools.feature.DefaultFeatureCollection;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.map.FeatureLayer;
import org.geotools.map.Layer;
import org.geotools.map.MapContent;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.renderer.lite.StreamingRenderer;
import org.geotools.styling.SLD;
import org.geotools.styling.Style;
import org.jfree.fx.FXGraphics2D;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class ResizingTest extends Application {

    @Override
    public void start(Stage stage) {

        Canvas canvas = new Canvas(640, 480);
        BorderPane root = new BorderPane(canvas);
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.show();

        // Create bindings for resizing.
        canvas.widthProperty().bind(root.widthProperty());
        canvas.heightProperty().bind(root.heightProperty());

        SimpleFeatureTypeBuilder lineFeatureTypeBuilder = new
SimpleFeatureTypeBuilder();
        lineFeatureTypeBuilder.setName("LineFeatureType");
        lineFeatureTypeBuilder.setCRS(DefaultGeographicCRS.WGS84);
        lineFeatureTypeBuilder.add("the_geom", LineString.class,
DefaultGeographicCRS.WGS84);
        SimpleFeatureType lineFeatureType = lineFeatureTypeBuilder.buildFe
atureType();
        SimpleFeatureBuilder lineFeatureBuilder = new
SimpleFeatureBuilder(lineFeatureType);

        DefaultFeatureCollection lines = new DefaultFeatureCollection();

        Coordinate[][] cs = {
                { new Coordinate(-1, 42), new Coordinate(4, 46) },
                { new Coordinate(-1, 46), new Coordinate(4, 42) }
        };

        GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFa
ctory();
        for(Coordinate [] c : cs) {
            LineString line = geometryFactory.createLineString(c);
            lineFeatureBuilder.add(line);
            SimpleFeature feature = lineFeatureBuilder.buildFeature(null);
            lines.add(feature);
        }

        MapContent map = new MapContent();
        Style style = SLD.createLineStyle(Color.RED, 1);
        Layer layer = new FeatureLayer(lines, style);
        map.addLayer(layer);
        //map.getViewport().setBounds(new ReferencedEnvelope(-1, 4, 42, 46,
DefaultGeographicCRS.WGS84));

        AnimationTimer loop = new AnimationTimer() {
            @Override
            public void handle(long now) {
                GraphicsContext g = canvas.getGraphicsContext2D();
                FXGraphics2D graphics = new FXGraphics2D(g);
                graphics.setBackground(java.awt.Color.BLUE);
                Rectangle rectangle = new Rectangle( (int)
canvas.getWidth(), (int) canvas.getHeight());
                graphics.clearRect(0, 0, (int) rectangle.getWidth(), (int)
rectangle.getHeight());
                graphics.drawRect(100, 100, 100, 100);
                map.getViewport().setScreenArea(rectangle); // Necessary ?
                StreamingRenderer renderer = new StreamingRenderer();
                renderer.setMapContent(map);
                renderer.paint(graphics, rectangle,
map.getViewport().getBounds());
                System.out.println("ScreenArea: " +
map.getViewport().getScreenArea() + " - Viewport: " +
map.getViewport().getBounds());
            }
        };
        loop.start();

    }

    public static void main(String[] args) {
        launch(args);
    }

}

When we expand the window, a part of the canvas is not rendered anymore, resulting on a "correct" cross (because it still goes from upper left to lower right corner), but cropped ! Anything drawn on the cropped part is not rendered

enter image description here

Edit :

I am not trying to make the canvas resizable, it already is (Proof : The cross goes from upper left to lower right pixel of canvas). The real issue is the rendering of the map that is cropped (we can't see the full cross).

2

There are 2 best solutions below

0
Elyas Tigre On BEST ANSWER

I finally found a fix ! As mentionned in geotools' StreamingRenderer code :

"the way this thing is built is a mess if you try to use it in a multithreaded environment"

Avoid using StreamingRenderer in an AnimationLoop, Platform.runLater(), etc... I called the draw function everytime the map was updated instead, and it works as expected ! :)

3
mipa On

Resizing a canvas can be tricky in JavaFX. Here is a SO answer which may be helpful for you. Automatically resize Canvas to fill the enclosing Parent