Skip to content

Commit bae6052

Browse files
committed
Adding tool enforcing polygon orientation.
1 parent e9f00a4 commit bae6052

File tree

1 file changed

+124
-0
lines changed

1 file changed

+124
-0
lines changed
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
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

Comments
 (0)