geometry STContains: Check Boundary Membership

geometry STContains and STIntersects can differ for a point on a polygon boundary. I include that boundary case before deciding which predicate matches an application meaning of inside.

A slotted wooden ballot box sits beside plain paper cards on a veranda near a small courtyard table.
A slotted wooden ballot box beside plain paper cards on a veranda.

A familiar word can hide a boundary rule

A user can say a point is inside a region while intending its edge to count too. Another rule can require a point strictly in the interior. Those meanings need an explicit predicate contract. A method name alone doesn’t settle the application wording.

STContains and STIntersects both return a bit for two geometry instances. They ask different spatial questions. This example compares both against one square. Its result specification keeps the boundary outcomes separate from the interior case.

I’d discuss the edge rule before writing a filter that assigns points to regions. Shared boundaries can also make assignments overlap when inclusion is permitted on each side. This four-point demonstration doesn’t implement a unique-region assignment policy. It only exposes the predicate distinction.

Compare interior, edge, corner and exterior

The polygon is a two-by-two square beginning at the origin. Its test points lie at the center, on the left edge, at the origin corner and outside to the right. All instances use spatial reference identifier zero.

The interior point is expected to produce true for both relationships. The edge and corner produce false for STContains but true for STIntersects. The exterior point produces false for both. Each case label remains beside the selected coordinates and results.

The square contains the interior point. Its edge and corner intersect the square without belonging to its interior; the exterior point is outside.
The square contains the interior point. Its edge and corner intersect the square without belonging to its interior; the exterior point is outside. Open the diagram at full size.

X and Y are displayed as decimal(12,3). The relationship columns retain their native bit type. Those explicit types keep the output contract small and complete. A missing coordinate isn’t introduced as a substitute for an exterior point.

WITH PolygonInput AS
(
    SELECT geometry::STGeomFromText(
        N'POLYGON((0 0, 2 0, 2 2, 0 2, 0 0))', 0) AS Region
), Points AS
(
    SELECT Id, CAST(CaseLabel AS varchar(20)) AS CaseLabel,
           geometry::STGeomFromText(PointText, 0) AS TestPoint
    FROM (VALUES (1, 'Interior', N'POINT(1 1)'), (2, 'Edge', N'POINT(0 1)'),
                 (3, 'Corner', N'POINT(0 0)'), (4, 'Exterior', N'POINT(3 1)'))
        AS v(Id, CaseLabel, PointText)
)
SELECT p.Id, p.CaseLabel, CAST(p.TestPoint.STX AS decimal(12,3)) AS X,
       CAST(p.TestPoint.STY AS decimal(12,3)) AS Y,
       g.Region.STContains(p.TestPoint) AS ContainsPoint,
       g.Region.STIntersects(p.TestPoint) AS IntersectsPoint
FROM PolygonInput AS g
CROSS JOIN Points AS p
ORDER BY p.Id;
Native SSMS results show all four points. Contains excludes the edge and corner, while Intersects includes both boundary points.
Native SSMS results show all four points. Contains excludes the edge and corner, while Intersects includes both boundary points. Open the results at full size.

Choose the predicate from the intended rule

If this point-in-polygon contract includes the edge, STIntersects demonstrates that inclusion for these selected points. If it excludes the edge, the containment result demonstrates the other choice. Broader geometry-to-geometry questions need their own examples. Don’t generalize a point case into every shape relationship.

I can justify excluding boundary points from an interior measurement. A coverage or contact check can require them instead. State that choice in plain language beside the query. Otherwise a correct spatial result can still disappoint the consumer.

The source coordinates are exact small integers rather than noisy measurements. Real-world coordinate uncertainty can introduce another boundary policy. This script doesn’t invent a tolerance or move points across the edge. It compares the supplied locations as written.

Keep reference identity and proof scope visible

Two geometry instances with different spatial reference identifiers give NULL from these methods. This example keeps every identifier equal. It doesn’t change labels to pretend a coordinate transformation occurred. An actual transformation is another operation requiring a suitable contract.

The complete script reads a literal polygon and point list through CTEs. It creates no objects or session settings. ORDER BY fixes the four-case sequence. The original polygon text remains available in the copyable SQL.

Compare every full coordinate and bit tuple with its SQL types. Include both boundary cases as well as interior and exterior. Keep the containment and intersection flags beside each other. A successful center point alone wouldn’t establish the selected inclusion rule.

Say what inside means for your data, then pick the predicate.

Inside is not a complete boundary policy, it is wording that needs a precise spatial relationship.

Published by Pinal Dave on SQLAuthority. More of my work at pinaldave.com.


Discover more from SQL Authority with Pinal Dave

Subscribe to get the latest posts sent to your email.

SQL Datatype, SQL Function, SQL Scripts, SQL Server
Previous Post
Silent Truncation When Building Strings in nvarchar(max) Variables
Next Post
SQL SERVER – Fix : Error 1418 – Microsoft SQL Server – The server network address can not be reached

Related Posts