import math from unittest import skipIf from unittest.mock import patch from django.contrib.gis.geos import GEOSGeometry, LineString from django.contrib.gis.geos import prototypes as capi from django.contrib.gis.geos.coordseq import GEOSCoordSeq from django.contrib.gis.geos.libgeos import geos_version_tuple from django.test import SimpleTestCase class GEOSCoordSeqTest(SimpleTestCase): def test_getitem(self): coord_seq = LineString([(x, x) for x in range(2)]).coord_seq for i in (0, 1): with self.subTest(i): self.assertEqual(coord_seq[i], (i, i)) for i in (-3, 10): msg = f"Invalid GEOS Geometry index: {i}" with self.subTest(i): with self.assertRaisesMessage(IndexError, msg): coord_seq[i] @skipIf(geos_version_tuple() < (3, 14), "GEOS M support requires 3.14+") def test_has_m(self): geom = GEOSGeometry("POINT ZM (1 2 3 4)") coord_seq = GEOSCoordSeq(capi.get_cs(geom.ptr), z=True) self.assertIs(coord_seq.hasm, True) geom = GEOSGeometry("POINT Z (1 2 3)") coord_seq = GEOSCoordSeq(capi.get_cs(geom.ptr), z=True) self.assertIs(coord_seq.hasm, False) geom = GEOSGeometry("POINT M (1 2 3)") coord_seq = GEOSCoordSeq(capi.get_cs(geom.ptr), z=False) self.assertIs(coord_seq.hasm, True) @skipIf(geos_version_tuple() < (3, 14), "GEOS M support requires 3.14+") def test_get_set_m(self): geom = GEOSGeometry("POINT ZM (1 2 3 4)") coord_seq = GEOSCoordSeq(capi.get_cs(geom.ptr), z=True) self.assertEqual(coord_seq.tuple, (1, 2, 3, 4)) self.assertEqual(coord_seq.getM(0), 4) coord_seq.setM(0, 10) self.assertEqual(coord_seq.tuple, (1, 2, 3, 10)) self.assertEqual(coord_seq.getM(0), 10) geom = GEOSGeometry("POINT M (1 2 4)") coord_seq = GEOSCoordSeq(capi.get_cs(geom.ptr), z=False) self.assertEqual(coord_seq.tuple, (1, 2, 4)) self.assertEqual(coord_seq.getM(0), 4) coord_seq.setM(0, 10) self.assertEqual(coord_seq.tuple, (1, 2, 10)) self.assertEqual(coord_seq.getM(0), 10) self.assertIs(math.isnan(coord_seq.getZ(0)), True) @skipIf(geos_version_tuple() < (3, 14), "GEOS M support requires 3.14+") def test_setitem(self): geom = GEOSGeometry("POINT ZM (1 2 3 4)") coord_seq = GEOSCoordSeq(capi.get_cs(geom.ptr), z=True) coord_seq[0] = (10, 20, 30, 40) self.assertEqual(coord_seq.tuple, (10, 20, 30, 40)) geom = GEOSGeometry("POINT M (1 2 4)") coord_seq = GEOSCoordSeq(capi.get_cs(geom.ptr), z=False) coord_seq[0] = (10, 20, 40) self.assertEqual(coord_seq.tuple, (10, 20, 40)) self.assertEqual(coord_seq.getM(0), 40) self.assertIs(math.isnan(coord_seq.getZ(0)), True) @skipIf(geos_version_tuple() < (3, 14), "GEOS M support requires 3.14+") def test_kml_m_dimension(self): geom = GEOSGeometry("POINT ZM (1 2 3 4)") coord_seq = GEOSCoordSeq(capi.get_cs(geom.ptr), z=True) self.assertEqual(coord_seq.kml, "1.0,2.0,3.0") geom = GEOSGeometry("POINT M (1 2 4)") coord_seq = GEOSCoordSeq(capi.get_cs(geom.ptr), z=False) self.assertEqual(coord_seq.kml, "1.0,2.0,0") @skipIf(geos_version_tuple() < (3, 14), "GEOS M support requires 3.14+") def test_clone_m_dimension(self): geom = GEOSGeometry("POINT ZM (1 2 3 4)") coord_seq = GEOSCoordSeq(capi.get_cs(geom.ptr), z=True) clone = coord_seq.clone() self.assertEqual(clone.tuple, (1, 2, 3, 4)) self.assertIs(clone.hasz, True) self.assertIs(clone.hasm, True) geom = GEOSGeometry("POINT M (1 2 4)") coord_seq = GEOSCoordSeq(capi.get_cs(geom.ptr), z=False) clone = coord_seq.clone() self.assertEqual(clone.tuple, (1, 2, 4)) self.assertIs(clone.hasz, False) self.assertIs(clone.hasm, True) @skipIf(geos_version_tuple() < (3, 14), "GEOS M support requires 3.14+") def test_dims(self): geom = GEOSGeometry("POINT ZM (1 2 3 4)") coord_seq = GEOSCoordSeq(capi.get_cs(geom.ptr), z=True) self.assertEqual(coord_seq.dims, 4) geom = GEOSGeometry("POINT M (1 2 4)") coord_seq = GEOSCoordSeq(capi.get_cs(geom.ptr), z=False) self.assertEqual(coord_seq.dims, 3) geom = GEOSGeometry("POINT Z (1 2 3)") coord_seq = GEOSCoordSeq(capi.get_cs(geom.ptr), z=True) self.assertEqual(coord_seq.dims, 3) geom = GEOSGeometry("POINT (1 2)") coord_seq = GEOSCoordSeq(capi.get_cs(geom.ptr), z=False) self.assertEqual(coord_seq.dims, 2) def test_size(self): geom = GEOSGeometry("POINT (1 2)") coord_seq = GEOSCoordSeq(capi.get_cs(geom.ptr), z=False) self.assertEqual(coord_seq.size, 1) geom = GEOSGeometry("POINT M (1 2 4)") coord_seq = GEOSCoordSeq(capi.get_cs(geom.ptr), z=False) self.assertEqual(coord_seq.size, 1) @skipIf(geos_version_tuple() < (3, 14), "GEOS M support requires 3.14+") def test_iscounterclockwise(self): geom = GEOSGeometry("LINEARRING ZM (0 0 3 0, 1 0 0 2, 0 1 1 3, 0 0 3 4)") coord_seq = GEOSCoordSeq(capi.get_cs(geom.ptr), z=True) self.assertEqual( coord_seq.tuple, ( (0.0, 0.0, 3.0, 0.0), (1.0, 0.0, 0.0, 2.0), (0.0, 1.0, 1.0, 3.0), (0.0, 0.0, 3.0, 4.0), ), ) self.assertIs(coord_seq.is_counterclockwise, True) def test_m_support_error(self): geom = GEOSGeometry("POINT M (1 2 4)") coord_seq = GEOSCoordSeq(capi.get_cs(geom.ptr), z=True) msg = "GEOSCoordSeq with an M dimension requires GEOS 3.14+." # mock geos_version_tuple to be 3.13.13 with patch( "django.contrib.gis.geos.coordseq.geos_version_tuple", return_value=(3, 13, 13), ): with self.assertRaisesMessage(NotImplementedError, msg): coord_seq.hasm