Ejemplo n.º 1
0
    def get_tile(self, x, y, z, extent=4096, buffer=256, clip_geom=True):
        # get tile coordinates from x, y and z
        xmin, ymin, xmax, ymax = self.get_bounds(x, y, z)
        features = self.get_vector_tile_queryset()

        # keep features intersecting tile
        filters = {
            f"{self.vector_tile_geom_name}__intersects":
            Transform(MakeEnvelope(xmin, ymin, xmax, ymax, 3857), 4326)
        }
        features = features.filter(**filters)
        # annotate prepared geometry for MVT
        features = features.annotate(geom_prepared=AsMVTGeom(
            Transform(self.vector_tile_geom_name, 3857),
            MakeEnvelope(xmin, ymin, xmax, ymax, 3857), extent, buffer,
            clip_geom))
        fields = self.vector_tile_fields + (
            "geom_prepared", ) if self.vector_tile_fields else (
                "geom_prepared", )
        # keep values to include in tile (extra included_fields + geometry)
        features = features.values(*fields)
        # generate MVT
        with connection.cursor() as cursor:
            cursor.execute(
                "SELECT ST_ASMVT(subquery.*, %s, %s, %s) FROM ({}) as subquery"
                .format(features.query),
                params=[
                    self.get_vector_tile_layer_name(), extent, "geom_prepared"
                ])
            row = cursor.fetchone()[0]
            return row.tobytes() if row else None
Ejemplo n.º 2
0
    def test_distance_transform(self):
        """
        Test the `Distance` function used with `Transform` on a geographic field.
        """
        # We'll be using a Polygon (created by buffering the centroid
        # of 77005 to 100m) -- which aren't allowed in geographic distance
        # queries normally, however our field has been transformed to
        # a non-geographic system.
        z = SouthTexasZipcode.objects.get(name='77005')

        # Reference query:
        # SELECT ST_Distance(ST_Transform("distapp_censuszipcode"."poly", 32140),
        #   ST_GeomFromText('<buffer_wkt>', 32140))
        # FROM "distapp_censuszipcode";
        dists_m = [3553.30384972258, 1243.18391525602, 2186.15439472242]

        # Having our buffer in the SRID of the transformation and of the field
        # -- should get the same results. The first buffer has no need for
        # transformation SQL because it is the same SRID as what was given
        # to `transform()`.  The second buffer will need to be transformed,
        # however.
        buf1 = z.poly.centroid.buffer(100)
        buf2 = buf1.transform(4269, clone=True)
        ref_zips = ['77002', '77025', '77401']

        for buf in [buf1, buf2]:
            qs = CensusZipcode.objects.exclude(
                name='77005').annotate(distance=Distance(
                    Transform('poly', 32140), buf)).order_by('name')
            self.assertEqual(ref_zips, sorted([c.name for c in qs]))
            for i, z in enumerate(qs):
                self.assertAlmostEqual(z.distance.m, dists_m[i], 5)
Ejemplo n.º 3
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)
Ejemplo n.º 4
0
 def get_queryset(self):
     qs = Site.objects.filter(published=True)
     if 'source' in self.request.GET:
         qs = qs.filter(source__name__in=self.request.GET['source'].split(','))
     if 'portal' in self.request.GET:
         qs = qs.filter(Q(portal__name=self.request.GET['portal']) | Q(portal=None))
     return qs.annotate(api_geom=Transform("geom", settings.API_SRID))
Ejemplo n.º 5
0
 def get_queryset(self):
     pk = self.kwargs['pk']
     dive = get_object_or_404(Dive.objects.existing(), pk=pk)
     if not dive.is_public():
         raise Http404
     return dive.services.filter(type__published=True).annotate(
         api_geom=Transform("geom", settings.API_SRID))
Ejemplo n.º 6
0
 def get_queryset(self):
     pk = self.kwargs['pk']
     trek = get_object_or_404(Trek.objects.existing(), pk=pk)
     if not self.request.user.has_perm(
             'trekking.read_service') and not trek.is_public():
         raise Http404
     return trek.services.filter(type__published=True).annotate(
         api_geom=Transform("geom", settings.API_SRID))
Ejemplo n.º 7
0
def kml(request,
        label,
        model,
        field_name=None,
        compress=False,
        using=DEFAULT_DB_ALIAS):
    """
    This view generates KML for the given app label, model, and field name.

    The model's default manager must be GeoManager, and the field name
    must be that of a geographic field.
    """
    placemarks = []
    try:
        klass = apps.get_model(label, model)
    except LookupError:
        raise Http404(
            'You must supply a valid app label and module name.  Got "%s.%s"' %
            (label, model))

    if field_name:
        try:
            field = klass._meta.get_field(field_name)
            if not isinstance(field, GeometryField):
                raise FieldDoesNotExist
        except FieldDoesNotExist:
            raise Http404('Invalid geometry field.')

    connection = connections[using]

    if connection.features.has_AsKML_function:
        # Database will take care of transformation.
        placemarks = klass._default_manager.using(using).annotate(
            kml=AsKML(field_name))
    else:
        # If the database offers no KML method, we use the `kml`
        # attribute of the lazy geometry instead.
        placemarks = []
        if connection.features.has_Transform_function:
            qs = klass._default_manager.using(using).annotate(
                **{'%s_4326' % field_name: Transform(field_name, 4326)})
            field_name += '_4326'
        else:
            qs = klass._default_manager.using(using).all()
        for mod in qs:
            mod.kml = getattr(mod, field_name).kml
            placemarks.append(mod)

    # Getting the render function and rendering to the correct.
    if compress:
        render = render_to_kmz
    else:
        render = render_to_kml
    return render('gis/kml/placemarks.kml', {'places': placemarks})
Ejemplo n.º 8
0
 def test_perimeter_geodetic(self):
     # Currently only Oracle supports calculating the perimeter on geodetic
     # geometries (without being transformed).
     qs1 = CensusZipcode.objects.annotate(perim=Perimeter('poly'))
     if connection.features.supports_perimeter_geodetic:
         self.assertAlmostEqual(qs1[0].perim.m, 18406.3818954314, 3)
     else:
         with self.assertRaises(NotSupportedError):
             list(qs1)
     # But should work fine when transformed to projected coordinates
     qs2 = CensusZipcode.objects.annotate(perim=Perimeter(Transform('poly', 32140))).filter(name='77002')
     self.assertAlmostEqual(qs2[0].perim.m, 18404.355, 3)
Ejemplo n.º 9
0
    def get_queryset(self):
        qs = _aquifer_qs(self.request)

        qs = qs.annotate(
            extent=Cast(Transform(Func('geom', function='ST_Envelope'), 4326),
                        output_field=TextField()))

        return qs.values('aquifer_id', 'aquifer_name', 'location_description',
                         'demand__description', 'material__description',
                         'subtype__description', 'vulnerability__description',
                         'productivity__description', 'area', 'mapping_year',
                         'litho_stratographic_unit', 'retire_date', 'extent')
Ejemplo n.º 10
0
        def get_queryset(self):
            dive = get_object_or_404(Dive.objects.existing(),
                                     pk=self.kwargs['pk'])

            queryset = dive.touristic_events.filter(published=True)
            if 'source' in self.request.GET:
                queryset = queryset.filter(
                    source__name__in=self.request.GET['source'].split(','))
            if 'portal' in self.request.GET:
                queryset = queryset.filter(
                    portal__name=self.request.GET['portal'])
            return queryset.annotate(
                api_geom=Transform("geom", settings.API_SRID))
Ejemplo n.º 11
0
 def serialize(self, treks):
     self.xml.startDocument()
     self.xml.startElement('circuits', {'version': '2'})
     for trek in treks:
         self.xml.startElement(
             'circuit', {
                 'date_creation': timestamp(trek.date_insert),
                 'date_modification': timestamp(trek.date_update),
                 'id_circuit': str(trek.pk),
             })
         orig_lang = translation.get_language()
         self.xml.startElement('informations', {})
         for lang in trek.published_langs:
             translation.activate(lang)
             self.xml.startElement('information', {'langue': lang})
             self.serialize_field('titre', trek.name)
             self.serialize_description(trek)
             self.serialize_medias(self.request, trek.serializable_pictures)
             if any([getattr(trek, name)
                     for name in self.ADDITIONNAL_INFO]):
                 self.xml.startElement('informations_complementaires', {})
                 for name in self.ADDITIONNAL_INFO:
                     self.serialize_additionnal_info(trek, name)
                 self.xml.endElement('informations_complementaires')
             self.serialize_tags(trek)
             self.xml.endElement('information')
         translation.activate(orig_lang)
         self.xml.endElement('informations')
         self.serialize_field('distance', int(trek.length))
         self.serialize_locomotions(trek)
         kml_url = reverse('trekking:trek_kml_detail',
                           kwargs={
                               'lang': get_language(),
                               'pk': trek.pk,
                               'slug': trek.slug
                           })
         self.serialize_field(
             'fichier_trace', '',
             {'url': self.request.build_absolute_uri(kml_url)})
         if not self.exclude_pois:
             if trek.published_pois:
                 self.xml.startElement('pois', {})
                 self.serialize_pois(
                     trek.published_pois.annotate(
                         transformed_geom=Transform('geom', 4326)))
                 self.xml.endElement('pois')
         self.xml.endElement('circuit')
     self.xml.endElement('circuits')
     self.xml.endDocument()
Ejemplo n.º 12
0
    def get_queryset(self):
        qs = self.model.objects.existing()
        qs = qs.select_related('structure', 'difficulty', 'practice')
        qs = qs.prefetch_related('levels', 'source', 'portal', 'themes',
                                 'attachments')
        qs = qs.filter(published=True).order_by('pk').distinct('pk')
        if 'source' in self.request.GET:
            qs = qs.filter(
                source__name__in=self.request.GET['source'].split(','))

        if 'portal' in self.request.GET:
            qs = qs.filter(
                Q(portal__name=self.request.GET['portal']) | Q(portal=None))

        qs = qs.annotate(api_geom=Transform("geom", settings.API_SRID))

        return qs
Ejemplo n.º 13
0
    def filter_queryset(self, request, queryset, view):
        point = request.query_params.get('point', None)
        radius = request.query_params.get('radius', None)
        srid = request.query_params.get('srid', 4326)

        if point and radius:
            try:
                shape = GEOSGeometry(point, srid=int(srid))
                assert shape.geom_type == 'Point'
            except (ValueError, AssertionError, GDALException, GEOSException):
                pass
            else:
                shape.transform(3005)
                queryset = queryset.annotate(geom_albers=Transform('geom', 3005)) \
                    .filter(geom_albers__dwithin=(shape, D(m=radius)))

        return queryset
Ejemplo n.º 14
0
    def get_queryset(self):
        trek = get_object_or_404(Trek.objects.existing(), pk=self.kwargs['pk'])
        if not trek.is_public():
            raise Http404
        queryset = trek.touristic_contents.filter(published=True)

        if 'categories' in self.request.GET:
            queryset = queryset.filter(
                category__pk__in=self.request.GET['categories'].split(','))

        if 'source' in self.request.GET:
            queryset = queryset.filter(
                source__name__in=self.request.GET['source'].split(','))

        if 'portal' in self.request.GET:
            queryset = queryset.filter(portal__name=self.request.GET['portal'])

        return queryset.annotate(api_geom=Transform("geom", settings.API_SRID))
Ejemplo n.º 15
0
    def get_queryset(self):
        qs = self.model.objects.existing()
        qs = qs.select_related('structure', 'difficulty', 'practice', 'route')
        qs = qs.prefetch_related(
            'networks',
            'source',
            'portal',
            'web_links',
            'accessibilities',
            'themes',
            'aggregations',
            'information_desks',
            'attachments',
            Prefetch('trek_relationship_a',
                     queryset=TrekRelationship.objects.select_related(
                         'trek_a', 'trek_b')),
            Prefetch('trek_relationship_b',
                     queryset=TrekRelationship.objects.select_related(
                         'trek_a', 'trek_b')),
            Prefetch('trek_children',
                     queryset=OrderedTrekChild.objects.select_related(
                         'parent', 'child')),
            Prefetch('trek_parents',
                     queryset=OrderedTrekChild.objects.select_related(
                         'parent', 'child')),
        )
        qs = qs.filter(Q(published=True) | Q(trek_parents__parent__published=True)).distinct('practice__order', 'pk').\
            order_by('-practice__order', 'pk')
        if 'source' in self.request.GET:
            qs = qs.filter(
                source__name__in=self.request.GET['source'].split(','))

        if 'portal' in self.request.GET:
            qs = qs.filter(
                Q(portal__name=self.request.GET['portal']) | Q(portal=None))

        qs = qs.annotate(api_geom=Transform("geom", settings.API_SRID))

        return qs
Ejemplo n.º 16
0
def guess_maxzoom(layer):
    features = layer.features.all()
    layer_query = features.annotate(geom3857=Transform('geom', EPSG_3857))

    layer_raw_query, args = layer_query.query.sql_with_params()

    try:
        with connection.cursor() as cursor:
            sql_query = f'''
                WITH
                q1 AS ({layer_raw_query}),
                q2 AS (SELECT ST_X((ST_DumpPoints(geom3857)).geom) AS x FROM q1),
                q3 AS (SELECT x - lag(x) OVER (ORDER BY x) AS dst FROM q2),
                q4 AS (SELECT * FROM q3 WHERE dst > 0)
                SELECT
                    exp(sum(ln(dst))/count(dst)) AS avg
                FROM
                    q4
                '''
            cursor.execute(sql_query, args)
            row = cursor.fetchone()

        # geometric mean of the |x_{i+1}-x_i| for all points (x,y) in layer.pk
        avg = row[0]

        # total number of pixels to represent length `avg` (equator)
        nb_pixels_total = 2 * pi * EARTH_RADIUS / avg

        tile_resolution = VectorTile.TILE_WIDTH_PIXEL * VectorTile.EXTENT_RATIO

        # zoom (ceil) to fit those pixels at `tile_resolution`
        max_zoom = ceil(log(nb_pixels_total / tile_resolution, 2))

        return min(max_zoom, 22)
    except TypeError:
        return 14  # Arbitrary zoom value
Ejemplo n.º 17
0
    def get_tile(self, x, y, z, name=None, features_pks=None):
        xmin, ymin, xmax, ymax = self.get_tile_bbox(x, y, z)
        pixel_width_x, pixel_width_y = self.pixel_widths(
            xmin, ymin, xmax, ymax)

        # Intersects on internal data projection using pixel buffer
        layer_query = self.layer.features.filter(
            geom__intersects=Transform(
                MakeEnvelope(xmin - pixel_width_x * self.pixel_buffer,
                             ymin - pixel_width_y * self.pixel_buffer,
                             xmax + pixel_width_x * self.pixel_buffer,
                             ymax + pixel_width_y * self.pixel_buffer,
                             EPSG_3857),
                app_settings.INTERNAL_GEOMETRY_SRID))\
            .annotate(
            outgeom3857=Transform('geom', EPSG_3857),
        )

        # Filter features
        layer_query = self._filter_on_property(layer_query,
                                               self.features_filter)
        layer_query = self._filter_on_geom_size(layer_query,
                                                self.layer.layer_geometry,
                                                pixel_width_x, pixel_width_y)
        if features_pks:
            layer_query = layer_query.filter(pk__in=list(features_pks))
        # Lighten geometry
        layer_query = self._simplify(layer_query, pixel_width_x, pixel_width_y)

        # Seatbelt
        layer_query = self._limit(layer_query, self.features_limit)

        layer_raw_query, args = layer_query.query.sql_with_params()

        if self.properties_filter:
            filter = ', '.join([f"'{f}'" for f in self.properties_filter])
            properties = f'''
                (
                    SELECT jsonb_object_agg(key, value) FROM
                    jsonb_each(properties)
                    WHERE key IN ({filter})
                )
                '''
        elif self.properties_filter == []:
            properties = "'{}'::jsonb"
        else:
            properties = "properties"

        properties += " || json_build_object('_id', identifier)::jsonb"

        with connection.cursor() as cursor:
            sql_query = f'''
                WITH
                fullgeom AS ({layer_raw_query}),
                tilegeom AS (
                    SELECT
                        ({properties}) AS properties,
                        ST_AsMvtGeom(
                            outgeom3857,
                            ST_MakeEnvelope({xmin}, {ymin}, {xmax}, {ymax}, {EPSG_3857}),
                            {self.TILE_WIDTH_PIXEL * self.EXTENT_RATIO},
                            {self.pixel_buffer * self.EXTENT_RATIO},
                            true) AS geometry
                    FROM
                        fullgeom)
                SELECT
                    count(*) AS count,
                    ST_AsMVT(
                        tilegeom,
                        CAST(%s AS text),
                        {self.TILE_WIDTH_PIXEL * self.EXTENT_RATIO},
                        'geometry'
                    ) AS mvt
                FROM
                    tilegeom
            '''
            name = name if name else self.layer.name
            cursor.execute(sql_query, args + (name, ))
            row = cursor.fetchone()

            return row[0], row[1]
Ejemplo n.º 18
0
 def get_queryset(self):
     pk = self.kwargs['pk']
     trek = get_object_or_404(Trek.objects.existing(), pk=pk)
     return trek.information_desks.all().annotate(
         api_geom=Transform("geom", settings.API_SRID))
Ejemplo n.º 19
0
 def get_extent(self, srid=3857):
     return self.features.annotate(
         geom_transformed=Transform('geom', srid)
     ).aggregate(
         extent=Extent('geom_transformed')
     )
Ejemplo n.º 20
0
 def get_queryset(self):
     return Blade.objects.all().annotate(
         api_geom=Transform("signage__geom", settings.API_SRID))
Ejemplo n.º 21
0
 def get_queryset(self):
     return super().get_queryset().annotate(_area=Area('geometry'), geom=Cast('geometry', output_field=models.GeometryField()), transformed=Transform('geom', 31370))
Ejemplo n.º 22
0
 def get_queryset(self):
     return Trail.objects.existing().annotate(
         api_geom=Transform("geom", settings.API_SRID))
Ejemplo n.º 23
0
 def get_queryset(self):
     return Path.objects.annotate(
         api_geom=Transform("geom", settings.API_SRID))
Ejemplo n.º 24
0
 def get_queryset(self):
     qs = super(InformationDeskViewSet, self).get_queryset()
     if self.kwargs.get('type'):
         qs = qs.filter(type_id=self.kwargs['type'])
     qs = qs.annotate(api_geom=Transform("geom", settings.API_SRID))
     return qs
Ejemplo n.º 25
0
def getfeature(request, service, wfs_version):
    context = {}
    propertyname = None
    featureversion = None
    maxfeatures = None
    typename = None
    featureid = None
    filtr = None
    bbox = None
    bbox_has_crs = False
    outputFormat = None
    resolution = None

    # A fallback value, if no features can be found
    crs = WGS84_CRS

    for key, value in request.GET.items():
        low_key = key.lower()
        low_value = value.lower()

        if low_key == "propertyname":
            propertyname = low_value

        elif low_key == "featureversion":
            featureversion = low_value

        elif low_key == "maxfeatures":
            try:
                maxfeatures = int(low_value)
            except:
                return wfs_exception(request, "InvalidParameterValue",
                                     "maxfeatures", value)
            else:
                if maxfeatures < 1:
                    return wfs_exception(request, "InvalidParameterValue",
                                         "maxfeatures", value)

        elif low_key == "typename":
            typename = low_value

        elif low_key == "featureid":
            featureid = low_value

        elif low_key == "filter":
            filtr = low_value

        elif low_key == "resolution":
            try:
                resolution = float(low_value)
            except:
                return wfs_exception(request, "InvalidParameterValue",
                                     "resolution", value)

        elif low_key == "bbox":
            #
            # See the following URL for all the gory details on the passed in bounding box:
            #
            # http://augusttown.blogspot.co.at/2010/08/mysterious-bbox-parameter-in-web.html
            bbox_values = low_value.split(",")

            if len(bbox_values) != 4 and (wfs_version == "1.0.0"
                                          or len(bbox_values) != 5):
                return wfs_exception(request, "InvalidParameterValue", "bbox",
                                     value)

            try:
                bbox_has_crs = len(bbox_values) == 5

                bbox_crs = CRS(bbox_values[4]) if bbox_has_crs else crs

                if bbox_crs.crsid == "CRS84":
                    # we and GeoDjango operate in longitude/latitude mode, so ban CRS84
                    bbox = Polygon.from_bbox(
                        (float(bbox_values[1]), float(bbox_values[0]),
                         float(bbox_values[3]), float(bbox_values[2])))
                    bbox_crs = WGS84_CRS
                else:
                    bbox = Polygon.from_bbox(
                        (float(bbox_values[0]), float(bbox_values[1]),
                         float(bbox_values[2]), float(bbox_values[3])))

                bbox.set_srid(bbox_crs.srid)
            except:
                return wfs_exception(request, "InvalidParameterValue",
                                     "maxfeatures", value)

        elif low_key == "srsname":
            try:
                crs = CRS(low_value)

                if crs.crsid == "CRS84":
                    # we and GeoDjango operate in longitude/latitude mode, so ban CRS84
                    crs = WGS84_CRS

            except:
                return wfs_exception(request, "InvalidParameterValue",
                                     "maxfeatures", value)

            # This is for the case, that srsname is hit after the bbox parameter above
            if bbox and not bbox_has_crs:
                bbox.set_srid(crs.srid)

        elif low_key == "filter":
            filtr = low_value

        elif low_key == "outputformat":

            if low_value in ALL_JSON_OUTPUT_FORMATS:
                outputFormat = JSON_OUTPUT_FORMAT
            elif low_value in ALL_XML_OUTPUT_FORMATS:
                outputFormat = XML_OUTPUT_FORMAT
            else:
                return wfs_exception(request, "InvalidParameterValue",
                                     "outputformat", value)

    if propertyname is not None:
        raise NotImplementedError

    if featureversion is not None:
        raise NotImplementedError

    if filtr is not None:
        raise NotImplementedError

    result_bbox = None

    # If FeatureID is present we return every feature on the list of ID's
    if featureid is not None:

        feature_list = []

        # we assume every feature is identified by its Featuretype name + its object ID like "name.id"
        for feature in featureid.split(","):
            try:
                ftname, fid = get_feature_from_parameter(feature)
            except ValueError:
                return wfs_exception(request, "InvalidParameterValue",
                                     "featureid", feature)
            try:
                ft = service.featuretype_set.get(name=ftname)
                ft_crs = CRS(ft.srs)
                try:
                    geom_field = ft.find_first_geometry_field()
                    if geom_field is None:
                        return wfs_exception(request, "NoGeometryField",
                                             "feature")

                    flter = json.loads(ft.query)
                    objs = ft.model.model_class().objects

                    if bbox:
                        bbox_args = {geom_field + "__bboverlaps": bbox}
                        objs = objs.filter(**bbox_args)

                    if crs.srid != ft_crs.srid:
                        objs = objs.annotate(
                            xform=Transform(geom_field, crs.srid))
                        geom_field = "xform"

                    if outputFormat == JSON_OUTPUT_FORMAT:
                        objs = objs.annotate(geojson=AsGeoJSON(geom_field))
                    else:
                        objs = objs.annotate(gml=AsGML(geom_field))

                    if flter:
                        objs = objs.filter(**flter)

                    f = objs.filter(id=fid)

                    bb_res = f.aggregate(Extent(geom_field))[geom_field +
                                                             '__extent']

                    if log.getEffectiveLevel() <= logging.DEBUG:
                        log.debug("Bounding box for feature [%s] is [%s]" %
                                  (feature, bb_res))

                    if result_bbox is None:
                        result_bbox = bb_res
                    else:
                        result_bbox = (min(result_bbox[0], bb_res[0]),
                                       min(result_bbox[1], bb_res[1]),
                                       max(result_bbox[2], bb_res[2]),
                                       max(result_bbox[3], bb_res[3]))

                    feature_list.append((ft, f[0]))
                except:
                    log.exception("caught exception in request [%s %s?%s]",
                                  request.method, request.path,
                                  request.environ['QUERY_STRING'])
                    return wfs_exception(request, "MalformedJSONQuery",
                                         "query")
            except FeatureType.DoesNotExist:
                return wfs_exception(request, "InvalidParameterValue",
                                     "featureid", feature)
    # If FeatureID isn't present we rely on TypeName and return every feature present it the requested FeatureTypes
    elif typename is not None:

        feature_list = type_feature_iter()

        for typen in typename.split(","):
            try:
                ft = service.featuretype_set.get(name__iexact=typen)
                ft_crs = CRS(ft.srs)
            except FeatureType.DoesNotExist:
                return wfs_exception(request, "InvalidParameterValue",
                                     "typename", typen)
            try:
                geom_field = ft.find_first_geometry_field()
                if geom_field is None:
                    return wfs_exception(request, "NoGeometryField", "feature")

                flter = json.loads(ft.query)

                objs = ft.model.model_class().objects

                if bbox:
                    bbox_args = {geom_field + "__bboverlaps": bbox}
                    objs = objs.filter(**bbox_args)

                if crs.srid != ft_crs.srid:
                    objs = objs.annotate(xform=Transform(geom_field, crs.srid))
                    geom_field = "xform"

                if outputFormat == JSON_OUTPUT_FORMAT:
                    objs = objs.annotate(geojson=AsGeoJSON(geom_field))
                else:
                    objs = objs.annotate(gml=AsGML(geom_field))

                if flter:
                    objs = objs.filter(**flter)

                if resolution is not None:

                    res_flter = ft.resolutionfilter_set.filter(
                        min_resolution__lte=resolution).order_by(
                            "-min_resolution").first()

                    if res_flter:
                        log.debug(
                            "Applying extra filter [%s] with condition [%s] for resolution [%f]"
                            % (res_flter, res_flter.query, resolution))
                        res_flter_parsed = json.loads(res_flter.query)
                        objs = objs.filter(**res_flter_parsed)

                bb_res = objs.aggregate(Extent(geom_field))[geom_field +
                                                            '__extent']

                if log.getEffectiveLevel() <= logging.DEBUG:
                    log.debug("Bounding box for feature type [%s] is [%s]" %
                              (typen, bb_res))

                if result_bbox is None:
                    result_bbox = bb_res
                else:
                    result_bbox = (min(result_bbox[0], bb_res[0]),
                                   min(result_bbox[1], bb_res[1]),
                                   max(result_bbox[2], bb_res[2]),
                                   max(result_bbox[3], bb_res[3]))

                feature_list.add_type_with_features(ft, objs)

            except:
                log.exception("caught exception in request [%s %s?%s]",
                              request.method, request.path,
                              request.environ['QUERY_STRING'])
                return wfs_exception(request, "MalformedJSONQuery", "query")
    else:
        return wfs_exception(request, "MissingParameter", "typename")

    if outputFormat == JSON_OUTPUT_FORMAT:

        return StreamingHttpResponse(streaming_content=GeoJsonIterator(
            service.id, crs, result_bbox, feature_list),
                                     content_type="application/json")

    else:
        context['features'] = feature_list
        if result_bbox:
            context['bbox0'] = result_bbox[0]
            context['bbox1'] = result_bbox[1]
            context['bbox2'] = result_bbox[2]
            context['bbox3'] = result_bbox[3]
        context['crs'] = crs
        context['version'] = wfs_version
        context[
            'wfs_path'] = "1.0.0/WFS-basic.xsd" if wfs_version == "1.0.0" else "1.1.0/wfs.xsd"
        return render(request,
                      'getFeature.xml',
                      context,
                      content_type="text/xml")
Ejemplo n.º 26
0
 def get_queryset(self):
     return Infrastructure.objects.existing().filter(published=True).annotate(api_geom=Transform("geom", settings.API_SRID))
Ejemplo n.º 27
0
 def get_queryset(self):
     return Service.objects.existing().filter(
         type__published=True).annotate(
             api_geom=Transform("geom", settings.API_SRID))
Ejemplo n.º 28
0
def getfeature(request, service, wfs_version):
    context = {}
    propertyname = None
    featureversion = None
    maxfeatures = None
    typename = None
    featureid = None
    filtr = None
    bbox = None
    bbox_has_crs = False
    outputFormat = None
    resolution = None
    precision = None

    # A fallback value, if no features can be found
    crs = WGS84_CRS

    for key, value in request.GET.items():
        low_key = key.lower()
        low_value = value.lower()

        if low_key == "propertyname":
            propertyname = low_value

        elif low_key == "featureversion":
            featureversion = low_value

        elif low_key == "maxfeatures":
            try:
                maxfeatures = int(low_value)
            except:
                return wfs_exception(request, "InvalidParameterValue",
                                     "maxfeatures", value)
            else:
                if maxfeatures < 1:
                    return wfs_exception(request, "InvalidParameterValue",
                                         "maxfeatures", value)

        elif low_key == "typename":
            typename = low_value

        elif low_key == "featureid":
            featureid = low_value

        elif low_key == "filter":
            filtr = low_value

        elif low_key == "resolution":
            try:
                resolution = float(low_value)
            except:
                return wfs_exception(request, "InvalidParameterValue",
                                     "resolution", value)

        elif low_key == "precision":
            try:
                precision = float(low_value)
            except:
                return wfs_exception(request, "InvalidParameterValue",
                                     "precision", value)

        elif low_key == "bbox":
            #
            # See the following URL for all the gory details on the passed in bounding box:
            #
            # http://augusttown.blogspot.co.at/2010/08/mysterious-bbox-parameter-in-web.html
            bbox_values = low_value.split(",")

            if len(bbox_values) != 4 and (wfs_version == "1.0.0"
                                          or len(bbox_values) != 5):
                return wfs_exception(request, "InvalidParameterValue", "bbox",
                                     value)

            try:
                bbox_has_crs = len(bbox_values) == 5

                bbox_crs = CRS(bbox_values[4]) if bbox_has_crs else crs

                if bbox_crs.crsid == "CRS84":
                    # we and GeoDjango operate in longitude/latitude mode, so ban CRS84
                    bbox = Polygon.from_bbox(
                        (float(bbox_values[1]), float(bbox_values[0]),
                         float(bbox_values[3]), float(bbox_values[2])))
                    bbox_crs = WGS84_CRS
                else:
                    bbox = Polygon.from_bbox(
                        (float(bbox_values[0]), float(bbox_values[1]),
                         float(bbox_values[2]), float(bbox_values[3])))

                bbox.set_srid(bbox_crs.srid)
            except:
                return wfs_exception(request, "InvalidParameterValue", "bbox",
                                     value)

        elif low_key == "srsname":
            try:
                crs = CRS(low_value)

                if crs.crsid == "CRS84":
                    # we and GeoDjango operate in longitude/latitude mode, so ban CRS84
                    crs = WGS84_CRS

            except:
                return wfs_exception(request, "InvalidParameterValue",
                                     "maxfeatures", value)

            # This is for the case, that srsname is hit after the bbox parameter above
            if bbox and not bbox_has_crs:
                bbox.set_srid(crs.srid)

        elif low_key == "filter":
            filtr = low_value

        elif low_key == "outputformat":

            if low_value in ALL_JSON_OUTPUT_FORMATS:
                outputFormat = JSON_OUTPUT_FORMAT
            elif low_value in ALL_XML_OUTPUT_FORMATS:
                outputFormat = XML_OUTPUT_FORMAT
            else:
                return wfs_exception(request, "InvalidParameterValue",
                                     "outputformat", value)

    if propertyname is not None:
        raise NotImplementedError

    if featureversion is not None:
        raise NotImplementedError

    if filtr is not None:
        raise NotImplementedError

    result_bbox = None

    closeable = None

    try:

        # If FeatureID is present we return every feature on the list of ID's
        if featureid is not None:

            feature_list = []

            # we assume every feature is identified by its Featuretype name + its object ID like "name.id"
            for feature in featureid.split(","):
                try:
                    ftname, fid = get_feature_from_parameter(feature)
                except ValueError:
                    return wfs_exception(request, "InvalidParameterValue",
                                         "featureid", feature)
                try:
                    ft = service.featuretype_set.get(name=ftname)
                    ft_crs = CRS(ft.srs)
                    try:

                        if ft.model is None:

                            # GML output of raw results not yet implemented
                            if outputFormat != JSON_OUTPUT_FORMAT:
                                raise NotImplementedError

                            # prepare SQL statement
                            select = parse_single(
                                preprocess_query(ft.query, resolution,
                                                 precision, bbox))
                            identifiers = get_identifiers(select)
                            shape = find_identifier(identifiers, "shape")
                            idi = find_identifier(identifiers, "id")

                            # replace shape by ST_Simplify(shape,%s)
                            if precision is not None:
                                simplified = build_function_call(
                                    "ST_Simplify", shape, 1, True)
                                replace_identifier(identifiers, shape,
                                                   simplified)

                            # add restriction id=%s
                            add_condition(select, build_comparison(idi, "="))

                            sql = str(select)

                            if log.getEffectiveLevel() <= logging.DEBUG:
                                log.debug(
                                    "Final SQL for feature [%s] is [%s]" %
                                    (feature, sql))

                            # raw SQL result set
                            with connection.cursor() as cur:

                                if precision is None:
                                    cur.execute(sql, (fid, ))
                                else:
                                    cur.execute(sql, (precision, fid))

                                row = cur.fetchone()

                                feature = RawFeature(cur.description, row,
                                                     crs.srid)

                                if feature.geometry is None:
                                    return wfs_exception(
                                        request, "NoGeometryField", "feature")

                                feature_list.append((ft, feature))
                        else:
                            # django model based result set.
                            geom_field = ft.find_first_geometry_field()
                            if geom_field is None:
                                return wfs_exception(request,
                                                     "NoGeometryField",
                                                     "feature")

                            flter = parse_query(ft.query)
                            objs = ft.model.model_class().objects

                            if flter:
                                objs = objs.filter(**flter)

                            if bbox:
                                bbox_args = {geom_field + "__bboverlaps": bbox}
                                objs = objs.filter(**bbox_args)

                            objs = objs.filter(id=fid)

                            if crs.srid != ft_crs.srid:
                                objs = objs.annotate(
                                    xform=Transform(geom_field, crs.srid))
                                geom_field = "xform"

                            bb_res = objs.aggregate(
                                Extent(geom_field))[geom_field + '__extent']

                            if log.getEffectiveLevel() <= logging.DEBUG:
                                log.debug(
                                    "Bounding box for feature [%s] is [%s]" %
                                    (feature, bb_res))

                            if result_bbox is None:
                                result_bbox = bb_res
                            else:
                                result_bbox = (min(result_bbox[0], bb_res[0]),
                                               min(result_bbox[1], bb_res[1]),
                                               max(result_bbox[2], bb_res[2]),
                                               max(result_bbox[3], bb_res[3]))

                            if outputFormat == XML_OUTPUT_FORMAT:
                                objs = objs.annotate(gml=AsGML(geom_field))

                            f = objs.first()

                            if f is None:
                                log.warning("Feature with ID [%s] not found." %
                                            feature)
                            else:
                                if outputFormat == JSON_OUTPUT_FORMAT:
                                    feature_list.append(
                                        (ft,
                                         DjangoFeature(ft, objs[0],
                                                       precision)))
                                else:
                                    feature_list.append((ft, objs[0]))

                    except:
                        log.exception("caught exception in request [%s %s?%s]",
                                      request.method, request.path,
                                      request.environ['QUERY_STRING'])
                        return wfs_exception(request, "MalformedJSONQuery",
                                             "query")
                except FeatureType.DoesNotExist:
                    return wfs_exception(request, "InvalidParameterValue",
                                         "featureid", feature)
        # If FeatureID isn't present we rely on TypeName and return every feature present it the requested FeatureTypes
        elif typename is not None:

            feature_list = type_feature_iter(
                outputFormat != JSON_OUTPUT_FORMAT, crs.srid, precision)
            closeable = feature_list

            for typen in typename.split(","):
                try:
                    ft = service.featuretype_set.get(name__iexact=typen)
                    ft_crs = CRS(ft.srs)
                except FeatureType.DoesNotExist:
                    return wfs_exception(request, "InvalidParameterValue",
                                         "typename", typen)

                if ft.model is None:

                    # raw SQL result set

                    # GML output of raw results not yet implemented
                    if outputFormat != JSON_OUTPUT_FORMAT:
                        raise NotImplementedError

                    # prepare SQL statement
                    select = parse_single(
                        preprocess_query(ft.query, resolution, precision,
                                         bbox))
                    identifiers = get_identifiers(select)
                    shape = find_identifier(identifiers, "shape")
                    idi = find_identifier(identifiers, "id")

                    # parameters of SQL query
                    params = []

                    # replace shape by ST_Simplify(shape,%s)
                    if precision is not None:
                        simplified = build_function_call(
                            "ST_Simplify", shape, 1, True)
                        replace_identifier(identifiers, shape, simplified)
                        params.append(precision)

                    if resolution is not None:

                        res_flter = ft.resolutionfilter_set.filter(
                            min_resolution__lte=resolution).order_by(
                                "-min_resolution").first()

                        if res_flter:
                            if log.getEffectiveLevel() <= logging.DEBUG:
                                log.debug(
                                    "Applying extra filter [%s] with condition [%s] for resolution [%f]"
                                    % (res_flter, res_flter.query, resolution))

                            res_flter_parsed = parse_single(res_flter.query)

                            add_condition(select, res_flter_parsed)

                    if bbox is not None:

                        if ft.fields:
                            if ft.fields != "{nobbox}":
                                add_condition(
                                    select,
                                    build_function_call(
                                        "ST_Intersects", ft.fields, 1))
                        else:
                            add_condition(
                                select,
                                build_function_call("ST_Intersects", shape, 1))

                        params.append(bbox.hexewkb.decode("utf-8"))

                    sql = str(select)

                    if log.getEffectiveLevel() <= logging.DEBUG:
                        log.debug("Final SQL for feature [%s] is [%s]" %
                                  (ft.name, sql))

                    cur = connection.cursor()

                    try:
                        cur.execute(sql, params)

                        has_geometry = False

                        for colinfo in cur.description:
                            if _is_geom_column(colinfo):
                                has_geometry = True
                                break

                        if not has_geometry:
                            return wfs_exception(request, "NoGeometryField",
                                                 "feature")

                        feature_list.add_type_with_features(ft, cur)

                    except:
                        cur.close()
                        log.exception("caught exception in request [%s %s?%s]",
                                      request.method, request.path,
                                      request.environ['QUERY_STRING'])
                        return wfs_exception(request, "MalformedJSONQuery",
                                             "query")

                else:
                    try:
                        geom_field = ft.find_first_geometry_field()
                        if geom_field is None:
                            return wfs_exception(request, "NoGeometryField",
                                                 "feature")

                        flter = parse_query(ft.query)

                        objs = ft.model.model_class().objects

                        if flter:
                            objs = objs.filter(**flter)

                        if resolution is not None:

                            res_flter = ft.resolutionfilter_set.filter(
                                min_resolution__lte=resolution).order_by(
                                    "-min_resolution").first()

                            if res_flter:
                                log.debug(
                                    "Applying extra filter [%s] with condition [%s] for resolution [%f]"
                                    % (res_flter, res_flter.query, resolution))
                                res_flter_parsed = parse_query(res_flter.query)
                                objs = objs.filter(**res_flter_parsed)

                        if bbox:
                            bbox_args = {geom_field + "__bboverlaps": bbox}
                            objs = objs.filter(**bbox_args)

                        if crs.srid != ft_crs.srid:
                            objs = objs.annotate(
                                xform=Transform(geom_field, crs.srid))
                            geom_field = "xform"

                        bb_res = objs.aggregate(
                            Extent(geom_field))[geom_field + '__extent']

                        if log.getEffectiveLevel() <= logging.DEBUG:
                            log.debug(
                                "Bounding box for feature type [%s] is [%s]" %
                                (typen, bb_res))

                        if result_bbox is None:
                            result_bbox = bb_res
                        else:
                            result_bbox = (min(result_bbox[0], bb_res[0]),
                                           min(result_bbox[1], bb_res[1]),
                                           max(result_bbox[2], bb_res[2]),
                                           max(result_bbox[3], bb_res[3]))

                        if outputFormat == XML_OUTPUT_FORMAT:
                            objs = objs.annotate(gml=AsGML(geom_field))

                        feature_list.add_type_with_features(ft, objs)

                    except:
                        log.exception("caught exception in request [%s %s?%s]",
                                      request.method, request.path,
                                      request.environ['QUERY_STRING'])
                        return wfs_exception(request, "MalformedJSONQuery",
                                             "query")
        else:
            return wfs_exception(request, "MissingParameter", "typename")

        if outputFormat == JSON_OUTPUT_FORMAT:

            ret = StreamingHttpResponse(streaming_content=GeoJsonIterator(
                service.id, crs, result_bbox, feature_list),
                                        content_type="application/json")

        else:
            context['features'] = feature_list
            if result_bbox:
                context['bbox0'] = result_bbox[0]
                context['bbox1'] = result_bbox[1]
                context['bbox2'] = result_bbox[2]
                context['bbox3'] = result_bbox[3]
            context['crs'] = crs
            context['version'] = wfs_version
            context[
                'wfs_path'] = "1.0.0/WFS-basic.xsd" if wfs_version == "1.0.0" else "1.1.0/wfs.xsd"
            ret = render(request,
                         'getFeature.xml',
                         context,
                         content_type="text/xml")

        # Now, closing of resources is delegated to the HTTP response
        closeable = None
        return ret

    finally:
        if closeable is not None:
            try:
                closeable.close()
            except:
                log.exception(
                    "Error closing left-over SQL cursor in WFS service.")
Ejemplo n.º 29
0
Archivo: api.py Proyecto: frwickst/ltj
class FeatureViewSet(ProtectedViewSet):
    queryset = Feature.objects.all().annotate(geom=Transform(
        'geometry', 4326))  # display coordinates in WGS84
    serializer_class = FeatureSerializer
Ejemplo n.º 30
0
def calculate_area_field(apps, schema_editor):
    SpatialUnit = apps.get_model('spatial', 'SpatialUnit')
    SpatialUnit.objects.exclude(geometry=None).extra(
        where=["geometrytype(geometry) LIKE 'POLYGON'"]).update(
            area=Area(Transform('geometry', 3857)))