How the ST_Within Geometry Checker works, and what it assumes

ST_Within(A, B) is true when no point of A lies outside B and at least one point of A's interior lies in B's interior. The tool computes the DE-9IM intersection matrix of the two geometries, which records, for the interior, boundary and exterior of each, whether they meet and in what dimension, and reads the answer from it with the pattern PostGIS documents, T*F**F***. The matrix is shown with the verdict, so the answer can be checked rather than trusted.

The second condition is the one that surprises people. A geometry lying entirely on B's boundary, such as a point on the edge of a polygon or a line running along it, is not within B, because its interior never enters B's interior. PostGIS offers ST_CoveredBy for the case where boundary points should count; its answer here is "within is false, touches is true".

Coordinates are compared as they are written, as PostGIS does for the geometry type, so the check works equally for longitude and latitude and for projected metres. The two inputs must be in the same system: if both carry an EWKT SRID and they differ, the check is refused. Z values are ignored, because the relationship is two-dimensional. The calculation runs in your browser on JSTS, an open-source port of the geometry engine family PostGIS uses.

Where this comes up in GIS work

  • Checking which administrative area, sales territory or flood zone a site falls in before writing the query that does it for thousands of rows.
  • Working out why a point-in-polygon query leaves out points that sit exactly on a boundary.
  • Testing that a parcel drawn by hand really lies inside the plot it belongs to.
  • Explaining the difference between ST_Within and ST_CoveredBy with a case in front of you.

A worked example

A small square inside a larger one:

A: POLYGON ((2 2, 5 2, 5 5, 2 5, 2 2))
B: POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))

ST_Within(A, B) = true
DE-9IM matrix: 2FF1FF212

Now test the bottom edge of the large square itself, LINESTRING (0 0, 10 0), against it. Every point of the line is on B's boundary, so the matrix is F1FF0F212: the first cell, interior against interior, is F. ST_Within is false and ST_Touches is true, which is exactly what PostGIS returns.

Using the ST_Within Geometry Checker

  1. Paste the geometry you are testing into Geometry A, as WKT, EWKT or GeoJSON, or select Load example.
  2. Paste the containing geometry into Geometry B. Swap A and B reverses the question.
  3. Select Check ST_Within, or press Ctrl + Enter (Cmd + Enter on a Mac).
  4. Read the TRUE or FALSE verdict and the sentence under it that explains why.
  5. Check the DE-9IM matrix and the plot, or copy the text result.

When the output looks wrong

A point on the edge of the polygon is not within it
That is the definition, not a fault. ST_Within needs the interiors to meet, and a point on the boundary touches the polygon without entering it. If boundary points should count, the PostGIS function you want is ST_CoveredBy, whose answer is shown here as the combination of within being false and touches being true.
ST_Within is false but the plot shows A inside B
Zoom in on the boundary with the pointer readout: a vertex of A sitting a fraction outside B, or on it, is enough. The matrix says which: a value other than F in the Interior of A / Exterior of B cell means part of A really is outside.
Geometry A has SRID 4326 and geometry B has SRID 27700
The two inputs are in different coordinate systems, so comparing their numbers means nothing and the check is refused, as PostGIS refuses it. Transform one into the other's system with the ST_Transform tool first.
Relationships of invalid geometries are not reliable
One of the polygons crosses itself or has a hole outside its shell. The answer is still shown, but an invalid polygon has no well-defined inside, so run it through the Geometry Validator and fix it before trusting the result.

Questions about the ST_Within Geometry Checker

What does ST_Within return?

True when every point of A lies inside B or on its boundary and the interiors of A and B share at least one point. In DE-9IM terms it matches the pattern T*F**F***. ST_Within(A, B) always gives the same answer as ST_Contains(B, A).

What is the difference between ST_Within and ST_CoveredBy?

Boundary points. A geometry lying entirely on the boundary of B, such as a point on its edge or a line along it, is covered by B but not within it, because its interior never enters B's interior. For point-in-polygon work where edge points should count, ST_CoveredBy is usually the better choice.

Does it work with longitude and latitude?

Yes. The relationship is computed on the coordinates as given, exactly as PostGIS does for the geometry type, so it works for degrees and for projected units alike. Only edges long enough to curve noticeably on the earth, hundreds of kilometres, could make a geography-type answer differ.

Can I test a FeatureCollection?

Yes. A FeatureCollection of points is compared as one MultiPoint, of lines as one MultiLineString, and of polygons as their union. The tool tells you when it has done this, because it changes what "within" is being asked of.

Is my geometry uploaded?

No. The calculation runs in your browser with JSTS, an open-source JavaScript port of the geometry engine family PostGIS uses. Nothing you paste is sent to our server.