STPointOnSurface: Choose a Point Inside a Polygon

I use STPointOnSurface when I need an interior point rather than a particular coordinate formula. The returned point is arbitrary. I’d validate its relationship to the polygon instead of expecting one fixed location from every implementation.

A ring cake with white icing and one cherry on top, on a white plate beside a knife.
Water channels around separate herb beds: a point must land in a bed, not a channel.

Keep the hole in the source

The first polygon has an outer square and a smaller square hole. The second has no hole. The third is an empty polygon. Each source uses the same planar SRID, so the membership checks compare compatible values.

A hole is excluded from the polygon’s interior. A representative point must therefore be in the remaining region, not just somewhere inside the outer ring. I keep the original Shape available beside the generated point. That makes the required membership relationship explicit.

WITH Inputs AS
(
 SELECT CaseId, Shape
 FROM (VALUES
  (1,geometry::STGeomFromText('POLYGON((0 0,6 0,6 6,0 6,0 0),(2 2,2 4,4 4,4 2,2 2))',0)),
  (2,geometry::STGeomFromText('POLYGON((0 0,4 0,4 4,0 4,0 0))',0)),
  (3,geometry::STGeomFromText('POLYGON EMPTY',0))
 ) v(CaseId,Shape)
), Chosen AS
(
 SELECT CaseId, Shape, Shape.STPointOnSurface() AS InteriorPoint FROM Inputs
)
SELECT CaseId, Shape.STIsEmpty() AS SourceIsEmpty,
       CAST(InteriorPoint.STGeometryType() AS nvarchar(40)) AS ChosenType,
       Shape.STContains(InteriorPoint) AS SourceContainsChosen,
       CAST(CASE WHEN InteriorPoint IS NULL THEN 1 ELSE 0 END AS bit) AS ChosenIsNull
FROM Chosen
ORDER BY CaseId;
Native SSMS result grids for point selection, empty input, including all returned rows and columns.
The nonempty polygons return a Point contained by their source. Empty input returns no point, with ChosenIsNull = 1. Open the result at full size.

Validate the point’s relationship

For each nonempty polygon, the expected chosen type is Point. SourceContainsChosen is true, and ChosenIsNull is false. Those properties capture the useful contract without guessing a specific x or y value.

The measured polygon excludes the central square. STPointOnSurface returned the marked coordinate in this execution. The marker is enlarged for readability, and the method does not guarantee this particular coordinate.
The measured polygon excludes the central square. STPointOnSurface returned the marked coordinate in this execution. The marker is enlarged for readability, and the method does not guarantee this particular coordinate. Open the diagram at full size.

I’d avoid storing an analytically invented coordinate in an expected-result table. The returned point is arbitrary, so one valid point doesn’t define every possible result. A consumer needing repeatable placement must establish that requirement separately. Interior membership alone doesn’t promise a preferred label position.

Read the empty case separately

The empty polygon expects a NULL chosen value. There is no Point type or membership result to report for that missing selection. ChosenIsNull makes the state visible without replacing it with an origin point.

Zero, zero is a real coordinate, not a universal missing-value marker. Substituting it could accidentally place a feature somewhere meaningful. I’d handle an empty region as a separate presentation state. The lack of a selected point is part of the result contract.

Avoid inferring a central location

The method name doesn’t guarantee the visually central point or a business-specific meeting location. Its purpose here is to return an interior point. Those are different requirements, especially for irregular shapes and polygons with excluded holes.

I’d explain the chosen property before using it in an application. A valid interior point can still be unsuitable for a label near an obstruction. Placement rules may include clearance, visibility or another constraint. This read-only example doesn’t invent those additional policies.

Keep the returned value available

The derived point remains a geometry value in the Chosen CTE. The output projects only properties needed for the check. A later application could keep the geometry itself instead of reducing it to a text coordinate immediately.

I’d preserve the spatial type while making further compatible comparisons. Formatting a point for display is a separate step. Losing that type can make a later consumer guess coordinate order or reference system. The small property table should explain behavior, not replace the underlying spatial contract.

Review complete states during validation

The three rows are explicitly ordered by CaseId. The query creates no objects and changes no data. Every returned column belongs to the expected comparison, including NULL membership in the empty case.

I’d test actual application inputs separately before relying on this selection. A valid sample doesn’t prove a production source is valid or uses the intended SRID. Keep source validation, point selection and business placement as distinct decisions. Each stage needs evidence for its own requirement.

Check that the point is inside the region, and treat an empty shape as no point at all.

An interior point is not a central point, it is any location inside the region.

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
Previous Post
Finding the Right System View for the Question You Have
Next Post
OR in a JOIN: Preserve Matching Pairs When Rewriting

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.