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

JTS Polygon.intersects()返回false但多边形实际相切问题排查

问题:JTS库intersects()无法检测多边形相切的问题

我尝试使用JTS库的.intersects()方法判断两个多边形是否相邻相切,视觉上两个多边形明显相切,但该方法却返回false。以下是测试代码(仅用于测试,实际代码会重构):

String testCoords1 = "M149.9 373.5l-3-3.4-9.4-7.2-5-2-0.7-7.6-1.1-4.1-1.7-3.6-3.3-1.7-2.8-2.3-3.8-3.8-4.2-2.8 5-6.3 6.7-0.7 3.3 2.3 3.8 0.6 2.8-1.6 2.4-2.9 0.4-4.3-2-3.9 7.8-6.5 0.2-10 3.8-7.6 2.5 1 2 2.4 8 5.3 7.7 2.2 8-3.4 7.3-1.6 6.2 5.7 6 0.4 5.7-4-2 5.7-3.3 6.2-8.6 19-3 13.3 2.4 4.7 6.8 16.5 8.4 14.9 5 4.8 1.6 7.2-4 4.1-4.5-2-6.7 1.1-4.3-2.9 1.8-7.1-3.2-6-1.1-3.7 0-2.6-6.5-1.4-3 6.3-4 6.2-5.7-1.4-5.7-4.5-13-7z";
String testCoords2 = "M114.9 335l4.2 2.8 3.8 3.8 2.8 2.3 3.3 1.7 1.7 3.6 1.1 4.1 0.7 7.6 5 2 9.4 7.2 3 3.4-5.4 8.2-3.6 9.7 1.7 9.4-2.1 3.2-0.7 3.9-4.4 0.6-4.2-2.3-4.8-0.8-4.6-4-2 5.9-2.7 0.4-3-2-8.6-2.9-3.6 1-9.6 0.8-6.4 5.3-4.4 0.8-3.7-2.3-2.7-4.6-3.5-3.5-3.6-2.2-2.5-4.1-3.3-4.1-2.5-3.8 0.5-6.9-2.8-4.2-4.7 1.4-2.7-3.2-0.6-4.5-2.8-2.9-3-5.2-2.1-6.2-4.9-2.6-6 0.6-7.8-1.2-6.4 0.5 1.2-7.6-1.1-3 4.1-7.9 2.2-2.1 0-2.6-2.4-1.9-2.2-3.3-3.8-9.2-0.3-1.7 1.5-2.3 1.4-1.3 4.1-2.1 1.7-1.5 2.4-3.8 1.5-1.3 5 0.4 2-1.9 2.2-1.5 4.3-0.6 12 3.3 4.9-1.2 4.8-2.1 2-2.6 4.4 4 2.7 4.3 0.9 2.7 1.4 2 1.5-0.2 1.2 1.1 2.6-0.5 2.2-3.9 2.3 1.3-1 6.9 3.2 2.2 3.9-2.4 3.1 3.8 2.7 5.4 4.9 0 1.7 2.9 3 0.7 4.8-0.7 3.1 5 2.4 6.5z";

GeometryFactory geometryFactory = new GeometryFactory();
ArrayList<Coordinate> coordinatesShape1 = calcGeo(testCoords1);
ArrayList<Coordinate> coordinatesShape2 = calcGeo(testCoords2);

Polygon poly1 = geometryFactory.createPolygon(coordinatesShape1.toArray(new Coordinate[] {}));
boolean valid = poly1.isValid();
System.out.println(valid);

Polygon poly2 = geometryFactory.createPolygon(coordinatesShape2.toArray(new Coordinate[] {}));
boolean valid2 = poly2.isValid();
System.out.println(valid2);

boolean intersects = poly1.intersects(poly2);
System.out.println(intersects);

以下是用于提取坐标并保存到ArrayList的calcGeo()方法(同样会重构):

private ArrayList<Coordinate> calcGeo(String coords)
{
    Pattern p = Pattern.compile("\\([mzlhvcsqta]|[\\+\\-]?(\\d*\\.\\d+|\\d+\\.?)([eE][\\+\\-]?\\d+)*");
    Matcher m = p.matcher(coords);
    double X = 0;
    double Y = 0;
    int index = 0;
    ArrayList<Coordinate> points = new ArrayList<>();

    while(m.find()) {
        //System.out.println(m.group());
        switch (index)
        {
            case 0: X = Double.parseDouble(m.group()); break;
            case 1: Y = Double.parseDouble(m.group()); break;
        }
        if (index % 2 == 0 && index != 0)
        {
            double calcX = X + Double.parseDouble(m.group());
            //System.out.println(calcX);
            X = calcX;
        }else if(index % 2 == 1 && index != 1)
        {
            double calcY = Y + Double.parseDouble(m.group());
            //System.out.println(calcY);
            Y = calcY;
        }
        if (index % 2 == 1)
        {
            points.add(new Coordinate(X, Y)); //Add the coords to the list every second time so both X and Y are calculated.
        }
        index++;
    }
    points.add(points.get(0));  //After all the points are mapped complete the polygon by adding the first pair of coords to the end of the list.
    return points;
}

我将包含SVG坐标的字符串传入calcGeo方法提取坐标,保存为ArrayList后构建Polygon对象,验证多边形有效性后调用intersects()方法,结果返回false,但视觉上两个多边形明显相切。

请问:

  1. 使用intersects()判断多边形是否相邻相切是否正确?
  2. 若正确,该如何修复此问题?若不正确,正确的检测方法是什么?

解答

核心结论

JTS的intersects()方法本身支持检测相切(两个几何体有公共点但内部不相交),问题出在坐标解析逻辑错误和浮点数精度误差上。

问题排查与修复步骤

1. 修复坐标解析逻辑的错误

你的calcGeo()方法手动解析SVG路径时存在两处关键问题:

  • 正则表达式错误:\\([mzlhvcsqta]多余了括号,SVG指令是直接跟在坐标前(如l-3-3.4),这个正则无法正确匹配指令字符,导致坐标计算逻辑混乱。
  • 相对坐标处理逻辑错误:SVG的l指令是相对当前点的增量,但你的代码仅靠索引判断坐标类型,没有正确识别指令,容易导致坐标计算偏差。

修复方案:

方案一:使用成熟库解析SVG路径

避免手动解析的错误,直接用batik库或JTS兼容的格式转换工具提取坐标,比如将SVG路径转为WKT格式后用WKTReader解析。

方案二:修正手动解析逻辑

// 修正正则:匹配SVG指令(大小写字母)和合法数字
Pattern p = Pattern.compile("[mzlhvcsqtaMZLHVCSQTA]|[\\+\\-]?(\\d*\\.\\d+|\\d+\\.?)([eE][\\+\\-]?\\d+)*");

同时要先识别指令类型(M是绝对坐标,l是相对坐标),再对应处理后续的坐标对,而不是单纯依赖索引判断。

2. 处理浮点数精度误差

JTS的几何计算依赖精确的坐标匹配,浮点数的微小精度偏差会导致看似相切的点实际不重合,从而intersects()返回false。

解决方案:

方案一:坐标精度化简

使用GeometryPrecisionReducer将坐标统一到指定精度(比如保留1位小数):

// 创建精度模型,保留1位小数(坐标值乘以10取整后再除以10)
PrecisionModel pm = new PrecisionModel(10);
GeometryFactory precisionFactory = new GeometryFactory(pm);

// 生成精度统一后的多边形
Polygon poly1Precise = (Polygon) precisionFactory.createPolygon(coordinatesShape1.toArray(new Coordinate[]{}));
Polygon poly2Precise = (Polygon) precisionFactory.createPolygon(coordinatesShape2.toArray(new Coordinate[]{}));

// 重新判断相交
boolean intersects = poly1Precise.intersects(poly2Precise);

方案二:用DE-9IM矩阵精确判断相切

相切的两个多边形的DE-9IM矩阵会匹配F***T****(有公共边界点但内部不相交),可以用relate()方法检测:

// 检测是否相切
boolean isTangent = poly1.relate(poly2).matches("F***T****");

3. 修复多边形有效性

即使isValid()返回true,部分存在微小自相交的多边形也会影响计算,可通过buffer(0)修复:

Polygon poly1Fixed = (Polygon) poly1.buffer(0);
Polygon poly2Fixed = (Polygon) poly2.buffer(0);

总结

  • intersects()可以检测相切,但需要坐标准确且处理好精度问题;
  • 优先修复坐标解析逻辑,推荐用成熟库解析SVG路径;
  • 浮点数精度处理是关键,精度化简或DE-9IM矩阵判断更可靠。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 20:48:20