【问题标题】:Finding polygons in 2D area在 2D 区域中查找多边形
【发布时间】:2015-08-13 10:16:34
【问题描述】:

我有一个包含 X 个多边形的二维区域。我拥有的唯一信息是多边形的边缘。多边形是根据 Voronoi 图的 Fortunes 算法形成的。

我正在尝试在 java 中形成一个多边形列表。我的问题在于找出属于多边形的边缘。我应该补充一点,我在每个多边形内也有一个点,这就是 Voronoi 图的形成。

我尝试了多种方法。我已经尝试计算到每个边缘的最近点,但这会产生错误。我也尝试过对角线扫描,试图以某种方式找出边缘,但也没有用。

编辑:

每条边都是一条线,它有一个 x1、y1、x2 和 y2。我有一个边列表,我有一个可用点列表,我可以绘制 Voronoi 图。我想要的输出是对于每个点,我都有一个边列表,这些边构成了该点所在的多边形的形状。

http://www.cs.wustl.edu/~pless/546/lectures/f16_voronoi.jpg

这是我目前所拥有的示例。我之所以能制作这张图片,是因为我知道每条线的起点和终点。我对多边形一无所知。我的目标是创建一个形状列表,以便我可以选择要绘制的形状。

编辑 5:

这是我设置的测试点。我正在寻找基于它们的 voronoi 图。我有分隔构成 voronoi 基础的点的线。我现在需要用这些线制作多边形。

vals = new double[2][6];
    vals[0][0] = 150;
    vals[1][0] = 250;
    vals[0][1] = 250;
    vals[1][1] = 275;
    vals[0][2] = 300;
    vals[1][2] = 300;
    vals[0][3] = 425;
    vals[1][3] = 425;
    vals[0][4] = 425;
    vals[1][4] = 125;
    vals[0][5] = 250;
    vals[1][5] = 500;

答案中提供的点和代码产生以下内容:

【问题讨论】:

  • 目前你的问题听起来不是很清楚。如果您为您的任务提供示例输入和所需的输出,并解释提供的输入数据为什么简单的算法在那里不起作用,那就太好了。
  • 如果给定了边,则解决方案非常先进:只需搜索属于彼此/有一个共同端点的边。除此之外,这个问题没有提供足够的信息来明确确切问题是什么
  • 你有例子吗?
  • 直到有人想出更好的答案,取每一行,并制作一棵树,将行的终点与另一行的起点连接起来。任何具有 3 条或更多线的树都是多边形。消除重复的多边形,并保存它们。
  • @GilbertLeBlanc 不会有可能得到包含多个点的多边形吗?

标签: java algorithm polygons


【解决方案1】:

关于 Voronoi 图的一些观察(使用 good ole Wikipedia 作为参考):

  1. 我们将多边形内部的内部点称为“种子”。
  2. 每个多边形都有一个种子,多边形本身代表所有点的集合,这些点比任何其他种子更接近其种子。
  3. 图表边界上的边段仅最接近一个种子。
  4. 图表内部的边缘段(不是图表边界上的边缘段)由与两个种子距离相同的段形成。
  5. 图表边界上的多边形顶点是与两个或多个种子的距离相同的点。一个可能的例外是边界的四个角点之一,尽管理论上这些角点也可以与多个种子等距。
  6. 图表内的多边形顶点(即不在边界上的顶点)是与三个或更多种子距离相同的点。

所以我建议的方法是循环遍历边缘段的集合,比较每个边缘段的端点与种子的距离并定位最近的种子。

以下没有优化,但应该满足要求,除非我误解了它们。 List<SeedPoint> seeds 将具有种子点本身以及围绕它的边缘。

顺便说一句,我是 ignoring precision / decimal rounding issues,这可能会影响逻辑。

// Get the list of edges and seeds from wherever you are getting them.
List<GraphEdge> edges = ...
List<SeedPoint> seeds = ...    // Assume SeedPoint is a subclass of Point.

for ( GraphEdge edge : edges )
{
  List<SeedPoint> closestSeeds = new ArrayList<>(2);

  // These can safely be instantiated to the diagram's hypotenuse + 1
  double closestStartDistance = ...
  double closestEndDistance = ...

  // Compare the distance of all seeds to the current edge's endpoints:
  for( SeedPoint seed : seeds )
  {
    double startEdgeToSeed = seed.distanceFrom( edge.getStartPoint() );
    double endEdgeToSeed   = seed.distanceFrom( edge.getEndPoint() );

    /* For a seed to be tracked as closest to the edge, BOTH the edge
       end points must be as close or closer to the seed than the
       current known closest edge.

       CAUTION: Update this to consider decimal precision issues! */

    if ( startEdgeToSeed == closestStartDistance &&
         endEdgeToSeed   == closestEndDistance )
    {
      // Same closeness to the currently known closest seed.
      closestSeeds.add(seed);
    }
    else if ( startEdgeToSeed <= closestStartDistance &&
              endEdgeToSeed   <= closestEndDistance )
    {
      /* Current seed is closer than the currently known closest seed.
         Clear previous seeds and track the current. */
      closestSeeds.clear();
      closestSeeds.add( seed );
      closestStartDistance = startEdgeToSeed;
      closestEndDistance   = endEdgeToSeed;
    }

  }

  /* At the end of the iteration, closestSeeds should have size
     of either 1 or 2.  Associate the edge to the seed or seeds
     to which it is closest. */
  for ( SeedPoint closestSeed : closestSeeds )
  {
    closestSeed.addPolygonEdge( edge );
  }

}

为方便起见,您可能需要一种方法,将两点作为参数并计算它们之间的距离。在上面的代码中,这就是somePoint.distanceFrom(someOtherPoint)

可能还有其他更好的方法,并且可能有优化上面示例的方法...

【讨论】:

    【解决方案2】:

    我最终想出了一个解决方案,它还不是 100% 有效,但大多数时候它确实有效。有一个奇怪的错误导致一两行错位,我仍在努力。代码几乎占用每一行,当它到达一个顶点时,它会向右移动,从而在起点或边界点着陆。一旦确定了多边形的种类,border 函数就会将所有缺失的边界放置在多边形中。之后我的计划是去掉重复的多边形,因为它们是多余的,并且会减慢方法的速度。

    private void constructPolygons() {
        listRoots = new ArrayList<>();
        int poly = 0;
        for (GraphEdge edge : edges) {
    
            List<GraphEdge> prevEdges = new ArrayList<>();
    
            prevEdges.add(edge);
    
            int count = 0;
    
            Point forward = edge.getEnd();
            Point reverse = edge.getStart();
    
            GraphEdge currentForward = edge;
            GraphEdge currentReverse = edge;
    
            List<GraphEdge> tempArray = new ArrayList<>();
            tempArray.add(edge);
    
            System.out.println("#############################################");
            System.out.printf("### Line %d is the start #####################\n", poly);
            System.out.println("#############################################");
    
            for (int ii = 0; ii < edges.size(); ii++) {
    
                GraphEdge compEdge = edges.get(ii);
    
                System.out.println("line: " + ii);
    
                System.out.println("forward: " + forward.xCord + " " + forward.yCord);
                System.out.println("reverse: " + reverse.xCord + " " + reverse.yCord);
    
                System.out.println("compEdge: " + compEdge.getStart().xCord + " " + compEdge.getStart().yCord + " " + compEdge.getEnd().xCord + " " + compEdge.getEnd().yCord);
    
                System.out.println("tempArray size: " + tempArray.size());
    
                // Check to see whether polygon is closed. If true, break and continue with other points.
                if( ((Math.abs(forward.xCord - reverse.xCord) <= tolerance) && (Math.abs(forward.yCord - forward.yCord) <= tolerance)) ) {
                    System.out.println("POLYGON MUST CLOSE");
                    break;
                }
    
                // Check to see whether point is on one of the borders
                if( (((Math.abs(forward.xCord - mapMaxX) <= tolerance) || (Math.abs(forward.yCord - mapMaxY) <= tolerance)) ||
                        ((Math.abs(forward.xCord - mapMinX) <= tolerance) || (Math.abs(forward.yCord - mapMinY) <= tolerance))) &&  (tempArray.size() > 1) ) {
                    System.out.println("POLYGON MUST CLOSE");
                    break;
                }
                // Check to see if edge has already been used
                if (!tempArray.contains(compEdge)) {
    
                    double compStartX = compEdge.getStart().xCord;
                    double compStartY = compEdge.getStart().yCord;
                    double compEndX = compEdge.getEnd().xCord;
                    double compEndY = compEdge.getEnd().yCord;
    
                    if( ((Math.abs(forward.xCord - mapMinX) <= tolerance || Math.abs(forward.xCord - mapMaxX) <= tolerance) || (Math.abs(forward.yCord - mapMinY) <= tolerance || Math.abs(forward.yCord - mapMaxY) <= tolerance)) && (tempArray.size() <= 1)){
                        System.out.println(tempArray.size() < 1);
                        System.out.println("Swap values around");
                        Point temp = forward;
                        forward = reverse;
                        reverse = temp;
                    }
    
                    // If end of currentForward == start of compEdge
                    // Start -- End --> Start -- End
                    if ((Math.abs(forward.xCord - compStartX) <= tolerance) && (Math.abs(forward.yCord - compStartY) <= tolerance)) {
                        System.out.println("end -> start");
    
                        double sign1 = isPointLeft( currentForward.x1, currentForward.y1, forward.xCord, forward.yCord, compEndX, compEndY );
                        double sign2 = isPointLeft( currentForward.x2, currentForward.y2, forward.xCord, forward.yCord, compEndX, compEndY );
                        System.out.println("sign: " + sign1);
                        System.out.println("sign: " + sign2);
    
                        // End point must be on the right side of the line
                        if (sign1 > 0 || sign2 > 0) {
                            ii = -1;
                            forward = compEdge.getEnd();
                            currentForward = compEdge;
                            tempArray.add(compEdge);
                            System.out.println("added: " + compEdge.getStart().xCord + " " + compEdge.getStart().yCord + " " + compEdge.getEnd().xCord + " " + compEdge.getEnd().yCord);
                        }
                    }
                    // If end of currentForward == end of compEdge
                    // Start -- End --> End -- Start
                    else if ((Math.abs(forward.xCord - compEndX) <= tolerance) && (Math.abs(forward.yCord - compEndY) <= tolerance)) {
                        System.out.println("end -> end");
    
                        double sign1 = isPointLeft( currentForward.x1, currentForward.y1, forward.xCord, forward.yCord, compStartX, compStartY );
                        double sign2 = isPointLeft( currentForward.x2, currentForward.y2, forward.xCord, forward.yCord, compStartX, compStartY );
                        System.out.println("sign: " + sign1);
                        System.out.println("sign: " + sign2);
    
                        // Start point must be on the right side of the line
                        if (sign1 > 0 || sign2 > 0) {
                            ii = -1;
                            forward = compEdge.getStart();
                            currentForward = compEdge;
                            tempArray.add(compEdge);
                            System.out.println("added: " + compEdge.getStart().xCord + " " + compEdge.getStart().yCord + " " + compEdge.getEnd().xCord + " " + compEdge.getEnd().yCord);
                        }
                    }
                } else {
                    System.out.println("already in list");
                }
                count++;
                prevEdges.add(compEdge);
                System.out.println("------------------------------------------");
    
            }
            if (tempArray.size() > 1) {
                listRoots.add(tempArray);
                poly++;
            }
        }
    
            for (List<GraphEdge> list : listRoots) {
            boolean point1 = false, point2 = false;
    
            Point bp1 = new Point(), bp2 = new Point();
    
             //            System.out.println("---------------------------------");
    
            for (GraphEdge ge : list) {
    
            //                System.out.println("Points: " + ge.x1 + "," + ge.y1 + "," + ge.x2 + "," + ge.y2);
    
                if (ge.x1 == mapMinX || ge.x1 == mapMaxX || ge.y1 == mapMinY || ge.y1 == mapMaxY) {
    
                    if (point1) {
                        point2 = true;
                        bp2.setPoint(ge.x1, ge.y1);
                    } else {
                        point1 = true;
                        bp1.setPoint(ge.x1, ge.y1);
                    }
    
                } else if (ge.x2 == mapMinX || ge.x2 == mapMaxX || ge.y2 == mapMinY || ge.y2 == mapMaxY) {
    
                    if (point1) {
                        point2 = true;
                        bp2.setPoint(ge.x2, ge.y2);
                    } else {
                        point1 = true;
                        bp1.setPoint(ge.x2, ge.y2);
                    }
                }
            }
    
            if (point1 && point2) {
            //                System.out.println("Add border");
                System.out.println(bp1.xCord + "," + bp1.yCord + "," + bp2.xCord + "," + bp2.yCord);
                insertBorderLine(bp1, bp2, list);
            }
        }
    
    
    }
    

    【讨论】:

      猜你喜欢
      • 2014-10-09
      • 2016-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-01
      相关资源
      最近更新 更多