forked from organicmaps/organicmaps
[android] Optimize bookmark search with native implementation
Replace inefficient Java bookmark search methods with a C++ implementation that leverages the core place page infrastructure. The previous approach had significant computational overhead due to redundant iterations over all bookmark categories. Signed-off-by: coderang-gk <coderang.gk@gmail.com>
This commit is contained in:
parent
2504282e67
commit
28545429ac
5 changed files with 66 additions and 196 deletions
|
@ -971,6 +971,48 @@ Java_app_organicmaps_Framework_nativeRemovePlacePageActivationListener(JNIEnv *e
|
|||
g_placePageActivationListener = nullptr;
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeFindBookmarkAtPoint(JNIEnv * env, jobject thiz, jdouble lat, jdouble lon)
|
||||
{
|
||||
LOG(LINFO, ("Native: Searching for bookmark at", lat, lon));
|
||||
|
||||
auto * framework = g_framework->NativeFramework();
|
||||
|
||||
auto const mercatorPoint = mercator::FromLatLon(lat, lon);
|
||||
|
||||
place_page::BuildInfo buildInfo;
|
||||
buildInfo.m_mercator = mercatorPoint;
|
||||
|
||||
framework->BuildAndSetPlacePageInfo(buildInfo);
|
||||
|
||||
if (framework->HasPlacePageInfo())
|
||||
{
|
||||
auto const & placePageInfo = framework->GetCurrentPlacePageInfo();
|
||||
if (placePageInfo.IsBookmark())
|
||||
{
|
||||
auto bookmarkId = placePageInfo.GetBookmarkId();
|
||||
return static_cast<jlong>(bookmarkId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
double const searchRadiusM = 2.0;
|
||||
auto const & bmManager = framework->GetBookmarkManager();
|
||||
|
||||
auto const rect = mercator::RectByCenterXYAndSizeInMeters(mercatorPoint, searchRadiusM);
|
||||
m2::AnyRectD searchRect(rect);
|
||||
|
||||
auto const * userMark = bmManager.FindNearestUserMark(searchRect);
|
||||
|
||||
if (userMark && userMark->GetMarkType() == UserMark::Type::BOOKMARK)
|
||||
{
|
||||
auto const bookmarkId = userMark->GetId();
|
||||
return static_cast<jlong>(bookmarkId);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_app_organicmaps_Framework_nativeGetGe0Url(JNIEnv * env, jclass, jdouble lat, jdouble lon, jdouble zoomLevel, jstring name)
|
||||
{
|
||||
|
|
|
@ -331,7 +331,6 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||
|
||||
if (intent != null && "app.organicmaps.action.SHOW_BOOKMARK".equals(intent.getAction()))
|
||||
{
|
||||
boolean fromWidget = intent.getBooleanExtra("FROM_WIDGET", false);
|
||||
|
||||
String bookmarkName = intent.getStringExtra("BOOKMARK_NAME");
|
||||
double lat = intent.getDoubleExtra("BOOKMARK_LAT", Double.NaN);
|
||||
|
@ -340,23 +339,15 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
|||
|
||||
if (!Double.isNaN(lat) && !Double.isNaN(lon))
|
||||
{
|
||||
try
|
||||
BookmarkInfo nearestBookmark = BookmarkManager.INSTANCE.findBookmarkByCoordinates(
|
||||
lat, lon, bookmarkName, categoryName
|
||||
);
|
||||
|
||||
if (nearestBookmark != null)
|
||||
{
|
||||
BookmarkInfo nearestBookmark = BookmarkManager.INSTANCE.findBookmarkByCoordinates(
|
||||
lat, lon, bookmarkName, categoryName
|
||||
);
|
||||
|
||||
if (nearestBookmark != null)
|
||||
{
|
||||
|
||||
BookmarkManager.INSTANCE.showBookmarkOnMap(nearestBookmark.getBookmarkId());
|
||||
return;
|
||||
}
|
||||
} catch (Exception e)
|
||||
{
|
||||
|
||||
BookmarkManager.INSTANCE.showBookmarkOnMap(nearestBookmark.getBookmarkId());
|
||||
return;
|
||||
}
|
||||
|
||||
Framework.nativeZoomToPoint(lat, lon, 16, true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ import app.organicmaps.R;
|
|||
import app.organicmaps.bookmarks.data.BookmarkCategory;
|
||||
import app.organicmaps.bookmarks.data.BookmarkInfo;
|
||||
import app.organicmaps.bookmarks.data.BookmarkManager;
|
||||
import app.organicmaps.bookmarks.data.Icon;
|
||||
|
||||
public class FavoriteBookmarkWidget extends AppWidgetProvider
|
||||
{
|
||||
|
@ -55,7 +54,6 @@ public class FavoriteBookmarkWidget extends AppWidgetProvider
|
|||
bookmarkInfo = BookmarkManager.INSTANCE.findBookmarkByCoordinates(lat, lon, bookmarkName, categoryName);
|
||||
}
|
||||
|
||||
// Always set the bookmark name, using stored name as fallback
|
||||
String displayName = bookmarkInfo != null ? bookmarkInfo.getName() :
|
||||
(bookmarkName != null && !bookmarkName.isEmpty() ? bookmarkName :
|
||||
context.getString(R.string.select_bookmark));
|
||||
|
@ -64,7 +62,6 @@ public class FavoriteBookmarkWidget extends AppWidgetProvider
|
|||
|
||||
if (bookmarkInfo != null)
|
||||
{
|
||||
int color = iconColor != 0 ? iconColor : bookmarkInfo.getIcon().getColor();
|
||||
|
||||
int iconResId = BookmarkManager.INSTANCE.getBookmarkIcon(bookmarkInfo.getBookmarkId());
|
||||
if (iconResId == 0)
|
||||
|
@ -119,19 +116,19 @@ public class FavoriteBookmarkWidget extends AppWidgetProvider
|
|||
{
|
||||
SharedPreferences.Editor prefs = context.getSharedPreferences(PREFS_NAME, 0).edit();
|
||||
|
||||
|
||||
prefs.putFloat(PREF_PREFIX_KEY + appWidgetId + SUFFIX_LAT, (float) bookmarkInfo.getLat());
|
||||
prefs.putFloat(PREF_PREFIX_KEY + appWidgetId + SUFFIX_LON, (float) bookmarkInfo.getLon());
|
||||
prefs.putString(PREF_PREFIX_KEY + appWidgetId + SUFFIX_NAME, bookmarkInfo.getName());
|
||||
|
||||
prefs.putString(PREF_PREFIX_KEY + appWidgetId + "_category_name", category.getName());
|
||||
prefs.putString(PREF_PREFIX_KEY + appWidgetId + SUFFIX_CATEGORY_NAME, category.getName());
|
||||
prefs.putLong(PREF_PREFIX_KEY + appWidgetId + "_bookmark_id", bookmarkInfo.getBookmarkId());
|
||||
prefs.putLong(PREF_PREFIX_KEY + appWidgetId + "_category_id", category.getId());
|
||||
|
||||
prefs.putString(PREF_PREFIX_KEY + appWidgetId + "_name_hash",
|
||||
String.valueOf(bookmarkInfo.getName().hashCode()));
|
||||
prefs.putString(PREF_PREFIX_KEY + appWidgetId + "_lat_lon_hash",
|
||||
String.valueOf((bookmarkInfo.getLat() + "," + bookmarkInfo.getLon()).hashCode()));
|
||||
|
||||
boolean success = prefs.commit();
|
||||
prefs.apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -148,189 +148,26 @@ public enum BookmarkManager
|
|||
}
|
||||
|
||||
@Nullable
|
||||
public BookmarkInfo findBookmarkByCoordinates(double latitude, double longitude, @Nullable String name, @Nullable String categoryName)
|
||||
public BookmarkInfo findBookmarkByCoordinates(double lat, double lon, @Nullable String name, @Nullable String categoryName)
|
||||
{
|
||||
final double MAX_DISTANCE_TOLERANCE = 50.0;
|
||||
long bookmarkId = nativeFindBookmarkAtPoint(lat, lon);
|
||||
|
||||
List<BookmarkCategory> categories = getCategories();
|
||||
if (bookmarkId == -1)
|
||||
return null;
|
||||
|
||||
BookmarkInfo closestMatch = null;
|
||||
double closestDistance = Double.MAX_VALUE;
|
||||
BookmarkInfo info = getBookmarkInfo(bookmarkId);
|
||||
|
||||
for (BookmarkCategory category : categories)
|
||||
if (info != null &&
|
||||
(name == null || name.isEmpty() || name.equals(info.getName())) &&
|
||||
(categoryName == null || categoryName.isEmpty() ||
|
||||
categoryName.equals(getCategoryById(info.getCategoryId()).getName())))
|
||||
{
|
||||
if (categoryName != null && !categoryName.isEmpty() &&
|
||||
!category.getName().equals(categoryName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < category.getBookmarksCount(); i++)
|
||||
{
|
||||
long bookmarkId = getBookmarkIdByPosition(category.getId(), i);
|
||||
BookmarkInfo bookmarkInfo = getBookmarkInfo(bookmarkId);
|
||||
|
||||
if (bookmarkInfo == null)
|
||||
continue;
|
||||
|
||||
boolean nameMatches = name == null || name.isEmpty() ||
|
||||
bookmarkInfo.getName().equals(name);
|
||||
|
||||
double distance = calculateDistance(latitude, longitude,
|
||||
bookmarkInfo.getLat(),
|
||||
bookmarkInfo.getLon());
|
||||
|
||||
if (nameMatches && distance <= MAX_DISTANCE_TOLERANCE)
|
||||
{
|
||||
if (distance < closestDistance)
|
||||
{
|
||||
closestMatch = bookmarkInfo;
|
||||
closestDistance = distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return closestMatch;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private BookmarkInfo findExactBookmarkByCoordinates(double lat, double lon, @Nullable String name, @Nullable String categoryName)
|
||||
{
|
||||
final double COORD_TOLERANCE = 0.0001;
|
||||
|
||||
List<BookmarkCategory> categories = getCategories();
|
||||
|
||||
if (categoryName != null && !categoryName.isEmpty())
|
||||
{
|
||||
for (BookmarkCategory category : categories)
|
||||
{
|
||||
if (categoryName.equals(category.getName()))
|
||||
{
|
||||
for (int i = 0; i < category.getBookmarksCount(); i++)
|
||||
{
|
||||
long bookmarkId = getBookmarkIdByPosition(category.getId(), i);
|
||||
BookmarkInfo bookmark = getBookmarkInfo(bookmarkId);
|
||||
|
||||
if (bookmark != null &&
|
||||
(name == null || name.isEmpty() || name.equals(bookmark.getName())) &&
|
||||
Math.abs(bookmark.getLat() - lat) < COORD_TOLERANCE &&
|
||||
Math.abs(bookmark.getLon() - lon) < COORD_TOLERANCE)
|
||||
{
|
||||
return bookmark;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (BookmarkCategory category : categories)
|
||||
{
|
||||
for (int i = 0; i < category.getBookmarksCount(); i++)
|
||||
{
|
||||
long bookmarkId = getBookmarkIdByPosition(category.getId(), i);
|
||||
BookmarkInfo bookmark = getBookmarkInfo(bookmarkId);
|
||||
|
||||
if (bookmark != null &&
|
||||
(name == null || name.isEmpty() || name.equals(bookmark.getName())) &&
|
||||
Math.abs(bookmark.getLat() - lat) < COORD_TOLERANCE &&
|
||||
Math.abs(bookmark.getLon() - lon) < COORD_TOLERANCE)
|
||||
{
|
||||
return bookmark;
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private BookmarkInfo findNearestBookmark(double lat, double lon, double maxDistanceMeters,
|
||||
@Nullable String name, @Nullable String categoryName)
|
||||
{
|
||||
List<BookmarkCategory> categories = getCategories();
|
||||
BookmarkInfo closestBookmark = null;
|
||||
double closestDistance = Double.MAX_VALUE;
|
||||
|
||||
if (categoryName != null && !categoryName.isEmpty())
|
||||
{
|
||||
for (BookmarkCategory category : categories)
|
||||
{
|
||||
if (categoryName.equals(category.getName()))
|
||||
{
|
||||
BookmarkInfo categoryResult = findNearestInCategory(category, lat, lon,
|
||||
maxDistanceMeters, name, closestDistance);
|
||||
if (categoryResult != null)
|
||||
{
|
||||
return categoryResult;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (BookmarkCategory category : categories)
|
||||
{
|
||||
if (categoryName != null && !categoryName.isEmpty() && categoryName.equals(category.getName()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
BookmarkInfo categoryResult = findNearestInCategory(category, lat, lon,
|
||||
maxDistanceMeters, name, closestDistance);
|
||||
if (categoryResult != null)
|
||||
{
|
||||
closestBookmark = categoryResult;
|
||||
closestDistance = calculateDistance(lat, lon, closestBookmark.getLat(), closestBookmark.getLon());
|
||||
}
|
||||
}
|
||||
|
||||
return closestBookmark;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private BookmarkInfo findNearestInCategory(BookmarkCategory category, double lat, double lon,
|
||||
double maxDistanceMeters, @Nullable String name, double currentClosestDistance)
|
||||
{
|
||||
BookmarkInfo closestBookmark = null;
|
||||
double closestDistance = currentClosestDistance;
|
||||
|
||||
for (int i = 0; i < category.getBookmarksCount(); i++)
|
||||
{
|
||||
long bookmarkId = getBookmarkIdByPosition(category.getId(), i);
|
||||
BookmarkInfo bookmark = getBookmarkInfo(bookmarkId);
|
||||
|
||||
if (bookmark != null && (name == null || name.isEmpty() || name.equals(bookmark.getName())))
|
||||
{
|
||||
double distance = calculateDistance(lat, lon, bookmark.getLat(), bookmark.getLon());
|
||||
|
||||
if (distance < closestDistance && distance <= maxDistanceMeters)
|
||||
{
|
||||
closestBookmark = bookmark;
|
||||
closestDistance = distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return closestBookmark;
|
||||
}
|
||||
|
||||
private double calculateDistance(double lat1, double lon1, double lat2, double lon2)
|
||||
{
|
||||
final double earthRadius = 6371000;
|
||||
|
||||
double dLat = Math.toRadians(lat2 - lat1);
|
||||
double dLon = Math.toRadians(lon2 - lon1);
|
||||
|
||||
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
|
||||
Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
|
||||
Math.sin(dLon / 2) * Math.sin(dLon / 2);
|
||||
|
||||
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
||||
|
||||
return earthRadius * c;
|
||||
}
|
||||
|
||||
// Called from JNI.
|
||||
@Keep
|
||||
@SuppressWarnings("unused")
|
||||
|
@ -927,6 +764,8 @@ public enum BookmarkManager
|
|||
return nativeGetElevationActivePointDistance(trackId);
|
||||
}
|
||||
|
||||
private native long nativeFindBookmarkAtPoint(double lat, double lon);
|
||||
|
||||
@Nullable
|
||||
private native Bookmark nativeUpdateBookmarkPlacePage(long bmkId);
|
||||
|
||||
|
|
|
@ -9,4 +9,5 @@
|
|||
android:widgetCategory="home_screen"
|
||||
android:description="@string/widget_description"
|
||||
android:configure="app.organicmaps.bookmarks.FavoriteBookmarkWidgetConfigActivity" />
|
||||
|
||||
|
Loading…
Add table
Reference in a new issue