Find the points using Oracle spatial directly in front of a polgon - database

I have many polygons and many points and want to find the point such that when a line is drawn between that point and the polygon it does not intersect with any other polygon. So basically I need a point that is very close to the polygon and no other polygon is between them.
I tried the following query and it gives me all the points whether or not they are being intersected by a polygon or not.
SELECT P.POINTLOC from pointTable P WHERE NOT MDSYS.SDO_OVERLAPBDYINTERSECT(P.POINTLOC," +
"MDSYS.SDO_GEOMETRY(2003,null,null,MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,1)," +
"MDSYS.SDO_ORDINATE_ARRAY(4, 226, 150, 254, 164, 240, 191, 212, 176,4,226))) = 'TRUE'";
Then I tried this query and it gives some correct points but miss a few correct points:
SELECT P.POINTLOC from pointTable P WHERE MDSYS.SDO_WITHIN_DISTANCE(P.POINTLOC," +
"MDSYS.SDO_GEOMETRY(2003,null,null,MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,1)," +
"MDSYS.SDO_ORDINATE_ARRAY(4, 226, 150, 254, 164, 240, 191, 212, 176,4,226)),'distance = 40') = 'TRUE'";
Can some one point out which Oracle spatial operator would be best suited for this situation?

It sounds like you're looking for a Nearest Neighbour implementation - Oracle provides the Spatial operator SDO_NN.
You can find more details here:
http://docs.oracle.com/database/121/SPATL/sdo_operat.htm#SPATL1032
This will only get you so far, in that it'll find the nearest point to a polygon, but it won't guarantee that there are no polygons between your point and your target polygon. I suspect if you want to ensure this, you'll have have to get creative.
My approach would be:
use SDO_NN to get the closest point or points
use SDO_GEOM.SDO_CENTROID to find the polygon centre of gravity
create an in-query/in-memory SDO_GEOMETRY line that joins the two points
use this as the basis of a NOT EXISTS clause to exclude points where a polygon intersects that line
Something like the following untested / not-quite finished example, perhaps:
SELECT *
FROM points pnt
WHERE sdo_nn(pnt.point, sdo_geometry(your polygon here)) = 'TRUE' -- fill this with your polygon
AND NOT EXISTS (
SELECT 1
FROM polygons plg
WHERE sdo_geom.sdo_intersection(
plg.polygon
, sdo_geometry(
2002
, NULL -- oracle srid
, NULL -- point
, sdo_elem_info_array(1, 2, 1) -- line
, sdo_ordinate_array(
, sdo_geom.sdo_centroid(
sdo_geometry(your polygon here) -- fill this with your polygon
, 0.05
).x
, sdo_geom.sdo_centroid(
sdo_geometry(your polygon here) -- fill this with your polygon
, 0.05 -- tolerance
).t
, pnt.point.sdo_point.x
, pnt.point.sdo_point.y
) -- line between point and polygon centroid
)
, 0.05 -- tolerance
) = 'TRUE'
)
Depending on your dataset/performance, you might want to do some of this in PL/SQL using collections or loops.
The example above is a bit rough and ready, but I hope you get the gist.

Related

SQL Server Polygon format

SELECT TOP 1 KMLLocation FROM Polygon
Result: 0xE61000000104210000004ACE893DB4BF19403EB2B96A9EFF534082919735B1C0194039807EDFBFFF534052F17F4754C81940976F7D586F0054405AD76839D0D31940AED3484BE50054409E961FB8CAD3194087BF266BD40054403F90BC7328D3194071C806D2C5005440844A5CC7B8D21940E4D70FB1C100544014CE6E2D93D1194062BF27D6A90054404FB2D5E594D01940E27668588C005440E910381268D01940E7E26F7B820054409AEAC9FCA3CF1940A54E4013610054409432A9A10DD01940CD902A8A5700544015E126A3CAD01940FE0E45813E0054407FBDC282FBD11940C30DF8FC30005440EB1B98DC28D2194038312427130054403065E08096CE19404A7CEE04FBFF534082035ABA82CD1940C2F7FE06EDFF5340462234828DCB19409373620FEDFF534031B2648EE5CD1940E338F06AB9FF5340CFDC43C2F7CE1940321EA5129EFF5340B98C9B1A68CE194055A3570394FF5340A8E15B5837CE1940639CBF0985FF53403868AF3E1ECA1940001FBC7669FF534029CB10C7BAC81940ED9C668176FF5340C6DB4AAFCDC61940AD18AE0E80FF534047CCECF318C51940F390291F82FF5340EDB776A224C41940FD851E317AFF5340E4F90CA837C31940C440D7BE80FF5340DF1AD82AC1C21940462234828DFF53409C69C2F693C1194007D2C5A695FF5340C5387F130AC119406AFB57569AFF5340D1E7A38CB8C01940574277499CFF53404ACE893DB4BF19403EB2B96A9EFF534001000000020000000001000000FFFFFFFF0000000003
SELECT TOP 1 KMLLocation .ToString() FROM Polygon
Result:
POLYGON ((79.994044 6.437211, 79.996086 6.438176, 80.006796 6.445634, 80.013995 6.456849...
Expected Result:
POLYGON ((6.437211 79.994044, 6.438176 79.996086, 6.445634 80.006796, 6.456849, 80.013995...
How do I swap Lat and Long from geography polygon?
Here's what I came up with:
DECLARE #g GEOGRAPHY = /* your hex representation from above */
#new VARCHAR(MAX);
WITH points AS (
SELECT #g.STPointN(n.n) AS p, n
FROM tempdb.dbo.Numbers AS n
WHERE n <= #g.STNumPoints()
)
SELECT #new = CONCAT('POLYGON((', (
SELECT STRING_AGG(CONCAT(p.Lat, ' ', p.Long), ',') WITHIN GROUP (ORDER BY p.n)
FROM points AS p
), '))')
SELECT geography::STGeomFromText(#new, #g.STSrid).ReorientObject();
It's pretty straightforward. I'm creating a common table expression (CTE) to decompose the existing polygon into its constituent corners using a numbers (or tally) table. All that is is a table with one column with integers from 1 to some large number. It's helpful for cases like this. From there, I'm swapping the latitude and longitude of the points and then re-assembling them into the WKT for the polygon. Lastly, I'm creating an actual geography instance from the WKT. Note - I'm calling ReorientObject() as the new polygon appears to suffer from a ring orientation problem insofar as it defined the whole globe with a small hole in it (the shape of your polygon).

PostGIS Raster compute min, max altitude value and slope from a DEM

I have a DEM dataset and some polygons that represents parcels. For each parcels I would like to compute the maximum/minimum altitude and the average slope. Based on the PostGIS documentation and several example on Internet, two functions could be used to compute this data. The first one is ST_SummaryStatsAgg and the other is ST_DumpAsPolygons.
So, I've created a trigger that computes, before a new parcel is inserted, some statistics, but I am confused about the results. Here is my code:
--First cut the raster based on the parcel shape
SELECT INTO __rasterClip
ST_Union(ST_Clip(foncier.reunion_mnt.rast, NEW.geom, -9999, TRUE))
FROM foncier.reunion_mnt
WHERE NEW.geom && foncier.reunion_mnt.rast;
--Compute slope with ST_DumpAsPolygons OR ST_SummaryStatsAgg
SELECT INTO __slope1 (ST_DumpAsPolygons(ST_Slope(__rasterClip, 1, '32BF', 'DEGREES', 1.0))).val;
SELECT INTO __slope2 (ST_SummaryStatsAgg(ST_Slope(__rasterClip, 1, '32BF', 'DEGREES', 1.0), 1, TRUE, 1)).max;
RAISE NOTICE 'Slope1 %', MAX(__slope1 );
RAISE NOTICE 'Slope2 %', __slope2;
--Compute min/max altitude
SELECT INTO __rasterStats (ST_SummaryStatsAgg(__rasterClip, 1, TRUE, 1)).*;
SELECT INTO __polyDump (ST_DumpAsPolygons(__rasterClip, 1, TRUE)).*;
RAISE NOTICE 'Stat % - %', __rasterStats.min, __rasterStats.max;
RAISE NOTICE 'Poly % - %', Min( __polyDump.val ), Max( __polyDump.val );
The results of the RAISE NOTICE:
NOTICE: Slope1 5.14276456832886
NOTICE: Slope2 51.9147148132324
NOTICE: Stat 222.76 - 251.22
NOTICE: Poly 225.929992675781 - 225.929992675781
There is clearly something wrong. The slope between the two functions is not the same and the min and max altitude for the ST_DumpAsPolygons is the same.
So could you please help me and tell me:
What is the most effective way to compute the min/max altitude and the average slope for a parcel based on a raster DEM?
For my general knowledge is it best to use ST_SummaryStatsAgg or ST_DumpAsPolygons. In which case is it best to use on or the other?
In a trigger how to declare the variable type of these two functions (ST_SummaryStatsAgg, ST_DumpAsPolygons). My first attempt was to declare them using their return type (summarystats and geomval). But I was getting errors so I switch to Record. Is it correct?
Thanks for your help!

How to expand a polygon to reach a nearby line

I would like to expand a polygon so that it fills an empty space between itself and a nearby (and touching in two points) line, as in the image posted here. As you can see the blue linestring makes an empty space on top of the pink polygon and I want to fill it with the polygon. Is there a postgis solution to this ? I havent' found any "easy" way.
Thanks !
The solution is similar to the one I presented here. Only in this case you need to buff up the linestring a bit.
WITH p AS (
SELECT ST_MakePolygon(ST_GeomFromText('LINESTRING(0 0,1 0,1 1, 0 1, 0 0)')) as geo
),
l AS (
SELECT ST_BUFFER(ST_GeomFromText('LINESTRING(0.0 0.0,0.5 0, 0.7 -1, 1 0)'),0.000000000000001) as geo
),
bigpoly AS(
SELECT ST_UNION(geo) as geom
FROM(
SELECT geo FROM p
UNION ALL
SELECT geo FROM l) as q
)
SELECT ST_BUFFER(ST_BuildArea(ST_InteriorRingN(geom,i)),0.000000000000001) as geo
FROM bigpoly
CROSS JOIN generate_series(1,(SELECT ST_NumInteriorRings(geom) FROM bigpoly)) as i
This will give you the missing piece, now you just need to ST_UNION it with the rest, you might also want to check if it's really a correct one if your original polygon contains holes.

Point on a polygon boundary using postgis & geodjango

I have point data and multipolygon data in tables. How can I find points lying on multipolygon boundary using postgis and in geodjango?
I can't help you with geodjango, but I can give you a PostGIS query.
SELECT ST_Contains(ST_Boundary(ST_GeomFromText('POLYGON((1 1,0 0, -1 1, 1 1))')),
ST_GeomFromText(points.g))
FROM UNNEST(ARRAY['POINT(1 1)', 'POINT(0 1)']) points (g)
The key is to use ST_Boundary to get the polygon's boundary and check if that contains the point.
You can just use PostGIS SQL I guess:
SELECT points,area from points_table,area WHERE
area_geometry && points
AND ST_Contains(area_geometry,points)
Use ST_Covers it contains own boundary. But be careful in that case one point can be included by many (multi)polygons.
SELECT ST_Covers(ST_GeomFromText('POLYGON((1 1,0 0, -1 1, 1 1))'),
ST_GeomFromText(points.g))
FROM UNNEST(ARRAY['POINT(1 1)', 'POINT(0 1)', 'POINT(0 0.5)']) points (g)

STintersects() to find the Intersection point

I have two sql server geometry-ies which I am using to check if they intersect. If they do I need the intersection point.
Currently I can get only Boolean output where if it intersects = 1 and if it does not intersect it will give =0 . Is there any way I can find the intersection of two shapes in geometry?
Update this question led to my next question concerning how can one check if a point (lat/long) exists in a region which has 4000 points (lat/long). Can one use stcontains or stintersects on geography?
sql - STContains on Geography column
DECLARE #line1 GEOMETRY = geometry::STGeomFromText('LINESTRING(0 0, 1 1)', 0)
DECLARE #line2 GEOMETRY = geometry::STGeomFromText('LINESTRING(1 0, 0 1)', 0)
SELECT #line1.STIntersection(#line2).ToString()

Resources