在JavaFX中绘制两个区域的交集

时间:2016-11-28 12:51:31

标签: java canvas javafx

我有一些限制类型的ax + by> = c(1)和x> = z和y> = k(2)。限制(1)和(2)构成一个区域。我需要找到这些区域的交集并填充其他颜色。我怎么能在JavaFX中做到这一点?我可以使用Canvas来解决这个问题吗?

Example

1 个答案:

答案 0 :(得分:0)

当然,只需使用多边形颜色填充所有内容,然后为每个区域填充不在具有背景颜色的区域中的所有内容。

请注意,这样就可以填充整个Canvas,但背景颜色的多边形除外。

public class Area {

    private final double x;
    private final double y;

    private final double threshold;
    private final int minCorner;

    public Area(double x, double y, double threshold, boolean greater) {
        if (x == 0 && y == 0) {
            throw new IllegalArgumentException();
        }

        if (greater) {
            x *= -1;
            y *= -1;
            threshold *= -1;
        }
        this.x = x;
        this.y = y;
        this.threshold = threshold;
        boolean yPos = y > 0;

        // find corner with minimum result for evaluate
        this.minCorner = x < 0 ? (yPos ? 1 : 2) : (yPos ? 0 : 3);  
    }

    public Area(double x, double y, double threshold) {
        this(x, y, threshold, false);
    }

    private static final int[][] CORNER_FACTORS = {
        {0, 0},
        {1, 0},
        {1, 1},
        {0, 1}
    };

    public boolean contains(double x, double y) {
        return evaluate(x, y) <= threshold;
    }

    public double hLineIntersection(double y) {
        if (x == 0) {
            return this.y * y == threshold ? Double.POSITIVE_INFINITY : Double.NaN;
        } else {
            return (threshold - this.y * y) / this.x;
        }
    }

    public double vLineIntersection(double x) {
        if (y == 0) {
            return this.x * x == threshold ? Double.POSITIVE_INFINITY : Double.NaN;
        } else {
            return (threshold - this.x * x) / this.y;
        }
    }

    private double evaluate(double x, double y) {
        return this.x * x + this.y * y;
    }

    public void fillCleanArea(GraphicsContext gc, double w, double h) {
        double[] xcoords = new double[5];
        double[] ycoords = new double[5];

        int[] factors = CORNER_FACTORS[minCorner];
        boolean inside = contains(factors[0] * w, factors[1] * h);
        int ptIndex = 0;

        for (int i = minCorner, max = minCorner + 4; i < max; i++) {
            factors = CORNER_FACTORS[i % 4];
            double x = factors[0] * w;
            double y = factors[1] * h;
            boolean nowInside = contains(x, y);
            if (inside != nowInside) {
                // add intersection point with side
                if ((i & 1) == 0) {
                    ycoords[ptIndex] = vLineIntersection(x);
                    xcoords[ptIndex++] = x;
                } else {
                    xcoords[ptIndex] = hLineIntersection(y);
                    ycoords[ptIndex++] = y;
                }

                inside = nowInside;

                // stop, if the end point is inside the area again
                if (inside) {
                    break;
                }
            }

            // add corners outside the bounds to polygon
            if (!inside) {
                xcoords[ptIndex] = x;
                ycoords[ptIndex++] = y;
            }
        }

        // draw polygon
        if (ptIndex > 0) {
            gc.fillPolygon(xcoords, ycoords, ptIndex);
        }
    }

}
public static void draw(Canvas canvas, Paint fill, Paint background, Area... areas) {
    GraphicsContext gc = canvas.getGraphicsContext2D();
    double w = canvas.getWidth();
    double h = canvas.getHeight();

    // fill everything with polygon color
    gc.setFill(fill);
    gc.fillRect(0, 0, w, h);

    // fill everything outside the polygon with background color
    gc.setFill(background);
    for (Area area : areas) {
        area.fillCleanArea(gc, w, h);
    }
}

@Override
public void start(Stage primaryStage) {
    Canvas canvas = new Canvas(400, 400);

    draw(canvas, Color.BLUE, Color.WHITE, 
            new Area(1, 1, 400), new Area(1, -1, 100), new Area(1, -1, -100, true), new Area(1, 2, 250, true));

    StackPane root = new StackPane(canvas);

    Scene scene = new Scene(root);

    primaryStage.setScene(scene);
    primaryStage.show();
}

虽然这不会给你多边形的角点......