【问题标题】:How to triangulate/tesselate some shape in Java?如何在 Java 中对某些形状进行三角剖分/镶嵌?
【发布时间】:2014-06-29 03:08:41
【问题描述】:

我想通过 GeoTools 细分国家形状,以便在地球表面以 3D 形式显示它。 GeoTools 使用 JTS 拓扑套件,内部看起来功能丰富。

它是否包含细分某些形状的实用程序?我看到有 triangulation 包,但不知道如何将它用于带孔的形状。

我也用它不仅像这里那样连接现有顶点

它应该用内部的多个顶点填充形状。

更新

我发现,JTS 包含 ConformingDelaunayTriangulationBuilder 类,它允许以某种方式制作所需的镶嵌,但效果不佳。首先,它只允许约束,这意味着需要额外的代码来从凹入区域中删除三角形。而且它还试图保留曲面细分的 Delaunay 特性,这会导致创建许多额外的部分。

最后它会导致ConstraintEnforcementException 用于复杂的形状,如国家和不可用。

我还发现了"triangle" package,它是用 C 语言编写的,实现了Chew's second algorithm 并且运行良好

现在我想知道,它是移植到 Java 还是封装到其中?

【问题讨论】:

  • 我绝不是一个足够熟练的程序员来为您提供解决方案,但也许您可以从边缘的顶点列表开始。然后,在形状内找到一个点并将最近的顶点连接到它。然后,在更远的地方找到一个点,然后重复。这样做直到每个顶点 A(连接的边数最少)或 B(点之间的距离永远不会超过 x 距离)。无论哪种方式,上面的朴素算法都只连接现有点;您所需的算法必须在现有点附近创建新点。
  • 想早点评论一下:创建一个“好的”三角测量真的具有挑战性。我使用来自 www3.math.tu-berlin.de/jtem/numericalMethodsRuppert 类取得了一些有希望的结果,但它不处理漏洞。我认为您提到的“三角形”包是 THE 三角测量解决方案(它真的很好)。但是 - 它以一种可怕的、可怕的“C”方式实现,甚至不能远程移植到 java(永远不会......可怕)。有一次我用 JNI 为这个库写了一个小包装器,但它还没有发布,可能还需要一些清理。
  • @Marco13 也许您应该尝试我的回答中建议的库:) 到目前为止对我来说效果很好......
  • @DarkCygnus 那里有一些 (java) 三角测量库 (see github),但从“按照维基百科的描述实现耳朵修剪”到 良好、健壮 具有 steiner 点、孔处理、角度约束等的库。您链接到的库至少看起来很重要,并且维护和测试了一段时间(尽管在测试之前我不会投票)。很遗憾,triangle lib 的创建者没有响应我为他的 lib 发布 Java 绑定的请求...
  • @Marco13 是的,试试看,到目前为止它对我来说效果很好。我在某个时候也考虑过 Triangle 库,但没有找到任何 Java 版本(现在我知道为什么了:/),并且还发现他们的许可证在计划商业化时有其限制。感谢您提供的其他链接,将检查它

标签: java mesh geotools tessellation jts


【解决方案1】:

我知道这篇文章比较老了,但我最近遇到了同样的情况,需要一些 Java 库或类似的工具来对一些复杂的多边形进行三角剖分(因为我想在 OpenGL 上显示它们,它只能将三角形绘制为原始操作) .

经过相当多的搜索和测试,对我有用的库是来自 Orbgis 的 Poly2Tri。您可以从 Maven here* 获取该库。

该库具有许多功能,包括带孔的多边形、用于优化三角剖分的 Steiner 点以及其他内容。一个基本的使用示例如下(基于链接仓库的示例):

//Create the polygon passing a List of PolygonPoints
Polygon polygon = new Polygon(
    Arrays.asList(
        new PolygonPoint(0, 0, 0),
        new PolygonPoint(10, 0, 1),
        new PolygonPoint(10, 10, 2),
        new PolygonPoint(0, 10, 3)));
//Here you could add holes as needed, passing them as Polygons
polygon.addHole(someHoleYouCreated);
//Next, proceed to calculate the triangulation of the polygon 
Poly2Tri.triangulate(polygon);
//Finally, obtain the resulting triangles
List<DelaunayTriangle> triangles = polygon.getTriangles();

编辑:不知道您是否已经尝试过,但 JTS Topology Suite 也有一个 DelaunayTriangulationBuilder 类(即没有 Conforming 部分)。它位于org.locationtech.jts.triangulate.DelaunayTriangulationBuilder,也许它比您尝试过但表现不佳的另一个效果更好。

*注意:注意不要改用this one,就像我一开始做的那样,发现它不是正确的依赖项(不是-core版本) em>

【讨论】:

  • 请注意,如果您需要在 3D 空间中对多边形进行三角剖分,此库将不起作用。虽然它的 PolygonPoint 类有一个 Z 坐标,但三角剖分代码只查看 X 和 Y,因此如果您有一个垂直多边形(例如一面墙),库会将其顶点视为共线并拒绝对其进行三角剖分。
【解决方案2】:

这是一种使用JTS的快速而肮脏的方法:

第一:

  • 使用 JTS DelaunayTriangulationBuilder 对几何进行三角测量
  • 准备一组站点,sites;从初始三角剖分复制到顶点位置

循环:

  • 迭代三角剖分的三角形几何,将三角形质心**添加到sites
  • 使用sites重新进行三角测量(现在由原始站点和新的质心站点组成)

最后:

  • 将三角剖分与原始几何相交以恢复其凹形外壳和任何孔

**对于这种肮脏的技术,我发现使用三角形 centroids 会比三角形 circumcenters 产生更好的结果,尽管后者往往用于更多正式的改进(ChewRuppert 等等..))。

代码

static Geometry refinedTriangulation(Geometry g, int nRefinements, double tolerance) {

    DelaunayTriangulationBuilder builder = new DelaunayTriangulationBuilder();
    builder.setSites(g); // set vertex sites
    builder.setTolerance(tolerance); // set tolerance for initial triangulation only

    Geometry triangulation = builder.getTriangles(geometryFactory); // initial triangulation

    HashSet<Coordinate> sites = new HashSet<>();
    for (int i = 0; i < triangulation.getCoordinates().length; i++) {
        sites.add(triangulation.getCoordinates()[i]);
    }

    for (int refinement = 0; refinement < nRefinements; refinement++) {
        for (int i = 0; i < triangulation.getNumGeometries(); i++) {
            Polygon triangle = (Polygon) triangulation.getGeometryN(i);

            if (triangle.getArea() > 50) { // skip small triangles
                sites.add(new Coordinate(triangle.getCentroid().getX(), triangle.getCentroid().getY()));
            }
        }
        builder = new DelaunayTriangulationBuilder();
        builder.setSites(sites);
        triangulation = builder.getTriangles(geometryFactory); // re-triangulate using new centroid sites
    }

    triangulation = triangulation.intersection(g); // restore concave hull and any holes
    return triangulation;
}

您可以使用triangle.getExteriorRing().getLength() &gt; Ntriangle.getArea() &gt; N 跳过细化已经很小的三角形。

示例

原始形状

JTS 三角剖分

带交叉点的 JTS 三角剖分

1 细化

3 项改进

【讨论】:

    猜你喜欢
    • 2020-08-12
    • 2020-04-21
    • 2011-07-15
    • 2021-06-02
    • 2021-11-23
    • 2016-09-28
    • 2015-07-23
    • 2012-09-06
    • 2016-09-27
    相关资源
    最近更新 更多