00001
00002
00003 """
00004 This module contains code to plan coverage paths
00005 """
00006
00007 from shapely.geometry import Point, Polygon, LineString
00008 from shapely.geometry import MultiLineString, MultiPoint
00009 from shapely.geometry import GeometryCollection
00010 from shapely.geos import TopologicalError
00011 import math
00012 import numpy as np
00013 from copy import deepcopy
00014
00015 from pprint import pprint
00016
00017 from logging import error
00018
00019 def generate_intersections(poly, width):
00020 "Subdivide a filed into coverage lines."
00021 starting_breakdown = poly.bounds[0:2]
00022 line = LineString([starting_breakdown, (starting_breakdown[0],
00023 starting_breakdown[1] +
00024 poly.bounds[3] - poly.bounds[1])])
00025 try:
00026 bounded_line = poly.intersection(line)
00027 except TopologicalError as e:
00028 error("Problem looking for intersection.", exc_info=1)
00029 return
00030 lines = [bounded_line]
00031 iterations = int(math.ceil((poly.bounds[2] - poly.bounds[0]) / width)) + 1
00032 for x in range(1, iterations):
00033 bounded_line = line.parallel_offset(x * width, 'right')
00034 if poly.intersects(bounded_line):
00035 try:
00036 bounded_line = poly.intersection(bounded_line)
00037 except TopologicalError as e:
00038 error("Problem looking for intersection.", exc_info=1)
00039 continue
00040 lines.append(bounded_line)
00041 return lines
00042
00043 def sort_to(point, list):
00044 "Sorts a set of points by distance to a point"
00045 l = deepcopy(list)
00046 l.sort(lambda x, y: cmp(x.distance(Point(*point)),
00047 y.distance(Point(*point))))
00048 return l
00049
00050 def get_furthest(ps, origin):
00051 "Get a point along a line furthest away from a given point"
00052 orig_point = Point(*origin)
00053 return sorted(ps, lambda x, y: cmp(orig_point.distance(Point(*x)),
00054 orig_point.distance(Point(*y))))
00055
00056 def order_points(lines, initial_origin):
00057 "Return a list of points in a given coverage path order"
00058 origin = initial_origin
00059 results = []
00060 while True:
00061 if not len(lines):
00062 break
00063 lines = sort_to(origin, lines)
00064 f = lines.pop(0)
00065 if type(f) == GeometryCollection:
00066 continue
00067 if type(f) == MultiLineString:
00068 for ln in f:
00069 lines.append(ln)
00070 continue
00071 if type(f) == Point or type(f) == MultiPoint:
00072 continue
00073 xs, ys = f.xy
00074 ps = zip(xs, ys)
00075 (start, end) = get_furthest(ps, origin)
00076 results.append(origin)
00077
00078 results.append(start)
00079
00080 origin = end
00081 return results
00082
00083 def bottom_left(points):
00084 """returns the bottom left point from the list of points given"""
00085 pass
00086
00087 def decompose(polygon, origin=None, width=1.0):
00088 """
00089 Decompose the field into a list of points to cover the field.
00090 """
00091 p = generate_intersections(polygon, width)
00092 if origin == None:
00093 return order_points(p, polygon.bounds[0:2])
00094 else:
00095 return order_points(p, origin)
00096
00097 if __name__ == '__main__':
00098 from maptools import RotationTransform, rotation_tf_from_longest_edge
00099 from maptools import rotate_polygon_to, make_axis, plot_polygon
00100 from maptools import zoom_extents, rotate_from, plot_line, rotate_to
00101
00102 ext = [(1, 1), (-3, 11), (4, 16), (10, 10)]
00103 polygon = Polygon(ext)
00104 polygon_points = np.array(polygon.exterior)
00105
00106 rt = RotationTransform(66)
00107
00108 tf_polygon = rotate_polygon_to(polygon, rt)
00109
00110 origin = rotate_to(np.array([(1,1)]),rt).tolist()
00111
00112 from time import time; start = time()
00113 result = decompose(tf_polygon, origin, width=0.5)
00114 print "Decomposition Time:", time()-start
00115
00116 tf_result = rotate_from(np.array(result), rt)
00117
00118 ll = LineString(tf_result)
00119
00120 ax, _ = make_axis()
00121 plot_polygon(polygon, ax, color='blue')
00122 plot_polygon(tf_polygon, ax, color='blue')
00123 plot_line(ll, ax)
00124 ax.axvline(x=0, color='black')
00125 ax.axhline(y=0, color='black')
00126 zoom_extents(ax, [polygon,tf_polygon])
00127 import pylab; pylab.show()