maptools.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 """
00004 Contains utilities for working with maps and field shapes.
00005 """
00006 
00007 import itertools
00008 import numpy as np
00009 from PIL import Image
00010 from shapely.geometry import Polygon, LineString
00011 from matplotlib.collections import LineCollection
00012 from math import cos, sin, sqrt, atan, degrees, radians
00013 
00014 ##### Numpy-PIL Functions #####
00015 def image2array(im):
00016     if im.mode not in ("L", "F"):
00017         raise ValueError, "can only convert single-layer images"
00018     if im.mode == "L":
00019         a = np.fromstring(im.tostring(), dtype=np.uint8)
00020     else:
00021         a = np.fromstring(im.tostring(), dtype=np.float32)
00022     a.shape = im.size[1], im.size[0]
00023     return a
00024 
00025 def array2image(a):
00026     if a.typecode() == np.uint8:
00027         mode = "L"
00028     elif a.typecode() == np.float32:
00029         mode = "F"
00030     else:
00031         raise ValueError, "unsupported image mode %s"%(a.typecode())
00032     return Image.fromstring(mode, (a.shape[1], a.shape[0]), a.tostring())
00033 
00034 
00035 ##### Numpy-Shapely Functions #####
00036 def ndarray2polygon(points):
00037     if type(points) != np.ndarray:
00038         raise TypeError("ndarray2polygon: takes an numpy.ndarray")
00039     new_tuples = []
00040     for point in points:
00041         new_tuples.append((float(point[0]),float(point[1])))
00042     return Polygon(new_tuples)
00043 
00044 
00045 ##### Rotation Transformations #####
00046 class RotationTransform:
00047     """Represents a rotational transform"""
00048     def __init__(self, angle):
00049         self.angle = angle
00050         self.w = radians(self.angle)
00051         self.irm = np.mat([[cos(self.w), -sin(self.w), 0.0],
00052                            [sin(self.w), cos(self.w),  0.0],
00053                            [0.0,         0.0,          1.0]])
00054     
00055 
00056 def rotation_tf_from_longest_edge(polygon):
00057     """Returns a rotation tf for the longest edge of the given polygon"""
00058     max_distance = None
00059     max_points = [(None, None),(None, None)]
00060     # Find the longest edge and the points that make it
00061     xs, ys = polygon.exterior.xy
00062     points = zip(xs, ys)
00063     for i in range(len(points)):
00064         if i == len(points)-1:
00065             pair = (points[i],points[0])
00066         else:
00067             pair = (points[i],points[i+1])
00068         distance = sqrt((pair[1][0]-pair[0][0])**2+(pair[1][1]-pair[0][1])**2)
00069         if max_distance == None or max_distance < distance:
00070             max_distance = distance
00071             max_points = pair
00072     # Calculate the angle and return the rotation tf
00073     dy = float(max_points[0][1] - max_points[1][1])
00074     dx = float(max_points[0][0] - max_points[1][0])
00075     return RotationTransform((degrees(atan(dy/dx))))
00076 
00077 def rotate_polygon_to(polygon, rotation_transform):
00078     """Takes a polygon and a rotation, returns a rotated polygon"""
00079     points = np.array(polygon.exterior)
00080     tf_points = rotate_to(points, rotation_transform)
00081     return ndarray2polygon(tf_points)
00082 
00083 def rotate_polygon_from(polygon, rotation_transform):
00084     """Takes a polygon and a rotation, returns an inverse rotated polygon"""
00085     points = np.array(polygon.exterior)
00086     tf_points = rotate_from(points, rotation_transform)
00087     return ndarray2polygon(tf_points)
00088 
00089 def rotate_to(points, rotation_transform):
00090     """Rotates an ndarray of given points(x,y) to a given rotation"""
00091     if type(points) != np.ndarray:
00092         raise TypeError("rotate_to: takes an numpy.ndarray")
00093     new_points = []
00094     for point in points:
00095         point_mat = np.mat([[point[0]],[point[1]],[0]], dtype='float64')
00096         new_point = rotation_transform.irm * point_mat
00097         new_points.append(np.array(new_point[:-1].T, dtype='float64'))
00098     return np.squeeze(np.array(new_points, dtype='float64'))
00099 
00100 def rotate_from(points, rotation_transform):
00101     """Rotate an ndarray of given points(x,y) from a given rotation"""
00102     if type(points) != np.ndarray:
00103         raise TypeError("rotate_from: takes an numpy.ndarray")
00104     new_points = []
00105     for point in points:
00106         point_mat = np.mat([[point[0]],[point[1]],[0]], dtype='float64')
00107         new_point = rotation_transform.irm.I * point_mat
00108         new_points.append(np.array(new_point[:-1].T, dtype='float64'))
00109     return np.squeeze(np.array(new_points, dtype='float64'))
00110 
00111 
00112 ##### Plotting Tools #####
00113 
00114 def zoom_extents(ax, polygons, buff=1.0):
00115     """Sets the axis to view all polygons given"""
00116     min_x = None
00117     max_x = None
00118     min_y = None
00119     max_y = None
00120     for polygon in polygons:
00121         bounds = polygon.bounds
00122         if min_x == None or bounds[0] < min_x:
00123             min_x = bounds[0]
00124         if min_y == None or bounds[1] < min_y:
00125             min_y = bounds[1]
00126         if max_x == None or bounds[2] > max_x:
00127             max_x = bounds[2]
00128         if max_y == None or bounds[3] > max_y:
00129             max_y = bounds[3]
00130     ax.set_xlim(min_x-buff,max_x+buff)
00131     ax.set_ylim(min_y-buff,max_y+buff)
00132     ax.set_aspect(1)
00133 
00134 def make_axis():
00135     from pylab import plot, figure
00136     return figure(1, dpi=90).add_subplot(111), True
00137 
00138 def plot_lines(lines, ax=None, color='#6699cc', alpha=1.0):
00139     import matplotlib.pyplot as pyplot
00140     show = False
00141     if ax == None:
00142         ax, show = make_axis()
00143     x, y = line.xy
00144     t = np.linspace(0, 10, len(x))
00145     lc = LineCollection(lines, cmap=pyplot.get_cmap('hot'),
00146                                norm=pyplot.Normalize(0, 20))
00147     ax.add_collection(lc)
00148     lc.set_array(t)
00149     lc.set_linewidth(2)
00150     if show:
00151         import pylab; pylab.show()
00152 
00153 def plot_line(line, ax=None, color='#6699cc', alpha=1.0):
00154     import matplotlib.pyplot as pyplot
00155     show = False
00156     if ax == None:
00157         ax, show = make_axis()
00158     x, y = line.xy
00159     lines = []
00160     for p in range(0, len(x), 2):
00161         lines.append(LineString([(x[p], y[p]), (x[p+1], y[p+1])]))
00162     t = np.linspace(12, 20, len(lines))
00163     lc = LineCollection(lines, cmap=pyplot.get_cmap('jet'),
00164                                norm=pyplot.Normalize(0, 20))
00165     ax.add_collection(lc)
00166     lc.set_array(t)
00167     lc.set_linewidth(2)
00168     if show:
00169         import pylab; pylab.show()
00170 
00171 def plot_coords(coords, ax=None, color='#999999', alpha=1.0):
00172     show = False
00173     if ax == None:
00174         ax, show = make_axis()
00175     x, y = coords.xy
00176     ax.plot(x, y, 'o', color=color, alpha=alpha, zorder=1)
00177     if show:
00178         import pylab; pylab.show()
00179 
00180 def plot_polygon(polygon, ax=None, color='#999999', alpha=1.0):
00181     show = False
00182     if ax == None:
00183         ax, show = make_axis()
00184     x,y = polygon.exterior.xy
00185     ax.plot(x,y, color=color, alpha=alpha)
00186     ax.set_xlim(min(x)-1,max(x)+1)
00187     ax.set_ylim(min(y)-1,max(y)+1)
00188     ax.set_aspect(1)
00189     if show:
00190         import pylab; pylab.show()
00191 
00192 
00193 ##### Tests #####
00194 if __name__ == '__main__':
00195     ext = [(1, 1), (-3, 11), (4, 16), (10, 10)]
00196     polygon = Polygon(ext)
00197     polygon_points = np.array(polygon.exterior)
00198     
00199     rt = rotation_tf_from_longest_edge(polygon)
00200     print rt.angle
00201     print rt.w
00202     
00203     tf_points = rotate_to(polygon_points, rt)
00204     tf_polygon = ndarray2polygon(tf_points)
00205     
00206     ax, _ = make_axis()
00207     plot_polygon(polygon, ax, color='blue')
00208     plot_polygon(tf_polygon, ax, color='red')
00209     ax.axvline(x=0, color='black')
00210     ax.axhline(y=0, color='black')
00211     zoom_extents(ax, [polygon,tf_polygon])
00212     import pylab; pylab.show()
00213     


heatmap
Author(s): Adrian Bauer
autogenerated on Thu Feb 11 2016 23:05:26