如何使用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
相关产品推荐
相关产品推荐

