GIS Cookie Cutting Library/Algorithms? - gis

Is there an open source GIS library available that provides cookie cutting? I have a series of polygons that are to be the cookie cutters, and then I have a series of geometries that I want to divide based on their location within the cookie cutting polygons.
If there's no library, is there a fairly simple algorithm for cookie cutting polygons? Points are easy, using OGR for example you can just loop through all polygons calling Contains() on each point. Lines are more difficult but seems reasonably straightforward using Intersection() and creating new lines with that.
Polygons strike me as using the same basic concepts, but more work. I was hoping someone already did this and made it public. Any thoughts?
Thanks much in advance.

Nevermind, OGR's Intersection() function returns lines/polygons if that's the intersection.
So if poly1 = [ (0,0), (1,0), (1,1) (0,1) ]
and poly2 = [ (0.5,0), (1.5,0), (1.5,1), (0.5,1) ]
then poly1.Intersection(poly2) returns [ (1,0), (0.5,0), (0.5,1), (1,1) ]
So the algorithm in Python would just be:
new_geometries = []
For cutting_poly in cookie_cutter_polygons:
For g in all_geometries:
new_geometries.append(cutting_poly.Intersection(g))
Hope that helps someone.

Related

Converting a geopandas geometry into a shapleys polygon

I am extremely new to python in general, but come from a decent programming background in Fortran and Matlab. I'm trying to figure out what seems to be a simple task:
I am importing a Shapefile using GeoPandas read_file command. It comes in with no problem, and includes the geometry column that contains the polygon represented by all the vertices as you would expect. The data is a single row.
What I need is a Shapely's Polygon to pass into py3dep so I can gather the spatial rasters I need, and I cannot figure out how to translate the geometry entry into a polygon.
The solution has to be simple, but I've been searching for hours, trying a thousand different things, all to no avail. If anyone could help with a simple demonstration I'd be eternally grateful.
Here's a snippet of what I'm trying to do, I've verified the code works when I pass it the tuple, and fails if I try to pass "shape" to "geom" as shape is not a shapelys polygon. (I understand this is a lame attempt and is just shown as "what I'm trying to do")
UPDATED CODE BELOW TO WORKING based on solution provided by #PaulH
import py3dep
import geopandas as gpd
shape = gpd.read_file("inputshape.shp")
print(shape.type)
geom = shape.loc[0, 'geometry']
dem = py3dep.get_map("DEM", geom, resolution=10, geo_crs="epsg:4326", crs="epsg:3857", output_dir="raster")

Leaflet markercluster: How can I change the bounds of the markercluster?

For university I create a webmap using leaflet - it´s about migration in Iraq. In the map I have one choropleth-layer with coordinates from a json (Iraq with its gouvernorates) with a value for each gouvernorate. Additionally I added a layer with markers from another json to the map. This json only contains the coordinates for markers with a value for each marker. I implemented a leaflet markerclustering where all child markers are summarized and the sum is shown in the parent-icon - although the sum isn´t correct until now, I think it is working, so far... I am allready looking for the mathematical error...
Now, I would like to change the bounds for the marker-clustering (currently I think they are built automatically and randomly by leaflet) to the bounds of the gouvernorates in the first json of Iraq. The aim is a regionbound clustering for the gouvernorates of Iraq. There are some examples on the web and I have tried a lot, but it doesn´t work...
maybe somebody here can help me.. If you have any questions or need further explanation, just tell me!
Sources:
- json code in an js-file "iraq_09_14.js" with the gouvernorate-polygon-coordinates of Iraq
json code in an js-file "target-location_09_14.js" with marker-polygones and value for each marker
this is the js-code where I create the leaflet map
this is the js-code where I create the markerclusters with the sum of the values
I would like to change the bounds for the marker-clustering [...] to the bounds of the gouvernorates in the first json of Iraq.
Then create one instance of MarkerClusterGroup per governorate, and add each marker to the corresponding cluster group.
This json only contains the coordinates for markers with a value for each marker.
You should really pre-process the data, so each marker has information about what governorate it belongs to. You might want to do point-in-polygon geoprocessing, via Turf or otherwise.
(currently I think [the clusters] are built automatically and randomly by leaflet)
They are not random, the hierarchical greedy clustering algorithm is deterministic. You can read more at https://www.mapbox.com/blog/supercluster/

Google maps web services/JavaScript API - problems with the bounding boxes

I need to get a decent bounding box for any given city. As of now, I know of no way to do it, but through the google maps API geocode function. However, there are problems.
For instance, consider Abu Dhabi.
Here is the code (using python googlemaps package):
>>> d = gmaps.geocode('Abu Dhabi, AE')
>>> pp.pprint(d)
{ u'Placemark': [ { u'AddressDetails': { u'Accuracy': 4,
u'Country': { u'AdministrativeArea': { u'AdministrativeAreaName': u'Abu Dhabi',
u'Locality': { u'LocalityName': u'Abu Dhabi'}},
u'CountryName': u'United Arab Emirates',
u'CountryNameCode': u'AE'}},
u'ExtendedData': { u'LatLonBox': { u'east': 54.8789043,
u'north': 24.7912388,
u'south': 24.1412558,
u'west': 53.8544291}},
u'Point': { u'coordinates': [54.3666667, 24.4666667, 0]},
u'address': u'Abu Dhabi - United Arab Emirates',
u'id': u'p1'}],
u'Status': { u'code': 200, u'request': u'geocode'},
u'name': u'Abu Dhabi, AE'}
The problem is that the returned LatLonBox is way too large - its diagonal is more than 126km long. With all due respect to Abu Dhabi, I do not think the city is that big.
Interestingly enough, the JavaScript API returns two boxes. Assuming results is the result of invoking google.maps.Geocoder.geocode on 'Abu Dhabi', we have two boxes:
results[0].geometry.bounds = ((24.1776, 54.30012), (24.5413, 54.7751))
results[0].geometry.viewport = ((24.1413, 53.8544), (24.7912, 54.8789))
Where the viewport is exactly the LatLonBox returned by the web services API. The bounds, on the other hand, looks much better both in terms of the size and the location - the below image depicts both boxes:
At first, I have suspected the python package to omit the bounds from the final result, but examining the json returned by the google maps web service reveals that no bounds box is returned by the web service - the python dictionary describing the result is an exact mirror of the returned json.
So, my question is how can I get a decent bounding box when using the web services API? Or is there an alternative API altogether? Does anyone have any experience with a non google maps API to get this kind of information?
Thanks.
EDIT
Another interesting twist. While some cities have huge bounding (or viewport) boxes, some have tiny ones. For instance, the diameter of one bounding Adelaide, AU is only 7km, which is, of course, too small:
You can use MySQL in the back-end and its Extensions for Spatial Data.
Envelope(g)
Returns the minimum bounding rectangle (MBR) for the geometry value g.
The result is returned as a Polygon value.
We used MySQL5.6 in a Geo search project and never looked back. Just make sure that you use MySQL 5.6 or higher for full Geo support.

Storing 3d shapes in sql server using geometry data type and WKT

I'm looking at the geometry data type in Sql Server 2008 and it looks interesting but the documentation does not seem that good. Would I be able to store cones, cylinders and spheres in the WKT format? These features traditionally have a radius and not hundreds of points.
To the best of my knowledge your are going to have to use an external application to render your shape as a large number of points. See this blog for a technique for rendering circles.
One possibility to consider is a CLR proc to render the shapes you need and a view with indexes. I don't know how well that will perform, but it just might work.
sorry for the late reply. You could always write your own User-Defined-Type called Circle, with two properties namely Centroid and Radius.
Inside the newly formed UDT, create a method that takes the properties Centroid (Point3D), and Radius (Double). After this, create a method that uses both SqlGeometry and SqlGeometryBuilder to build the newly formed object.
First, create a Point instance of Geometry. Inherit the Centroid values from the class object, then, create another Geometry Polygon that's derived from the Point object, and STBuffer(Radius) it.
Below is my example: (written in 30min)
public SqlGeometry ToSQLGeometry()
{
int srid = this.SRID; // i.e. 4326
SqlGeometry geom = new SqlGeometry();
SqlGeometryBuilder gb = new SqlGeometryBuilder();
OpenGisGeometryType pt = OpenGisGeometryType.Point;
gb.SetSrid(srid);
gb.BeginGeometry(pt);
gb.BeginFigure(this.Centroid.X, this.Centroid.Y, this.Centroid.Z, this.Centroid.M);
gb.EndFigure();
gb.EndGeometry();
geom = gb.ConstructedGeometry;
geom = geom.MakeValid(); // Optional for Point data
SqlGeometry geomCircle = new SqlGeometry();
geomCircle = geom.STBuffer(this.Radius);
return geomCircle;
}
When you've done this in VS2010 by using the CLR project type, you can deploy it to your database.
In SQL, you can call the object as such:: Parse(X Y Z M,R)
declare #c Circle
set #c = Circle::Parse('5 6 7 8,2')
select 'Circle', #c.ToString(), #c.ToSQLGeometry()
Had a quick look around and found this MSDN page on Spatial Samples. It covers all the Methods to enter data in WKT, WKB & XML(GML) as well as functions to view the in Human Readable form. It also covers MakeValid, STIsValid & STSrid.
There looks to be a fair few SQL examples that you may find useful

Saving and restoring geometries in OpenLayers

Context: I'm a just-hours-old newbie at OpenLayers, please be gentle.
Fundamentally, I have a map with some drawn objects on it. If I understand things correctly, I have a number of OpenLayer.Feature.Vector (layers?) with a number of OpenLayer.Geometry "things" (like LinearRing) on it.
At the moment, I seem to be able to get a nice representation of the geometry, using .toString(). Yes, I suspect I'm doing it wrong -- feel free to point me in the right direction.
This yields a very human readable, and database storable, strings such as:
POINT(-104.74560546875 44.2841796875)
POLYGON((-96.52783203125 44.6796875,-96.52783203125 45.734375,-92.22119140625 45.734375,-92.22119140625 44.6796875,-96.52783203125 44.6796875))
LINESTRING(-105.71240234375 44.6796875,-106.06396484375 42.658203125,-103.55908203125 42.7021484375,-103.47119140625 45.55859375,-104.65771484375 45.20703125)
Is there an inverse way of getting these back into the object format from whence they came?
I'd love to be using JSON, but can't seem to get GeoJSON to accept my OpenLayer.Feature.Vector object (which is what the CLASS_NAME property says it is when I peer inside).
Many thanks.
The Openlayers.Geometry objects’ toString method converts them nicely to WKT (Well-Known Text). If you use a GIS layer on top of your database (like PostGIS for PostGres, SQL Spatial for SQL Server, Spatialite for SQLite, etc.), they should offer functions that enable you to process WKT.
But if you want to convert that WKT to a new Openlayers.Geometry object (in the browser), you can use the fromWKT function:
var point = OpenLayers.Geometry.fromWKT('POINT(-104.74560546875 44.2841796875)');
alert(point.toString()); // POINT(-104.74560546875 44.2841796875)
Here, the variable point will now contain a new Openlayers.Geometry object, which has the same properties as the original one you used toString() on.
If you pass an array to the fromWKT function, it will return a GeometryCollection containing all the generated geometries.
var geometryTexts = [
'POINT(-104.74560546875 44.2841796875)'
, 'POLYGON((-96.52783203125 44.6796875,-96.52783203125 45.734375,-92.22119140625 45.734375,-92.22119140625 44.6796875,-96.52783203125 44.6796875))'
, 'LINESTRING(-105.71240234375 44.6796875,-106.06396484375 42.658203125,-103.55908203125 42.7021484375,-103.47119140625 45.55859375,-104.65771484375 45.20703125)'
],
collection = OpenLayers.Geometry.fromWKT(geometryTexts);
After this, collection.toString() should yield the following:
GEOMETRYCOLLECTION(POINT(-104.74560546875 44.2841796875),POLYGON((-96.52783203125 44.6796875,-96.52783203125 45.734375,-92.22119140625 45.734375,-92.22119140625 44.6796875,-96.52783203125 44.6796875)),LINESTRING(-105.71240234375 44.6796875,-106.06396484375 42.658203125,-103.55908203125 42.7021484375,-103.47119140625 45.55859375,-104.65771484375 45.20703125))
In my other answer, I went with WKT because you mentioned it. I now see that you seem to prefer GeoJSON.
To convert a vector layer or an Openlayers.Geometry object to a GeoJSON string, you should use the OpenLayers.Format.GeoJSON.write function:
var geoJSON = new OpenLayers.Format.GeoJSON(),
geoJSONText = geoJSON.write(geometryObject);
Note that you should be able to pass your object to this function, since (according to documentation) it accepts an OpenLayers.Feature.Vector as well as a OpenLayers.Geometry or an array of features.
Conversely, when you’ve got a GeoJSON string, you can convert that back to an object using the OpenLayers.Format.GeoJSON.read function:
var geometry = geoJSON.read(geoJSONText, 'Geometry');
The second parameter lets you indicate which type of object you’d like returned. Read the docs linked to for more information.
Also, take a look at this demo for a more extensive example. (View the source of the page to see how they’re doing it).