Fixing Invalid Geography Polygons and Ring Orientation

A polygon can look correct on a map and still fail geography validation or cover the wrong side of the earth. Invalid geography polygons need a shape check and an orientation check before anyone trusts their area.

Garden edging with the flowers outside the ring and bare soil inside

Invalid Geography Polygons Versus Wrong Hemispheres

Geography uses a curved surface and directed rings. A self-intersection or malformed ring can make a value invalid. A ring with the opposite orientation can describe the complement of the intended region, so a small area appears to cover almost the globe. I inspect both conditions. STIsValid and IsValidDetailed address structural validity. EnvelopeAngle helps flag shapes whose bounding cap is unexpectedly wide. Neither function knows which country or service area the business intended.

Keep the original WKT or source geometry before repair. A GIS import can also swap latitude and longitude or assign the wrong SRID. Those errors can produce valid geography values that sit in the wrong place. A successful validity check is not a map review.

List Invalid Geography Polygons in the Import

Run validation against a sample or the affected import table. The example uses a variable; replace it with your geography column in a real table. IsValidDetailed gives a reason and location for an invalid shape. Capture that detail before calling MakeValid, because the repaired object can differ from the input. I check the source identifier and SRID with each result so the data team can trace the file or API record. The sample triangle runs clockwise. It passes with "24400: Valid", yet EnvelopeAngle returns 180, the value for a shape larger than a hemisphere.

DECLARE @region geography =
    geography::STGeomFromText('POLYGON((-80 25,-80 26,-79 26,-80 25))', 4326);
SELECT @region.STSrid AS srid,
       @region.STIsValid() AS is_valid,
       @region.IsValidDetailed() AS validity_detail,
       @region.EnvelopeAngle() AS envelope_angle;

Repair, Then Compare

MakeValid returns a valid geography instance where it can repair an invalid one. It can change the type or split a problematic shape, so do not overwrite the original column in one mass update. Write repaired values to a staging column or table, then compare type, area, envelope, and representative points. I have seen a repair clear an error while changing the business meaning of the border. A syntactically valid answer can still be geographically wrong.

The example below uses a bow-tie ring that crosses itself, so this block declares its own variable. STIsValid returns 0 and IsValidDetailed reports error 24409. MakeValid turns it into a valid MultiPolygon with two parts.

DECLARE @bowtie geography =
    geography::STGeomFromText('POLYGON((-80 25,-79 26,-79 25,-80 26,-80 25))', 4326);
SELECT @bowtie.STIsValid() AS is_valid,
       @bowtie.MakeValid().STIsValid() AS repaired_is_valid,
       @bowtie.MakeValid().STGeometryType() AS repaired_type,
       @bowtie.MakeValid().STArea() AS repaired_area;

Check Ring Direction

If a polygon covers the complementary region, ReorientObject flips the orientation. Compare STArea and EnvelopeAngle before and after on a copy. A near-global area for a neighborhood boundary is a clear review flag, but use domain expectations instead of a universal threshold. A region crossing the date line or covering a large geographic area needs different interpretation. The result should be checked on a map with known points inside and outside the intended region. The block below declares the clockwise sample again so it runs on its own. The flipped version reports a small area and an EnvelopeAngle well under one degree.

DECLARE @region geography =
    geography::STGeomFromText('POLYGON((-80 25,-80 26,-79 26,-80 25))', 4326);
SELECT @region.STArea() AS original_area,
       @region.ReorientObject().STArea() AS flipped_area,
       @region.EnvelopeAngle() AS original_angle,
       @region.ReorientObject().EnvelopeAngle() AS flipped_angle;
From a raw ring to a reviewed region: a diagram about the invalid geography polygons

Test Points, Not Just Area

Choose a point known to be inside and one known to be outside. Use STIntersects for each candidate polygon and its repaired or reoriented version. If both points return the opposite result, the ring direction is the likely issue. If neither makes sense, inspect coordinates and SRID again. What does the business call "inside" for boundary points? Decide that before using the polygon for pricing or access rules.

I also compare shapes visually in a GIS tool after the SQL checks. The database can tell you whether a value is valid; a map and domain owner tell you whether it is the intended place. Keep screenshots or reference coordinates with the import validation record.

Watch for Coordinate and SRID Mistakes

Geography WKT uses longitude before latitude for coordinate pairs. An import that reverses them can place a polygon in a valid but completely different location. I check sample points against a trusted map and inspect the SRID before trying MakeValid. If the source uses another coordinate reference system, transform it before creating a geography value with SRID 4326. Simply labeling coordinates with a different SRID does not transform them. A validity check cannot identify that semantic mistake.

Keep the raw source coordinates and import version. If a corrected import changes orientation or projection, you need to know which stored rows came from which version. I tag each batch and stage its candidate geography separately. That makes rollback possible without trying to reverse-engineer a transformed polygon from its final binary value.

Treat Repair as a Reviewed Change

MakeValid can return a MultiPolygon or change boundaries around a self-intersection. ReorientObject changes which side of the ring is inside. Compare type, area, number of components, envelope, and known-point containment before accepting either output. I ask a domain owner to review shapes with large changes rather than applying one threshold to every geography. A small city polygon and a national territory have different expected areas and edge cases.

What happens to application queries after a repair? Recheck STIntersects, distance calculations, and spatial index behavior on representative requests. A shape that loads successfully can still change which customers fall inside a service area. Preserve the original value and approval record until the affected business process has been validated. I prefer a staging report that says "invalid," "valid but suspicious orientation," or "accepted" over one UPDATE that silently fixes every row in a batch.

A geography value that crosses the international date line can look strange in a simple bounding-box check. Test known points and a trusted map before labeling it inverted. I use EnvelopeAngle as a flag for review, not an automatic reversal rule. A domain expert should approve the corrected region when it affects service eligibility, tax, or routing.

Keep Invalid Geography Polygons Out of the Next Import

Validate SRID, coordinate range, STIsValid, EnvelopeAngle, and known-point tests in staging before moving shapes into the application table. Reject invalid geography polygons with a clear reason and keep the raw input for correction. Do not make MakeValid and ReorientObject automatic for every imported row; each can alter meaning. Apply them only under a rule agreed with the data owner.

I prefer a repeatable import report with counts of rejected, repaired, and manually reviewed shapes. The report should derive its counts from queries, not from a comforting guess. Spatial data deserves the same data-quality discipline as customer IDs, even if the mistakes look more colorful on a map.

Related reading on this blog: Validating Spatial Object with IsValidDetailed Function and Finding the Nearest Location With a Spatial Index.

What a passing validity check proves: a checklist on the invalid geography polygons

A closed ring is not a correct region, it is only the start of a geography check.

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

Spatial Database, SQL Datatype, SQL Server
Previous Post
SQL SERVER – Datetime Function TODATETIMEOFFSET Example
Next Post
Fast Exports With bcp

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.