diff --git a/django/contrib/gis/geos/prototypes/io.py b/django/contrib/gis/geos/prototypes/io.py index ed28bcdccd..87aec30605 100644 --- a/django/contrib/gis/geos/prototypes/io.py +++ b/django/contrib/gis/geos/prototypes/io.py @@ -54,6 +54,9 @@ wkt_writer_set_outdim = GEOSFuncFactory( 'GEOSWKTWriter_setOutputDimension', argtypes=[WKT_WRITE_PTR, c_int] ) +wkt_writer_set_trim = GEOSFuncFactory('GEOSWKTWriter_setTrim', argtypes=[WKT_WRITE_PTR, c_char]) +wkt_writer_set_precision = GEOSFuncFactory('GEOSWKTWriter_setRoundingPrecision', argtypes=[WKT_WRITE_PTR, c_int]) + # WKBReader routines wkb_reader_create = GEOSFuncFactory('GEOSWKBReader_create', restype=WKB_READ_PTR) wkb_reader_destroy = GEOSFuncFactory('GEOSWKBReader_destroy', argtypes=[WKB_READ_PTR]) @@ -164,6 +167,9 @@ class WKTWriter(IOBase): _destructor = wkt_writer_destroy ptr_type = WKT_WRITE_PTR + _trim = False + _precision = None + def write(self, geom): "Returns the WKT representation of the given geometry." return wkt_writer_write(self.ptr, geom.ptr) @@ -178,6 +184,27 @@ class WKTWriter(IOBase): raise ValueError('WKT output dimension must be 2 or 3') wkt_writer_set_outdim(self.ptr, new_dim) + @property + def trim(self): + return self._trim + + @trim.setter + def trim(self, flag): + self._trim = bool(flag) + wkt_writer_set_trim(self.ptr, b'\x01' if flag else b'\x00') + + @property + def precision(self): + return self._precision + + @precision.setter + def precision(self, precision): + if isinstance(precision, int) and precision >= 0 or precision is None: + self._precision = precision + wkt_writer_set_precision(self.ptr, -1 if precision is None else precision) + else: + raise AttributeError('WKT output rounding precision must be non-negative integer or None.') + class WKBWriter(IOBase): _constructor = wkb_writer_create diff --git a/docs/ref/contrib/gis/geos.txt b/docs/ref/contrib/gis/geos.txt index 476ea7e233..ddf4f0706f 100644 --- a/docs/ref/contrib/gis/geos.txt +++ b/docs/ref/contrib/gis/geos.txt @@ -1052,6 +1052,44 @@ Returns the WKT of the given geometry. Example:: >>> wkt_w.write(pnt) 'POINT (1.0000000000000000 1.0000000000000000)' +.. attribute:: WKTWriter.trim + +.. versionadded:: 1.10 + +This property is used to enable or disable trimming of +unnecessary decimals. + + >>> from django.contrib.gis.geos import Point, WKTWriter + >>> pnt = Point(1, 1) + >>> wkt_w = WKTWriter() + >>> wkt_w.trim + False + >>> wkt_w.write(pnt) + 'POINT (1.0000000000000000 1.0000000000000000)' + >>> wkt_w.trim = True + >>> wkt_w.write(pnt) + 'POINT (1 1)' + +.. attribute:: WKTWriter.precision + +.. versionadded:: 1.10 + +This property controls the rounding precision of coordinates; +if set to ``None`` rounding is disabled. + + >>> from django.contrib.gis.geos import Point, WKTWriter + >>> pnt = Point(1.44, 1.66) + >>> wkt_w = WKTWriter() + >>> print(wkt_w.precision) + None + >>> wkt_w.write(pnt) + 'POINT (1.4399999999999999 1.6599999999999999)' + >>> wkt_w.precision = 0 + >>> wkt_w.write(pnt) + 'POINT (1 2)' + >>> wkt_w.precision = 1 + >>> wkt_w.write(pnt) + 'POINT (1.4 1.7)' .. rubric:: Footnotes .. [#fnogc] *See* `PostGIS EWKB, EWKT and Canonical Forms `_, PostGIS documentation at Ch. 4.1.2. diff --git a/docs/releases/1.10.txt b/docs/releases/1.10.txt index 64b92a26b6..7be22b12f4 100644 --- a/docs/releases/1.10.txt +++ b/docs/releases/1.10.txt @@ -94,6 +94,11 @@ Minor features * Added support for instantiating empty GEOS geometries. +* The new :attr:`~django.contrib.gis.geos.WKTWriter.trim` and + :attr:`~django.contrib.gis.geos.WKTWriter.precision` properties + of :class:`~django.contrib.gis.geos.WKTWriter` allow controlling + output of the fractional part of the coordinates in WKT. + :mod:`django.contrib.messages` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/gis_tests/geos_tests/test_io.py b/tests/gis_tests/geos_tests/test_io.py index 59cb54b6b4..920767ded4 100644 --- a/tests/gis_tests/geos_tests/test_io.py +++ b/tests/gis_tests/geos_tests/test_io.py @@ -1,17 +1,17 @@ from __future__ import unicode_literals import binascii -import unittest from unittest import skipUnless from django.contrib.gis.geos import ( - HAS_GEOS, GEOSGeometry, WKBReader, WKBWriter, WKTReader, WKTWriter, + HAS_GEOS, GEOSGeometry, Point, WKBReader, WKBWriter, WKTReader, WKTWriter, ) +from django.test import SimpleTestCase from django.utils.six import memoryview @skipUnless(HAS_GEOS, "Geos is required.") -class GEOSIOTest(unittest.TestCase): +class GEOSIOTest(SimpleTestCase): def test01_wktreader(self): # Creating a WKTReader instance @@ -109,3 +109,38 @@ class GEOSIOTest(unittest.TestCase): wkb_w.srid = True self.assertEqual(hex3d_srid, wkb_w.write_hex(g)) self.assertEqual(wkb3d_srid, wkb_w.write(g)) + + def test_wkt_writer_trim(self): + wkt_w = WKTWriter() + self.assertFalse(wkt_w.trim) + self.assertEqual(wkt_w.write(Point(1, 1)), b'POINT (1.0000000000000000 1.0000000000000000)') + + wkt_w.trim = True + self.assertTrue(wkt_w.trim) + self.assertEqual(wkt_w.write(Point(1, 1)), b'POINT (1 1)') + self.assertEqual(wkt_w.write(Point(1.1, 1)), b'POINT (1.1 1)') + self.assertEqual(wkt_w.write(Point(1. / 3, 1)), b'POINT (0.3333333333333333 1)') + + wkt_w.trim = False + self.assertFalse(wkt_w.trim) + self.assertEqual(wkt_w.write(Point(1, 1)), b'POINT (1.0000000000000000 1.0000000000000000)') + + def test_wkt_writer_precision(self): + wkt_w = WKTWriter() + self.assertEqual(wkt_w.precision, None) + self.assertEqual(wkt_w.write(Point(1. / 3, 2. / 3)), b'POINT (0.3333333333333333 0.6666666666666666)') + + wkt_w.precision = 1 + self.assertEqual(wkt_w.precision, 1) + self.assertEqual(wkt_w.write(Point(1. / 3, 2. / 3)), b'POINT (0.3 0.7)') + + wkt_w.precision = 0 + self.assertEqual(wkt_w.precision, 0) + self.assertEqual(wkt_w.write(Point(1. / 3, 2. / 3)), b'POINT (0 1)') + + wkt_w.precision = None + self.assertEqual(wkt_w.precision, None) + self.assertEqual(wkt_w.write(Point(1. / 3, 2. / 3)), b'POINT (0.3333333333333333 0.6666666666666666)') + + with self.assertRaisesMessage(AttributeError, 'WKT output rounding precision must be '): + wkt_w.precision = 'potato'