Commit c984e2bc authored by Sergey Fedoseev's avatar Sergey Fedoseev Committed by Claude Paroz
Browse files

Fixed #25869 -- Added trim and precision properties to WKTWriter.

parent cd3c042b
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -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
+38 −0
Original line number Diff line number Diff line
@@ -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 <http://postgis.net/docs/using_postgis_dbmanagement.html#EWKB_EWKT>`_, PostGIS documentation at Ch. 4.1.2.
+5 −0
Original line number Diff line number Diff line
@@ -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`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

+38 −3
Original line number Diff line number Diff line
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'