0

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).

Giorgio
  • 1,973
  • 4
  • 36
  • 51
  • I would recommend using a custom wrapper pane to make the canvas resizable, instead of binding the width and height properties. See https://stackoverflow.com/a/31761362/2189127 for an example. I don't know the other libraries, so I can't really tell easily if this will solve the issue. – James_D Nov 29 '22 at 15:03
  • I used your solution in my main solution and it doesn't solve the issue. The issue is mainly because of FXGraphics2D and geotool's StreamingRenderer – Elyas Tigre Nov 29 '22 at 15:28

2 Answers2

2

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

mipa
  • 10,369
  • 2
  • 16
  • 35
  • My canvas is correctly resized, see lines under // Create bindings for resizing. That does exactly what your link advise to do. That doesn't solve the rendering issue – Elyas Tigre Nov 29 '22 at 13:17
  • There is more than just that to do but I can't tell you exactly without running the code. But I don't have the time for that. – mipa Nov 29 '22 at 18:00
  • [tag:jfreechart-fx] also uses `FXGraphics2D`; you might look at the relation between `ChartViewer` and `ChartCanvas`. – trashgod Nov 29 '22 at 18:01
0

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 ! :)