Query Features in box

This example shows how to Query features in the box on MapView

  • Query features about existing layer id and filter

  • Query features about custom layer id

Query Features in box

For all code examples, refer to Android Maps SDK Code Examples

activity_query_feature_and_symbol.xml view source

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ai.nextbillion.maps.core.MapView
        android:id="@+id/mapView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:nbmap_cameraTargetLat="52.0907"
        app:nbmap_cameraTargetLng="5.1214"
        app:nbmap_cameraZoom="16" />

    <FrameLayout
        android:id="@+id/selection_box"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:layout_centerInParent="true"
        android:alpha="0.3"
        android:background="@color/palette_mint_100" />

</RelativeLayout>

QueryFeatureAndSymbolActivity view source

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package ai.nextbillion;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.RectF;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import java.io.IOException;
import java.util.List;

import ai.nextbillion.kits.geojson.Feature;
import ai.nextbillion.kits.geojson.FeatureCollection;
import ai.nextbillion.maps.camera.CameraPosition;
import ai.nextbillion.maps.camera.CameraUpdateFactory;
import ai.nextbillion.maps.core.MapView;
import ai.nextbillion.maps.core.NextbillionMap;
import ai.nextbillion.maps.core.Style;
import ai.nextbillion.maps.geometry.LatLng;
import ai.nextbillion.maps.style.expressions.Expression;
import ai.nextbillion.maps.style.layers.FillLayer;
import ai.nextbillion.maps.style.layers.Layer;
import ai.nextbillion.maps.style.layers.SymbolLayer;
import ai.nextbillion.maps.style.sources.GeoJsonSource;
import ai.nextbillion.utils.ResourceUtils;
import androidx.appcompat.app.AppCompatActivity;

import static ai.nextbillion.maps.style.expressions.Expression.get;
import static ai.nextbillion.maps.style.expressions.Expression.literal;
import static ai.nextbillion.maps.style.expressions.Expression.lt;
import static ai.nextbillion.maps.style.expressions.Expression.toNumber;
import static ai.nextbillion.maps.style.layers.PropertyFactory.fillColor;
import static ai.nextbillion.maps.style.layers.PropertyFactory.iconImage;

/**
 * Demo's query rendered features
 */
public class QueryFeatureAndSymbolActivity extends AppCompatActivity {

    public MapView mapView;
    private NextbillionMap nextbillionMap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_query_feature_and_symbol);

        final View selectionBox = findViewById(R.id.selection_box);

        // Initialize map as normal
        mapView = (MapView) findViewById(R.id.mapView);
        mapView.onCreate(savedInstanceState);
        mapView.getMapAsync(nextbillionMap -> {
            QueryFeatureAndSymbolActivity.this.nextbillionMap = nextbillionMap;

            CameraPosition position = new CameraPosition.Builder()
                    .target(new LatLng(14.589503119868022, 120.98188196701062))
                    .zoom(16)
                    .bearing(0)
                    .tilt(30)
                    .build();
            nextbillionMap.animateCamera(CameraUpdateFactory.newCameraPosition(position));

            // Add layer / source
            final GeoJsonSource source = new GeoJsonSource("highlighted-shapes-source");
            final Layer layer = new FillLayer("highlighted-shapes-layer", "highlighted-shapes-source")
                    .withProperties(fillColor(Color.YELLOW));

            selectionBox.setOnClickListener(view -> {
                // Query
                int top = selectionBox.getTop() - mapView.getTop();
                int left = selectionBox.getLeft() - mapView.getLeft();
                RectF box = new RectF(left, top, left + selectionBox.getWidth(), top + selectionBox.getHeight());

                Expression filter = lt(toNumber(get("height")), literal(10));
                List<Feature> features = nextbillionMap.queryRenderedFeatures(box, filter, "building");
                List<Feature> symbols = nextbillionMap.queryRenderedFeatures(box, "symbols-layer");

                // Show count
                Toast.makeText(
                        QueryFeatureAndSymbolActivity.this,
                        String.format("%s buildings in box\n%s symbols in box", features.size(), symbols.size()),
                        Toast.LENGTH_SHORT).show();

                // Update source data
                source.setGeoJson(FeatureCollection.fromFeatures(features));
            });

            nextbillionMap.setStyle(new Style.Builder()
                            .fromUri(StyleConstants.NBMAP_STREETS)
                            .withSource(source)
                            .withLayer(layer)
                    , style -> addSymbolLayer(style));

        });
    }

    public void addSymbolLayer(Style style) {
        try {
            String testPoints = ResourceUtils.readRawResource(mapView.getContext(), R.raw.test_points_utrecht);
            Bitmap markerImage = BitmapFactory.decodeResource(getResources(), R.drawable.nbmap_marker_icon_default);

            style.addImage("test-icon", markerImage);
            style.addSource(new GeoJsonSource("symbols-source", testPoints));
            style.addLayer(new SymbolLayer("symbols-layer", "symbols-source")
                    .withProperties(
                            iconImage("test-icon")
                    ));
        } catch (IOException exception) {
            exception.printStackTrace();
        }
    }

    public NextbillionMap getNextbillionMap() {
        return nextbillionMap;
    }

    @Override
    protected void onStart() {
        super.onStart();
        mapView.onStart();
    }

    @Override
    protected void onResume() {
        super.onResume();
        mapView.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        mapView.onPause();
    }

    @Override
    protected void onStop() {
        super.onStop();
        mapView.onStop();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        mapView.onSaveInstanceState(outState);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mapView.onDestroy();
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        mapView.onLowMemory();
    }
}

The given code is an Android activity that demonstrates how to initialize a MapView, query features on a map, and display the results.

Initializing the MapView:

  • The onCreate method initializes the MapView by setting the content view and obtaining a reference to it using findViewById.

  • The onCreate method also calls mapView.onCreate(savedInstanceState) to create the MapView and mapView.getMapAsync(this) to get a reference to the NextbillionMap instance when it is ready.

Querying Features of an Existing Layer:

  • The code sets up a map and adds a layer called "highlighted-shapes-layer" with a source named "highlighted-shapes-source".

  • The selectionBox view is used to define a rectangular area on the map.

  • When the selectionBox is clicked, the queryRenderedFeatures method is called to query the features within the defined area.

  • The queried features are filtered based on a condition (in this case, the height is less than 10) using an Expression.

  • The queried features are displayed in a toast message.

Querying Features of a Custom Layer:

  • The code adds a custom symbol layer to the map, which is based on a GeoJSON source named "symbols-source".

  • The addSymbolLayer method reads GeoJSON data from a resource file and adds it as a source and layer to the map style.

  • The queryRenderedFeatures method is used to query the features within the defined area for the "symbols-layer" specifically.

  • The queried features are displayed in a toast message.

Other Lifecycle Methods: The code also includes various lifecycle methods (onStart, onResume, onPause, onStop, onSaveInstanceState, onDestroy, onLowMemory) that should be implemented when using the MapView to properly manage its lifecycle and handle configuration changes.

Note: The code uses the Nextbillion Maps SDK and NextbillionMap class to handle map-related operations. It also utilizes the Style class to define the map's visual style, GeoJsonSource class to add data sources, and various layer classes to display map features.

Have Questions ?