Результатом STIntersection является STIntersects = 0 - PullRequest
0 голосов
/ 29 декабря 2018

У меня есть линия @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)

Ответы [ 2 ]

0 голосов
/ 17 января 2019

Это сводится к общему подходу, который вы должны использовать при работе с числами с плавающей точкой в ​​вычислениях.Не следует использовать сравнение на равенство с числами с плавающей запятой, например if a == b, но всегда сравнивайте их с некоторой точностью эпсилона, которая имеет смысл в вашей прикладной области, например if abs(a-b) < 1e-8.

Это концептуально аналогично выполнению некоторыхнетривиальные вычисления, например:

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

и последующее ожидание, что if a == 2.0 вернет истину вместо записи 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.

0 голосов
/ 31 декабря 2018

Это похоже на ошибку округления.Если я добавлю в ваш код следующее:

SELECT @b.STDistance(@intersectionPoint);

, я получу ≈ 3 фемтометра.Что, если вы не измеряете что-то в атомном масштабе, вероятно, достаточно хорошо, чтобы считаться «на линии».

Из любопытства, какую проблему вы на самом деле пытаетесь решить?

...