Why simple sql geography polygon fill whole Earth? - sql-server

I'm trying to create a geography polygon in sqlserver:
declare #poly geography = geography::STGeomFromText('POLYGON ((37.1834472346309 55.9627364130318, 37.1843162703518 55.9615689125515, 37.1847990679744 55.9603833217405, 37.1861294436458 55.9590893612134, 37.1858183074 55.9583972249632, 37.1860757994655 55.9580361054639, 37.1851960349086 55.9576990575455, 37.1834901499751 55.9592217684712, 37.1819451975825 55.9611416225876, 37.1812692809108 55.9626581795365, 37.1834472346309 55.9627364130318))', 4326)
select #poly
And result looks like this:
Why my polygon fill whole Earth?
I have an another polygon, and it's looks ok:
declare #poly2 geography = geography::STGeomFromText('POLYGON ((37.1880241973734 55.964234021191, 37.1895369632579 55.9640354359623, 37.1900519473887 55.9640655246991, 37.1912964923716 55.9645830472949, 37.1928736312724 55.9647996825904, 37.193699751649 55.9648598588536, 37.1936568363047 55.965563914075, 37.1913823230601 55.9656120541331, 37.1905669315196 55.966273973827, 37.1896227939463 55.9666891721997, 37.1887323005534 55.9674172628857, 37.1882924182749 55.9681333056029, 37.1881851299143 55.9689095049396, 37.1880027397013 55.9692163701344, 37.1877452476359 55.9693788271893, 37.1874341113901 55.9694570470084, 37.1870371444559 55.9694690808126, 37.186693821702 55.9694510301049, 37.1863504989481 55.9693246749138, 37.1861144645548 55.9691682345792, 37.1860179050303 55.9689696747783, 37.185974989686 55.9687711139541, 37.1862324817515 55.9675737103232, 37.186693821702 55.9673631078402, 37.1868332965708 55.9667192588449, 37.1874555690622 55.9663883042339, 37.1876165016031 55.9657384214668, 37.1881529434061 55.9652269319451, 37.1880134685373 55.964577029591, 37.1880241973734 55.964234021191))', 4326)
select #poly2
I trying this query in different versions of SqlServer (SqlExpress 2017 and SqlServer Professional 2016)- the results are same.

There are 2 ways to interpret polygons and it seems the order of the points you are supplying SQL Server with is not the one that it expects, so it's picking the area of the "outside" rather than the "inside".
This is the right to left rule, and the simple fix is to call native function ReorientObject() before selecting the polygon.
declare #poly geography = geography::STGeomFromText('POLYGON ((37.1834472346309 55.9627364130318, 37.1843162703518 55.9615689125515, 37.1847990679744 55.9603833217405, 37.1861294436458 55.9590893612134, 37.1858183074 55.9583972249632, 37.1860757994655 55.9580361054639, 37.1851960349086 55.9576990575455, 37.1834901499751 55.9592217684712, 37.1819451975825 55.9611416225876, 37.1812692809108 55.9626581795365, 37.1834472346309 55.9627364130318))', 4326)
select #poly.ReorientObject()

Note ReorientObject() is not supported with sql < 2012 the solution i came up is to draw right to left instead on left to right
If we specify points in clockwise direction, it takes all the points in the entire world except the region of the polygon whereas if we specify in counter clockwise direction, we get the expected region 😃.
Right to left
DECLARE #polygon geography = 'POLYGON((10 10, 30 10, 30 30, 10 10))';
SELECT #polygon
Left to right
DECLARE #polygon geography = 'POLYGON((10 10, 30 30, 30 10, 10 10))';
SELECT #polygon

Related

SQL Server Spatial convert from Linestring to Polygon

Can someone help me with convert SQL Server Geometry Shape object to Geometry Polygon object.
I have have a Shape object which is of "Ohio state plan south" coordinate with SRID 32123 and I want to convert it to Geometry Polygon with SRID 3857
This is what I have so far... when I am running it getting below error.
Error: "24119: The Polygon input is not valid because the start and end points of the exterior ring are not the same. Each ring of a polygon must have the same start and end points."
DECLARE #predata varchar(MAX) = 'LINESTRING (544447.66750002524 219649.36696754955, 544446.556000026 219690.21900326665, 544443.99000002549 219720.61000326276, 544435.09000002721 219836.23000326566, 544431.66000001959 219896.72000326123, 544430.0600000252 219924.97000326123, 544422.56000002555 219999.65000326186, 544419.05563904892 220098.02782277763)';
DECLARE #data geometry;
DECLARE #linestring geometry = #predata;
DECLARE #srid int;
SET #predata = REPLACE(#predata, 'LINESTRING', 'POLYGON(') + ')';
SELECT #predata AS PolygonString
SET #data = geometry::STGeomFromText(#predata, 3857);
SELECT #data AS GeographyPolygon
The error is telling you what the problem is. That is, polygons need to start and end with the same point. Your linestring does not (starts at 544447.66750002524 219649.36696754955, ends at 544419.05563904892 220098.02782277763). I was able to get it to work by taking the starting point of the linestring and appending it to the end. If this is a one-time operation, that should suffice.
As agreed with the previous answer please simply use your scripts with a bit change shown as below:
--start point should be same as end point
DECLARE #predata varchar(MAX) = 'LINESTRING (
544447.66750002524 219649.36696754955,
544446.556000026 219690.21900326665,
544443.99000002549 219720.61000326276,
544435.09000002721 219836.23000326566,
544431.66000001959 219896.72000326123,
544430.0600000252 219924.97000326123,
544422.56000002555 219999.65000326186,
544447.66750002524 219649.36696754955)';
--end point should be same as start point
DECLARE #data geometry;
DECLARE #linestring geometry = #predata;
DECLARE #srid int;
SET #predata = REPLACE(#predata, 'LINESTRING', 'POLYGON(') + ')';
SELECT #predata AS PolygonString
SET #data = geometry::STGeomFromText(#predata, 3857);
SELECT #data AS GeographyPolygon

SQL Server geography: Reduce size (decimal precision) of WKT text

For my farming app, a stored proc retrieves paddock/field boundaries that are stored as SQL Server geography data type, for display on the user's mobile device.
SQL Server's .ToString() and .STAsText() functions render each vertex as a lat/long pair, to 15 decimal places. From this answer, 15 decimals defines a location to within the width of an atom! To the nearest metre would be good enough for me.
The resulting overly-precise payload is extremely large and too slow for use on larger farms.
From my SQL Server geography data, I would like to produce WKT that is formatted to 4 or 5 decimals. I could find no built-in methods, but my best leads are:
Postgis and Google Cloud "BigQuery" have the ST_SNAPTOGRID function, which would be perfect, and
Regex might be useful, e.g. this answer, but SQL Server doesn't seem to have a regex replace.
I would think this is a common problem: is there a simple solution?
By stepping through #iamdave's excellent answer, and using that same approach, it looks like we need split only on periods.... I think we can ignore all parantheses and commas, and ignore the POLYGON prefix (which means it'll work across other GEOGRAPHY types, such as MULTIPOLYGON.)
i.e. Each time we find a period, grab only the next 4 characters after it, and throw away any numbers after that (until we hit a non-number.)
This works for me (using #iamdave's test data):
DECLARE #wkt NVARCHAR(MAX), #wktShort NVARCHAR(MAX);
DECLARE #decimalPlaces int = 4;
SET #wkt = 'POLYGON((-121.973669 37.365336,-121.97367 37.365336,-121.973642 37.365309,-121.973415 37.365309,-121.973189 37.365309,-121.973002 37.365912,-121.972815 37.366515,-121.972796 37.366532,-121.972776 37.366549,-121.972627 37.366424,-121.972478 37.366299,-121.972422 37.366299,-121.972366 37.366299,-121.972298 37.366356,-121.97223 37.366412,-121.97215 37.366505,-121.97207 37.366598,-121.971908 37.366794,-121.971489 37.367353,-121.971396 37.367484,-121.971285 37.36769,-121.971173 37.367897,-121.971121 37.368072,-121.971068 37.368248,-121.971028 37.36847,-121.970987 37.368692,-121.970987 37.368779,-121.970987 37.368866,-121.970949 37.368923,-121.970912 37.36898,-121.970935 37.36898,-121.970958 37.36898,-121.970975 37.368933,-121.970993 37.368887,-121.971067 37.368807,-121.97114 37.368726,-121.971124 37.368705,-121.971108 37.368685,-121.971136 37.368698,-121.971163 37.368712,-121.97134 37.368531,-121.971516 37.368351,-121.971697 37.368186,-121.971878 37.368021,-121.972085 37.367846,-121.972293 37.36767,-121.972331 37.367629,-121.972369 37.367588,-121.972125 37.367763,-121.97188 37.367938,-121.971612 37.36815,-121.971345 37.368362,-121.971321 37.36835,-121.971297 37.368338,-121.971323 37.368298,-121.97135 37.368259,-121.971569 37.368062,-121.971788 37.367865,-121.971977 37.367716,-121.972166 37.367567,-121.972345 37.367442,-121.972524 37.367317,-121.972605 37.367272,-121.972687 37.367227,-121.972728 37.367227,-121.972769 37.367227,-121.972769 37.367259,-121.972769 37.367291,-121.972612 37.367416,-121.972454 37.367542,-121.972488 37.367558,-121.972521 37.367575,-121.972404 37.367674,-121.972286 37.367773,-121.972194 37.367851,-121.972101 37.367928,-121.972046 37.36799,-121.971991 37.368052,-121.972008 37.368052,-121.972025 37.368052,-121.972143 37.367959,-121.972261 37.367866,-121.972296 37.367866,-121.972276 37.36794,-121.972221 37.36798,-121.972094 37.368097,-121.971966 37.368214,-121.971956 37.368324,-121.971945 37.368433,-121.971907 37.368753,-121.971868 37.369073,-121.97184 37.369578,-121.971812 37.370083,-121.971798 37.370212,-121.971783 37.370342,-121.971542 37.370486,-121.971904 37.370324,-121.972085 37.37028,-121.972266 37.370236,-121.972559 37.370196,-121.972852 37.370155,-121.973019 37.370155,-121.973186 37.370155,-121.973232 37.370136,-121.973279 37.370116,-121.973307 37.370058,-121.973336 37.370001,-121.973363 37.369836,-121.973391 37.369671,-121.973419 37.369227,-121.973446 37.368784,-121.973429 37.368413,-121.973413 37.368041,-121.973361 37.367714,-121.973308 37.367387,-121.973285 37.367339,-121.973262 37.36729,-121.973126 37.3673,-121.972989 37.36731,-121.973066 37.36728,-121.973144 37.367251,-121.973269 37.367237,-121.973393 37.367223,-121.973443 37.367158,-121.973493 37.367093,-121.973518 37.36702,-121.973543 37.366947,-121.973582 37.366618,-121.973622 37.366288,-121.97366 37.365826,-121.973698 37.365363,-121.973669 37.365336))';
-- Split on '.', then get the next N decimals, and find the index of the first non-number.
-- Then recombine the fragments, skipping the unwanted numbers.
WITH points AS (
SELECT value, LEFT(value, #decimalPlaces) AS decimals, PATINDEX('%[^0-9]%', value) AS indx
FROM STRING_SPLIT(#wkt, '.')
)
SELECT #wktShort = STRING_AGG(IIF(indx < #decimalPlaces, '', decimals) + SUBSTRING(value, indx, LEN(value)), '.')
FROM points;
Comparing original vs shortened, we can see that each number is truncated to 4dp:
SELECT #wkt AS Text UNION ALL SELECT #wktShort;
Edit
I believe I may have misunderstood your question and you are looking to transmit the WKT rather than the binary representations of the polygons? If that is the case, my answer below still shows you how to chop off some decimal places (without rounding them). Just don't wrap the stuff(...) FOR XML in a STGeomFromText and you have the amended WKT.
When working with geography data types, it can be handy to maintain a very detailed 'master' version, from which you generate and persist less detailed versions based on your requirements.
An easy way to generate these reduced complexity polygons is to use the helpfully named Reduce function, which I think will actually help you in this situation.
If you would prefer to go down the route of reducing the number of decimal places you will either have to write a custom CLR function or enter the wonderful world of SQL Server string manipulation!
SQL Query
declare #DecimalPlaces int = 4; -- Specify the desired number of lat/long decimals
with g as(
select p.g -- Original polygon, for comparison purposes
,geography::STGeomFromText('POLYGON((' -- stripped apart and then recreated polygon from text, using a custom string split function. You won't be able to use the built in STRING_SPLIT here as it doesn't guarantee sort order.
+ stuff((select ', ' + left(s.item,charindex('.',s.item,0) + #DecimalPlaces) + substring(s.item,charindex(' ',s.item,0),charindex('.',s.item,charindex(' ',s.item,0)) - charindex(' ',s.item,0) + 1 + #DecimalPlaces)
from dbo.fn_StringSplitMax(replace(replace(p.g.STAsText(),'POLYGON ((',''),'))',''),', ',null) as s
for xml path(''), type).value('.', 'NVARCHAR(MAX)') -- STUFF and FOR XML mimics GROUP_CONCAT functionality seen in other SQL languages, to recombine shortened Points back into a Polygon string
,1,2,''
)
+ '))', 4326).MakeValid() as x -- Remember to make the polygon valid again, as you have been messing with the Point data
from(values(geography::STGeomFromText('POLYGON((-121.973669 37.365336,-121.97367 37.365336,-121.973642 37.365309,-121.973415 37.365309,-121.973189 37.365309,-121.973002 37.365912,-121.972815 37.366515,-121.972796 37.366532,-121.972776 37.366549,-121.972627 37.366424,-121.972478 37.366299,-121.972422 37.366299,-121.972366 37.366299,-121.972298 37.366356,-121.97223 37.366412,-121.97215 37.366505,-121.97207 37.366598,-121.971908 37.366794,-121.971489 37.367353,-121.971396 37.367484,-121.971285 37.36769,-121.971173 37.367897,-121.971121 37.368072,-121.971068 37.368248,-121.971028 37.36847,-121.970987 37.368692,-121.970987 37.368779,-121.970987 37.368866,-121.970949 37.368923,-121.970912 37.36898,-121.970935 37.36898,-121.970958 37.36898,-121.970975 37.368933,-121.970993 37.368887,-121.971067 37.368807,-121.97114 37.368726,-121.971124 37.368705,-121.971108 37.368685,-121.971136 37.368698,-121.971163 37.368712,-121.97134 37.368531,-121.971516 37.368351,-121.971697 37.368186,-121.971878 37.368021,-121.972085 37.367846,-121.972293 37.36767,-121.972331 37.367629,-121.972369 37.367588,-121.972125 37.367763,-121.97188 37.367938,-121.971612 37.36815,-121.971345 37.368362,-121.971321 37.36835,-121.971297 37.368338,-121.971323 37.368298,-121.97135 37.368259,-121.971569 37.368062,-121.971788 37.367865,-121.971977 37.367716,-121.972166 37.367567,-121.972345 37.367442,-121.972524 37.367317,-121.972605 37.367272,-121.972687 37.367227,-121.972728 37.367227,-121.972769 37.367227,-121.972769 37.367259,-121.972769 37.367291,-121.972612 37.367416,-121.972454 37.367542,-121.972488 37.367558,-121.972521 37.367575,-121.972404 37.367674,-121.972286 37.367773,-121.972194 37.367851,-121.972101 37.367928,-121.972046 37.36799,-121.971991 37.368052,-121.972008 37.368052,-121.972025 37.368052,-121.972143 37.367959,-121.972261 37.367866,-121.972296 37.367866,-121.972276 37.36794,-121.972221 37.36798,-121.972094 37.368097,-121.971966 37.368214,-121.971956 37.368324,-121.971945 37.368433,-121.971907 37.368753,-121.971868 37.369073,-121.97184 37.369578,-121.971812 37.370083,-121.971798 37.370212,-121.971783 37.370342,-121.971542 37.370486,-121.971904 37.370324,-121.972085 37.37028,-121.972266 37.370236,-121.972559 37.370196,-121.972852 37.370155,-121.973019 37.370155,-121.973186 37.370155,-121.973232 37.370136,-121.973279 37.370116,-121.973307 37.370058,-121.973336 37.370001,-121.973363 37.369836,-121.973391 37.369671,-121.973419 37.369227,-121.973446 37.368784,-121.973429 37.368413,-121.973413 37.368041,-121.973361 37.367714,-121.973308 37.367387,-121.973285 37.367339,-121.973262 37.36729,-121.973126 37.3673,-121.972989 37.36731,-121.973066 37.36728,-121.973144 37.367251,-121.973269 37.367237,-121.973393 37.367223,-121.973443 37.367158,-121.973493 37.367093,-121.973518 37.36702,-121.973543 37.366947,-121.973582 37.366618,-121.973622 37.366288,-121.97366 37.365826,-121.973698 37.365363,-121.973669 37.365336))', 4326))) as p(g)
)
-- select various versions of the polygons into the same column for overlay comparison in SSMS
select 'Original' as l
,g
from g
union all
select 'Short' as l
,x
from g
union all
select 'Original Reduced' as l
,g.Reduce(10)
from g
union all
select 'Short Reduced' as l
,x.Reduce(10)
from g;
Output
What is interesting to note here is the difference in length of the geog binary representation (simple count of characters as displayed). As I mentioned above, simply using the Reduce function may do what you need, so you will want to test various approaches to see how best you cut down on your data transfer.
+------------------+--------------------+------+
| l | g | Len |
+------------------+--------------------+------+
| Original | 0xE6100000010484...| 4290 |
| Short | 0xE6100000010471...| 3840 |
| Original Reduced | 0xE6100000010418...| 834 |
| Short Reduced | 0xE610000001041E...| 1184 |
+------------------+--------------------+------+
Visual Comparison
String Split Function
As polygon data can be bloody huge, you will need a string splitter that can handle more then 4k or 8k characters. In my case I tend to opt for an xml based approach:
create function [dbo].[fn_StringSplitMax]
(
#str nvarchar(max) = ' ' -- String to split.
,#delimiter as nvarchar(max) = ',' -- Delimiting value to split on.
,#num as int = null -- Which value to return.
)
returns table
as
return
with s as
( -- Convert the string to an XML value, replacing the delimiter with XML tags
select convert(xml,'<x>' + replace((select #str for xml path('')),#delimiter,'</x><x>') + '</x>').query('.') as s
)
select rn
,item -- Select the values from the generated XML value by CROSS APPLYing to the XML nodes
from(select row_number() over (order by (select null)) as rn
,n.x.value('.','nvarchar(max)') as item
from s
cross apply s.nodes('x') as n(x)
) a
where rn = #num
or #num is null;

Wrong area in STArea() in SQL Server

I am trying to count the surface (STArea ()) of a geometry saved as a WKT, but I get the wrong value.
I mention that using geography did not help. I also noticed, that in Postgis area is counted properly when I set use_spheroid=false.
DECLARE #g geometry = geometry::STGeomFromText('POLYGON((21.5601775022348 52.1813862660549,21.5601461469143 52.1813295549141,21.559853091877 52.1813993365177,21.5597665803865 52.1812613330339,21.5593037698201 52.1813692515792,21.5592677194965 52.1813021172669,21.5592607711581 52.1813034375092,21.5592188506351 52.1812334620465,21.5591248909245 52.1812561912586,21.5590395906618 52.1811137531269,21.5587491625113 52.1811808662478,21.5589985172752 52.1816470941761,21.5595646783963 52.1815219107667,21.5601775022348 52.1813862660549))', 4326);
select #g;
select #g.STArea()
In geography, the left hand side is the interior as you traverse the polygon. So you have specified the inverse of the polygon you want. With geometry it doesn't matter, as the interior is always the the bounded area.
Try
DECLARE #g geography = geography::STGeomFromText('POLYGON((21.5601775022348 52.1813862660549,21.5601461469143 52.1813295549141,21.559853091877 52.1813993365177,21.5597665803865 52.1812613330339,21.5593037698201 52.1813692515792,21.5592677194965 52.1813021172669,21.5592607711581 52.1813034375092,21.5592188506351 52.1812334620465,21.5591248909245 52.1812561912586,21.5590395906618 52.1811137531269,21.5587491625113 52.1811808662478,21.5589985172752 52.1816470941761,21.5595646783963 52.1815219107667,21.5601775022348 52.1813862660549))', 4326);
set #g = #g.ReorientObject()
select #g, #g.STArea()
outputs
2381.30781687796

How to select all points near a line?

I have a linestring:
LINESTRING( -43.0965167 -22.8808585,-43.0980368 -22.8807975,-43.0986518
-22.8807735,-43.0990955 -22.8807701,-43.0991492 -22.8807697,-43.1005956
-22.8807353,-43.1013221 -22.8807107,-43.1016904 -22.8807003,-43.1019484
-22.8806902,-43.1020398 -22.8806866,-43.102591 -22.8806801,-43.1029336
-22.8806666,-43.1036051 -22.8806402,-43.1039349 -22.8806272,-43.1042967
-22.880613,-43.1061912 -22.8805398 )
Now I can select all points at a distance "x" from this line ( around the line ). I already tried Find the nearest points along the linestring in specified distance limit and order with no success ( always take a lot of points in a box like distribution ). This is a piece of code I started to write:
select p.way,p.name from planet_osm_point p where ST_DWithin(
ST_Transform( theLineGeom, 4326), ST_Transform( p.way,4326 ), 0.9)
limit 50;
I think you are getting lots of points because ST_DWithin uses the unit of the geometries srid to perform the calculation.
boolean ST_DWithin(geometry g1, geometry g2, double precision distance_of_srid);
So you are getting all the points with 0.9 degrees from your linestring.
You could use
boolean ST_DWithin(geography gg1, geography gg2, double precision distance_meters);
converting your geometries to geography.
Otherwise you could use another srid.
Solved. I just get too many points because the limit was too big. If I have 2 points near the route and tell the query to give me the first 50 then 48 points will be far from the line but inside the bounding box. This is why the box like distribution I saw.
select * from pointscanner('<geomRoute_WILL_BE_HERE>') where round(distance::numeric, 5) < 500 /* meters */
CREATE OR REPLACE FUNCTION public.pointscanner( IN routeGeometry text)
RETURNS TABLE(way geometry, name text, distance double precision, tags hstore, operator text, admin_level text, z_order integer) AS
$BODY$
DECLARE
geomRoute geometry;
routeBB box2d;
BEGIN
geomRoute = ST_GeomFromText('MULTILINESTRING(
(-43.1761935 -22.90642,-43.1755606 -22.9064116,-43.1754828 -22.9064106,-43.1753675 -22.9064091),
(-43.176696 -22.9064062,-43.1761935 -22.90642),(-43.176805 -22.9064027,-43.176696 -22.9064062),
(-43.1776911 -22.9049927,-43.1776625 -22.9050849,-43.1775227 -22.9055527,-43.1775045 -22.9056041,-43.1774504 -22.9057582),
(-43.1782012 -22.9036858,-43.1778613 -22.9045254,-43.1777841 -22.9047287,-43.1777446 -22.9048326,-43.1777179 -22.9049164,-43.1776911 -22.9049927),
(-43.1772218 -22.9063929,-43.1771252 -22.9063944,-43.1771118 -22.9063946,-43.1769202 -22.9064008,-43.176805 -22.9064027),
(-43.1774504 -22.9057582,-43.1773182 -22.9061373,-43.1772868 -22.9062205,-43.1772218 -22.9063929),
(-43.1834587 -22.9028997,-43.1833984 -22.9028862,-43.1830022 -22.9027778,-43.1825446 -22.9026278,-43.1821151 -22.9024891,-43.1816491 -22.9023374,-43.1815912 -22.9023186,-43.1813461 -22.9022388),
(-43.1793173 -22.901581,-43.1791549 -22.9015418,-43.179105 -22.9015365,-43.1790457 -22.9015482,-43.1790174 -22.9015689,-43.178994 -22.9016082),
(-43.1788184 -22.9020931,-43.1786726 -22.9025241,-43.1786518 -22.9025769,-43.1786063 -22.9026931),
(-43.1813461 -22.9022388,-43.1806028 -22.9019969,-43.1805417 -22.901977,-43.1799074 -22.9017705),
(-43.1799074 -22.9017705,-43.1797658 -22.9017244,-43.1793732 -22.9015989,-43.1793173 -22.901581),
(-43.178994 -22.9016082,-43.1788184 -22.9020931),(-43.1784337 -22.9031366,-43.1782012 -22.9036858),
(-43.1786063 -22.9026931,-43.17848 -22.9030174,-43.178461 -22.9030662,-43.1784337 -22.9031366))',4326);
routeBB := ST_Extent(geomRoute);
RETURN QUERY
SELECT pt.way, pt.name, ST_Distance( geomRoute, ST_Transform(pt.way,4326) ) * 111195 as distance,
pt.tags, pt.operator, pt.admin_level, pt.z_order
FROM planet_osm_point pt
where routeBB && ST_Transform(pt.way,4326);
END; $BODY$
LANGUAGE plpgsql VOLATILE

STIntersect geography,geometry datatype

I have a circle and point, point intersects circle in geometry but not in geography.
DECLARE #circle GEOGRAPHY = GEOGRAPHY::Point(39.10591303215, 21.923140028856, 4120).STBuffer(500)
DECLARE #geogpoint GEOGRAPHY = GEOGRAPHY::Point(51.590294, 25.16387, 4120)
select #circle,#geogpoint.ToString(),#geogpoint,#circle.STIntersects(#geogpoint)
DECLARE #circle1 geometry = geometry::Point(39.10591303215, 21.923140028856, 4120).STBuffer(500)
DECLARE #geomgpoint geometry = geometry::Point(51.590294, 25.16387, 4120)
select #circle1,#geomgpoint.ToString(),#geomgpoint,#circle1.STIntersects(#geomgpoint)
I have lot of circle and point,problem is geometry is intersecting almost all and geography very few.
For Geography, the buffer is in units per the SRID. For 4120:
SELECT unit_of_measure FROM sys.spatial_reference_systems WHERE spatial_reference_id = 4120
gives 'metre'
You are therefore adding a 500m buffer to your point. Now, what's the distance between your two (unbuffered) points?
DECLARE #circle GEOGRAPHY = GEOGRAPHY::Point(39.10591303215, 21.923140028856, 4120)
DECLARE #geogpoint GEOGRAPHY = GEOGRAPHY::Point(51.590294, 25.16387, 4120)
SELECT #circle.STDistance(#geogpoint)
1410017.60306578 metres
which explains why STIntersects returns false.
For Geometery, you are working in 'units'. What's the distance between your two points?
DECLARE #circle1 geometry = geometry::Point(39.10591303215, 21.923140028856, 4120)
DECLARE #geomgpoint geometry = geometry::Point(51.590294, 25.16387, 4120)
select #circle1.STDistance(#geomgpoint)
12.898143234446 'units' (in this case degrees)
which is why your second query returns true.
Have a look at the section "Measurements in spatial data types"
https://msdn.microsoft.com/en-us/library/bb964711.aspx

Resources