5

i'm new to JavaFX and i'm trying to draw some things on a canvas.

First I'm setting the linecolor to black and draw a line.

canvas.getGraphicsContext2D().setStroke(Color.BLACK);
canvas.getGraphicsContext2D().strokeLine(20,20,100,100);

After this I'm trying to erase this line by draw a white line over this line:

canvas.getGraphicsContext2D().setStroke(Color.WHITE);  
canvas.getGraphicsContext2D().strokeLine(20,20,100,100);

But there will be some gray pixels left on canvas. What is the reason for this and how can i prevent this?

this ist the way i create the scene

Pane root = new Pane();
canvas = new Canvas(200, 200);
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.strokeLine(20,20,100,100);
scene = new Scene(root, 200, 200);
this.setColor(Color.WHITE);
root.getChildren().add(canvas);

Thanks, Martin

Ma Sch
  • 501
  • 1
  • 4
  • 8
  • Is the `Canvas` background color set to white? – SedJ601 Dec 08 '17 at 22:35
  • Yes, i tried `canvas.setStyle("-fx-background-color: white;");` and `((Pane)scene.getRoot()).setBackground(new Background(new BackgroundFill(Color.WHITE, CornerRadii.EMPTY, Insets.EMPTY))); ` – Ma Sch Dec 08 '17 at 22:57
  • 1
    I found out something weird, it does go white after a while. Try looping over it 13 times. – Kiraged Dec 08 '17 at 22:59
  • The comment by @Emrage makes me suspect aliasing artifact; please [edit] your question to include a [mcve] that exhibits the problem you describe. – trashgod Dec 09 '17 at 16:58
  • See me edit above. Is there a way to disable antialiasing? – Ma Sch Dec 09 '17 at 18:33

1 Answers1

0

This problem is related to antialiasing. If some point has non-integer coordinates, its drawing will be divided into several pixels with partial fill. Like this (in zoom):enter image description here So, if you draw something different from a horizontal or vertical line you will get this effect. If you want to get around this effect, use pixel-by-pixel drawing:

public class Test extends Application {

    @Override
    public void start(Stage primaryStage) {
        Canvas canvas = new Canvas();
        canvas.setWidth(200);
        canvas.setHeight(200);
        GraphicsContext gc = canvas.getGraphicsContext2D();

        gc.setLineWidth(4);
        gc.setStroke(Color.BLACK);
        drawLine(gc, 20, 20, 180, 180);
        gc.setStroke(Color.WHITE);
        drawLine(gc, 20, 20, 180, 180);

        Pane pane = new Pane(canvas);
        primaryStage.setScene(new Scene(pane));
        primaryStage.show();
    }

    private void drawLine(GraphicsContext gc, double x1, double y1, double x2, double y2) {
        double lineWidth = gc.getLineWidth();
        Color color = (Color) gc.getStroke();
        PixelWriter pw = gc.getPixelWriter();

        double k = (y2 - y1) / (x2 - x1);
        double b = (x1 * y2 - x2 * y1) / (x1 - x2);

        int val;
        for (int x = (int) x1; x <= (int) x2; x++) {
            val = (int) (k * x + b);
            for (int y = (int) (val - (lineWidth-1) / 2); y < val + lineWidth / 2; y++) {
                pw.setColor(x, y, color);
            }
        }

    }


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

It works, but it's so complex. You will need to create a lot of methods for different shapes. The best solution is cleaning and drawing again with changes.

gearquicker
  • 571
  • 4
  • 18