Anton
Anton

Reputation: 450

How to do spatial lookup "contained" on MultiPolygon or several Polygons?

I have a map with a lot of markers on it. And I have a two not intersecting polygons (Box). I want to get all markers which covered by these polygons.

qb_1 = Polygon.from_bbox((-35.19153, -5.84512, -35.24054, -5.78552))
qb_2 = Polygon.from_bbox((64.16016, 50.26125, 61.80359, 52.04911))
q_box = MultiPolygon(qb_1, qb_2)

test1 = Marker.objects.filter(point__contained=qb_1)
test2 = Marker.objects.filter(point__contained=qb_2)

test = Marker.objects.filter(point__contained=q_box)

print "Count of Polygon 1 = %s" % test1.count()
print "Count of Polygon 2 = %s" % test2.count()
print "Count of MultiPolygon = %s" % test.count()

But the results are:

Count of Polygon 1 = 4
Count of Polygon 2 = 12
Count of MultiPolygon = 237

Why Polygon 1 + Polygon 2 is not equal MultiPolygon ?

Upvotes: 2

Views: 646

Answers (1)

e4c5
e4c5

Reputation: 53734

The secret lies in the words I have highlighted (from the geoqueryset documentation)

contained

Availability: PostGIS, MySQL, SpatiaLite

Tests if the geometry field’s bounding box is completely contained by the lookup geometry’s bounding box

The two polygons you have created happen to be have small areas, and the multipoligon you have created also has a small area, but the same cannot be said about it's bounding box.

qb_1.envelope.area   # 0.0029209960000001417
qb_2.envelope.area   # 4.213217240200014
qbox.envelope.area   # 5754.726987961

as you will see the last one is huge in comparison an it covers a lot more points than the two polygons taken on their own. Thus the whole is greater than the sum of it's parts.

You should be able to get the actual points covered by the two polygons as follows:

from django.db.models import Q Marker.objects.filter(Q(point__contained=qb_1) | Q(point__contained=qb_1))

But perhaps contains_properly is what you are really looking for? But that's available only in postgresql so contains is a good substitute.

contains

Availability: PostGIS, Oracle, MySQL, SpatiaLite

Tests if the geometry field spatially contains the lookup geometry.

Then your query becomes

Marker.objects.filter(Q(point__contains=qb_1) | Q(point__contains=qb_1))

Upvotes: 3

Related Questions