Search code examples
sql-serversqlgeographywkt

Using EnvelopeCenter on a Geography variable is not returning the correct value in SQL Server


I have an SQL query where I declare two Geography variables, and then I'm trying to find the center point of the polygons after values are assigned to those variables.

This is my code:

DECLARE @g1 GEOGRAPHY;
DECLARE @g2 GEOGRAPHY;

SET @g1 = geography::STGeomFromText('POLYGON((-90.06875038146973 35.512324341620996,-90.06767749786377 35.51504904492378,-90.06407260894775 35.51499664765537,-90.06381511688232 35.512219543493465,-90.06875038146973 35.512324341620996))',4326);
SET @g2 = geography::STGeomFromText('POLYGON ((-122.358 47.653, -122.348 47.649, -122.348 47.658, -122.358 47.658, -122.358 47.653))',4326);

SELECT  @g1 AS 'G1' ,
        @g2 AS 'G2';

SELECT  'G1' AS 'Polygon' ,
        @g1.EnvelopeCenter().Lat AS 'Lat' ,
        @g1.EnvelopeCenter().Long AS 'Long'
UNION ALL
SELECT  'G2' AS 'Polygon' ,
        @g2.EnvelopeCenter().Lat AS 'Lat' ,
        @g2.EnvelopeCenter().Long AS 'Long'

Now, for the second polygon, it returns the center lat/long value correctly as 47.6545001086162, -122.352999904254. But for the first one, it returns the value of 90, 0.

Why am I not getting the proper center point for the first polygon? If for some reason it's not possible this way, is there any other way through which I can find the center point for a given WKT string?


Solution

  • Any closed line on the surface of the globe can describe one of two different finite spaces. In order to know which space is being defined, you need to determine where the "inside" of the shape is.

    In this case, G1 currently describes a large portion of the globe minus a small amount of space around about -90.066, 35.513.

    If you want it to describe a small portion of the globe that includes -90.066, 35.513, then you need to change the sequence of points that you're using to describe the shape:

    DECLARE @g1 GEOGRAPHY;
    DECLARE @g2 GEOGRAPHY;
    
    SET @g1 = geography::STGeomFromText('POLYGON((
                                                  -90.06875038146973 35.512324341620996,
                                                  -90.06381511688232 35.512219543493465,
                                                  -90.06407260894775 35.51499664765537,
                                                  -90.06767749786377 35.51504904492378,
                                                  -90.06875038146973 35.512324341620996
                                                  ))',4326);
    SET @g2 = geography::STGeomFromText('POLYGON ((-122.358 47.653, -122.348 47.649, -122.348 47.658, -122.358 47.658, -122.358 47.653))',4326);
    
    SELECT  @g1 AS 'G1' ,
            @g2 AS 'G2';
    
    SELECT  'G1' AS 'Polygon' ,
            @g1.EnvelopeCenter().Lat AS 'Lat' ,
            @g1.EnvelopeCenter().Long AS 'Long'
    UNION ALL
    SELECT  'G2' AS 'Polygon' ,
            @g2.EnvelopeCenter().Lat AS 'Lat' ,
            @g2.EnvelopeCenter().Long AS 'Long'
    

    Result (2):

    Polygon Lat                    Long
    ------- ---------------------- ----------------------
    G1      35.5136474138606       -90.0660789036838
    G2      47.6545001086162       -122.352999904254
    

    This is because it's the sequence of points describing the shape that is used to determine the inside vs the outside of the shape - it's referred to as the "left-hand rule".