Skip to main content

Getting started with Search

|

The Maps SDK for C++ provides a flexible and robust search functionality, allowing the search of locations using text queries and coordinates:

  • Text Search: Perform searches using a text query and geographic coordinates to prioritize results within a specific area.
  • Search Preferences: Customize search behavior using various options, such as allowing fuzzy results, limiting search distance, or specifying the number of results.
  • Category-Based Search: Filter search results by predefined categories, such as gas stations or parking areas.
  • Proximity Search: Retrieve all nearby landmarks without specifying a text query.

The simplest way to search for something is by providing text and specifying coordinates. The coordinates serve as a hint, prioritizing points of interest (POIs) within the indicated area.

LandmarkList results;

SearchPreferences preferences;
preferences.setMaxMatches(40);
preferences.setAllowFuzzyResults(true);

auto listener = StrongPointerFactory<YourProgressListenerImpl>();

const String textFilter("Paris");
Coordinates referenceCoords(45.0, 10.0);

int startErr = SearchService().search(
results,
listener, // progress listener
textFilter,
referenceCoords,
preferences // preferences
// optional locationHint omitted
);

ASSERT_EQ(startErr, KNoError) << "Search did not start";

// Wait for async completion (up to 5s)
WAIT_UNTIL(std::bind(&YourProgressListenerImpl::IsFinished, listener), 5000);

int completeErr = listener->GetError();
if (completeErr == KNoError)
{
GEM_INFO_LOG("Search completed. Results: %d", (int)results.size());
// Basic inspection (names if available)
for (auto &lm : results)
{
if (!lm.isDefault())
{
auto name = lm.getName();
(void)name;
}
}
}
else if (completeErr == error::KCancel)
{
GEM_INFO_LOG("Search canceled by user");
SUCCEED();
}
else
{
GEM_INFO_LOG("Search failed. Error: %d", completeErr);
FAIL() << "Search failed";
}

The err provided notifyComplete or operation start can have the following values:

ValueSignificance
KNoErrorsuccessfully completed
error::KCancelcancelled by the user
error::KNoMemorysearch engine couldn't allocate the necessary memory for the operation
error::KOperationTimeoutsearch was executed on the online service and the operation took too much time to complete (usually more than 1 min, depending on the server overload state)
error::KNetworkTimeoutcan't establish the connection or the server didn't respond on time
error::KNetworkFailedsearch was executed on the online service and the operation failed due to bad network connection

Specifying preferences

As seen in the previous example, before searching we need to specify some SearchPreferences. The following characteristics apply to a search:

MethodsTypeDefault ValueExplanation
setAllowFuzzyResultsbooltrueAllows fuzzy search results, enabling approximate matches for queries.
setEstimateMissingHouseNumbersbooltrueEnables estimation of missing house numbers in address searches.
setExactMatchboolfalseRestricts results to only those that exactly match the query.
setMaxMatchesint40Specifies the maximum number of search results to return.
setSearchAddressesbooltrueIncludes addresses in the search results. This option also includes roads.
setSearchMapPOIsbooltrueIncludes points of interest (POIs) on the map in the search results.
setSearchOnlyOnboardboolfalseLimits the search to onboard (offline) data only.
setThresholdDistanceint2147483647Defines the maximum distance (in meters) for search results from the query location.
setEasyAccessOnlyResultsboolfalseRestricts results to locations that are easily accessible.

Search by category

The Maps SDK for C++ allows the user to filter results based on the category. Some predefined categories are available and can be accessed using GenericCategories()::getCategories.

In the following example, we perform a search for a text query, limiting the results to the first two categories (e.g., gas stations and parking):

LandmarkList results;

SearchPreferences preferences;
preferences.setMaxMatches(40);
preferences.setAllowFuzzyResults(true);
preferences.setSearchMapPOIs(true);
preferences.setSearchAddresses(false);

auto categories = GenericCategories().getCategories();
if (categories.size() >= 2)
{
auto first = categories[0];
auto second = categories[1];
preferences.lmks().addStoreCategoryId(first.getLandmarkStoreId(), first.getId());
preferences.lmks().addStoreCategoryId(second.getLandmarkStoreId(), second.getId());
}

Coordinates position(48.83952, 2.334284);
const String textFilter("Paris");

auto listener = StrongPointerFactory<YourProgressListenerImpl>();

int startErr = SearchService().searchAroundPosition(
results,
listener,
position,
textFilter,
preferences
);

if (startErr != KNoError)
{
GEM_INFO_LOG("searchAroundPosition did not start. Err=%d", startErr);
}
else
{
WAIT_UNTIL(std::bind(&YourProgressListenerImpl::IsFinished, listener), 5000);

int completeErr = listener->GetError();
if (completeErr == KNoError)
{
GEM_INFO_LOG("searchAroundPosition completed. Results=%d", (int)results.size());
for (auto &lm : results)
{
if (!lm.isDefault())
{
auto name = lm.getName();
(void)name;
}
}
}
else if (completeErr == error::KCancel)
{
GEM_INFO_LOG("searchAroundPosition canceled");
}
else
{
GEM_INFO_LOG("searchAroundPosition failed. Err=%d", completeErr);
}
}
tip

Set the searchAddresses to false in order to filter non-relevant results.

Search on custom landmarks

By default all search methods operate on the landmarks provided by default on the map. You can enable search functionality for custom landmarks by creating a landmark store containing the desired landmarks and adding it to the search preferences.

Landmark landmark1;
landmark1.setCoordinates( Coordinates(25.0, 30.0) );
landmark1.setName( "My Custom Landmark1" );

Landmark landmark2;
landmark2.setCoordinates( Coordinates(25.005, 30.005) );
landmark2.setName( "My Custom Landmark2" );

// Create a store and add the landmarks
auto storeResult = LandmarkStoreService().createLandmarkStore( "LandmarksToBeSearched" );
if (storeResult.second == KNoError || storeResult.second == error::KExist)
{
LandmarkStore& store = *storeResult.first;
store.addLandmark( landmark1 );
store.addLandmark( landmark2 );

// Configure search preferences (disable map POIs + addresses: search only custom landmarks)
SearchPreferences preferences;
preferences.setSearchMapPOIs( false );
preferences.setSearchAddresses( false );

// Add the custom store to search preferences
preferences.lmks().add( store );

// Prepare results container and progress listener
LandmarkList results;

auto listener = StrongPointerFactory<YourProgressListenerImpl>();

// Start search
int startErr = SearchService().search(
results,
listener,
String( "My Custom Landmark" ),
Coordinates( 25.003, 30.003 ),
preferences
);

if (startErr == KNoError)
{
// Wait for async completion (max 5s)
WAIT_UNTIL( std::bind( &ProgressListenerImpl::IsFinished, listener ), 5000 );

int completeErr = listener->GetError();
if (completeErr == KNoError)
{
GEM_INFO_LOG( "Number of results: %d", (int)results.size() );
for (auto &lm : results)
{
if (!lm.isDefault())
{
auto name = lm.getName();
(void)name;
}
}
}
else if (completeErr == error::KCancel)
{
GEM_INFO_LOG( "Search canceled" );
}
else
{
GEM_INFO_LOG( "Search failed. Err=%d", completeErr );
}
}
else
{
GEM_INFO_LOG( "Search did not start. Err=%d", startErr );
}
}
else
{
GEM_INFO_LOG( "Could not create or access landmark store. Err=%d", storeResult.second );
}
warning

The landmark store retains the landmarks added to it across sessions, until the app is uninstalled. This means a previously created landmark store with the same name might already exist in persistent storage and may contain pre-existing landmarks. For more details, refer to the documentation on LandmarkStore.

tip

Set the searchAddresses and searchMapPOIs to false in order to filter non-relevant results.

Search on overlays

You can perform searches on overlays by specifying the overlay ID. It is recommended to consult the Overlay documentation for a deeper understanding and details about proper usage.

In the example below, we demonstrate how to search within items from the safety overlay. Custom overlays can also be used, provided they are activated in the applied map style:

int overlayId = ECommonOverlayId::OID_Safety;

OverlayService().enableOverlay( overlayId );

SearchPreferences preferences;
preferences.setSearchMapPOIs(false);
preferences.setSearchAddresses(false);
preferences.overlays().add(overlayId);

LandmarkList results;

auto listener = StrongPointerFactory<YourProgressListenerImpl>();

int startErr = SearchService().search(
results,
listener,
String("Speed"),
Coordinates(48.76930, 2.34483),
preferences
);

if (startErr == KNoError)
{
WAIT_UNTIL(std::bind(&YourProgressListenerImpl::IsFinished, listener), 5000);

int completeErr = listener->GetError();
if (completeErr == KNoError)
{
if (results.empty())
{
GEM_INFO_LOG("No results");
}
else
{
GEM_INFO_LOG("Number of results: %d", (int)results.size());
// If you have a MapView instance:
// mapView->centerOnCoordinates(results.front().getCoordinates());
}
}
else if (completeErr == error::KCancel)
{
GEM_INFO_LOG("Search canceled");
}
else
{
GEM_INFO_LOG("Search failed. Err=%d", completeErr);
}
}
else
{
GEM_INFO_LOG("Search did not start. Err=%d", startErr);
}

In order to convert the returned Landmark to a OverlayItem use the getOverlayItem getter of the Landmark class. This methods returns the associated OverlayItem if available, emtpy otherwise.

tip

Set the searchAddresses and searchMapPOIs to false in order to filter non-relevant results.

warning

Overlay search requires the existence of a MapView with a style that includes the overlay being searched.

If the map is not initialized or the overlay is not part of the current map style, the preferences().overlays().add operation will fail with a error::KNotFound error, and the search will return error::KInvalidInput with no results. The default map style does include all common overlays.

Search for location

If you don't specify any text, all the landmarks in the closest proximity are returned, limited to maxMatches.

LandmarkList results;
SearchPreferences preferences;
preferences.setMaxMatches(40)
.setAllowFuzzyResults(true);

auto listener = StrongPointerFactory<YourProgressListenerImpl>();

Coordinates coords(45.0, 10.0);

int startErr = SearchService().searchAroundPosition(
results,
listener,
coords, // position
String(), // empty text filter
preferences
);

if (startErr == KNoError)
{
WAIT_UNTIL(std::bind(&YourProgressListenerImpl::IsFinished, listener), 5000);

int completeErr = listener->GetError();
if (completeErr == KNoError)
{
if (results.empty())
{
GEM_INFO_LOG("No results");
}
else
{
GEM_INFO_LOG("Number of results: %d", (int)results.size());
}
}
else
{
GEM_INFO_LOG("Error: %d", completeErr);
}
}
else
{
GEM_INFO_LOG("Search did not start: %d", startErr);
}

To limit the search to a specific area, provide a RectangleGeographicArea to the optional locationHint parameter.

Coordinates coords(41.68905, -72.64296);

RectangleGeographicArea searchArea(
Coordinates(41.98846, -73.12412), // top-left
Coordinates(41.37716, -72.02342) // bottom-right
);

LandmarkList results;

SearchPreferences preferences;
preferences.setMaxMatches(400);

auto listener = StrongPointerFactory<YourProgressListenerImpl>();

int startErr = SearchService().search(
results,
listener,
String("N"),
coords,
preferences,
searchArea // locationHint
);

// wait notifyComplete, handle errors
warning

The reference coordinates used for search must be located within the RectangleGeographicArea provided to the locationHint parameter. Otherwise, the search will return an empty list.

Show the results on the map

In most use cases the landmarks found by search are already present on the map. If the search was made on custom landmark stores see the add map landmarks section for adding landmarks to the map.

To zoom to a landmark found via search, we can use MapView::centerOnCoordinates on the coordinates of the landmark found (Landmark::getCoordinates). See the documentation for map centering for more info.

Change the language of the results

The language of search results and category names is determined by the SdkSettings::setLanguage() setting. Check the the internationalization guide section for more details.