【问题标题】:Why does the resulting shape from Shape.intersect appear at an incorrect position?为什么 Shape.intersect 生成的形状出现在不正确的位置?
【发布时间】:2017-10-16 16:40:09
【问题描述】:

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

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

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

如您所见,圆 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,但我不确定我对该点的近似值是否只是舍入太多,因为它仍未正确对齐:

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

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

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

【问题讨论】:

  • 我尝试重现您的问题,但 it worked fine 和我一起。我看到您有一个菜单栏和一个状态栏,可能是因为您的交叉点绑定到一组不包含这两个元素之一的坐标吗?也许如果您共享绑定或调整形状大小的代码,修复起来会更容易?
  • 感谢您的回复。我将看看是否可以为我的问题制作一个非常简洁的示例,因为我的代码现在又长又乱,按原样上传会适得其反。今天完成工作后,我将在几个小时内更新。我怀疑问题出在我正在使用的画布对象的大小调整上,所以是的,我同意这对分享肯定很重要。

标签: javafx javafx-8 shape intersection


【解决方案1】:

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

// 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 的类中,该类扩展了 Pane。

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

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

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

这会更新圆圈的布局位置以及添加到 CanvasPane 的任何其他对象(不仅仅是我最初的画布),从而使生成的交叉部分实际上位于正确的位置。

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

【讨论】:

    猜你喜欢
    • 2015-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多