Advertisement
Marrin

tin_reducer_gml

Sep 23rd, 2013
183
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.00 KB | None | 0 0
  1. import time
  2. from functools import partial
  3. from itertools import chain, imap
  4. from osgeo import ogr
  5. from pywps.Process.Process import WPSProcess
  6.  
  7.  
  8. def iter_points(layer):
  9.     for feature in layer:
  10.         exterior_ring = feature.GetGeometryRef().GetGeometryRef(0)
  11.         for i in xrange(exterior_ring.GetPointCount()):
  12.             yield exterior_ring.GetPoint(i)
  13.  
  14.  
  15. def clean_points(points):
  16.     #
  17.     # Delete the last point of each triangle (we only need three point for our
  18.     # calculations)
  19.     #
  20.     # TODO: The code below has the effect of the original code but it doesn't
  21.     #       match the description above and it repeats points which will get
  22.     #       filtered out in a later processing step anyway.  I guess the
  23.     #       `drop_every_nth()` function below is actually wanted here instead.
  24.     #
  25.     points = iter(points)
  26.     try:
  27.         while True:
  28.             yield next(points)
  29.             next(points)
  30.             point = next(points)
  31.             yield point
  32.             yield point
  33.             next(points)
  34.     except StopIteration:
  35.         pass  # Ignored intentionally.
  36.  
  37.  
  38. def drop_every_nth(iterable, nth):
  39.     return (item for i, item in enumerate(iterable) if i % nth != 0)
  40.  
  41.  
  42. def calculate_mid_value(a, b):
  43.     return min(a, b) + abs(b - a) / 2.0
  44.  
  45.  
  46. def partition_points(points, bounding_box):
  47.     bbox_xmin, bbox_xmax, bbox_ymin, bbox_ymax = bounding_box
  48.     vertical_middle = calculate_mid_value(bbox_xmin, bbox_xmax)
  49.     horizontal_middle = calculate_mid_value(bbox_ymin, bbox_ymax)
  50.     result = [[list(), list()], [list(), list()]]
  51.     for point in points:
  52.         x, y, _ = point
  53.         #
  54.         # TODO: Points *on* the lines won't get filtered out here.  If that's
  55.         #       a bug we need an extra test here.
  56.         #
  57.         result[y < horizontal_middle][x < vertical_middle].append(point)
  58.  
  59.     for row in result:
  60.         for cell in row:
  61.             yield cell
  62.  
  63.  
  64. def distance(point_a, point_b):
  65.     return sum((a - b)**2 for a, b in zip(point_a, point_b))
  66.  
  67.  
  68. def filter_close_points(minimal_distance, points):
  69.     seen = set()
  70.     for point in points:
  71.         if (
  72.             point not in seen
  73.             and all(distance(point, p) >= minimal_distance for p in points)
  74.         ):
  75.             seen.add(point)
  76.             yield point
  77.  
  78.  
  79. def create_geometry(points):
  80.     geometry = ogr.Geometry(ogr.wkbMultiPoint)
  81.     wkb_point = ogr.Geometry(ogr.wkbPoint)
  82.     for point in points:
  83.         wkb_point.AddPoint(*point)
  84.         geometry.AddGeometry(wkb_point)
  85.     return geometry
  86.  
  87.  
  88. class Process(WPSProcess):
  89.     def __init__(self):
  90.         WPSProcess.__init__(
  91.             self,
  92.             identifier=__name__,
  93.             title='Pollmueller Tin-Reducer',
  94.             version = '0.1',
  95.             storeSupported='true',
  96.             statusSupported='true',
  97.             abstract=(
  98.                 'reduces the points of a given triangulated irregular network'
  99.                 ' by a variable factor'
  100.             ),
  101.             grassLocation=False
  102.         )
  103.         self.data_output = self.addComplexOutput(
  104.             identifier='output',
  105.             title='Output vector data',
  106.             formats=[{'mimeType': 'text/xml'}]
  107.         )
  108.         self.time_output = self.addLiteralOutput(
  109.             identifier='output2',
  110.             title='computation time (to compare different approaches)'
  111.         )
  112.         self.data_filename_input = self.addComplexInput(
  113.             identifier='data',
  114.             title='Input vector data',
  115.             formats=[{'mimeType': 'text/xml'}]
  116.         )
  117.         self.minimal_distance_input = self.addLiteralInput(
  118.             identifier='input2', title='minimal distance between points'
  119.         )
  120.  
  121.     def execute(self):
  122.         #
  123.         # TODO: Different operating systems have different semantics and
  124.         #       resolutions for `time()` and `clock()`.  Make sure `clock()` is
  125.         #       the correct one here.
  126.         #
  127.         start_timestamp = time.clock()
  128.  
  129.         shape_file = ogr.Open(self.data_filename_input.getValue())
  130.         if shape_file is None:
  131.             raise Exception('failed to open shape file.')
  132.         #
  133.         # Get the first layer.
  134.         #
  135.         layer = shape_file.GetLayer(0)
  136.         layer.ResetReading()
  137.         #
  138.         # Read points.
  139.         #
  140.         cleaned_points = clean_points(iter_points(layer))
  141.         #
  142.         # Create raster cells with the corresponding points (5% overlap added).
  143.         #
  144.         # TODO: Where is the 5% overlap actually realized?
  145.         #
  146.         cells = partition_points(cleaned_points, layer.GetExtent())
  147.         minimal_distance = self.minimal_distance_input.getValue()
  148.         result_points = chain.from_iterable(
  149.             imap(partial(filter_close_points, minimal_distance), cells)
  150.         )
  151.         gml = create_geometry(result_points).ExportToGML()
  152.         elapsed_time = time.clock() - start_timestamp
  153.         self.data_output.setValue(gml)
  154.         self.time_output.setValue(elapsed_time)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement