为什么Shape.intersect产生的形状出现在错误的位置?

时间:2017-01-29 22:41:02

标签: javafx javafx-8 shape intersection

对于我目前的一个javafx项目,我正在与Venn Diagrams合作。我想利用Shape.intersect来减轻我必须亲自完成的数学计算量(并避免使用Path对象)。 Shape.intersect产生一个完美的形状,但它被翻译/移动了一点,我无法弄清楚要多少钱。理想情况下,我希望交叉区域恰好出现在两个原始形状相交的位置 - 即新交叉点与原始形状无缝匹配。

目前,我的代码会生成一个三维维恩图,可以随窗口缩放。我可以访问圆圈的3个中心点以及其他重要交叉点的粗略近似值。这些其他点是近似的,因为它们依赖于sin和cos值来确保所有三个圆都是相同的大小并且是对称的。

我模拟了下面的图像(点/字母在外部添加了油漆,但底层图像是我的应用程序现在生成的图像)​​: enter image description here

如您所见,圆圈A和B(以蓝色显示)的交点不在标记处。

为了产生这个,我的代码将底层画布缩放到窗口大小,计算放置圆心的位置,然后绘制具有相同半径的所有3。切掉所有额外的绒毛,我的代码基本上是这样的:

// Constructor creates 3 circles and adds to canvas
Circle a = new Circle();
canvas.getChildren().add(a);
// etc. for the other two circles

// And also makes a Shape object to hold the intersection
Shape ab = Shape.intersect(a,b); // initially empty
canvas.getChildren().add(ab);

稍后......

// Resizing the window calls an update function
// which recalculates the circles' centers and 
// radii and then updates them. Since circles are
// drawn from upper left corner, the relocate call 
// makes sure to subtract the radius to center it
a.setRadius(radius);
a.relocate(acx-radius,acy-radius);

交叉逻辑(也在更新函数中):

canvas.getChildren().remove(ab);
ab = Shape.intersect(a,b);

// Can relocate to point c, but this doesn't do the job either (see below)
ab.relocate(pcx,pcy);

// Add the new intersection back to the canvas
canvas.getChildren().add(ab);

我尝试将生成的交叉点形状重新定位到C点,但我不确定我对该点的近似是否过于圆滑,因为它仍未正确对齐:

enter image description here

我猜这个偏移可能与布局边界/视觉边界有关,或者在调整大小时被改变并且从未正确更新的东西,但我花了很长时间查看文档并且无法弄明白

理想情况下,我想避免必须手动计算C点,因为圆圈本身是通过近似/舍入生成的,这使得C几乎不可能精确计算。我希望有人可以指出一个只能使用原始圆圈的解决方案,但是无论当前画布的大小如何,我都会采取任何使交叉点出现在正确位置的方法。

总结:如何使Shape.intersect返回的形状出现在它创建的两个形状的中心?谢谢你的时间。

1 个答案:

答案 0 :(得分:0)

我设法解决了这个问题。我正在使用一个自动调整大小的画布对象,该对象受到我在StackOverflow上找到的this post的启发。如果链接发生变化,我从那里借来的代码的关键位如下所示:

// Update function when the window is resized
@Override
protected void layoutChildren() {
    final double top = snappedTopInset();
    final double right = snappedRightInset();
    final double bottom = snappedBottomInset();
    final double left = snappedLeftInset();

    width = getWidth() - left - right;
    height = getHeight() - top - bottom;

    // Update the layout
    canvas.setLayoutX(left);
    canvas.setLayoutY(top);

    if (width != canvas.getWidth() || height != canvas.getHeight()) {
        // Resize
        canvas.setWidth(width);
        canvas.setHeight(height);

        // Determine center
        cx = width / 2;
        cy = height / 2;

        // Determine radius of circles
        radius = 0.25 * Math.min(width, height);

        // Clear and redraw circles
        clear();
        redraw();
    }
}

其中"画布"是一个Canvas对象的私有实例,整个函数都在一个名为CanvasPane的类中,它扩展了Pane。

我发现了什么 当您还将诸如Circles之类的对象添加到CanvasPane的children()时,上面的代码会出现问题。我的redraw()方法只移动了圆的中心并调整了半径。 我从未更新.setLayoutX()和.setLayoutY()函数,就像我为实际圆圈的实际画布对象所做的那样。因此,调整CanvasPane的大小会不一致地更新布局信息和所有圈子。基础布局位置将不同步。

因此,此处的修复方法是将“更新布局”部分更改为以下内容:

// Update the layout
for (Node n : getChildren()) {
    n.setLayoutX(left);
    n.setLayoutY(top);
}

这会更新圆圈的布局位置以及添加到CanvasPane的任何其他对象(不仅仅是我原来的画布),使得到的交叉点实际上位于正确的位置。

事后来说,我绝对应该在原始问题中加入更多代码,以便其他人可以提供帮助。希望有一天某人会遇到与我相同的问题,并能够找到答案。