|
| 1 | +#!/usr/bin/env python |
| 2 | +#------------------------------------------------------------------------------ |
| 3 | +# |
| 4 | +# orientation (clock-wise / counter-clock-wise) of the linear rings |
| 5 | +# |
| 6 | +# Project: Image Processing Tools |
| 7 | +# Authors: Martin Paces <[email protected]> |
| 8 | +# |
| 9 | +#------------------------------------------------------------------------------- |
| 10 | +# Copyright (C) 2014 EOX IT Services GmbH |
| 11 | +# |
| 12 | +# Permission is hereby granted, free of charge, to any person obtaining a copy |
| 13 | +# of this software and associated documentation files (the "Software"), to deal |
| 14 | +# in the Software without restriction, including without limitation the rights |
| 15 | +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 16 | +# copies of the Software, and to permit persons to whom the Software is |
| 17 | +# furnished to do so, subject to the following conditions: |
| 18 | +# |
| 19 | +# The above copyright notice and this permission notice shall be included in all |
| 20 | +# copies of this Software or works derived from this Software. |
| 21 | +# |
| 22 | +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 23 | +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 24 | +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 25 | +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 26 | +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 27 | +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 28 | +# THE SOFTWARE. |
| 29 | +#------------------------------------------------------------------------------- |
| 30 | + |
| 31 | +import sys |
| 32 | +import os.path |
| 33 | +import img_geom as ig |
| 34 | +from osgeo import ogr; ogr.UseExceptions() |
| 35 | +#from osgeo import osr; ogr.UseExceptions() |
| 36 | +#from osgeo import gdal; gdal.UseExceptions() |
| 37 | + |
| 38 | +def force_winding(geom, is_cw, level=0, inner_loop=False): |
| 39 | + |
| 40 | + gname = geom.GetGeometryName() |
| 41 | + if gname == "LINEARRING": |
| 42 | + if inner_loop: # reversed ordering for innner loop |
| 43 | + is_cw = not is_cw |
| 44 | + |
| 45 | + xy = [geom.GetPoint_2D(0)] |
| 46 | + area = 0.0 |
| 47 | + for i in xrange(geom.GetPointCount()-1): |
| 48 | + x0, y0 = geom.GetPoint_2D(i) |
| 49 | + x1, y1 = geom.GetPoint_2D(i+1) |
| 50 | + xy.append((x1, y1)) |
| 51 | + area += x0*y1 - x1*y0 |
| 52 | + |
| 53 | + if (is_cw and area > 0) or (not is_cw and area < 0): |
| 54 | + # change orientations (point's order) |
| 55 | + gout = ogr.Geometry(ogr.wkbLinearRing) |
| 56 | + for x, y in reversed(xy): |
| 57 | + gout.AddPoint_2D(x, y) |
| 58 | + |
| 59 | + else: |
| 60 | + # nothig's to be changed |
| 61 | + gout = geom.clone() |
| 62 | + |
| 63 | + elif gname == "POLYGON": |
| 64 | + gout = ogr.Geometry(ogr.wkbPolygon) |
| 65 | + inner_loop = False |
| 66 | + for i in xrange(geom.GetGeometryCount()): |
| 67 | + gout.AddGeometry(force_winding(geom.GetGeometryRef(i), is_cw, level+1, inner_loop)) |
| 68 | + inner_loop = True |
| 69 | + |
| 70 | + elif gname == "MULTIPOLYGON": |
| 71 | + gout = ogr.Geometry(ogr.wkbMultiPolygon) |
| 72 | + for i in xrange(geom.GetGeometryCount()): |
| 73 | + gout.AddGeometry(force_winding(geom.GetGeometryRef(i), is_cw, level+1)) |
| 74 | + |
| 75 | + elif gname == "GEOMETRYCOLLECTION": |
| 76 | + gout = ogr.Geometry(ogr.wkbGeometryCollection) |
| 77 | + for i in xrange(geom.GetGeometryCount()): |
| 78 | + gout.AddGeometry(force_winding(geom.GetGeometryRef(i), is_cw, level+1)) |
| 79 | + |
| 80 | + else: |
| 81 | + gout = geom.Clone() |
| 82 | + |
| 83 | + return gout |
| 84 | + |
| 85 | + |
| 86 | +if __name__ == "__main__": |
| 87 | + # TODO: to improve CLI |
| 88 | + EXENAME = os.path.basename(sys.argv[0]) |
| 89 | + DEBUG = False |
| 90 | + IS_CW = False |
| 91 | + FORMAT = "WKB" |
| 92 | + |
| 93 | + try: |
| 94 | + INPUT = sys.argv[1] |
| 95 | + ORIENT = sys.argv[2] |
| 96 | + NP = 2 |
| 97 | + if len(sys.argv) > NP: |
| 98 | + for arg in sys.argv[NP:]: |
| 99 | + if arg == "DEBUG": |
| 100 | + DEBUG = True # dump debuging output |
| 101 | + elif arg in ig.OUTPUT_FORMATS: |
| 102 | + FORMAT = arg # output format |
| 103 | + elif arg == "CW": |
| 104 | + ORIENT = "CW" |
| 105 | + elif arg == "CCW": |
| 106 | + ORIENT = "CCW" |
| 107 | + IS_CW = ORIENT == "CW" |
| 108 | + |
| 109 | + except IndexError: |
| 110 | + sys.stderr.write("ERROR: Not enough input arguments!\n") |
| 111 | + sys.stderr.write("\nForce linear ring orientation.\n") |
| 112 | + sys.stderr.write("USAGE: %s <WKT|WKB> CW|CCW [WKT|WKB][DEBUG]\n"%EXENAME) |
| 113 | + sys.exit(1) |
| 114 | + |
| 115 | + try: |
| 116 | + fin = sys.stdin if INPUT == "-" else open(INPUT) |
| 117 | + geom = ig.parseGeom(fin.read(), DEBUG) |
| 118 | + geom = ig.setSR(force_winding(geom, IS_CW), geom.GetSpatialReference()) |
| 119 | + sys.stdout.write(ig.dumpGeom(geom, FORMAT)) |
| 120 | + |
| 121 | + except Exception as e: |
| 122 | + print >>sys.stderr, "ERROR: %s: %s"%(EXENAME, e) |
| 123 | + sys.exit(1) |
| 124 | + |
0 commit comments