def test_union(self): """Union with all combinations of geometries/geometry fields.""" geom = Point(-95.363151, 29.763374, srid=4326) union = ( City.objects.annotate(union=functions.Union("point", geom)) .get(name="Dallas") .union ) expected = fromstr( "MULTIPOINT(-96.801611 32.782057,-95.363151 29.763374)", srid=4326 ) self.assertTrue(expected.equals(union)) union = ( City.objects.annotate(union=functions.Union(geom, "point")) .get(name="Dallas") .union ) self.assertTrue(expected.equals(union)) union = ( City.objects.annotate(union=functions.Union("point", "point")) .get(name="Dallas") .union ) expected = GEOSGeometry("POINT(-96.801611 32.782057)", srid=4326) self.assertTrue(expected.equals(union)) union = ( City.objects.annotate(union=functions.Union(geom, geom)) .get(name="Dallas") .union ) self.assertTrue(geom.equals(union))
def test_union_mixed_srid(self): """The result SRID depends on the order of parameters.""" geom = Point(61.42915, 55.15402, srid=4326) geom_3857 = geom.transform(3857, clone=True) tol = 0.001 for city in City.objects.annotate(union=functions.Union('point', geom_3857)): expected = city.point | geom self.assertTrue(city.union.equals_exact(expected, tol)) self.assertEqual(city.union.srid, 4326) for city in City.objects.annotate(union=functions.Union(geom_3857, 'point')): expected = geom_3857 | city.point.transform(3857, clone=True) self.assertTrue(expected.equals_exact(city.union, tol)) self.assertEqual(city.union.srid, 3857)
def test_diff_intersection_union(self): "Testing the `difference`, `intersection`, `sym_difference`, and `union` GeoQuerySet methods." geom = Point(5, 23, srid=4326) qs = Country.objects.all().annotate( difference=functions.Difference('mpoly', geom), sym_difference=functions.SymDifference('mpoly', geom), union=functions.Union('mpoly', geom), ) # For some reason SpatiaLite does something screwy with the Texas geometry here. # Also, it doesn't like the null intersection. if spatialite: qs = qs.exclude(name='Texas') else: qs = qs.annotate( intersection=functions.Intersection('mpoly', geom)) if oracle: # Should be able to execute the queries; however, they won't be the same # as GEOS (because Oracle doesn't use GEOS internally like PostGIS or # SpatiaLite). return for c in qs: self.assertTrue(c.mpoly.difference(geom).equals(c.difference)) if not (spatialite or mysql): self.assertEqual(c.mpoly.intersection(geom), c.intersection) self.assertTrue( c.mpoly.sym_difference(geom).equals(c.sym_difference)) self.assertTrue(c.mpoly.union(geom).equals(c.union))
def test_gis_lookups_with_complex_expressions(self): multiple_arg_lookups = {'dwithin', 'relate'} # These lookups are tested elsewhere. lookups = connection.ops.gis_operators.keys() - multiple_arg_lookups self.assertTrue(lookups, 'No lookups found') for lookup in lookups: with self.subTest(lookup): City.objects.filter(**{'point__' + lookup: functions.Union('point', 'point')}).exists()
def test_union(self): geom = Point(-95.363151, 29.763374, srid=4326) ptown = City.objects.annotate( union=functions.Union('point', geom)).get(name='Dallas') expected = fromstr( 'MULTIPOINT(-96.801611 32.782057,-95.363151 29.763374)', srid=4326) self.assertTrue(expected.equals(ptown.union))
def test_union(self): """Union with all combinations of geometries/geometry fields.""" geom = Point(-95.363151, 29.763374, srid=4326) union = City.objects.annotate(union=functions.Union('point', geom)).get(name='Dallas').union expected = fromstr('MULTIPOINT(-96.801611 32.782057,-95.363151 29.763374)', srid=4326) self.assertTrue(expected.equals(union)) union = City.objects.annotate(union=functions.Union(geom, 'point')).get(name='Dallas').union self.assertTrue(expected.equals(union)) union = City.objects.annotate(union=functions.Union('point', 'point')).get(name='Dallas').union expected = GEOSGeometry('POINT(-96.801611 32.782057)', srid=4326) self.assertTrue(expected.equals(union)) union = City.objects.annotate(union=functions.Union(geom, geom)).get(name='Dallas').union self.assertTrue(geom.equals(union))
def test_union(self): geom = Point(-95.363151, 29.763374, srid=4326) ptown = City.objects.annotate(union=functions.Union('point', geom)).get(name='Dallas') tol = 0.00001 # Undefined ordering expected1 = fromstr('MULTIPOINT(-96.801611 32.782057,-95.363151 29.763374)', srid=4326) expected2 = fromstr('MULTIPOINT(-95.363151 29.763374,-96.801611 32.782057)', srid=4326) self.assertTrue(expected1.equals_exact(ptown.union, tol) or expected2.equals_exact(ptown.union, tol))
def test_relate_lookup(self): "Testing the 'relate' lookup type." # To make things more interesting, we will have our Texas reference point in # different SRIDs. pnt1 = fromstr('POINT (649287.0363174 4177429.4494686)', srid=2847) pnt2 = fromstr('POINT(-98.4919715741052 29.4333344025053)', srid=4326) # Not passing in a geometry as first param raises a TypeError when # initializing the QuerySet. with self.assertRaises(ValueError): Country.objects.filter(mpoly__relate=(23, 'foo')) # Making sure the right exception is raised for the given # bad arguments. for bad_args, e in [((pnt1, 0), ValueError), ((pnt2, 'T*T***FF*', 0), ValueError)]: qs = Country.objects.filter(mpoly__relate=bad_args) with self.assertRaises(e): qs.count() # Relate works differently for the different backends. if postgis or spatialite or mariadb: contains_mask = 'T*T***FF*' within_mask = 'T*F**F***' intersects_mask = 'T********' elif oracle: contains_mask = 'contains' within_mask = 'inside' # TODO: This is not quite the same as the PostGIS mask above intersects_mask = 'overlapbdyintersect' # Testing contains relation mask. if connection.features.supports_transform: self.assertEqual( Country.objects.get(mpoly__relate=(pnt1, contains_mask)).name, 'Texas', ) self.assertEqual('Texas', Country.objects.get(mpoly__relate=(pnt2, contains_mask)).name) # Testing within relation mask. ks = State.objects.get(name='Kansas') self.assertEqual('Lawrence', City.objects.get(point__relate=(ks.poly, within_mask)).name) # Testing intersection relation mask. if not oracle: if connection.features.supports_transform: self.assertEqual( Country.objects.get(mpoly__relate=(pnt1, intersects_mask)).name, 'Texas', ) self.assertEqual('Texas', Country.objects.get(mpoly__relate=(pnt2, intersects_mask)).name) self.assertEqual('Lawrence', City.objects.get(point__relate=(ks.poly, intersects_mask)).name) # With a complex geometry expression mask = 'anyinteract' if oracle else within_mask self.assertFalse(City.objects.exclude(point__relate=(functions.Union('point', 'point'), mask)))
def test_gis_lookups_with_complex_expressions(self): multiple_arg_lookups = { "dwithin", "relate", } # These lookups are tested elsewhere. lookups = connection.ops.gis_operators.keys() - multiple_arg_lookups self.assertTrue(lookups, "No lookups found") for lookup in lookups: with self.subTest(lookup): City.objects.filter( **{"point__" + lookup: functions.Union("point", "point")} ).exists()
def get_geometries_union(field_names: List[str], using="default") -> Union[str, functions.Union]: """Generate a union of multiple geometry fields.""" if len(field_names) == 1: return next(iter(field_names)) # fastest in set data type elif len(field_names) == 2: return functions.Union(*field_names) elif connections[using].vendor == "postgresql": # postgres can handle multiple field names return ST_Union(field_names) else: # other databases do Union(Union(1, 2), 3) return reduce(functions.Union, field_names)
def get_geometries_union( expressions: list[str | functions.GeoFunc], using="default" ) -> str | functions.Union: """Generate a union of multiple geometry fields.""" if not expressions: raise ValueError("Missing geometery fields for get_geometries_union()") if len(expressions) == 1: return next(iter(expressions)) # fastest in set data type elif len(expressions) == 2: return functions.Union(*expressions) elif connections[using].vendor == "postgresql": # postgres can handle multiple field names return ST_Union(expressions) else: # other databases do Union(Union(1, 2), 3) return reduce(functions.Union, expressions)
def test_diff_intersection_union(self): geom = Point(5, 23, srid=4326) qs = Country.objects.all().annotate( difference=functions.Difference('mpoly', geom), sym_difference=functions.SymDifference('mpoly', geom), union=functions.Union('mpoly', geom), intersection=functions.Intersection('mpoly', geom), ) if oracle: # Should be able to execute the queries; however, they won't be the same # as GEOS (because Oracle doesn't use GEOS internally like PostGIS or # SpatiaLite). return for c in qs: self.assertTrue(c.mpoly.difference(geom).equals(c.difference)) if not (spatialite or mysql): self.assertEqual(c.mpoly.intersection(geom), c.intersection) self.assertTrue(c.mpoly.sym_difference(geom).equals(c.sym_difference)) self.assertTrue(c.mpoly.union(geom).equals(c.union))
def test_diff_intersection_union(self): geom = Point(5, 23, srid=4326) qs = Country.objects.annotate( difference=functions.Difference("mpoly", geom), sym_difference=functions.SymDifference("mpoly", geom), union=functions.Union("mpoly", geom), intersection=functions.Intersection("mpoly", geom), ) if connection.ops.oracle: # Should be able to execute the queries; however, they won't be the same # as GEOS (because Oracle doesn't use GEOS internally like PostGIS or # SpatiaLite). return for c in qs: self.assertTrue(c.mpoly.difference(geom).equals(c.difference)) if connection.features.empty_intersection_returns_none: self.assertIsNone(c.intersection) else: self.assertIs(c.intersection.empty, True) self.assertTrue(c.mpoly.sym_difference(geom).equals(c.sym_difference)) self.assertTrue(c.mpoly.union(geom).equals(c.union))
def test_relate_lookup(self): "Testing the 'relate' lookup type." # To make things more interesting, we will have our Texas reference point in # different SRIDs. pnt1 = fromstr("POINT (649287.0363174 4177429.4494686)", srid=2847) pnt2 = fromstr("POINT(-98.4919715741052 29.4333344025053)", srid=4326) # Not passing in a geometry as first param raises a TypeError when # initializing the QuerySet. with self.assertRaises(ValueError): Country.objects.filter(mpoly__relate=(23, "foo")) # Making sure the right exception is raised for the given # bad arguments. for bad_args, e in [ ((pnt1, 0), ValueError), ((pnt2, "T*T***FF*", 0), ValueError), ]: qs = Country.objects.filter(mpoly__relate=bad_args) with self.assertRaises(e): qs.count() contains_mask = "T*T***FF*" within_mask = "T*F**F***" intersects_mask = "T********" # Relate works differently on Oracle. if connection.ops.oracle: contains_mask = "contains" within_mask = "inside" # TODO: This is not quite the same as the PostGIS mask above intersects_mask = "overlapbdyintersect" # Testing contains relation mask. if connection.features.supports_transform: self.assertEqual( Country.objects.get(mpoly__relate=(pnt1, contains_mask)).name, "Texas", ) self.assertEqual( "Texas", Country.objects.get(mpoly__relate=(pnt2, contains_mask)).name) # Testing within relation mask. ks = State.objects.get(name="Kansas") self.assertEqual( "Lawrence", City.objects.get(point__relate=(ks.poly, within_mask)).name) # Testing intersection relation mask. if not connection.ops.oracle: if connection.features.supports_transform: self.assertEqual( Country.objects.get(mpoly__relate=(pnt1, intersects_mask)).name, "Texas", ) self.assertEqual( "Texas", Country.objects.get(mpoly__relate=(pnt2, intersects_mask)).name) self.assertEqual( "Lawrence", City.objects.get(point__relate=(ks.poly, intersects_mask)).name, ) # With a complex geometry expression mask = "anyinteract" if connection.ops.oracle else within_mask self.assertFalse( City.objects.exclude( point__relate=(functions.Union("point", "point"), mask)))