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

Why does the resulting shape from Shape.intersect appear at an incorrect position?

对于我当前的一个 javafx 项目,我正在使用维恩图。我想利用 Shape.intersect 来减轻我必须亲自完成的数学计算量(并避免使用 Path 对象)。 Shape.intersect 产生了一个完美的形状,但它被平移/移动了一点,我不知道要放回去多少。理想情况下,我希望交叉区域恰好出现在两个原始形状相交的位置 - 即新交叉点将与原始形状无缝贴合。

目前,我的代码生成了一个与 window 成比例的三重维恩图。我可以访问圆的 3 个中心点以及其他重要交点的粗略近似值。这些其他点是近似值,因为它们依赖 sin 和 cos 值来确保所有三个圆的大小相同且对称。

我模拟了下图(points/letters 是在画图外部添加的,但底层图像是我的应用程序现在生成的):

如您所见,圆 A 和圆 B 的交点(以蓝色显示)偏离了标记。

为此,我的代码将基础 canvas 缩放到 window 大小,计算放置圆心的位置,然后绘制所有 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,但我不确定我对该点的近似值是否四舍五入太多,因为它仍然没有正确对齐:

我猜这个偏移量可能与布局边界/视觉边界或在调整大小时发生变化并且从未正确更新的东西有关,但我花了很长时间查看文档并且无法理解出来了。

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

的大小

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

我设法弄清楚了这个问题。我正在使用一个 auto-resizing canvas 对象,其灵感来自于我在 Whosebug 上找到的 。以防 link 发生变化,我从那里借用的关键代码如下所示:

// 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" 是 Canvas 对象的私有实例,并且整个函数位于一个名为 CanvasPane 的 class 中,它扩展了 Pane。

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

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

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

这会更新圆圈的布局位置以及添加到 Canvas 窗格的任何其他对象(不仅仅是我原来的 canvas),使生成的交叉部分实际上在右侧位置。

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