def get_prep_value(self, value): obj = super().get_prep_value(value) if obj is None: return None # When the input is not a geometry or raster, attempt to construct one # from the given string input. if isinstance(obj, GEOSGeometry): pass else: # Check if input is a candidate for conversion to raster or geometry. is_candidate = isinstance(obj, (bytes, str)) or hasattr( obj, '__geo_interface__') # Try to convert the input to raster. raster = self.get_raster_prep_value(obj, is_candidate) if raster: obj = raster elif is_candidate: try: obj = GEOSGeometry(obj) except (GEOSException, GDALException): raise ValueError( "Couldn't create spatial object from lookup value '%s'." % obj) else: raise ValueError( 'Cannot use object with type %s for a spatial lookup parameter.' % type(obj).__name__) # Assigning the SRID value. obj.srid = self.get_srid(obj) return obj
def setUp(self): # A point we are testing distances with -- using a WGS84 # coordinate that'll be implicitly transformed to that to # the coordinate system of the field, EPSG:32140 (Texas South Central # w/units in meters) self.stx_pnt = GEOSGeometry( 'POINT (-95.370401017314293 29.704867409475465)', 4326) # Another one for Australia self.au_pnt = GEOSGeometry('POINT (150.791 -34.4919)', 4326)
def test04_wkbwriter(self): wkb_w = WKBWriter() # Representations of 'POINT (5 23)' in hex -- one normal and # the other with the byte order changed. g = GEOSGeometry('POINT (5 23)') hex1 = b'010100000000000000000014400000000000003740' wkb1 = memoryview(binascii.a2b_hex(hex1)) hex2 = b'000000000140140000000000004037000000000000' wkb2 = memoryview(binascii.a2b_hex(hex2)) self.assertEqual(hex1, wkb_w.write_hex(g)) self.assertEqual(wkb1, wkb_w.write(g)) # Ensuring bad byteorders are not accepted. for bad_byteorder in (-1, 2, 523, 'foo', None): # Equivalent of `wkb_w.byteorder = bad_byteorder` with self.assertRaises(ValueError): wkb_w._set_byteorder(bad_byteorder) # Setting the byteorder to 0 (for Big Endian) wkb_w.byteorder = 0 self.assertEqual(hex2, wkb_w.write_hex(g)) self.assertEqual(wkb2, wkb_w.write(g)) # Back to Little Endian wkb_w.byteorder = 1 # Now, trying out the 3D and SRID flags. g = GEOSGeometry('POINT (5 23 17)') g.srid = 4326 hex3d = b'0101000080000000000000144000000000000037400000000000003140' wkb3d = memoryview(binascii.a2b_hex(hex3d)) hex3d_srid = b'01010000A0E6100000000000000000144000000000000037400000000000003140' wkb3d_srid = memoryview(binascii.a2b_hex(hex3d_srid)) # Ensuring bad output dimensions are not accepted for bad_outdim in (-1, 0, 1, 4, 423, 'foo', None): with self.assertRaisesMessage( ValueError, 'WKB output dimension must be 2 or 3'): wkb_w.outdim = bad_outdim # Now setting the output dimensions to be 3 wkb_w.outdim = 3 self.assertEqual(hex3d, wkb_w.write_hex(g)) self.assertEqual(wkb3d, wkb_w.write(g)) # Telling the WKBWriter to include the srid in the representation. wkb_w.srid = True self.assertEqual(hex3d_srid, wkb_w.write_hex(g)) self.assertEqual(wkb3d_srid, wkb_w.write(g))
def test_field_with_text_widget(self): class PointForm(forms.Form): pt = forms.PointField(srid=4326, widget=forms.TextInput) form = PointForm() cleaned_pt = form.fields['pt'].clean('POINT(5 23)') self.assertEqual(cleaned_pt, GEOSGeometry('POINT(5 23)', srid=4326)) self.assertEqual(4326, cleaned_pt.srid) with self.assertRaisesMessage(ValidationError, 'Invalid geometry value.'): form.fields['pt'].clean('POINT(5)') point = GEOSGeometry('SRID=4326;POINT(5 23)') form = PointForm(data={'pt': 'POINT(5 23)'}, initial={'pt': point}) self.assertFalse(form.has_changed())
def deserialize(self, value): try: return GEOSGeometry(value) except (GEOSException, ValueError, TypeError) as err: logger.error("Error creating geometry from value '%s' (%s)", value, err) return None
def test_custom_serialization_widget(self): class CustomGeometryWidget(forms.BaseGeometryWidget): template_name = 'gis/openlayers.html' deserialize_called = 0 def serialize(self, value): return value.json if value else '' def deserialize(self, value): self.deserialize_called += 1 return GEOSGeometry(value) class PointForm(forms.Form): p = forms.PointField(widget=CustomGeometryWidget) point = GEOSGeometry("SRID=4326;POINT(9.052734375 42.451171875)") form = PointForm(data={'p': point}) self.assertIn(escape(point.json), form.as_p()) CustomGeometryWidget.called = 0 widget = form.fields['p'].widget # Force deserialize use due to a string value self.assertIn(escape(point.json), widget.render('p', point.json)) self.assertEqual(widget.deserialize_called, 1) form = PointForm(data={'p': point.json}) self.assertTrue(form.is_valid()) self.assertEqual(form.cleaned_data['p'].srid, 4326)
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 _load_polygon_data(self): bbox_wkt, bbox_z = bbox_data bbox_2d = GEOSGeometry(bbox_wkt, srid=32140) bbox_3d = Polygon(tuple( (x, y, z) for (x, y), z in zip(bbox_2d[0].coords, bbox_z)), srid=32140) Polygon2D.objects.create(name='2D BBox', poly=bbox_2d) Polygon3D.objects.create(name='3D BBox', poly=bbox_3d)
def test_result_of_gis_lookup_with_rasters(self): # Point is in the interior qs = RasterModel.objects.filter( rast__contains=GEOSGeometry('POINT (-0.5 0.5)', 4326)) self.assertEqual(qs.count(), 1) # Point is in the exterior qs = RasterModel.objects.filter( rast__contains=GEOSGeometry('POINT (0.5 0.5)', 4326)) self.assertEqual(qs.count(), 0) # A point on the boundary is not contained properly qs = RasterModel.objects.filter( rast__contains_properly=GEOSGeometry('POINT (0 0)', 4326)) self.assertEqual(qs.count(), 0) # Raster is located left of the point qs = RasterModel.objects.filter( rast__left=GEOSGeometry('POINT (1 0)', 4326)) self.assertEqual(qs.count(), 1)
def test02_wktwriter(self): # Creating a WKTWriter instance, testing its ptr property. wkt_w = WKTWriter() with self.assertRaises(TypeError): wkt_w.ptr = WKTReader.ptr_type() ref = GEOSGeometry('POINT (5 23)') ref_wkt = 'POINT (5.0000000000000000 23.0000000000000000)' self.assertEqual(ref_wkt, wkt_w.write(ref).decode())
def test_srid(self): "Testing GeometryField with a SRID set." # Input that doesn't specify the SRID is assumed to be in the SRID # of the input field. fld = forms.GeometryField(srid=4326) geom = fld.clean('POINT(5 23)') self.assertEqual(4326, geom.srid) # Making the field in a different SRID from that of the geometry, and # asserting it transforms. fld = forms.GeometryField(srid=32140) tol = 0.0000001 xform_geom = GEOSGeometry('POINT (951640.547328465 4219369.26171664)', srid=32140) # The cleaned geometry is transformed to 32140 (the widget map_srid is 3857). cleaned_geom = fld.clean( 'SRID=3857;POINT (-10615777.40976205 3473169.895707852)') self.assertEqual(cleaned_geom.srid, 32140) self.assertTrue(xform_geom.equals_exact(cleaned_geom, tol))
def setUp(self): self.geometries = { 'point': GEOSGeometry("SRID=4326;POINT(9.052734375 42.451171875)"), 'multipoint': GEOSGeometry("SRID=4326;MULTIPOINT(" "(13.18634033203125 14.504356384277344)," "(13.207969665527 14.490966796875)," "(13.177070617675 14.454917907714))"), 'linestring': GEOSGeometry("SRID=4326;LINESTRING(" "-8.26171875 -0.52734375," "-7.734375 4.21875," "6.85546875 3.779296875," "5.44921875 -3.515625)"), 'multilinestring': GEOSGeometry("SRID=4326;MULTILINESTRING(" "(-16.435546875 -2.98828125," "-17.2265625 2.98828125," "-0.703125 3.515625," "-1.494140625 -3.33984375)," "(-8.0859375 -5.9765625," "8.525390625 -8.7890625," "12.392578125 -0.87890625," "10.01953125 7.646484375))"), 'polygon': GEOSGeometry("SRID=4326;POLYGON(" "(-1.669921875 6.240234375," "-3.8671875 -0.615234375," "5.9765625 -3.955078125," "18.193359375 3.955078125," "9.84375 9.4921875," "-1.669921875 6.240234375))"), 'multipolygon': GEOSGeometry("SRID=4326;MULTIPOLYGON(" "((-17.578125 13.095703125," "-17.2265625 10.8984375," "-13.974609375 10.1953125," "-13.359375 12.744140625," "-15.732421875 13.7109375," "-17.578125 13.095703125))," "((-8.525390625 5.537109375," "-8.876953125 2.548828125," "-5.888671875 1.93359375," "-5.09765625 4.21875," "-6.064453125 6.240234375," "-8.525390625 5.537109375)))"), 'geometrycollection': GEOSGeometry("SRID=4326;GEOMETRYCOLLECTION(" "POINT(5.625 -0.263671875)," "POINT(6.767578125 -3.603515625)," "POINT(8.525390625 0.087890625)," "POINT(8.0859375 -2.13134765625)," "LINESTRING(" "6.273193359375 -1.175537109375," "5.77880859375 -1.812744140625," "7.27294921875 -2.230224609375," "7.657470703125 -1.25244140625))"), }
def test_empty_polygon_wkb(self): p = Polygon(srid=4326) p_no_srid = Polygon() wkb_w = WKBWriter() wkb_w.srid = True for byteorder, hexes in enumerate([ (b'000000000300000000', b'0020000003000010E600000000'), (b'010300000000000000', b'0103000020E610000000000000'), ]): wkb_w.byteorder = byteorder for srid, hex in enumerate(hexes): wkb_w.srid = srid self.assertEqual(wkb_w.write_hex(p), hex) self.assertEqual(GEOSGeometry(wkb_w.write_hex(p)), p if srid else p_no_srid) self.assertEqual(wkb_w.write(p), memoryview(binascii.a2b_hex(hex))) self.assertEqual(GEOSGeometry(wkb_w.write(p)), p if srid else p_no_srid)
def get_geoms(self, geos=False): """ Return a list containing the OGRGeometry for every Feature in the Layer. """ if geos: from djmodels.contrib.gis.geos import GEOSGeometry return [GEOSGeometry(feat.geom.wkb) for feat in self] else: return [feat.geom for feat in self]
def test_unionagg(self): """ Testing the `Union` aggregate. """ tx = Country.objects.get(name='Texas').mpoly # Houston, Dallas -- Ordering may differ depending on backend or GEOS version. union = GEOSGeometry( 'MULTIPOINT(-96.801611 32.782057,-95.363151 29.763374)') qs = City.objects.filter(point__within=tx) with self.assertRaises(ValueError): qs.aggregate(Union('name')) # Using `field_name` keyword argument in one query and specifying an # order in the other (which should not be used because this is # an aggregate method on a spatial column) u1 = qs.aggregate(Union('point'))['point__union'] u2 = qs.order_by('name').aggregate(Union('point'))['point__union'] self.assertTrue(union.equals(u1)) self.assertTrue(union.equals(u2)) qs = City.objects.filter(name='NotACity') self.assertIsNone(qs.aggregate(Union('point'))['point__union'])
def test_distance_simple(self): """ Test a simple distance query, with projected coordinates and without transformation. """ lagrange = GEOSGeometry('POINT(805066.295722839 4231496.29461335)', 32140) houston = SouthTexasCity.objects.annotate( dist=Distance('point', lagrange)).order_by('id').first() tol = 2 if oracle else 5 self.assertAlmostEqual(houston.dist.m, 147075.069813, tol)
def _load_interstate_data(self): # Interstate (2D / 3D and Geographic/Projected variants) for name, line, exp_z in interstate_data: line_3d = GEOSGeometry(line, srid=4269) line_2d = LineString([l[:2] for l in line_3d.coords], srid=4269) # Creating a geographic and projected version of the # interstate in both 2D and 3D. Interstate3D.objects.create(name=name, line=line_3d) InterstateProj3D.objects.create(name=name, line=line_3d) Interstate2D.objects.create(name=name, line=line_2d) InterstateProj2D.objects.create(name=name, line=line_2d)
def test_empty_point_wkb(self): p = Point(srid=4326) wkb_w = WKBWriter() wkb_w.srid = False with self.assertRaisesMessage( ValueError, 'Empty point is not representable in WKB.'): wkb_w.write(p) with self.assertRaisesMessage( ValueError, 'Empty point is not representable in WKB.'): wkb_w.write_hex(p) wkb_w.srid = True for byteorder, hex in enumerate([ b'0020000001000010E67FF80000000000007FF8000000000000', b'0101000020E6100000000000000000F87F000000000000F87F', ]): wkb_w.byteorder = byteorder self.assertEqual(wkb_w.write_hex(p), hex) self.assertEqual(GEOSGeometry(wkb_w.write_hex(p)), p) self.assertEqual(wkb_w.write(p), memoryview(binascii.a2b_hex(hex))) self.assertEqual(GEOSGeometry(wkb_w.write(p)), p)
def test_geom_type(self): "Testing GeometryField's handling of different geometry types." # By default, all geometry types are allowed. fld = forms.GeometryField() for wkt in ('POINT(5 23)', 'MULTIPOLYGON(((0 0, 0 1, 1 1, 1 0, 0 0)))', 'LINESTRING(0 0, 1 1)'): with self.subTest(wkt=wkt): # to_python() uses the SRID of OpenLayersWidget if the # converted value doesn't have an SRID. self.assertEqual(GEOSGeometry(wkt, srid=fld.widget.map_srid), fld.clean(wkt)) pnt_fld = forms.GeometryField(geom_type='POINT') self.assertEqual( GEOSGeometry('POINT(5 23)', srid=pnt_fld.widget.map_srid), pnt_fld.clean('POINT(5 23)')) # a WKT for any other geom_type will be properly transformed by `to_python` self.assertEqual( GEOSGeometry('LINESTRING(0 0, 1 1)', srid=pnt_fld.widget.map_srid), pnt_fld.to_python('LINESTRING(0 0, 1 1)')) # but rejected by `clean` with self.assertRaises(forms.ValidationError): pnt_fld.clean('LINESTRING(0 0, 1 1)')
def test_make_line(self): """ Testing the `MakeLine` aggregate. """ if not connection.features.supports_make_line_aggr: with self.assertRaises(NotSupportedError): City.objects.all().aggregate(MakeLine('point')) return # MakeLine on an inappropriate field returns simply None self.assertIsNone( State.objects.aggregate(MakeLine('poly'))['poly__makeline']) # Reference query: # SELECT AsText(ST_MakeLine(geoapp_city.point)) FROM geoapp_city; ref_line = GEOSGeometry( 'LINESTRING(-95.363151 29.763374,-96.801611 32.782057,' '-97.521157 34.464642,174.783117 -41.315268,-104.609252 38.255001,' '-95.23506 38.971823,-87.650175 41.850385,-123.305196 48.462611)', srid=4326) # We check for equality with a tolerance of 10e-5 which is a lower bound # of the precisions of ref_line coordinates line = City.objects.aggregate(MakeLine('point'))['point__makeline'] self.assertTrue(ref_line.equals_exact(line, tolerance=10e-5), "%s != %s" % (ref_line, line))
def test_union(self): """ Testing the Union aggregate of 3D models. """ # PostGIS query that returned the reference EWKT for this test: # `SELECT ST_AsText(ST_Union(point)) FROM geo3d_city3d;` self._load_city_data() ref_ewkt = ( 'SRID=4326;MULTIPOINT(-123.305196 48.462611 15,-104.609252 38.255001 1433,' '-97.521157 34.464642 380,-96.801611 32.782057 147,-95.363151 29.763374 18,' '-95.23506 38.971823 251,-87.650175 41.850385 181,174.783117 -41.315268 14)' ) ref_union = GEOSGeometry(ref_ewkt) union = City3D.objects.aggregate(Union('point'))['point__union'] self.assertTrue(union.hasz) # Ordering of points in the resulting geometry may vary between implementations self.assertEqual({p.ewkt for p in ref_union}, {p.ewkt for p in union})
def test_to_python(self): """ Testing to_python returns a correct GEOSGeometry object or a ValidationError """ fld = forms.GeometryField() # to_python returns the same GEOSGeometry for a WKT for wkt in ('POINT(5 23)', 'MULTIPOLYGON(((0 0, 0 1, 1 1, 1 0, 0 0)))', 'LINESTRING(0 0, 1 1)'): with self.subTest(wkt=wkt): self.assertEqual(GEOSGeometry(wkt, srid=fld.widget.map_srid), fld.to_python(wkt)) # but raises a ValidationError for any other string for wkt in ('POINT(5)', 'MULTI POLYGON(((0 0, 0 1, 1 1, 1 0, 0 0)))', 'BLAH(0 0, 1 1)'): with self.subTest(wkt=wkt): with self.assertRaises(forms.ValidationError): fld.to_python(wkt)
def test_db_function_errors(self): """ Errors are raised when using DB functions with raster content. """ point = GEOSGeometry( "SRID=3086;POINT (-697024.9213808845 683729.1705516104)") rast = GDALRaster(json.loads(JSON_RASTER)) msg = "Distance function requires a geometric argument in position 2." with self.assertRaisesMessage(TypeError, msg): RasterModel.objects.annotate( distance_from_point=Distance("geom", rast)) with self.assertRaisesMessage(TypeError, msg): RasterModel.objects.annotate( distance_from_point=Distance("rastprojected", rast)) msg = "Distance function requires a GeometryField in position 1, got RasterField." with self.assertRaisesMessage(TypeError, msg): RasterModel.objects.annotate( distance_from_point=Distance("rastprojected", point)).count()
def test01_wktreader(self): # Creating a WKTReader instance wkt_r = WKTReader() wkt = 'POINT (5 23)' # read() should return a GEOSGeometry ref = GEOSGeometry(wkt) g1 = wkt_r.read(wkt.encode()) g2 = wkt_r.read(wkt) for geom in (g1, g2): self.assertEqual(ref, geom) # Should only accept string objects. with self.assertRaises(TypeError): wkt_r.read(1) with self.assertRaises(TypeError): wkt_r.read(memoryview(b'foo'))
def test03_wkbreader(self): # Creating a WKBReader instance wkb_r = WKBReader() hex = b'000000000140140000000000004037000000000000' wkb = memoryview(binascii.a2b_hex(hex)) ref = GEOSGeometry(hex) # read() should return a GEOSGeometry on either a hex string or # a WKB buffer. g1 = wkb_r.read(wkb) g2 = wkb_r.read(hex) for geom in (g1, g2): self.assertEqual(ref, geom) bad_input = (1, 5.23, None, False) for bad_wkb in bad_input: with self.assertRaises(TypeError): wkb_r.read(bad_wkb)
def test_distance_projected(self): """ Test the `Distance` function on projected coordinate systems. """ # The point for La Grange, TX lagrange = GEOSGeometry('POINT(-96.876369 29.905320)', 4326) # Reference distances in feet and in meters. Got these values from # using the provided raw SQL statements. # SELECT ST_Distance(point, ST_Transform(ST_GeomFromText('POINT(-96.876369 29.905320)', 4326), 32140)) # FROM distapp_southtexascity; m_distances = [ 147075.069813, 139630.198056, 140888.552826, 138809.684197, 158309.246259, 212183.594374, 70870.188967, 165337.758878, 139196.085105 ] # SELECT ST_Distance(point, ST_Transform(ST_GeomFromText('POINT(-96.876369 29.905320)', 4326), 2278)) # FROM distapp_southtexascityft; ft_distances = [ 482528.79154625, 458103.408123001, 462231.860397575, 455411.438904354, 519386.252102563, 696139.009211594, 232513.278304279, 542445.630586414, 456679.155883207 ] # Testing using different variations of parameters and using models # with different projected coordinate systems. dist1 = SouthTexasCity.objects.annotate( distance=Distance('point', lagrange)).order_by('id') dist2 = SouthTexasCityFt.objects.annotate( distance=Distance('point', lagrange)).order_by('id') dist_qs = [dist1, dist2] # Original query done on PostGIS, have to adjust AlmostEqual tolerance # for Oracle. tol = 2 if oracle else 5 # Ensuring expected distances are returned for each distance queryset. for qs in dist_qs: for i, c in enumerate(qs): with self.subTest(c=c): self.assertAlmostEqual(m_distances[i], c.distance.m, tol) self.assertAlmostEqual(ft_distances[i], c.distance.survey_ft, tol)
def test_field_string_value(self): """ Initialization of a geometry field with a valid/empty/invalid string. Only the invalid string should trigger an error log entry. """ class PointForm(forms.Form): pt1 = forms.PointField(srid=4326) pt2 = forms.PointField(srid=4326) pt3 = forms.PointField(srid=4326) form = PointForm({ 'pt1': 'SRID=4326;POINT(7.3 44)', # valid 'pt2': '', # empty 'pt3': 'PNT(0)', # invalid }) with self.assertLogs('djmodels.contrib.gis', 'ERROR') as logger_calls: output = str(form) # The first point can't use assertInHTML() due to non-deterministic # ordering of the rendered dictionary. pt1_serialized = re.search(r'<textarea [^>]*>({[^<]+})<', output).groups()[0] pt1_json = pt1_serialized.replace('"', '"') pt1_expected = GEOSGeometry(form.data['pt1']).transform(3857, clone=True) self.assertJSONEqual(pt1_json, pt1_expected.json) self.assertInHTML( '<textarea id="id_pt2" class="vSerializedField required" cols="150"' ' rows="10" name="pt2"></textarea>', output) self.assertInHTML( '<textarea id="id_pt3" class="vSerializedField required" cols="150"' ' rows="10" name="pt3"></textarea>', output) # Only the invalid PNT(0) triggers an error log entry. # Deserialization is called in form clean and in widget rendering. self.assertEqual(len(logger_calls.records), 2) self.assertEqual( logger_calls.records[0].getMessage(), "Error creating geometry from value 'PNT(0)' (String input " "unrecognized as WKT EWKT, and HEXEWKB.)")
def test_dwithin_gis_lookup_ouptut_with_rasters(self): """ Check the logical functionality of the dwithin lookup for different input parameters. """ # Create test raster and geom. rast = GDALRaster(json.loads(JSON_RASTER)) stx_pnt = GEOSGeometry( 'POINT (-95.370401017314293 29.704867409475465)', 4326) stx_pnt.transform(3086) # Filter raster with different lookup raster formats. qs = RasterModel.objects.filter(rastprojected__dwithin=(rast, D(km=1))) self.assertEqual(qs.count(), 1) qs = RasterModel.objects.filter( rastprojected__dwithin=(json.loads(JSON_RASTER), D(km=1))) self.assertEqual(qs.count(), 1) qs = RasterModel.objects.filter(rastprojected__dwithin=(JSON_RASTER, D(km=1))) self.assertEqual(qs.count(), 1) # Filter in an unprojected coordinate system. qs = RasterModel.objects.filter(rast__dwithin=(rast, 40)) self.assertEqual(qs.count(), 1) # Filter with band index transform. qs = RasterModel.objects.filter(rast__1__dwithin=(rast, 1, 40)) self.assertEqual(qs.count(), 1) qs = RasterModel.objects.filter(rast__1__dwithin=(rast, 40)) self.assertEqual(qs.count(), 1) qs = RasterModel.objects.filter(rast__dwithin=(rast, 1, 40)) self.assertEqual(qs.count(), 1) # Filter raster by geom. qs = RasterModel.objects.filter(rast__dwithin=(stx_pnt, 500)) self.assertEqual(qs.count(), 1) qs = RasterModel.objects.filter(rastprojected__dwithin=(stx_pnt, D(km=10000))) self.assertEqual(qs.count(), 1) qs = RasterModel.objects.filter(rast__dwithin=(stx_pnt, 5)) self.assertEqual(qs.count(), 0) qs = RasterModel.objects.filter(rastprojected__dwithin=(stx_pnt, D(km=100))) self.assertEqual(qs.count(), 0) # Filter geom by raster. qs = RasterModel.objects.filter(geom__dwithin=(rast, 500)) self.assertEqual(qs.count(), 1) # Filter through related model. qs = RasterRelatedModel.objects.filter( rastermodel__rast__dwithin=(rast, 40)) self.assertEqual(qs.count(), 1) # Filter through related model with band index transform qs = RasterRelatedModel.objects.filter( rastermodel__rast__1__dwithin=(rast, 40)) self.assertEqual(qs.count(), 1) # Filter through conditional statements. qs = RasterModel.objects.filter( Q(rast__dwithin=(rast, 40)) & Q(rastprojected__dwithin=(stx_pnt, D(km=10000)))) self.assertEqual(qs.count(), 1) # Filter through different lookup. qs = RasterModel.objects.filter(rastprojected__bbcontains=rast) self.assertEqual(qs.count(), 1)
def geos(self): "Return a GEOSGeometry object from this OGRGeometry." from djmodels.contrib.gis.geos import GEOSGeometry return GEOSGeometry(self._geos_ptr(), self.srid)
def test_all_gis_lookups_with_rasters(self): """ Evaluate all possible lookups for all input combinations (i.e. raster-raster, raster-geom, geom-raster) and for projected and unprojected coordinate systems. This test just checks that the lookup can be called, but doesn't check if the result makes logical sense. """ from djmodels.contrib.gis.db.backends.postgis.operations import PostGISOperations # Create test raster and geom. rast = GDALRaster(json.loads(JSON_RASTER)) stx_pnt = GEOSGeometry( 'POINT (-95.370401017314293 29.704867409475465)', 4326) stx_pnt.transform(3086) lookups = [(name, lookup) for name, lookup in BaseSpatialField.get_lookups().items() if issubclass(lookup, GISLookup)] self.assertNotEqual(lookups, [], 'No lookups found') # Loop through all the GIS lookups. for name, lookup in lookups: # Construct lookup filter strings. combo_keys = [ field + name for field in [ 'rast__', 'rast__', 'rastprojected__0__', 'rast__', 'rastprojected__', 'geom__', 'rast__', ] ] if issubclass(lookup, DistanceLookupBase): # Set lookup values for distance lookups. combo_values = [ (rast, 50, 'spheroid'), (rast, 0, 50, 'spheroid'), (rast, 0, D(km=1)), (stx_pnt, 0, 500), (stx_pnt, D(km=1000)), (rast, 500), (json.loads(JSON_RASTER), 500), ] elif name == 'relate': # Set lookup values for the relate lookup. combo_values = [ (rast, 'T*T***FF*'), (rast, 0, 'T*T***FF*'), (rast, 0, 'T*T***FF*'), (stx_pnt, 0, 'T*T***FF*'), (stx_pnt, 'T*T***FF*'), (rast, 'T*T***FF*'), (json.loads(JSON_RASTER), 'T*T***FF*'), ] elif name == 'isvalid': # The isvalid lookup doesn't make sense for rasters. continue elif PostGISOperations.gis_operators[name].func: # Set lookup values for all function based operators. combo_values = [ rast, (rast, 0), (rast, 0), (stx_pnt, 0), stx_pnt, rast, json.loads(JSON_RASTER) ] else: # Override band lookup for these, as it's not supported. combo_keys[2] = 'rastprojected__' + name # Set lookup values for all other operators. combo_values = [ rast, None, rast, stx_pnt, stx_pnt, rast, json.loads(JSON_RASTER) ] # Create query filter combinations. self.assertEqual( len(combo_keys), len(combo_values), 'Number of lookup names and values should be the same', ) combos = [x for x in zip(combo_keys, combo_values) if x[1]] self.assertEqual( [(n, x) for n, x in enumerate(combos) if x in combos[:n]], [], 'There are repeated test lookups', ) combos = [{k: v} for k, v in combos] for combo in combos: # Apply this query filter. qs = RasterModel.objects.filter(**combo) # Evaluate normal filter qs. self.assertIn(qs.count(), [0, 1]) # Evaluate on conditional Q expressions. qs = RasterModel.objects.filter(Q(**combos[0]) & Q(**combos[1])) self.assertIn(qs.count(), [0, 1])