Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

STIntersection result is STIntersects = 0

I have line @a that intersects another line @b. When I take the intersection point and detect if/where it intersects @b, it returns 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)
like image 433
CuriousDeveloper Avatar asked Dec 28 '18 22:12

CuriousDeveloper


2 Answers

It boils down to general approach that you should use when dealing with floating-point numbers in calculations. You should not use equality comparison with floating point numbers, like if a == b, but always compare them with some epsilon precision that makes sense in your application domain, like if abs(a-b) < 1e-8.

It is conceptually similar to performing some non-trivial calculations, for example:

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

and then expecting that if a == 2.0 would return true instead of writing if abs(a-2.0) < 1e-8.


Geometry point in SQL Server is represented as floating point numbers, which are not exact.

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

calculates intersection point to the best of its precision, but it will never be exact.

So, expression like @b.STIntersects(@intersectionPoint) is conceptually equivalent to equality comparison. It is equivalent to if @b.STDistance(@intersectionPoint) == 0, which will be true only in few special cases.

You should use something like @b.STDistance(@intersectionPoint) < 1e-8 instead.

like image 131
Vladimir Baranov Avatar answered Nov 02 '22 01:11

Vladimir Baranov


This appears to be a rounding error. If I add the following to your code:

SELECT @b.STDistance(@intersectionPoint);

I get ≈ 3 femtometers. Which unless you're measuring something at the atomic scale is probably good enough to be considered as "on the line".

Out of curiosity, what problem are you actually trying to solve?

like image 4
Ben Thul Avatar answered Nov 02 '22 00:11

Ben Thul