2009-12-22 23:18:51 +08:00
|
|
|
from cx_Oracle import CLOB
|
2015-01-28 20:35:27 +08:00
|
|
|
|
2015-01-13 04:20:40 +08:00
|
|
|
from django.contrib.gis.db.backends.base.adapter import WKTAdapter
|
2015-09-20 18:41:25 +08:00
|
|
|
from django.contrib.gis.geos import GeometryCollection, Polygon
|
2009-12-22 23:18:51 +08:00
|
|
|
|
2013-11-03 01:18:46 +08:00
|
|
|
|
2009-12-22 23:18:51 +08:00
|
|
|
class OracleSpatialAdapter(WKTAdapter):
|
|
|
|
input_size = CLOB
|
2015-09-20 18:41:25 +08:00
|
|
|
|
|
|
|
def __init__(self, geom):
|
|
|
|
"""
|
|
|
|
Oracle requires that polygon rings are in proper orientation. This
|
|
|
|
affects spatial operations and an invalid orientation may cause
|
|
|
|
failures. Correct orientations are:
|
|
|
|
* Outer ring - counter clockwise
|
|
|
|
* Inner ring(s) - clockwise
|
|
|
|
"""
|
|
|
|
if isinstance(geom, Polygon):
|
|
|
|
self._fix_polygon(geom)
|
|
|
|
elif isinstance(geom, GeometryCollection):
|
|
|
|
self._fix_geometry_collection(geom)
|
|
|
|
|
|
|
|
self.wkt = geom.wkt
|
|
|
|
self.srid = geom.srid
|
|
|
|
|
|
|
|
def _fix_polygon(self, poly):
|
2017-01-25 04:31:57 +08:00
|
|
|
"""Fix single polygon orientation as described in __init__()."""
|
2015-09-20 18:41:25 +08:00
|
|
|
if self._isClockwise(poly.exterior_ring):
|
|
|
|
poly.exterior_ring = list(reversed(poly.exterior_ring))
|
|
|
|
|
|
|
|
for i in range(1, len(poly)):
|
|
|
|
if not self._isClockwise(poly[i]):
|
|
|
|
poly[i] = list(reversed(poly[i]))
|
|
|
|
|
|
|
|
return poly
|
|
|
|
|
|
|
|
def _fix_geometry_collection(self, coll):
|
2017-01-25 04:31:57 +08:00
|
|
|
"""
|
|
|
|
Fix polygon orientations in geometry collections as described in
|
|
|
|
__init__().
|
|
|
|
"""
|
2015-09-20 18:41:25 +08:00
|
|
|
for i, geom in enumerate(coll):
|
|
|
|
if isinstance(geom, Polygon):
|
|
|
|
coll[i] = self._fix_polygon(geom)
|
|
|
|
|
|
|
|
def _isClockwise(self, coords):
|
2017-01-25 04:31:57 +08:00
|
|
|
"""
|
|
|
|
A modified shoelace algorithm to determine polygon orientation.
|
|
|
|
See https://en.wikipedia.org/wiki/Shoelace_formula.
|
|
|
|
"""
|
2015-09-20 18:41:25 +08:00
|
|
|
n = len(coords)
|
|
|
|
area = 0.0
|
|
|
|
for i in range(n):
|
|
|
|
j = (i + 1) % n
|
|
|
|
area += coords[i][0] * coords[j][1]
|
|
|
|
area -= coords[j][0] * coords[i][1]
|
|
|
|
return area < 0.0
|