package canvastest;
import java.awt.geom.Rectangle2D;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.control.ToolBar;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.StrokeLineCap;
import javafx.scene.shape.StrokeLineJoin;
import javafx.scene.transform.Affine;
import javafx.stage.Stage;
public class JFXMapRenderingTest extends Application {
/** X coordinates of points to testing */
private final static double[] XPoints = { 839688.142, 842040.845, 842067.716, 839828.468, 840900.322, 840748.053 };
/** Y coordinates of points to testing */
private final static double[] YPoints = { 834278.158, 834322.943, 835979.987, 835978.944, 835224.614, 835129.073 };
/** Max map extent: [ xmin, xmax, ymin, ymax ] */
private final static double[] MaxMapExtent = { 839650.414, 842180.086, 834204.376, 835988.085 };
/** Current map extent: [ xmin, xmax, ymin, ymax ] */
private final static double[] CurrentMapExtent = { 839650.414, 842180.086, 833831.3944999999, 836361.0665 };
/** Viewport extent: [ xmin, xmax, ymin, ymax ] */
private static Rectangle2D.Double viewport;
/** Map Scale X */
private static double mapscaleX = 1.0;
/** Map Scale Y */
private static double mapscaleY = 1.0;
/** Map Scale */
private static double mapscale = 1.0;
/** Map Translation X*/
private static double maptranslateX = 0.0;
/** Map Translation Y*/
private static double maptranslateY = 0.0;
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("JFX Canvas Map Rendering Test");
BorderPane root = new BorderPane();
Scene scene = new Scene(root, 500, 533);
ScrollPane scrollPane = new ScrollPane();
scrollPane.setHbarPolicy(ScrollBarPolicy.NEVER);
scrollPane.setVbarPolicy(ScrollBarPolicy.NEVER);
root.setCenter(scrollPane);
Canvas canvas = new Canvas();
canvas.widthProperty().bind(scrollPane.widthProperty());
canvas.heightProperty().bind(scrollPane.heightProperty());
scrollPane.setContent(canvas);
canvas.setScaleY(-1); // change the origin(0, 0) to lower left
Button btnDraw = new Button("Draw");
btnDraw.setOnAction((ActionEvent event) -> {
clear(canvas);
draw(canvas);
});
Button btnClear = new Button("Clear");
btnClear.setOnAction((ActionEvent event) -> {
clear(canvas);
});
Button btnFullExtent = new Button("FullExtent");
btnFullExtent.setOnAction((ActionEvent event) -> {
double scalex = canvas.getScaleX();
double scaley = canvas.getScaleY();
scalex = scalex > 0 ? 1.0 : -1.0;
scaley = scaley > 0 ? 1.0 : -1.0;
canvas.setScaleX(scalex);
canvas.setScaleY(scaley);
// draw(canvas);
});
Button btnZoomin = new Button("ZoomIn");
btnZoomin.setOnAction((ActionEvent event) -> {
canvas.setScaleX(2 * canvas.getScaleX());
canvas.setScaleY(2 * canvas.getScaleY());
// draw(canvas);
});
Button btnZoomout = new Button("ZoomOut");
btnZoomout.setOnAction((ActionEvent event) -> {
canvas.setScaleX(0.5 * canvas.getScaleX());
canvas.setScaleY(0.5 * canvas.getScaleY());
// draw(canvas);
});
ToolBar toolbar = new ToolBar(btnDraw, btnClear, btnFullExtent, btnZoomin, btnZoomout);
root.setTop(toolbar);
primaryStage.setScene(scene);
primaryStage.show();
viewport = new Rectangle2D.Double(0, 0, canvas.getWidth(), canvas.getHeight());
}
private void clear(Canvas canvas) {
double xmin = MaxMapExtent[0];
double xmax = MaxMapExtent[1];
double ymin = MaxMapExtent[2];
double ymax = MaxMapExtent[3];
double width = xmax - xmin;
double height = ymax - ymin;
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.clearRect(xmin, ymin, width, height);
}
private void draw(Canvas canvas) {
GraphicsContext gc = canvas.getGraphicsContext2D();
// Adjust the scope of the current map to match the width to height ratio of the viewport
double aspectRatio = viewport.width / viewport.height;
double xmin = CurrentMapExtent[0];
double xmax = CurrentMapExtent[1];
double ymin = CurrentMapExtent[2];
double ymax = CurrentMapExtent[3];
double w = (xmax - xmin);
double h = (ymax - ymin);
if (w < h) {
xmin = CurrentMapExtent[0] -= Math.abs((w - aspectRatio * h) / 2);
xmax = CurrentMapExtent[1] += Math.abs((w - aspectRatio * h) / 2);
} else {
ymin = CurrentMapExtent[2] -= Math.abs((h - w / aspectRatio) / 2);
ymax = CurrentMapExtent[3] += Math.abs((h - w / aspectRatio) / 2);
}
w = (xmax - xmin);
h = (ymax - ymin);
mapscaleX = canvas.getWidth() / w;
mapscaleY = canvas.getHeight() / h;
mapscale = mapscaleX > mapscaleY ? mapscaleX : mapscaleY;
maptranslateX = canvas.getTranslateX() - xmin; // 0 - xmin
maptranslateY = canvas.getTranslateY() - ymin; // 0 - ymin
/** No.1: why can't do like this??? what's the different with the No.2??? */
// gc.setTransform(mapscale, 0.0, 0.0, mapscale, maptranslateX, maptranslateY);
/** No.2: this will be ok */
// gc.setTransform(mapscale, 0.0, 0.0, mapscale, 0, 0);
// gc.translate(maptranslateX, maptranslateY);
/** No.3: why can't do like this??? what's the different with the No.4??? */
// Affine affine = new Affine(mapscale, 0.0, maptranslateX, 0.0, mapscaleY, maptranslateY);
// gc.setTransform(affine);
/** No.4: this will be ok */
Affine affine = new Affine();
affine.appendScale(mapscale, mapscale);
affine.appendTranslation(maptranslateX, maptranslateY);
gc.setTransform(affine);
System.out.println("start rendering...");
long st = System.currentTimeMillis();
gc.setFill(Color.GREEN);
gc.setStroke(Color.ORANGE);
gc.setLineCap(StrokeLineCap.ROUND);
gc.setLineJoin(StrokeLineJoin.ROUND);
gc.setLineWidth(2.0);
gc.strokePolyline(XPoints, YPoints, XPoints.length);
System.out.println("Time consuming: " + (System.currentTimeMillis() - st) / 1000.0 + " s\n");
}
public static void main(String[] args) {
launch(args);
}
}
Question 1: please see draw() method that like "No.1, No.2 ..." etc.
Question 2: when I call the draw() method first, the line width looks very well... but from after the second, the line width looks bad and different with the first one, why??
import java.awt.geom.Rectangle2D;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.control.ToolBar;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.StrokeLineCap;
import javafx.scene.shape.StrokeLineJoin;
import javafx.scene.transform.Affine;
import javafx.stage.Stage;
public class JFXMapRenderingTest extends Application {
/** X coordinates of points to testing */
private final static double[] XPoints = { 839688.142, 842040.845, 842067.716, 839828.468, 840900.322, 840748.053 };
/** Y coordinates of points to testing */
private final static double[] YPoints = { 834278.158, 834322.943, 835979.987, 835978.944, 835224.614, 835129.073 };
/** Max map extent: [ xmin, xmax, ymin, ymax ] */
private final static double[] MaxMapExtent = { 839650.414, 842180.086, 834204.376, 835988.085 };
/** Current map extent: [ xmin, xmax, ymin, ymax ] */
private final static double[] CurrentMapExtent = { 839650.414, 842180.086, 833831.3944999999, 836361.0665 };
/** Viewport extent: [ xmin, xmax, ymin, ymax ] */
private static Rectangle2D.Double viewport;
/** Map Scale X */
private static double mapscaleX = 1.0;
/** Map Scale Y */
private static double mapscaleY = 1.0;
/** Map Scale */
private static double mapscale = 1.0;
/** Map Translation X*/
private static double maptranslateX = 0.0;
/** Map Translation Y*/
private static double maptranslateY = 0.0;
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("JFX Canvas Map Rendering Test");
BorderPane root = new BorderPane();
Scene scene = new Scene(root, 500, 533);
ScrollPane scrollPane = new ScrollPane();
scrollPane.setHbarPolicy(ScrollBarPolicy.NEVER);
scrollPane.setVbarPolicy(ScrollBarPolicy.NEVER);
root.setCenter(scrollPane);
Canvas canvas = new Canvas();
canvas.widthProperty().bind(scrollPane.widthProperty());
canvas.heightProperty().bind(scrollPane.heightProperty());
scrollPane.setContent(canvas);
canvas.setScaleY(-1); // change the origin(0, 0) to lower left
Button btnDraw = new Button("Draw");
btnDraw.setOnAction((ActionEvent event) -> {
clear(canvas);
draw(canvas);
});
Button btnClear = new Button("Clear");
btnClear.setOnAction((ActionEvent event) -> {
clear(canvas);
});
Button btnFullExtent = new Button("FullExtent");
btnFullExtent.setOnAction((ActionEvent event) -> {
double scalex = canvas.getScaleX();
double scaley = canvas.getScaleY();
scalex = scalex > 0 ? 1.0 : -1.0;
scaley = scaley > 0 ? 1.0 : -1.0;
canvas.setScaleX(scalex);
canvas.setScaleY(scaley);
// draw(canvas);
});
Button btnZoomin = new Button("ZoomIn");
btnZoomin.setOnAction((ActionEvent event) -> {
canvas.setScaleX(2 * canvas.getScaleX());
canvas.setScaleY(2 * canvas.getScaleY());
// draw(canvas);
});
Button btnZoomout = new Button("ZoomOut");
btnZoomout.setOnAction((ActionEvent event) -> {
canvas.setScaleX(0.5 * canvas.getScaleX());
canvas.setScaleY(0.5 * canvas.getScaleY());
// draw(canvas);
});
ToolBar toolbar = new ToolBar(btnDraw, btnClear, btnFullExtent, btnZoomin, btnZoomout);
root.setTop(toolbar);
primaryStage.setScene(scene);
primaryStage.show();
viewport = new Rectangle2D.Double(0, 0, canvas.getWidth(), canvas.getHeight());
}
private void clear(Canvas canvas) {
double xmin = MaxMapExtent[0];
double xmax = MaxMapExtent[1];
double ymin = MaxMapExtent[2];
double ymax = MaxMapExtent[3];
double width = xmax - xmin;
double height = ymax - ymin;
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.clearRect(xmin, ymin, width, height);
}
private void draw(Canvas canvas) {
GraphicsContext gc = canvas.getGraphicsContext2D();
// Adjust the scope of the current map to match the width to height ratio of the viewport
double aspectRatio = viewport.width / viewport.height;
double xmin = CurrentMapExtent[0];
double xmax = CurrentMapExtent[1];
double ymin = CurrentMapExtent[2];
double ymax = CurrentMapExtent[3];
double w = (xmax - xmin);
double h = (ymax - ymin);
if (w < h) {
xmin = CurrentMapExtent[0] -= Math.abs((w - aspectRatio * h) / 2);
xmax = CurrentMapExtent[1] += Math.abs((w - aspectRatio * h) / 2);
} else {
ymin = CurrentMapExtent[2] -= Math.abs((h - w / aspectRatio) / 2);
ymax = CurrentMapExtent[3] += Math.abs((h - w / aspectRatio) / 2);
}
w = (xmax - xmin);
h = (ymax - ymin);
mapscaleX = canvas.getWidth() / w;
mapscaleY = canvas.getHeight() / h;
mapscale = mapscaleX > mapscaleY ? mapscaleX : mapscaleY;
maptranslateX = canvas.getTranslateX() - xmin; // 0 - xmin
maptranslateY = canvas.getTranslateY() - ymin; // 0 - ymin
/** No.1: why can't do like this??? what's the different with the No.2??? */
// gc.setTransform(mapscale, 0.0, 0.0, mapscale, maptranslateX, maptranslateY);
/** No.2: this will be ok */
// gc.setTransform(mapscale, 0.0, 0.0, mapscale, 0, 0);
// gc.translate(maptranslateX, maptranslateY);
/** No.3: why can't do like this??? what's the different with the No.4??? */
// Affine affine = new Affine(mapscale, 0.0, maptranslateX, 0.0, mapscaleY, maptranslateY);
// gc.setTransform(affine);
/** No.4: this will be ok */
Affine affine = new Affine();
affine.appendScale(mapscale, mapscale);
affine.appendTranslation(maptranslateX, maptranslateY);
gc.setTransform(affine);
System.out.println("start rendering...");
long st = System.currentTimeMillis();
gc.setFill(Color.GREEN);
gc.setStroke(Color.ORANGE);
gc.setLineCap(StrokeLineCap.ROUND);
gc.setLineJoin(StrokeLineJoin.ROUND);
gc.setLineWidth(2.0);
gc.strokePolyline(XPoints, YPoints, XPoints.length);
System.out.println("Time consuming: " + (System.currentTimeMillis() - st) / 1000.0 + " s\n");
}
public static void main(String[] args) {
launch(args);
}
}
Question 1: please see draw() method that like "No.1, No.2 ..." etc.
Question 2: when I call the draw() method first, the line width looks very well... but from after the second, the line width looks bad and different with the first one, why??
- duplicates
-
JDK-8096716 [Canvas] GraphicsContext.{fill/stroke}Poly{line/gon}() methods do not flush transform
- Resolved