I am testing various SQL geography type methods - specifically, I want to understand the difference between STContains()
and STWithin()
.
According to the docs:
StWithin()
- Returns 1 if a geography instance is spatially within another geography instance;
STContains()
- Specifies whether the calling geography instance spatially contains the geography instance passed to the method.
I created a simple 1 km x 1 km POLYGON (a square actually) around Microsoft headquarters, visually, it looks like this:
The data points used were as follows:
Center point: 47.6423318, -122.1391189
Polygon (Square) corner points:
SE: 47.6378402235794, -122.13244353271
NE: 47.6468233764206, -122.13244353271
NW: 47.6468233764206, -122.14577646729
SW: 47.6378402235794, -122.14577646729
The POLYGON was declared (using the left-hand rule) as follows, and checked if valid:
DECLARE @bounds geography;
SET @bounds = geography::STPolyFromText('POLYGON((-122.13244353271 47.6378402235794, -122.13244353271 47.6468233764206, -122.14577646729 47.6468233764206, -122.14577646729 47.6378402235794, -122.13244353271 47.6378402235794))', 4326 );
SELECT @bounds.STIsValid() AS 'STIsValid', @bounds.STIsClosed() AS 'STIsClosed';
SQL Returns:
STIsValid STIsClosed
True True
Next, I check if the center point is within the bounds (should be), as follows
DECLARE @point geography;
SET @point = geography::Point( 47.6423318, -122.1391189, 4326 );
SELECT @bounds.STContains( @point) AS 'STContains',
@bounds.STIntersects( @point ) AS 'STIntersects',
@bounds.STOverlaps( @point ) AS 'STOverlaps',
@bounds.STWithin( @point ) AS 'STWithin';
SQL Returns:
STContains STIntersects STOverlaps STWithin
True True False False
Note: I was expecting STWithin
to be True
, but it turns out the center point is NOT "within" the bounds?
Next, I check if the SW corner point is considered "in" bounds, as follows:
SET @point = geography::Point( 47.6378402235794, -122.14577646729, 4326 );
SELECT @bounds.STContains( @point) AS 'STContains',
@bounds.STIntersects( @point ) AS 'STIntersects',
@bounds.STOverlaps( @point ) AS 'STOverlaps',
@bounds.STWithin( @point ) AS 'STWithin';
SQL Returns:
STContains STIntersects STOverlaps STWithin
False True False False
Note: In this case, STContains()
returns False
(which is expected), but STIntersects()
returns True
; useful if you need to consider the edge points as being "in" bounds or not.
Last test - a point OUTSIDE of the bounds:
SET @point = geography::Point( 47.647, -122.13244353271, 4326 );
SELECT @bounds.STContains( @point) AS 'STContains',
@bounds.STIntersects( @point ) AS 'STIntersects',
@bounds.STOverlaps( @point ) AS 'STOverlaps',
@bounds.STWithin( @point ) AS 'STWithin';
SQL Returns:
STContains STIntersects STOverlaps STWithin
False False False False
In all of the tests above, that is, testing for a point INSIDE the bounds, on the EDGE of the bounds, and OUTSIDE the bounds, STWithin()
returns False
- What condition is required for STWithin()
to return True
? (Or, does STWithin()
simply not work?)
Also, I was expecting STOverlaps()
to return true in some cases, but if someone can comment on that method, it would help as well.
Any advice would be appreciated.
What condition is required for STWithin() to return True? (Or, does STWithin() simply not work?)
STWithin, STContains : OGC standard methods, return 1 or 0, they indicate whether ALL the points of one instance exist entirely inside the other instance.
For your example, the point can exist within the polygon, but the polygon cannot exist within the point. Think of within as the "inverse" of contains: If x is within y then y contains x. --> If polygon contains point then point is within polygon:
SELECT
@bounds.STContains( @point) AS 'bounds contains point', --if this is true...
@point.STWithin( @bounds ) AS 'point is within bounds'; --...then this is also true
Also, I was expecting STOverlaps() to return true in some cases
This is a bit vague in the documentation (for geometry but it applies to geography too):
Remarks Two geometry instances overlap if the region representing their intersection has the same dimension as the instances do and the region does NOT equal either instance.
Point overlap with polygon --> the overlap is point (==equals either instance) --> 0.
You could test this by "cloning" the same spatial instance and check if it overlaps itself:
DECLARE @bounds geography;
SET @bounds = geography::STPolyFromText('POLYGON((-122.13244353271 47.6378402235794, -122.13244353271 47.6468233764206, -122.14577646729 47.6468233764206, -122.14577646729 47.6378402235794, -122.13244353271 47.6378402235794))', 4326 );
DECLARE @boundsclone geography=@bounds;
select @bounds.STOverlaps(@boundsclone), @boundsclone.STOverlaps(@bounds);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With