Exemplo n.º 1
0
    def test_distance_lookups_with_expression_rhs(self):
        qs = SouthTexasCity.objects.filter(
            point__distance_lte=(self.stx_pnt, F('radius')),
        ).order_by('name')
        self.assertEqual(
            self.get_names(qs),
            ['Bellaire', 'Downtown Houston', 'Southside Place', 'West University Place']
        )

        # With a combined expression
        qs = SouthTexasCity.objects.filter(
            point__distance_lte=(self.stx_pnt, F('radius') * 2),
        ).order_by('name')
        self.assertEqual(len(qs), 5)
        self.assertIn('Pearland', self.get_names(qs))

        # With spheroid param
        if connection.features.supports_distance_geodetic:
            hobart = AustraliaCity.objects.get(name='Hobart')
            qs = AustraliaCity.objects.filter(
                point__distance_lte=(hobart.point, F('radius') * 70, 'spheroid'),
            ).order_by('name')
            self.assertEqual(self.get_names(qs), ['Canberra', 'Hobart', 'Melbourne'])

        # With a complex geometry expression
        self.assertFalse(SouthTexasCity.objects.filter(point__distance_gt=(Intersection('point', 'point'), 0)))
        self.assertEqual(
            SouthTexasCity.objects.filter(point__distance_lte=(Intersection('point', 'point'), 0)).count(),
            SouthTexasCity.objects.count(),
        )
Exemplo n.º 2
0
 def handle(self, *args, **options):
     print("Calculando country codes")
     b = kings
     aas = AdministrativeArea.objects.filter(depth=1)
     for aa in aas:
         cc = next(v['country_code'] for k, v in kings.items()
                   if v['id'] == aa.osm_id)
         print(f' > {aa.osm_type} {aa.osm_id} {aa.name}')
         print('   - Lineas: ', end='')
         # Linea.objects.filter(envolvente__intersects=aa.geometry_simple).update(country_code=cc)
         print(Linea.objects \
             .annotate(intersection_area=Area(Intersection(F('envolvente'), aa.geometry_simple)) / Area(F('envolvente'))) \
             .filter(intersection_area__gt=A(sq_m=0.65)) \
             .update(country_code=cc))
         print('   - Recorrido: ', end='')
         print(Recorrido.objects \
             .annotate(intersection_len=Length(Intersection(F('ruta_simple'), aa.geometry_simple)) / Length(F('ruta_simple'))) \
             .filter(intersection_len__gt=D(m=0.65)) \
             .update(country_code=cc))
         print('   - Parada: ', end='')
         print(
             Parada.objects.filter(
                 latlng__intersects=aa.geometry_simple).update(
                     country_code=cc))
         print('   - Poi: ', end='')
         print(
             Poi.objects.filter(
                 latlng__intersects=aa.geometry_simple).update(
                     country_code=cc))
         print('   - AdministrativeArea: ', end='')
         print(AdministrativeArea.objects \
             .annotate(intersection_area=Area(Intersection(F('geometry_simple'), aa.geometry_simple)) / Area(F('geometry_simple'))) \
             .filter(intersection_area__gt=A(sq_m=0.65)) \
             .update(country_code=cc))
         print(' > DONE')
Exemplo n.º 3
0
    def get_queryset(self):
        """
        Inspired by Glen Roberton's django-geojson-tiles view
        """
        self.z, self.x, self.y = self._parse_args()
        nw = self.tile_coord(self.x, self.y, self.z)
        se = self.tile_coord(self.x + 1, self.y + 1, self.z)
        bbox = Polygon((nw, (se[0], nw[1]), se, (nw[0], se[1]), nw))
        qs = super(TiledGeoJSONLayerView, self).get_queryset()
        qs = qs.filter(**{'%s__intersects' % self.geometry_field: bbox})
        self.bbox = bbox.extent

        # Simplification dict by zoom level
        simplifications = self.simplifications or {}
        z = self.z
        self.simplify = simplifications.get(z)
        while self.simplify is None and z < 32:
            z += 1
            self.simplify = simplifications.get(z)

        # Won't trim point geometries to a boundary
        model_field = qs.model._meta.get_field(self.geometry_field)
        self.trim_to_boundary = (self.trim_to_boundary
                                 and not isinstance(model_field, PointField))
        if self.trim_to_boundary:
            if django.VERSION < (1, 9):
                qs = qs.intersection(bbox)
            else:
                qs = qs.annotate(
                    intersection=Intersection(self.geometry_field, bbox))
            self.geometry_field = 'intersection'

        return qs
Exemplo n.º 4
0
    def test_job_region_intersection(self,):
        job = Job.objects.all()[0]
        # use the_geog
        regions = Region.objects.filter(the_geog__intersects=job.the_geog).annotate(
            intersection=Area(Intersection('the_geog', job.the_geog))).order_by('-intersection')
        self.assertEquals(2, len(regions))
        asia = regions[0]
        africa = regions[1]
        self.assertIsNotNone(asia)
        self.assertIsNotNone(africa)
        self.assertEquals('Central Asia/Middle East', asia.name)
        self.assertEquals('Africa', africa.name)
        self.assertTrue(asia.intersection > africa.intersection)

        # use the_geom
        regions = Region.objects.filter(the_geom__intersects=job.the_geom).intersection(job.the_geom,
                                                                                        field_name='the_geom').order_by(
            '-intersection')
        # logger.debug('Geometry lookup took: %s' % geom_time)
        self.assertEquals(2, len(regions))
        asia = regions[0]
        africa = regions[1]
        self.assertIsNotNone(asia)
        self.assertIsNotNone(africa)
        self.assertEquals('Central Asia/Middle East', asia.name)
        self.assertEquals('Africa', africa.name)
        self.assertTrue(asia.intersection.area > africa.intersection.area)
Exemplo n.º 5
0
    def _get_from_pricing_layer_price(cls, **kwargs):
        """
        The area is expected to be in hectares
        As the price may vary from one polygon to
        the other, it has to be taken in the
        pricing layer
        """
        polygon = kwargs.get('polygon')
        pricing_instance = kwargs.get('pricing_instance')
        pricing_geometry_instance = pricing_instance.pricinggeometry_set
        if pricing_geometry_instance.count() == 0:
            LOGGER.info('%s HAS NO GEOMETRIES LINKED TO IT',
                        pricing_instance.name)
            send_geoshop_email(
                _('Geoshop - Error, pricing has no geometries linked to it'),
                template_name='email_admin',
                template_data={
                    'messages': [
                        _('The pricing "{}" is defined but no geometries were found for it.'
                          ).format(pricing_instance.name)
                    ]
                })
            return cls._get_manual_price(**kwargs)
        total = pricing_geometry_instance.filter(
            pricing=pricing_instance.id).filter(
                geom__intersects=polygon).aggregate(sum=ExpressionWrapper(
                    Sum((Area(Intersection('geom', polygon)) / 10000) *
                        F('unit_price')),
                    output_field=MoneyField()))

        return Money(total['sum'], pricing_instance.unit_price_currency)
Exemplo n.º 6
0
    def get_tile(self, x, y, z, extent=4096, buffer=256, clip_geom=True):
        # get tile coordinates from x, y and z
        west, south, east, north = self.get_bounds(x, y, z)
        features = self.get_vector_tile_queryset()

        pixel = self.pixel_length(z)
        final_buffer = 4 * pixel
        bbox = Polygon.from_bbox((west - final_buffer, south - final_buffer, east + final_buffer, north + final_buffer))
        bbox.srid = 3857

        filters = {
            f"{self.vector_tile_geom_name}__intersects": bbox
        }
        features = features.filter(**filters)
        features = features.annotate(clipped=Intersection(Transform(self.vector_tile_geom_name, 3857), bbox))
        if features:
            tile = {
                "name": self.get_vector_tile_layer_name(),
                "features": [
                    {
                        "geometry": feature.clipped.simplify(pixel, preserve_topology=True).wkb.tobytes(),
                        "properties": {
                            key: getattr(feature, key) for key in self.vector_tile_fields if
                            self.vector_tile_fields
                        }
                    }
                    for feature in features
                ],
            }
            return mapbox_vector_tile.encode(tile,
                                             quantize_bounds=(west, south, east, north),
                                             extents=extent)
Exemplo n.º 7
0
def get_regions_for_zone(zone):
    """Returns the best region for the zone based on amount of overlap with the zone's bounding box.

    If the zone only falls within one region, that region is returned.

    Otherwise, this calculates the amount of overlap between the zone's bounding box and the region
    and returns the one with the highest amount of overlap, as an approximation of the region that
    contains most or all of the zone polygon.

    Parameters
    ----------
    extent : SeedZone instance

    Returns
    -------
    Region instance
    """

    extent = Polygon.from_bbox(zone.polygon.extent)
    regions = Region.objects.filter(polygons__intersects=extent)

    if len(regions) == 1:
        return list(regions)

    # calculate amount of overlap and return one with highest overlap with extent
    return list(
        regions.annotate(overlap=Area(Intersection(
            "polygons", extent))).order_by("-overlap"))
Exemplo n.º 8
0
    def list(self, request, aggregationlayer, x, y, z, frmt, *args, **kwargs):
        # Select which agglayer to use for this tile.
        lyr = get_object_or_404(AggregationLayer, pk=aggregationlayer)

        # Compute tile boundary coorner coordinates.
        bounds_coords = tile_bounds(int(x), int(y), int(z))

        # Create a geometry with a 1% buffer around the tile. This buffered
        # tile boundary will be used for clipping the geometry. The overflow
        # will visually dissolve the polygons on the frontend visualization.
        bounds = OGRGeometry.from_bbox(bounds_coords)
        bounds.srid = WEB_MERCATOR_SRID
        bounds = bounds.geos
        bounds_buffer = bounds.buffer(
            (bounds_coords[2] - bounds_coords[0]) / 100)

        # Get the intersection of the aggregation areas and the tile boundary.
        # use buffer to clip the aggregation area.
        result = AggregationArea.objects.filter(
            aggregationlayer=lyr,
            geom__intersects=bounds,
        ).annotate(intersection=Intersection('geom', bounds_buffer)).only(
            'id', 'name')

        # Render intersection as vector tile in two different available formats.
        if frmt == 'json':
            result = [
                '{{"geometry": {0}, "properties": {{"id": {1}, "name": "{2}"}}}}'
                .format(dat.intersection.geojson, dat.id, dat.name)
                for dat in result
            ]
            result = ','.join(result)
            result = '{"type": "FeatureCollection","features":[' + result + ']}'
            return HttpResponse(result, content_type="application/json")
        elif frmt == 'pbf':
            features = [{
                "geometry": bytes(dat.intersection.wkb),
                "properties": {
                    "id": dat.id,
                    "name": dat.name,
                    "attributes": dat.attributes,
                },
            } for dat in result]
            data = [
                {
                    "name": lyr.name,
                    "features": features,
                },
            ]
            vtile = mapbox_vector_tile.encode(data,
                                              quantize_bounds=bounds_coords)
            return HttpResponse(vtile, content_type='application/x-protobuf')
Exemplo n.º 9
0
 def test_job_region_intersection(self, ):
     job = Job.objects.all()[0]
     # use the_geog
     regions = Region.objects.filter(
         the_geog__intersects=job.the_geog).annotate(
             intersection=Area(Intersection(
                 'the_geog', job.the_geog))).order_by('-intersection')
     self.assertEqual(2, len(regions))
     asia = regions[0]
     africa = regions[1]
     self.assertIsNotNone(asia)
     self.assertIsNotNone(africa)
     self.assertEqual('Central Asia/Middle East', asia.name)
     self.assertEqual('Africa', africa.name)
     self.assertTrue(asia.intersection > africa.intersection)
Exemplo n.º 10
0
    def calculate_capacity_estimate(self):
        """
        Calculate capacity estimate of this region from parking areas.

        :rtype: int
        """
        areas = ParkingArea.objects.all()
        covered_areas = areas.inside_region(self)
        partial_areas = (areas.intersecting_region(self).exclude(
            pk__in=covered_areas).annotate(
                intsect=Intersection('geom', self.geom)))
        sum_covered = covered_areas.total_estimated_capacity
        sum_partials = sum(
            # Scale the estimated capacity according to ratio of area of
            # the intersection and total area
            int(round(x.estimated_capacity * x.intsect.area / x.geom.area))
            for x in partial_areas)
        return sum_covered + sum_partials
Exemplo n.º 11
0
def tile_view(request, zoom, x, y):
    """
    Returns an MVT tiles given zoom, x and y in TMS format

    References:
        https://www.mapbox.com/vector-tiles/
        http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification#global-mercator

    """
    bounds = mercantile.bounds(int(x), int(y), int(zoom))
    west, south = mercantile.xy(bounds.west, bounds.south)
    east, north = mercantile.xy(bounds.east, bounds.north)

    pixel = pixel_length(zoom)
    buffer = 4 * pixel
    bbox = Polygon.from_bbox(
        (west - buffer, south - buffer, east + buffer, north + buffer))

    departements = Departement.objects.filter(geom__intersects=bbox)
    departements = departements.annotate(clipped=Intersection('geom', bbox))

    tile = {
        "name":
        "departements",
        "features": [{
            "geometry":
            departement.clipped.simplify(pixel, preserve_topology=True).wkt,
            "properties": {
                "numero": departement.code_dept,
                "nom": departement.nom_dept,
            },
        } for departement in departements],
    }
    vector_tile = mapbox_vector_tile.encode(tile,
                                            quantize_bounds=(west, south, east,
                                                             north))
    return HttpResponse(vector_tile,
                        content_type="application/vnd.mapbox-vector-tile")
Exemplo n.º 12
0
def get_landcover(point, radius=100):
    buffer = point.buffer(radius)
    result = LandCover.objects.filter(geometry__intersects=buffer.envelope)\
                          .annotate(intersection=Intersection('geometry', buffer.envelope))
    return result
Exemplo n.º 13
0
def ver_linea(request, osm_type=None, osm_id=None, slug=None, country_code=None):
    """
        osm_type =
            - 'c': cualbondi recorrido, usar id de la tabla directamente
            - 'r': relation de osm, usar osm_id con el campo osm_id
    """
    # TODO: redirect id c123 a r123 si viene con osm_type=c y existe el osm_id
    linea_q = Linea.objects.only('nombre', 'slug', 'img_cuadrada', 'info_empresa', 'info_terminal', 'img_panorama', 'envolvente')
    linea = None
    if osm_type == 'c':
        linea = get_object_or_404(linea_q, id=osm_id)
    elif osm_type == 'r':
        linea = get_object_or_404(linea_q, osm_id=osm_id)

    linea__envolvente = linea.envolvente.simplify(0.001, True)

    recorridos = natural_sort_qs(linea.recorridos.all().defer('ruta'), 'slug')

    # aa = AdministrativeArea.objects \
    #     .filter(geometry_simple__intersects=linea.envolvente) \
    #     .annotate(inter_area=DBArea(Intersection(F('geometry_simple'), linea.envolvente))) \
    #     .filter(inter_area__gt=Area(sq_m=linea.envolvente.area * 0.8)) \
    #     .annotate(area=DBArea(F('geometry_simple'))) \
    #     .order_by('area')

    # aa = AdministrativeArea.objects \
    #     .filter(geometry_simple__intersects=linea.envolvente) \
    #     .annotate(symdiff_area=Area(SymDifference(F('geometry_simple'), linea.envolvente)) / Area(Union(F('geometry_simple'), linea.envolvente))) \
    #     .order_by('symdiff_area')

    aa = AdministrativeArea.objects \
        .filter(geometry_simple__intersects=linea__envolvente) \
        .annotate(symdiff_area=Area(SymDifference(F('geometry_simple'), linea__envolvente)) / (Area(F('geometry_simple')) + Area(linea__envolvente))) \
        .annotate(intersection_area=Area(Intersection(F('geometry_simple'), linea__envolvente)) / Area(linea__envolvente)) \
        .filter(intersection_area__gt=A(sq_m=0.8)) \
        .order_by('symdiff_area')

    # for a in aa:
    #     print(f'{a.symdiff_area, a.intersection_area, a.name}')

    # aa = AdministrativeArea.objects \
    #     .filter(geometry_simple__intersects=linea.envolvente) \
    #     .annotate(symdiff_area=Area(SymDifference(F('geometry_simple'), linea.envolvente))) \
    #     .order_by('symdiff_area')

    if aa:
        aa = aa[0]
        aaancestors = aa.get_ancestors().reverse()
    else:
        aa = None
        aaancestors = None

    # linea found, check if url is ok
    correct_url = linea.get_absolute_url()
    if correct_url not in request.build_absolute_uri():
        return HttpResponsePermanentRedirect(add_lang_qs(correct_url, request))

    # Zonas por las que pasa el recorrido
    aas = AdministrativeArea.objects \
        .filter(geometry_simple__intersects=linea__envolvente, depth__gt=3) \
        .order_by('depth', 'name')

    return render(
        request,
        "core/ver_linea.html",
        {
            'obj': linea,
            'recorridos': recorridos,
            'adminarea': aa,
            'adminareaancestors': aaancestors,
            'adminareas': aas,
        }
    )
Exemplo n.º 14
0
def ver_recorrido(request, osm_type=None, osm_id=None, slug=None, country_code=None):
    """
        osm_type =
            - 'c': cualbondi recorrido, usar id de la tabla directamente
            - 'r': relation de osm, usar osm_id con el campo osm_id
    """
    recorrido_q = Recorrido.objects \
        .only('nombre', 'slug', 'inicio', 'fin', 'img_cuadrada', 'img_panorama', 'ruta', 'linea', 'osm_id') \
        .select_related('linea')
    recorrido = None
    if osm_type == 'c':
        recorrido = get_object_or_404(recorrido_q, id=osm_id)
    elif osm_type == 'w':
        # there can be multiple with the same id, so we filter using the most approximate slug
        recorridos = Recorrido.objects.filter(osm_id=osm_id).annotate(similarity=TrigramSimilarity('slug', slug or '')).order_by('-similarity')
        if recorridos:
            recorrido = recorridos[0]
        else:
            raise Http404


    recorrido_simplified = recorrido.ruta.simplify(0.00005)
    recorrido_buffer = recorrido_simplified.buffer(0.0001)

    # aa = AdministrativeArea.objects \
    #     .filter(geometry_simple__intersects=recorrido_simplified) \
    #     .annotate(symdiff_area=Area(SymDifference(F('geometry_simple'), recorrido_simplified)) / (Area(F('geometry_simple')) + Area(recorrido_simplified))) \
    #     .order_by('symdiff_area')

    aa = AdministrativeArea.objects \
        .filter(geometry_simple__intersects=recorrido_buffer) \
        .annotate(symdiff_area=Area(SymDifference(F('geometry_simple'), recorrido_buffer)) / (Area(F('geometry_simple')) + Area(recorrido_buffer))) \
        .annotate(intersection_area=Area(Intersection(F('geometry_simple'), recorrido_buffer)) / Area(recorrido_buffer)) \
        .filter(intersection_area__gt=A(sq_m=0.8)) \
        .order_by('symdiff_area')

    if aa:
        aa = aa[0]
        aaancestors = aa.get_ancestors().reverse()
    else:
        aa = None
        aaancestors = None

    # recorrido found, check if url is ok
    correct_url = recorrido.get_absolute_url()
    if correct_url not in request.build_absolute_uri():
        return HttpResponsePermanentRedirect(add_lang_qs(correct_url, request))

    # Calles por las que pasa el recorrido
    """
    # solucion 1
    # toma todas las calles cercanas al recorrido
    # simple pero no funciona bien, genera "falsos positivos", trae calles perpendiculares al recorrido
    # igual es lento: 13 seg
    calles_fin = Calle.objects.filter(way__distance_lte=(recorrido.ruta, D(m=20)))

    # alternativa con dwithin
    # igual es lento, pero 10 veces mejor que antes: 1.4 seg
    calles_fin = Calle.objects.filter(way__dwithin=(recorrido.ruta, D(m=20)))
    """
    """
    # solucion 2
    # toma las calles que estan cercanas y se repiten cada par de puntos
    # hace 1 query lenta por cada punto: funciona bien, pero un poco lento!
    # 0.003 seg x cant_puntos
    calles_ant = None
    calles_fin = []
    for p in recorrido.ruta.coords:
        calles = Calle.objects.filter(way__dwithin=(Point(p), D(m=50)))
        if calles_ant is not None:
            for c in calles_ant:
                if len(calles_fin) > 0:
                    if c.nom != calles_fin[-1].nom and c in calles:
                        calles_fin.append(c)
                else:
                    calles_fin.append(c)
        calles_ant = calles
    # TODO: tal vez se pueda mejorar eso con una custom query sola.
    """
    # solucion 3, como la solucion 2 pero con raw query (para bs as no anda bien)
    if not recorrido.descripcion or not recorrido.descripcion.strip():
        def uniquify(seq, idfun=None):
            if idfun is None:
                def idfun(x):
                    return x
            seen = {}
            result = []
            for item in seq:
                marker = idfun(item)
                if marker in seen:
                    continue
                seen[marker] = 1
                result.append(item)
            return result

        from django.db import connection
        cursor = connection.cursor()
        cursor.execute(
            '''
                SELECT
                    (dp).path[1] as idp,
                    cc.nom       as nom
                FROM
                    (SELECT ST_DumpPoints(%s) as dp ) as dpa
                    JOIN catastro_calle as cc
                    ON ST_DWithin(cc.way, (dp).geom, 20)
            ''',
            (
                recorrido_simplified.ewkb,
            )
        )
        from collections import OrderedDict
        calles = OrderedDict()
        for c in cursor.fetchall():
            if c[0] in calles:
                calles[c[0]].append(c[1])
            else:
                calles[c[0]] = [c[1]]

        calles_fin = []
        calles_ant = []
        for k in calles:
            calles_aca = []
            for c in calles_ant:
                if len(calles_fin) > 0:
                    if c not in calles_fin[-1] and c in calles[k]:
                        calles_aca.append(c)
                else:
                    calles_aca.append(c)
            if calles_aca:
                calles_fin.append(calles_aca)
            calles_ant = calles[k]

        calles_fin = [item for sublist in calles_fin for item in uniquify(sublist)]
    else:
        calles_fin = None

    # POI por los que pasa el recorrido
    pois = Poi.objects.filter(latlng__dwithin=(recorrido_simplified, D(m=400))).order_by('?')[:60]

    # Zonas por las que pasa el recorrido
    aas = AdministrativeArea.objects \
        .filter(geometry_simple__intersects=recorrido_buffer, depth__gt=3) \
        .order_by('depth')

    # Horarios + paradas que tiene este recorrido
    horarios = recorrido.horario_set.all().prefetch_related('parada').order_by('?')[:60]

    recorridos_similares = Recorrido.objects.similar_hausdorff(recorrido_simplified)

    aaancestors, calles_fin, pois, aas, horarios, recorridos_similares = parallelize(aaancestors, calles_fin, pois, aas, horarios, recorridos_similares)

    try:
        schemaorg_itemtype = {
            'bus': 'BusTrip',
            'trolleybus': 'BusTrip',
            'train': 'TrainTrip',
            'subway': 'TrainTrip',
            'monorail': 'TrainTrip',
            'tram': 'TrainTrip',
            'light_rail': 'TrainTrip',
        }[recorrido.type]
    except:
        schemaorg_itemtype = 'Trip'

    context = {
        'schemaorg_itemtype': schemaorg_itemtype,
        'obj': recorrido,
        'linea': recorrido.linea,
        'adminarea': aa,
        'adminareaancestors': aaancestors,
        'calles': calles_fin,
        'pois': pois,
        'adminareas': aas,
        'horarios': horarios,
        'recorridos_similares': recorridos_similares,
    }

    return render(request, "core/ver_recorrido.html", context)