I'm having an issue with SQL Server 2008 and the geometry functions. I'm trying to create non-overlapping shapes using the STDifference function... but it does not seem to be working 100% of the time.
Here is all the sample code to demonstrate the issue. Anybody have any idea to make these non-overlapping polygons? (except "don't make your polygons so complex")
-- create our Geometry polygons.
DECLARE #Geo1 Geometry, #Geo2 Geometry;
SET #Geo1 = geometry::STGeomFromText('POLYGON ((-79725887.5234375 42951274.765625, -79699548.921875 42991827.84375, -79695546.375697568 42997990.498925969, -79695559.967852488 42998690.733179785, -79696152.0625 43029192.375, -79715247.75 43051708.75, -79802181.8984375 43020797.71875, -79806253.6640625 43018621.6953125, -79810436.03125 43014767.046875, -79825837.5 43000572.375, -79830640.625 42973672.03125, -79832936.7265625 42960812.4296875, -79725887.5234375 42951274.765625))',0);
SET #Geo2 = geometry::STGeomFromText('POLYGON ((-79863430.6875 42937209.4375, -79850399.0625 42940068.75, -79850394.9375 42940069.625, -79845320.6875 42946082.625, -79843216.25 42948576.375, -79832949.125 42960743, -79814909.939453125 43061773.556640625, -79817218.30078125 43060262.947265625, -79823496.6875 43056154.3125, -79867800.5 43027161.5625, -79871834.50390625 43024521.70703125, -79875660.228515625 43022018.123046875, -79875666.8125 43022013.8125, -79875674.536313191 43022008.760254942, -79875676.408203125 43022007.53515625, -79875677.236328125 43022006.994140625, -79875718.458984375 43021980.017578125, -79875728.506891936 43021973.442301653, -79881723.017578125 43018050.58984375, -79882437.0625 43017583.3125, -79882585.375 43017486.25, -79884466.9375 43016254.9375, -79884550.875 43016200, -79886514.3125 43014915.125, -79887785.5 43014083.25, -79887790.4375 43014080, -79887793.125 43014078.26953125, -79887807.171875 43014069.076171875, -79887825.568359375 43014057.03515625, -79887831.322335 43014053.269705132, -79888029.5 43013923.5625, -79890094.5625 43012572.1875, -79934236.875 42983685.125, -79863430.6875 42937209.4375))',0);
-- A quick test so you can see them
SELECT #Geo1, 'Geo1' as MyName UNION ALL SELECT #Geo2, 'Geo2' as MyName;
-- how do they compare initially?
SELECT
#Geo1.STTouches(#Geo2) as 'Touches'
,#Geo1.STOverlaps(#Geo2) as 'Overlaps'
,#Geo1.STIntersects(#Geo2) as 'Intersects'
-- try to make them NOT overlap or intersect
SET #Geo1 = #Geo1.STDifference(#Geo2);
SET #Geo2 = #Geo2.STDifference(#Geo1);
-- Now, how do they compare?
SELECT
#Geo1.STTouches(#Geo2) as 'Touches'
,#Geo1.STOverlaps(#Geo2) as 'Overlaps'
,#Geo1.STIntersects(#Geo2) as 'Intersects'
-- what does the intersection look like?
SELECT #Geo1.STIntersection(#Geo2).STAsText();
This is the final select result:
MULTIPOLYGON (((-79831832.015625 42966999.5078125, -79830502.34765625 42974446.45703125, -79830181.430394545 42976243.79133676, -79830220.96484375 42976022.375, -79831832.015625 42966999.5078125)), ((-79832481.0538819 42963364.484146826, -79832328.75390625 42964217.45703125, -79831832.015625 42966999.5078125, -79832481.0538819 42963364.484146826)))
Not an answer, just an observation... I get different results if I introduce two new variables for the two differences.
-- create our Geometry polygons.
DECLARE #Geo1 Geometry, #Geo2 Geometry, #Geo3 Geometry, #Geo4 Geometry;
SET #Geo1 = geometry::STGeomFromText('POLYGON ((-79725887.5234375 42951274.765625, -79699548.921875 42991827.84375, -79695546.375697568 42997990.498925969, -79695559.967852488 42998690.733179785, -79696152.0625 43029192.375, -79715247.75 43051708.75, -79802181.8984375 43020797.71875, -79806253.6640625 43018621.6953125, -79810436.03125 43014767.046875, -79825837.5 43000572.375, -79830640.625 42973672.03125, -79832936.7265625 42960812.4296875, -79725887.5234375 42951274.765625))',0);
SET #Geo2 = geometry::STGeomFromText('POLYGON ((-79863430.6875 42937209.4375, -79850399.0625 42940068.75, -79850394.9375 42940069.625, -79845320.6875 42946082.625, -79843216.25 42948576.375, -79832949.125 42960743, -79814909.939453125 43061773.556640625, -79817218.30078125 43060262.947265625, -79823496.6875 43056154.3125, -79867800.5 43027161.5625, -79871834.50390625 43024521.70703125, -79875660.228515625 43022018.123046875, -79875666.8125 43022013.8125, -79875674.536313191 43022008.760254942, -79875676.408203125 43022007.53515625, -79875677.236328125 43022006.994140625, -79875718.458984375 43021980.017578125, -79875728.506891936 43021973.442301653, -79881723.017578125 43018050.58984375, -79882437.0625 43017583.3125, -79882585.375 43017486.25, -79884466.9375 43016254.9375, -79884550.875 43016200, -79886514.3125 43014915.125, -79887785.5 43014083.25, -79887790.4375 43014080, -79887793.125 43014078.26953125, -79887807.171875 43014069.076171875, -79887825.568359375 43014057.03515625, -79887831.322335 43014053.269705132, -79888029.5 43013923.5625, -79890094.5625 43012572.1875, -79934236.875 42983685.125, -79863430.6875 42937209.4375))',0);
-- A quick test so you can see them
SELECT #Geo1, 'Geo1' as MyName UNION ALL SELECT #Geo2, 'Geo2' as MyName;
-- how do they compare initially?
SELECT
#Geo1.STTouches(#Geo2) as 'Touches'
,#Geo1.STOverlaps(#Geo2) as 'Overlaps'
,#Geo1.STIntersects(#Geo2) as 'Intersects'
-- try to make them NOT overlap or intersect
SET #Geo3 = #Geo1.STDifference(#Geo2);
SET #Geo4 = #Geo2.STDifference(#Geo1);
-- Now, how do they compare?
SELECT
#Geo3.STTouches(#Geo4) as 'Touches'
,#Geo3.STOverlaps(#Geo4) as 'Overlaps'
,#Geo3.STIntersects(#Geo4) as 'Intersects'
-- what does the intersection look like?
SELECT #Geo3.STIntersection(#Geo4).STAsText();
Compare:
Touches Overlaps Intersects
1 0 1
Final Select:
MULTIPOINT ((-79830220.96484375 42976022.375), (-79831832.015625 42966999.5078125))
I suspect this is due to the method/precision with which SQL Server performs spatial calculations. For operations like STIntersection() etc, SQL Server rounds the supplied float coordinate values to a 27 bit integer grid. This can introduce slight distortions to the coordinates returned as the result of spatial operations.
In your case, your coordinate values are large, which means that the fixed size integer grid must be made quite coarse to accommodate the full range of data. The relative difference between the intersecting coordinates that you're trying to remove, however, is very small. When snapped to this coarse grid, SQL Server is unable to correctly identify the area of intersection.
See here for a explanation, and also a suggestion that this situation has been improved in SQL Server Denali:
https://connect.microsoft.com/SQLServer/feedback/details/580254/spatial-operations-are-done-with-a-low-precision-causing-troubles-in-the-returned-data
As pointed out by Joe Stefanelli, your polygons don't technically overlap but they do intersect. The reason is that if you cut a hole out of one polygon using a smaller polygon, the smaller polygon will not overlap the new polygon but it will intersect it along the edge of the cut. It isn't like a table saw that removes some material along the edge of the cut. I could not include the code because SO is having a problem with certain SQL statements and blocks the post.
SEE REFERENCE A in image
If you would like it not to overlap OR intersect, you can create your own sawblade effect. Apply a very small buffer around the smaller of the geometries when using it in the STDifference() function.
SEE REFERENCE B in image
I know this post is old but it does seem pertinent still for those of us who will still be on 2008 for a while.
Related
What I have so far:
select Metro.Object_ID
from Geocoding_tab.dbo.Part1_Part2_Combined_Final as paypal
,Object_id.dbo.All_Combined_9_Metros as Metro
where paypal.geom.STIntersect(Metro.GEOM) = 1;
You can amend the query to use JOIN syntax
SELECT Metro.Object_ID
FROM
Geocoding_tab.dbo.Part1_Part2_Combined_Final as paypal
INNER JOIN
Object_id.dbo.All_Combined_9_Metros as Metro ON paypal.geom.STIntersects(Metro.GEOM) = 1;
EDIT - following error shown in comments below
You can use the STIsValid Method to detect if you have shape that's invalid. The method will return 0 if invalid.
The MakeValid Method will fix invalid shape data
for example:
UPDATE table SET geom = geom.MakeValid() where geom.STIsValid() = 0
Note
As the error suggests, the MakeValid could alter your shape in a way that you might consider incorrect, depending on the original problem with the shape. So you should confirm that you're happy with the "corrected" shape before proceeding.
I am trying to check point in polygon, but STIntersect producing wrong result, below is given both point and polygon.
DECLARE #point GEOGRAPHY = GEOGRAPHY::Point(25.631119, 54.666181, 4326)
DECLARE #polygon GEOGRAPHY = GEOGRAPHY::STGeomFromText('POLYGON
((55.368827104612151 25.270499845366924, 55.368226289792808
25.268578811810126, 55.367410898252288 25.269529630198974,
55.368054628415855 25.270364015710307, 55.368827104612151
25.270499845366924))', 4326)
SELECT #polygon.STIntersects(#point), #point.STIntersects(#polygon)
Result is returning 1, however it should return 0, because i pick the point out side of fence,,
Am I making anything wrong with polygon coordinates? Please advice me for any stupid mistake of mine as I am new in spatial data types.
In order to "fix" this, we need to make some form of assumption. If the assumption cannot be "instruct the users to enter polygons that obey the left-hand rule" then we have to use something else.
Here, I'm assuming that the correct "sense" for the polygon is whichever way around means that it's enclosing the smallest area:
DECLARE #point GEOGRAPHY = GEOGRAPHY::Point(25.631119, 54.666181, 4326)
DECLARE #polygon GEOGRAPHY = GEOGRAPHY::STGeomFromText('POLYGON
((55.368827104612151 25.270499845366924,
55.368226289792808 25.268578811810126,
55.367410898252288 25.269529630198974,
55.368054628415855 25.270364015710307,
55.368827104612151 25.270499845366924))', 4326)
SET #polygon = CASE
WHEN #polygon.STArea() > #polygon.ReorientObject().STArea()
THEN #polygon.ReorientObject()
ELSE #polygon
END
SELECT #polygon
(You may also wish to do a plain SELECT #polygon before the CASE to see what the original looked like)
However, take careful note of what the above assumption means - if your users may wish to provide "the whole planet minus this small area around 55 degrees East/25 degrees North", there's now no way for you to accept such a value.
References - STArea ReorientObject
I've got a table full of WKT (well known text) in a varchar(max) column. This is formatted exactly as geometry. So, for example, one of the values is:
POLYGON ((174.893529167059 -37.0260462162965,174.89351593407 -37.0260221329151,174.893508034056 -37.0260077002766,174.893444415879 -37.0258916500588,174.893416916056 -37.0258414997842,174.893481733297 -37.0258186834198,174.893492016755 -37.0258150663863,174.89349653254 -37.025823316032,174.893512415978 -37.0258522827285,174.893556883897 -37.0259333832477,174.893591032956 -37.0259956661343,174.893604265986 -37.0260197504078,174.893575149738 -37.0260300006258,174.893529167059 -37.0260462162965))
However, I need to convert this varchar(max) field into a geometry field. Unfortunately, SQL Server needs to have some other information in order to do this, so I can't just change the type of the field from varchar(max) to geometry.
I've created a blank geometry column in the same table (MyGeometry) but I'm failing in trying to convert it. Here is my code (where 2193 is the CRS I'm dealing with). WKT is my varchar(max) field and MyGeometry is my new geometry field.
UPDATE MY_TABLE
SET MyGeometry = geometry::STPolyFromText('' + WKT + '', 2193)
EDIT - currently coming back saying the WKT is not valid (System.FormatException 24111 - the input isn't valid).
Which is strange as it matches up perfectly with some other inputs I have in how it's styled.
This will do :
UPDATE MY_TABLE
SET MyGeometry = geometry::STGeomFromText('POLYGON ((174.893529167059 -37.0260462162965,174.89351593407 -37.0260221329151,174.893508034056 -37.0260077002766,174.893444415879 -37.0258916500588,174.893416916056 -37.0258414997842,174.893481733297 -37.0258186834198,174.893492016755 -37.0258150663863,174.89349653254 -37.025823316032,174.893512415978 -37.0258522827285,174.893556883897 -37.0259333832477,174.893591032956 -37.0259956661343,174.893604265986 -37.0260197504078,174.893575149738 -37.0260300006258,174.893529167059 -37.0260462162965))', 0)
You can change that 'POLYGON....' to your VARCHAR(MAX) field.
0 at the end, which is SRID only relevant if you're using Geography.
You can also try :-
UPDATE MY_TABLE SET MyGeometry = GEOMETRY::STGeomFromText('POLYGON ((174.893529167059 -37.0260462162965,174.89351593407 -37.0260221329151,174.893508034056 -37.0260077002766,174.893444415879 -37.0258916500588,174.893416916056 -37.0258414997842,174.893481733297 -37.0258186834198,174.893492016755 -37.0258150663863,174.89349653254 -37.025823316032,174.893512415978 -37.0258522827285,174.893556883897 -37.0259333832477,174.893591032956 -37.0259956661343,174.893604265986 -37.0260197504078,174.893575149738 -37.0260300006258,174.893529167059 -37.0260462162965))',4326);
The value of SRID passed should be 4326 and not 0
You can check the URL below. I found this information in another similar question (older post) so pasting it without any changes
I found solution, SQL Server Spatial Tools
http://sqlspatialtools.codeplex.com/
Followings are the methods solved my problem.
IsValidGeographyFromText(string inputWKT, int srid)
Check if an input WKT can represent a valid geography. This function requires that the WTK coordinate values are longitude/latitude values, in that order and that a valid geography SRID value is supplied. This function will not throw an exception even in edge conditions (i.e. longitude/latitude coordinates are reversed to latitude/longitude).
SqlGeography MakeValidGeographyFromText(string inputWKT, int srid)
Convert an input WKT to a valid geography instance. This function requires that the WKT coordinate values are longitude/latitude values, in that order and that a valid geography SRID value is supplied.
I would like to ask you something regarding Intersection on SQL Server.
I am running a project in which I am using a gmap. I have a polygon through which some polylines are passing through and some are not. I am using the STIntersection in order to get the exactly part of polyline which is in the polygon.
Below is the t-sql that I am using to achieve this.
The issue now is that I want to find the exactly point in which each polyline touches the polygon through passing out. Do you have any workaround concerning this?
DECLARE #polygon geography;
DECLARE #polyline geography;
SET #g = (select Polygon from Polygons where id = #polygonID)
SET #h = (select GeogPolyline from Polylines where ID = #polylineId)
SET #intersectedpart = (SELECT #g.STIntersection(#h).STAsText() )
I manage to resolve this using the below :
SET #result = (SELECT #g.STIntersection(#h).STStartPoint())
Using this you are geting the first point of intersection between the polyline and polygon
I am trying to run the following PostGIS query:
select ST_distance_spheroid(
ST_GeomFromText('POINT(
(select AsText(location) from test where name="EGMC")
)', 4326),
ST_GeomFromText('POINT(
(select AsText(location) from test where name="EGDY")
)', 4326),
'SPHEROID["WGS_1984",6378137,298.257223563]'
);
but keep getting an error:
ERROR: parse error - invalid geometry
HINT: "POINT(
(s" <-- parse error at position 9 within geometry
I'm happy that I know what the error means, I just don't know how to go about achieving what I want to do. I don't want to manually specify the location, it's stored in the database! I know the name of the place, so I want to get it's location by looking it up. How should I be doing this? Also, it seems a bit unnecessary to convert to a string to convert back, what else can I do?
If I can do this without having to specify variables that would be great.
Thanks.
You are mixing SQL and WKT, which are not the same. Furthermore, you don't need to recreate geometries that already exist. Query the existing geometries instead:
select ST_distance_spheroid(g1.location, g2.location, 'SPHEROID["WGS_1984",6378137,298.257223563]')
from test g1, test g2
where g1.name = "EGMC" and g2.name = "EGDY";