Ruby 关于RGeo交函数的问题

Ruby 关于RGeo交函数的问题,ruby,geometry,geospatial,rgeo,Ruby,Geometry,Geospatial,Rgeo,我从RGeo多边形相交函数(Ruby 2.3.0,RGeo 0.5.3)中得到奇怪/不正确的结果 例1: 我有两个多边形,我相信它们共享一个边界,但不共享任何内部空间(即它们不共享): 当我们检查它们之间的交点时,它会返回一条直线,这与仅共享边界的几何体的预期一样: poly_1.intersection poly_2 => #<RGeo::Geos::CAPILineStringImpl:0x3fc0249af168 "LINESTRING (-8224757.546680832

我从RGeo多边形相交函数(Ruby 2.3.0,RGeo 0.5.3)中得到奇怪/不正确的结果

例1: 我有两个多边形,我相信它们共享一个边界,但不共享任何内部空间(即它们不共享):

当我们检查它们之间的交点时,它会返回一条直线,这与仅共享边界的几何体的预期一样:

poly_1.intersection poly_2
=> #<RGeo::Geos::CAPILineStringImpl:0x3fc0249af168 "LINESTRING (-8224757.546680832 4960523.476563589, -8225598.074380083 4961210.51680879)">
例2: 我们选取两个合法重叠的多边形:

wkt_3 = "POLYGON ((-8243237.0 4970203.0, -8243237.0 4968735.0, -8242123.0 4968735.0, -8242123.0 4970203.0, -8243237.0 4970203.0))"
wkt_4 = "POLYGON ((-8244765.0 4966076.0, -8244765.0 4964608.0, -8243652.0 4964608.0, -8243652.0 4966076.0, -8242680.0 4969362.0, -8244765.0 4966076.0))"
poly_3 = RGeo::Geos.factory(:srid => 3857).parse_wkt(wkt_3)
poly_4 = RGeo::Geos.factory(:srid => 3857).parse_wkt(wkt_4)

并计算两个方向上的差异:

diff_a = poly_3.difference poly_4
=> #<RGeo::Geos::CAPIPolygonImpl:0x3fe3fca26028 "POLYGON ((-8243077.837796713 4968735.0, -8243237.0 4968735.0, -8243237.0 4970203.0, -8242123.0 4970203.0, -8242123.0 4968735.0, -8242865.466828971 4968735.0, -8242680.0 4969362.0, -8243077.837796713 4968735.0))">
diff_b = poly_4.difference poly_3
=> #<RGeo::Geos::CAPIPolygonImpl:0x3fe3fd1dda28 "POLYGON ((-8242865.466828971 4968735.0, -8243652.0 4966076.0, -8243652.0 4964608.0, -8244765.0 4964608.0, -8244765.0 4966076.0, -8243077.837796713 4968735.0, -8242865.466828971 4968735.0))">
这很好

diff_a.touches? poly_4
=> false
diff_a.overlaps? poly_4
=> true
这是不可能的-从另一个多边形减去的多边形的剩余部分不可能与该多边形重叠

为什么它只发生在一个方向上

例3: 这种奇怪的情况还在继续。现在让我们得到poly_3和poly_4的交点

intersection_a = poly_3.intersection poly_4
=> #<RGeo::Geos::CAPIPolygonImpl:0x3fd1084ece88 "POLYGON ((-8242865.724520766 4968734.582337743, -8243078.32501591 4968734.582337743, -8242680.062418439 4969362.301390027, -8242865.724520766 4968734.582337743))">
intersection_a=poly_3.intersection poly_4
=> #
既然这是应该从poly_3中减去的,从而得到diff_a,那么diff_a应该以与poly_4(减法器)相交的完全相同的方式与交集_a相交

除非它没有:

diff_a.touches? poly_4
=> false
diff_a.touches? intersection_a
=> true
diff_a.intersection poly_4
=> #<RGeo::Geos::CAPILineStringImpl:0x3fe3f98fb854 "LINESTRING (-8242680.0 4969362.0, -8243077.837796713 4968735.0)">
diff_a.intersection intersection_a
=> #<RGeo::Geos::CAPIMultiLineStringImpl:0x3fe3fca157b4 "MULTILINESTRING ((-8242865.466828971 4968735.0, -8242680.0 4969362.0), (-8242680.0 4969362.0, -8243077.837796713 4968735.0))">
diff_a.touch?聚铀4
=>错误
不同的触摸?交叉口
=>正确
差分a.相交多边形4
=> #
不同的交叉点交叉点
=> #

更糟糕的是,这两个相交结果都没有意义。它应该是一条2段的单直线,这两条直线都不是。

在第一个示例中,您为两个多边形提供了一些浮点数。是什么让你认为它们相互接触而不重叠?你怎么知道?在一般情况下,不能用绝对值(不使用公差)表示两条线段是否完全重叠。您可以提供具有舍入坐标的线,在这种情况下,可以为相同的线创建参数

浮点数的使用是实数空间离散化的一种形式。当使用不同的算法或方法计算相同的结果时,这会导致结果不一致。例如,考虑2D空间中的三条线的交集,使得它们应该在同一点相交。现在,独立地计算交点,每次使用不同的线对计算三次。每次你都可能得到相似但不相等的答案

我没有使用RGeo,但是在计算交叉点几何图形时,有没有调整公差的方法?尝试减小公差值(使该阈值更小)。这将允许函数计算几何体,而无需合并彼此太近的点。

简短回答 不幸的是,当使用浮点坐标时,您不能期望从
接触?
重叠?
获得可靠和正确的输出

它不依赖于RGeo或GEOS版本(或者GEOS所基于的项目)

如果需要关于两个多边形位置的信息,可以使用并检查它是否小于给定的ε

它比
触摸?
重叠?
更可靠,但也不能保证适用于所有示例


这是精度问题吗? 理论
接触?
根据定义是非常敏感的:多边形必须在其边界上共享一个点或一条线,但不应具有任何公共内部点

  • 如果它们彼此距离太远,则它们没有任何共同点,
    touch?
    为false
  • 如果它们太近,则它们的交点为多边形,
    接触?
    为假
敏感性分析 它到底有多敏感

我们考虑两个多边形,一个在另一个上面:

我们可以移动上多边形的下边界一个ε,看看它有什么影响:

require 'rgeo'

epsilon = 1E-15

deltas = [-epsilon, 0, epsilon]

deltas.each do |delta|
  puts "--------------------------------"
  puts "Delta : #{delta}\n\n"
  simple1 = 'POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))'
  simple2 = "POLYGON((0 #{1+delta}, 0 2, 1 2, 1 #{1+delta}, 0 #{1+delta}))"

  puts "Polygon #1 : #{simple1}\n"
  puts "Polygon #2 : #{simple2}\n\n"

  poly_1 = RGeo::Geos.factory(:srid => 4326).parse_wkt(simple1)
  poly_2 = RGeo::Geos.factory(:srid => 4326).parse_wkt(simple2)

  puts "Intersection : #{poly_1.intersection poly_2}"
  puts

  puts "Distance between polygons :"
  puts format('%.30f°', poly_1.distance(poly_2))
  puts

  puts "Overlaps? : #{poly_1.overlaps? poly_2}"
  puts "Touches? : #{poly_1.touches? poly_2}"
end
它输出:

--------------------------------
Delta : -1.0e-15

Polygon #1 : POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))
Polygon #2 : POLYGON((0 0.999999999999999, 0 2, 1 2, 1 0.999999999999999, 0 0.999999999999999))

Intersection : POLYGON ((0.0 0.999999999999999, 0.0 1.0, 1.0 1.0, 1.0 0.999999999999999, 0.0 0.999999999999999))

Distance between polygons :
0.000000000000000000000000000000°

Overlaps? : true
Touches? : false
--------------------------------
Delta : 0

Polygon #1 : POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))
Polygon #2 : POLYGON((0 1, 0 2, 1 2, 1 1, 0 1))

Intersection : LINESTRING (0.0 1.0, 1.0 1.0)

Distance between polygons :
0.000000000000000000000000000000°

Overlaps? : false
Touches? : true
--------------------------------
Delta : 1.0e-15

Polygon #1 : POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))
Polygon #2 : POLYGON((0 1.000000000000001, 0 2, 1 2, 1 1.000000000000001, 0 1.000000000000001))

Intersection : GEOMETRYCOLLECTION EMPTY

Distance between polygons :
0.000000000000001110223024625157°

Overlaps? : false
Touches? : false
Intersection : LINESTRING (-8224757.546680832 4960523.476563589, -8225598.074380083 4961210.51680879)
Overlaps?    : true
Intersects?  : true
Touches?     : false

212
101
212
这些是表现良好的多边形,具有

  • 平行于轴线的边
  • 同样大小
  • 整个长度上的共用边
1E-15
一个程度(大约)就足以完全改变结果,并且
重叠?
接触?
之间切换

交叉点为空、直线或多边形,但至少在
交叉点
重叠?
接触?
之间,结果似乎是一致的

在您的例子中,具有更复杂的倾斜边的多边形会使问题更加困难。当计算两段的交点时,很难保持1-Ångström的精度

这是RGeo的问题吗? 使用,它是.< /p>的C++端口 为了检查问题是否不是特定于RGeo或GEOS,我计算了 JTS 1.14的示例1:

WKTReader wktReader = new WKTReader();
String wkt1 = "POLYGON ((-8226874.27782158 4962626.76394919, -8223358.174520462 4961756.817075645, -8223358.174520462 4960289.557693501, -8224471.369428394 4960289.557693501, -8226874.27782158 4962253.674727506, -8226874.27782158 4962626.76394919))";
String wkt2 = "POLYGON ((-8224757.546680832 4960523.476563589, -8225269.1002275925 4959296.105368667, -8226993.791361805 4959219.668340384, -8226420.900079966 4961883.087589158, -8224757.546680832 4960523.476563589))";
Polygon poly1 = (Polygon) wktReader.read(wkt1);
Polygon poly2 = (Polygon) wktReader.read(wkt2);
System.out.println("Intersection : " + poly1.intersection(poly2));
System.out.println("Overlaps?    : " + poly1.overlaps(poly2));
System.out.println("Intersects?  : " + poly1.intersects(poly2));
System.out.println("Touches?     : " + poly1.touches(poly2));
showMatrixWith(poly1, poly2);
它输出:

--------------------------------
Delta : -1.0e-15

Polygon #1 : POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))
Polygon #2 : POLYGON((0 0.999999999999999, 0 2, 1 2, 1 0.999999999999999, 0 0.999999999999999))

Intersection : POLYGON ((0.0 0.999999999999999, 0.0 1.0, 1.0 1.0, 1.0 0.999999999999999, 0.0 0.999999999999999))

Distance between polygons :
0.000000000000000000000000000000°

Overlaps? : true
Touches? : false
--------------------------------
Delta : 0

Polygon #1 : POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))
Polygon #2 : POLYGON((0 1, 0 2, 1 2, 1 1, 0 1))

Intersection : LINESTRING (0.0 1.0, 1.0 1.0)

Distance between polygons :
0.000000000000000000000000000000°

Overlaps? : false
Touches? : true
--------------------------------
Delta : 1.0e-15

Polygon #1 : POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))
Polygon #2 : POLYGON((0 1.000000000000001, 0 2, 1 2, 1 1.000000000000001, 0 1.000000000000001))

Intersection : GEOMETRYCOLLECTION EMPTY

Distance between polygons :
0.000000000000001110223024625157°

Overlaps? : false
Touches? : false
Intersection : LINESTRING (-8224757.546680832 4960523.476563589, -8225598.074380083 4961210.51680879)
Overlaps?    : true
Intersects?  : true
Touches?     : false

212
101
212
交叉点与示例中的完全相同,
交叉?
接触?
输出与RGeo相同的错误结果

为什么结果不一致? 为什么
交叉点
接触?
返回不一致的结果

DE-9IM
接触?
相交?
重叠?
和其他谓词都是从中派生出来的。它是一个矩阵,描述几何体内部、边界和外部之间的交集尺寸

该矩阵在GEOS中src/operation/relate/RelateComputer.cpp的第72行计算:

IntersectionMatrix* RelateComputer::computeIM()
void OverlayOp::computeOverlay(OverlayOp::OpCode opCode)
算法似乎是正确的,但在您的任何示例中都不是这样

我能找到的所有JTS测试都使用整数坐标,甚至是一个称为“复杂多边形接触”的测试:

代码中的注释似乎表明不需要精确点头,并且有多个if语句来检查结果是否正确

这种方法似乎比RelateComputer::computeIM更健壮

使用GeometryPrecisionReducer? 使用
GeometryPrecisionReducer
精密模型<
IntersectionMatrix* RelateComputer::computeIM()
  # line 477 in jts-1.14/testxml/general/TestFunctionAA.xml
  <desc>mAmA - complex polygons touching</desc>
  <a>
    MULTIPOLYGON(
      (
        (100 200, 100 180, 120 180, 120 200, 100 200)),
      (
        (60 240, 60 140, 220 140, 220 160, 160 160, 160 180, 200 180, 200 200, 160 200,
        160 220, 220 220, 220 240, 60 240),
        (80 220, 80 160, 140 160, 140 220, 80 220)),
      (
        (280 220, 240 180, 260 160, 300 200, 280 220)))
  </a>
  <b>
    MULTIPOLYGON(
      (
        (80 220, 80 160, 140 160, 140 220, 80 220),
        (100 200, 100 180, 120 180, 120 200, 100 200)),
      (
        (220 240, 220 220, 160 220, 160 200, 220 200, 220 180, 160 180, 160 160, 220 160,
        220 140, 320 140, 320 240, 220 240),
        (240 220, 240 160, 300 160, 300 220, 240 220)))
  </b>
void OverlayOp::computeOverlay(OverlayOp::OpCode opCode)