【问题标题】:STIntersection result is STIntersects = 0STIntersection 结果为 STIntersects = 0
【发布时间】:2019-05-26 15:52:49
【问题描述】:

我有一条线 @a 与另一条线 @b 相交。当我取交点并检测它是否/与@b相交时,它返回false

declare @a GEOMETRY = Geometry::STGeomFromText('LINESTRING (-83 24, -80.4907132243685 24.788632986627039)', 4326)
declare @b GEOMETRY = Geometry::STGeomFromText('LINESTRING (-74.7 21.8, -75.7 22.1, -77.8 22.6, -79.4 23.3, -80.4 24.5, -81.5 28, -84 33, -87 36)', 4326)


DECLARE @intersectionPoint geometry = @a.STIntersection(@b) -- POINT (-80.49071322436852 24.788632986627078)

IF @intersectionPoint IS NULL
    THROW 50000, '@intersectionPoint not found', 1


-- Expect 1, Result 0
SELECT @b.STIntersects(@intersectionPoint)

【问题讨论】:

    标签: sql sql-server floating-point geometry geography


    【解决方案1】:

    归结为在计算中处理浮点数时应使用的一般方法。您不应该对浮点数使用相等比较,例如 if a == b,而应始终将它们与在您的应用程序域中有意义的某个 epsilon 精度进行比较,例如 if abs(a-b) < 1e-8

    它在概念上类似于执行一些非平凡的计算,例如:

    double a = 2.0;
    a = sqrt(a);
    a = a*a;
    

    然后期望 if a == 2.0 会返回 true 而不是写 if abs(a-2.0) < 1e-8


    SQL Server 中的几何点表示为浮点数,不精确。

    DECLARE @intersectionPoint geometry = @a.STIntersection(@b)
    

    以最佳精度计算交点,但永远不会精确。

    因此,@b.STIntersects(@intersectionPoint) 这样的表达式在概念上等同于相等比较。等价于if @b.STDistance(@intersectionPoint) == 0,仅在少数特殊情况下为真。

    您应该改用 @b.STDistance(@intersectionPoint) < 1e-8 之类的东西。

    【讨论】:

      【解决方案2】:

      这似乎是一个舍入错误。如果我将以下内容添加到您的代码中:

      SELECT @b.STDistance(@intersectionPoint);
      

      我得到 ≈ 3 飞米。除非您在原子尺度上测量某些东西,否则这可能足以被视为“在线”。

      出于好奇,您实际上想解决什么问题?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-04-03
        • 2018-03-07
        • 1970-01-01
        • 2013-09-09
        • 2013-02-18
        • 2015-07-25
        • 1970-01-01
        相关资源
        最近更新 更多