You have many solutions but you choose to use ogr and the GeoJSON format (you could have chosen Fiona and shapely or one of the many modules to parse gpx files: Pypi:gpx or to parse XML files).
1) Is there a more direct or idiomatic way to create this rectangle?
ogr is is verbose, look at Python GDAL/OGR Cookbook
With the GeoJSON format:
import json
polygs = {"type": "Polygon", "coordinates": [[[-51.22, -30.027, 0.0], [-51.22, -30.047, 0.0], [-51.18, -30.047, 0.0], [-51.18, -30.027, 0.0], [-51.22, -30.027, 0.0]]]}
poly = ogr.CreateGeometryFromJson(json.dumps(polygs))
With shapely and the wkt format:
from shapely.geometry import Polygon
polys = Polygon([(-51.22,-30.027, 0),(-51.22, -30.047, 0),(-51.18, -30.047, 0),(-51.18, -30.027, 0),(-51.22, -30.027, 0)])
poly = ogr.CreateGeometryFromWkt(polys.wkt)
2) Are all those "if not X: continue" statements the right way to check?
Use a single for loop to find the layers in a gpx file (replace your script for loops)
from osgeo import ogr
datasource = ogr.Open('my.gpx')
for i in range(datasource.GetLayerCount()):
print datasource.GetLayer(i).GetName()," :", datasource.GetLayer(i).GetFeatureCount()
waypoints : 0
routes : 0
tracks : 1
route_points : 0
track_points : 547
3) Exporting was the only way I found to get numeric values. Is there any other?
Examine the first layer with one feature: tracks
: what is the geometry ?
# geometry type
layer = datasource.GetLayerByName('tracks')
first = layer.GetFeature(0)
geom = first.GetGeometryRef()
print geom.GetGeometryName()
MULTILINESTRING
a) Processing with the GeoJSON format: define two simple functions to plot the lines and the multilines formats from GeoJSON coordinates with matplotlib (you don't need the segments computation)
def plot_line(ax, ob, col):
x,y = zip(*[(j[0],j[1]) for j in ob])
ax.plot(x, y, color=col)
def plot_multiline(ax, ob,col):
for line in ob:
plot_line(ax,line,col)
Plot the feature
# transform the geometry to GeoJSON format
import json
geomjson = json.loads(geom.ExportToJson())
# plot the feature
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.gca()
geomcoor = geomjson['coordinates']
if geomjson['type'] == 'LineString':
plot_line(ax, a,'g')
if geomjson['type'] == 'MultiLineString':
plot_multiline(ax, a,'g')
Result:
If there are many features, use a simple for loop
b) Examine the second layer with features: tracks_points
(Points) and simple processing without the GeoJSON format
layer2 = datasource.GetLayerByName('track_points')
fig = plt.figure()
ax = fig.gca()
for i in range(layer2.GetFeatureCount()):
point = layer2.GetFeature(i)
geom_point = point.GetGeometryRef()
x,y,z = geom_point.GetPoint()
ax.scatter(x,y)
Result:
It is easy to adapt these solutions with:
geometryfeature.GetGeometryRef().Intersection(poly)
New: solution with Fiona and shapely
import fiona
fiona.listlayers('my.gpx')
[u'waypoints', u'routes', u'tracks', u'route_points', u'track_points']
# open layer tracks
layer = fiona.open('my.gpx', layer='tracks')
geom = layer[0] # only one feature here)
geom['geometry']['type']
'MultiLineString'
# convert to shapely geometry
from shapely.geometry import shape, mapping
tracks = shape(geom['geometry'])
Polygon
polygs = {'type': 'Polygon', 'coordinates': [[(-79.159610379971326, 35.615399458474776), (-79.153546268732796, 35.615411586697256), (-79.153109652723629, 35.611215221720187), (-79.159392071966749, 35.611118195940371), (-79.159610379971326, 35.615399458474776)]]}
poly = shape(polygs)
Intersection:
geometry = poly.intersection(tracks)
mapping(geometry)['type']
'MultiLineString'
Plot:
import matplotlib.pyplot as plt
from descartes.patch import PolygonPatch
def plot_poly(ax,ob):
patch = PolygonPatch(ob, facecolor='#6699cc', edgecolor='#6699cc')
ax.add_patch(patch)
def plot_line(ax, ob, col):
x, y = ob.xy
ax.plot(x, y, color=col)
def plot_multiline(ax, ob,col):
for line in ob:
plot_line(ax,line,col)
fig = plt.figure()
ax = fig.gca()
plot_multiline(ax, tracks,'b')
plot_poly(ax,poly)
plot_multiline(ax, geometry,'r')
Result:
And you can save the resulting shapefile:
schema = {'geometry': 'MultiLineString','properties': {'test': 'int'}}
with fiona.open('intersect.shp', 'w', 'ESRI Shapefile', schema) as output:
feature = {'geometry': {'coordinates': mapping(geometry)['coordinates'] ,'type': 'MultiLineString'},'properties': {'test': 1}}
output.write(feature)