Remove Geometry data that is outside of a polygon - sql-server

I am creating a SQL Server table that takes data from a OS MasterMap layer if it sits within the SITES_TEST layer.
First I am using STIntersects to get the OS MM data into an ASSETS layer.
INSERT INTO ASSETS(GEOMETRY, THEMES)
(select b.GEOMETRY, b.THEMES from
SITES_TEST a,
MM_TOPO b
where a.geometry.STBuffer(1).STIntersects(b.geometry) = 1 AND (b.THEMES ='Land' or b.THEMES ='Roads Tracks And Paths'))
The Blue boundary is my site layer and in the background OS MasterMap.
After the query above is run in SQL Server it returns the overlapping data as well as the contained data. I get that I could use STContains but then that leaves out data that goes both within and outside the boundary.
I was hoping I would be able to run an UPDATE on the ASSETS table using STDifference.
UPDATE ASSETS(GEOMETRY)
(select b.GEOMETRY from
SITES_TEST a,
MM_TOPO b
where a.geometry.STDifference(b.geometry)=1)
But I think I am going about it the wrong way as this is returning a boolean error.
Invalid operator for data type. Operator equals equal to, type equals
geometry.
Summary:
I am trying to remove geometry that is outside of another geometry. The first picture shows a blue polygon, then the SQL script is run which results in the second picture which shows data in red that sits outside the blue boundary polygon from the first picture. I want to remove the data that is now outside the blue polygon.

Instead of just asking for geometries that intersect the polygon of interest, which returns all of the intersecting geometry (as you found out) you want just the parts of the geometry that intersect your polygon of interest. So something like:
INSERT INTO ASSETS(GEOMETRY, THEMES)
(select b.GEOMETRY.STIntersection(a.geometry, b.THEMES from
SITES_TEST a,
MM_TOPO b
where a.geometry.STBuffer(1).STIntersects(b.geometry) = 1 AND (b.THEMES ='Land' or b.THEMES ='Roads Tracks And Paths'))

Related

How to calculate distance in "km" using a points geometry column to the nearest linestring geometry column in SQL Server spatial

I am looking to create a field that tells me the nearest neighbour distance in km between 2 geometric columns.
I have a point dataset and multiline dataset both with the geometric fields.
I tried the following:
SELECT
p.GEOM.STDistance(l.GEOM) AS distance
FROM
[points] p, [dbo].[lines] l
after running this query I get the following message
Msg 6522, Level 16, State 1, Line 2
A .NET Framework error occurred during execution of user-defined routine or aggregate "geometry":
System.ArgumentException: 24144: This operation cannot be completed because the instance is not valid. Use MakeValid to convert the instance to a valid instance. Note that MakeValid may cause the points of a geometry instance to shift slightly.
System.ArgumentException:
Could you help me with this one please?
Much appreciated!
Thanks!
The error seems to indicate you have bad spatial data in one of the tables but the query you're using has issues as well. Run this
select ID, geom.STisValid() from lines
and
SELECT ID, geom.STisValid() from points
To see if you have any bad geometry records. If you do run
update table 'with bad spatial datatype'
set geom = geom.MakeValid()
Once you're sure the spatial data is valid rework your query to use a cross join (compare every line to every point (and get the distance) and store the results in a temp table.
Query the temp table for the min(distance) for each point or line. Provided you only need to know the closest feature and not a distance you can do all this with geometry data. If you need to have a measure in feet or meters you will need to convert your data from geometry to geography.
If you have a large number of features in either table the cross join could take forever. Try to work it out on a subset.

Merging SQL Spatial polygons where there is a calculated column

I'm having trouble getting polygons in a SQL Spatial table to merge where there is a calculated column.
The original query works great:
SELECT RollNumber, Geometry, geometry::UnionAggregate(Geometry_SPA.MakeValid()) AS Geometry_SPA
FROM dbo.LegalParcel
GROUP BY RollNumber, Geometry
It returns a set of polygons merged by their tax roll numbers.
However we want to know areas, so we added a computed column:
SELECT RollNumber, Geometry_SPA.STArea() AS SqMetres, Geometry, geometry::UnionAggregate(Geometry_SPA.MakeValid()) AS Geometry_SPA
FROM dbo.LegalParcel
GROUP BY RollNumber, Geometry, Geometry_SPA.STArea()
Since this required adding Geometry_SPA to the Group By, now the polygons which are supposed to merge come back as discrete records.
I attempted to add the aggregation onto the new SqMetres column
columngeometry::UnionAggregate(Geometry_SPA.STArea()) As SqMetres
However that ends with the error ‘Operand type clash: float is incompatible with geometry’
How can I get the necessary records to merge?
Note for anyone wondering why there are two Geometry columns: It is a requirement of our GIS software.
Apparently the issue traced back to some questionable polygons in the source table. After running
update dbo.legalparcel set Geometry_SPA=Geometry_SPA.MakeValid()
where Geometry_SPA.STIsValid() = 0
I'm now getting correct results using the original computed column.

How to make a polygon with a hole

I'm using postgresSQL with postgis and I'm trying to create a polygon with a hole. I read a lot of users asking for something similar, but I can't do it for myself. My code is
insert into distritos(nombre,geom) values ('Distrito6',ST_MakePolygon(ST_GeomFromText('LINESTRING((-15.66486 27.91996, -15.60610 27.91820, -15.60359 27.97169, -15.66586 27.97144,-15.66486 27.91996),(-15.65753 27.95894, -15.61610 27.95995, -15.61459 27.93157, -15.65477 27.27.93007,-15.65753 27.95894))',4258)));
but it doesn't work. What do I have to do?
A Polygon has a double parenthesis at the start and end, and inner rings are delineated by using single pairs of parenthesis, between commas, ie, ),( whereas a Linestring only has one set of parenthesis at the beginning and end. You are actually using the syntax for a MultiLinestring, which is probably where your issue is. You can fix you query like this:
insert into distritos(nombre, geom) values
('Distrito6', ST_GeomFromText('POLYGON((-15.66486 27.91996,
-15.60610 27.91820, -15.60359 27.97169, -15.66586 27.97144,-15.66486 27.91996),
(-15.65753 27.95894, -15.61610 27.95995, -15.61459 27.93157,
-15.65477 27.93007,-15.65753 27.95894))',4258));
Also, you do not need to use ST_MakePolygon, as if you are using ST_GeomFromText, you can create the polygon directly by using POLYGON instead of LINESTRING in your example above. ST_MakePolygon is probably more useful when you have arrays of Linestrings representing inner rings.
The Wikipedia WKT article details this very clearly, with WKT and accompanying graphics.
NOTE: You also have an error in you linestring, you have a repeated 27. in 27.27.93007.

Point in polygon algorithm for SQL Server

I'm trying to write a SQL query which determine if a given point is into a polygon. (I'm using SQL Server 2008 R2).
I was following this tutorial (just copy / paste it and change some table name) and it approximatively works BUT it is not precise at all. For example, let's considerate a given point which coordinates are :
P = 45.7664, 4.87383.
If you draw a little polygon (an approximate square) around this point with 4 vertices coordinates :
S = 45.97215 4.693909, 45.687 4.674683, 45.73302 5.460205, 46.05227 5.366821, 45.97215 4.693909
the procedure given in the link below answers the point is NOT in polygon, whereas it is...
This is the output (with my own formatting text) :
(Polygon 20 is the polygon above)
But if you enlarged the square (10 times bigger in my test), the procedure answers my point is in the square.
So, I'm seeking for another algorithm, more precise.
Here is my VERTICE table, containing all vertices coordinates of each polygon of my DB
I need to check, for ALL polygons (there are a few thousands) if a given point passed in parameter is in a polygon (and if yes, which one(s)). I can do the loop by myself, but I miss a correct Point in polygon algorithm.
Could someone help me ?
Thank you very much.
SUMMARY
The corresponding SQL fiddle : http://sqlfiddle.com/#!3/0caa4/1
Your problem is that you've defined the polygon backwards. Let's explore this with the native SQL geography types
declare #s geography, #t geography, #p geography;
select #s = geography::STPolyFromText('POLYGON((45.97215 4.693909, 45.687 4.674683, 45.73302 5.460205, 46.05227 5.366821, 45.97215 4.693909))', 4326);
select #t = geography::STPolyFromText('POLYGON((46.05227 5.366821, 45.73302 5.460205, 45.687 4.674683, 45.97215 4.693909, 46.05227 5.366821))', 4326);
select #p = geography::STPointFromText('POINT(45.7664 4.87383)', 4326);
select #p.STIntersects(#s), #p.STIntersects(#t);
select #p.STBuffer(10), #s, #t;
As you can see, #s holds pretty much the whole world. In the result set viewer, if you zoom into where your "square" should be, you'll find a hole. Contrast that with #t which is the area that you expect. Also note that I ran this in SQL 2012 which improved on a limitation that existed pre-2012 that says that a geospatial instance can't cross a hemisphere boundary. If you run the above on a 2008 instance, you'll likely get an error to that effect for #s. Comment out the line defining #s and it'll run.
There's a "right-hand" rule when defining geo(graphy/metry) polygons. Imagine that you were in a car visiting the points in the order you've specified. The area that you're defining is what you'd see if you were looking out the right side of the car.

PostGIS point attributes to polygons, where poligon contain point

I have a polygon database (bdus) and a point database (bdps) under the same schema in PostGIS. These databases were imported from shapefiles with the Shapefile and DBF loader. What I want to do is to join the point attributes on the polygon layer based on the contain criteria.
So for every polygon that contain one to n points, to add the columns of points to polygons. If there are more than one point a good approach would be to average column values.
Can someone guide me? I am new to PostGreSQL and PostGIS but I managed to run this query
SELECT * FROM bdps
JOIN
bdus
ON
ST_Contains(bdus.the_geom, bdps.the_geom);
which return a table with bdps joined with the corresponding bdus, but I want the reverse.
Thanks in advance for any help!
Did you meant, that you want to create a new polygon with the polygon and the points that satisfy the ST_Contains(polys, points) criteria?
SELECT ST_Union(bdus.the_geom, bdps.the_geom) FROM bdus,bdps WHERE
ST_Contains(bdus.the_geom, bdps.the_geom);

Resources