You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

关于使用JTS生成包含全部原始点的简化外凸包的问题咨询

关于使用JTS生成包含全部原始点的简化外凸包的问题咨询

嘿,我来帮你拆解一下你遇到的问题,以及怎么实现你想要的效果~

先解决你的第一个困惑:为什么convexHull()的结果看起来不像凸包?

JTS的convexHull()方法绝对是会返回严格凸包的,你觉得“不像”大概率是这两个原因:

  • 你的原始点集里有大量点本来就落在凸包的边上,convexHull()只是把这些内部点过滤掉了,剩下的就是凸包的顶点。如果这些顶点在可视化时因为渲染精度或者点的密度问题看起来“不凸”,可以用几何对象的isConvex()方法验证一下,它会直接告诉你是不是严格凸的。
  • 有可能你在可视化时没正确处理返回的几何对象?比如convexHull()返回的是Polygon或者LinearRing,如果渲染时没正确闭合或者样式有问题,也会产生视觉错觉。

再解决核心困惑:为什么hullByAreaDelta()对外凸包调参数没变化?

这是你对这个方法的逻辑理解错啦!PolygonHullSimplifier.hullByAreaDelta()对外凸包的简化逻辑有个关键限制:它必须保持凸性,同时不能丢失任何原始凸包的顶点。而凸包本身已经是“最紧凑”的凸形状了——你没法在保持凸性且包含所有原始凸包顶点的前提下,通过允许面积变大来减少顶点数。因为凸包的每个顶点都是“极端点”,去掉任何一个都会导致凸包不再包含那个顶点对应的原始点,或者直接破坏凸性。

你说对内凸包时有变化,这完全合理,因为内凸包可以通过向内部收缩来简化,而外凸包根本没有这个操作空间。

那怎么实现你要的效果:包含所有原始点、顶点更少、允许面积比原凸包大的“简化外凸包”?

你想要的其实不是“简化凸包”,而是包含所有原始点的、近似凸的简化多边形,同时允许它比原凸包大一点来减少顶点数。这里给你两个可行的方案:

方案1:先缓冲再简化(最稳妥,保证包含所有点)

这个思路是先把凸包放大一点,再用道格拉斯-普克法简化,既保证包含所有原始点,又能减少顶点数:

  1. 先计算原始点集的严格凸包
  2. 对凸包做向外的缓冲(缓冲距离根据你能接受的面积增大比例调整)
  3. DouglasPeuckerSimplifier对缓冲后的多边形进行简化
  4. 可选:验证所有原始点都在简化后的多边形内(只要缓冲距离足够,这一步基本可以省略)

代码示例大概是这样:

// 1. 计算原始点集的凸包
Geometry convexHull = pointCollection.convexHull();
// 2. 向外缓冲,距离根据你的单位和需求调整
Geometry bufferedHull = convexHull.buffer(0.5);
// 3. 道格拉斯-普克简化,容差同样根据需求调整
Geometry simplifiedHull = DouglasPeuckerSimplifier.simplify(bufferedHull, 1.0);
// 4. 可选:验证所有原始点都被包含
for (Coordinate coord : pointCollection.getCoordinates()) {
    if (!simplifiedHull.contains(new GeometryFactory().createPoint(coord))) {
        // 这里可以调整缓冲距离或简化容差
    }
}

方案2:自定义筛选极端点(更贴近凸包形状)

如果你想尽量保持凸性,也可以手动筛选原始点集中的“极端点”——比如只保留x最大/最小、y最大/最小的点,再加上几个斜向的极端点(比如x+y最大/最小、x-y最大/最小),用这些点生成的凸包顶点数很少,且肯定包含所有原始点。这个方法需要你根据自己的业务需求定义筛选规则。

关于DouglasPeuckerSimplifier的补充

你提到它不能保证包含所有原始点,这个是对的——它是通过抽稀顶点简化,可能会导致某个原始点落在简化后的多边形外。但先缓冲再简化就避开了这个问题:缓冲后的多边形已经比原凸包大,只要简化容差设置合理,就能确保所有原始点都被包含。

最后给你个小技巧:可以用JTS的isValid()isConvex()方法验证生成的几何对象,能帮你快速排查问题~

内容来源于stack exchange

火山引擎 最新活动