You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用JavaFX原生方法判断坐标是否处于闭合Path图形内部?

解决JavaFX中检测坐标是否在闭合Path内部的问题

你遇到的问题其实是对JavaFX中几个方法的使用方式理解有误,原生JavaFX完全可以实现你想要的功能,不需要依赖JTS库。下面给你分析问题并给出具体解决方案:

问题根源分析

你测试的几个方法本身是有效的,但你用错了姿势:

  • Node.contains():这个方法需要传入相对于当前Node的本地坐标,且判断的是坐标是否在Node的填充区域内(默认pickOnBounds为false,基于实际形状而非边界框)。你之前直接传入pane的坐标,虽然这个例子里Path和pane位置重合,但如果Path有偏移就会出错;另外你误以为它只检测边缘,大概率是测试时的坐标转换或填充设置问题。
  • Node.intersects():这个方法默认检测的是Node的边界框,确实不符合你的需求,不用考虑。
  • Shape.intersect():你之前只是打印了方法返回值,但没判断返回的Shape是否有效——当点在Path内部时,相交结果会是一个有实际几何形状的Shape,边界框不为空;如果在外部,返回的是一个空Shape,边界框为空。

正确的解决方案

方案1:正确使用Path.contains()

确保传入Path的本地坐标,并且Path有填充(默认就有,除非你手动设置fill=null)。修改鼠标事件代码如下:

pane.setOnMouseMoved(event -> {
    // 将场景坐标转换为Path的本地坐标
    Point2D localPoint = path.sceneToLocal(event.getSceneX(), event.getSceneY());
    boolean isInside = path.contains(localPoint.getX(), localPoint.getY());
    System.out.println("Contains? " + isInside);
});

这样当鼠标在三角形内部时,isInside会返回true,而不仅仅是边缘。

方案2:使用Shape.intersect()并判断结果

如果更倾向于用形状相交的逻辑,可以检查相交后的Shape是否有有效边界:

pane.setOnMouseMoved(event -> {
    Circle point = new Circle(event.getX(), event.getY(), 1);
    Shape intersection = Shape.intersect(path, point);
    boolean isInside = !intersection.getBoundsInLocal().isEmpty();
    System.out.println("Is inside? " + isInside);
});

原理很简单:点在Path内部时,相交结果就是这个小Circle,边界框不为空;点在外部时,相交结果是一个空Shape,边界框为空。

完整测试代码

修改后的完整可运行代码如下:

public class ShapeContainsTest extends Application {
    public static void main(String[] args) {
        Application.launch(ShapeContainsTest.class);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        Path path = new Path();
        path.getElements().add(new MoveTo(100, 100));
        path.getElements().add(new LineTo(200, 100));
        path.getElements().add(new LineTo(150, 200));
        path.getElements().add(new ClosePath());
        // 显式设置填充,确保contains方法基于填充区域判断(默认已有,这里是明确化)
        path.setFill(Color.BLACK);

        Pane pane = new Pane(path);
        pane.setPrefSize(300, 300);

        pane.setOnMouseMoved(event -> {
            // 方案1:Path.contains()
            Point2D localPoint = path.sceneToLocal(event.getSceneX(), event.getSceneY());
            boolean contains = path.contains(localPoint.getX(), localPoint.getY());
            System.out.println("Contains (local)? " + contains);

            // 方案2:Shape.intersect()
            Circle point = new Circle(event.getX(), event.getY(), 1);
            Shape intersection = Shape.intersect(path, point);
            boolean isInside = !intersection.getBoundsInLocal().isEmpty();
            System.out.println("Is inside (intersect)? " + isInside);
        });

        primaryStage.setScene(new Scene(pane));
        primaryStage.show();
    }
}

额外说明

  • 如果你的Path有复杂的填充规则(比如奇偶规则、非零环绕规则),可以通过path.setFillRule(FillRule)设置,默认是FillRule.NON_ZERO,适合大多数闭合图形。
  • 避免使用com.sun.javafx包下的内部API,这些API可能在JavaFX版本更新中被修改或移除,稳定性无法保证。

内容的提问来源于stack exchange,提问作者Adam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 21:48:11