android - 클릭 - 안드로이드 스튜디오 구글맵 마커 지우기




지도에서 여러 마커의 거리를 계산 한 다음 최소 하나를 선택하는 방법 (6)

나는지도상의 다른 마커로부터 장치의 현재 위치까지 거리를 가져야하고 가장 짧은 것을 선택해야합니다. 나는 마커에 대한 위도와 경도를 가지며 현재 위치 lat와 long을 동적으로 가져올 수 있습니다.

방갈로르 (위도 12.971599, 길게 77.594563), 델리 (위도 28.635308, 길게 77.224960), 뭄바이 (위 ​​19.075984, 길 72.877656), 첸나이 (길 13.052414, 길 : 80.250825), 콜카타 (Lat : 22.572646, Long : 88.363895).

이제 사용자가 하이데라바드 근처 어딘가에 서 있다고 가정 해 보겠습니다 (Lat : 17.385044, Long : 78.486671). 사용자가 버튼을 클릭하면 앱은 각 마커와의 거리를 계산하고 가장 짧은 것을 반환해야합니다. 여기가 방갈로 르입니다.

로컬 데이터베이스의 도움을 받아이를 수행 할 수있는 방법이 있습니다. 누구든지 그걸 도와 줄 수 있어요.?

누구든지 내게 이것을 할 수있는 좋은 방법을 제안하거나, 할 수 있다면 좋은 코드를 제안 할 수 있습니까? 고맙습니다.


가장 가까운 것을 나열하고 가장 가까운 것을 나열하고 프로세스를 많은 양의 위치로 확장하려면 거리계산 하기 전에 일부 필터링을 수행하고 그렇지 않은 경우 속도를 높이기 위해 수식을 단순화 할 수 있습니다 실제 거리에 대해주의를 기울이십시오 (즉, 지구 반경으로 곱셈을 제거하십시오).

각 위치를 반복하는 필터링 알고리즘 :

  1. 위도와 경도의 차이를 계산하십시오.
  2. 두 차이가 이전에 처리 된 쌍보다 큰 경우이를 버립니다.
  3. 거리를 계산하고 가장 작게 유지하십시오.

가까운 위치부터 먼저 알고리즘을 제공함으로써 알고리즘을 더욱 효과적으로 지원할 수 있습니다. 예를 들어 포인트 중 하나가 같은 국가 또는 주에 있음을 알고있는 경우입니다.

다음은이를 수행 할 파이썬 코드입니다. 솔루션의 의사 코드로 사용하십시오.

locations = { 
    'Bangalore' : (12.971599, 77.594563), 
    'Delhi' : (28.635308,  77.224960), 
    'Mumbai' : (19.075984,  72.877656), 
    'Chennai' : (13.052414,  80.250825), 
    'Kolkata' : (22.572646,  88.363895)
    }

from math import sin, cos, atan2, sqrt

EARTH_RADIUS = 6373  # km

def distance(a, b):  # pass tuples
    (lat1, lon1) = a
    (lat2, lon2) = b
    dlon = lon2 - lon1 
    dlat = lat2 - lat1 
    a = (sin(dlat/2))**2 + cos(lat1) * cos(lat2) * (sin(dlon/2))**2 
    c = 2 * atan2( sqrt(a), sqrt(1-a) ) 
    return EARTH_RADIUS * c


current = (17.385044, 78.486671)  # current lat & lng

closest = None
closest_name = None
for name, cordinates in locations.iteritems():
    d = distance(current, cordinates)
    if closest is None or d < closest:
        closest = d
        closest_name = name
    print "~%dkm (%s)" % (distance(current, cordinates), name)

print "\nClosest location is %s, %d km away." % (closest_name, closest)

출력 :

~5700km (Kolkata)
~13219km (Chennai)
~12159km (Bangalore)
~7928km (Delhi)
~10921km (Mumbai)

Closest location is Kolkata, 5700 km away.

단일 지점 (자주 변경 될 수 있음)과 큰 지점 집합 사이의 최소 거리를 2 차원으로 검색하는 효율적인 방법은 QuadTree 를 사용하는 입니다. QuadTree를 처음으로 만들 때 (즉, 데이터 구조에 마커 위치를 추가하는 데 드는 비용), 한 번만 (또는 가끔씩) 수행하기를 원합니다. 그러나 일단 생성되면, 가장 가까운 점에 대한 검색은 일반적으로 큰 집합의 모든 점에 대한 무차별 포스 비교보다 빠릅니다.

BBN의 OpenMap 프로젝트에는 가장 가까운 지점을 반환하는 get(float lat, float lon) 메서드가있는 Android에서 작동해야한다고 생각 하는 오픈 소스 QuadTree Java 구현 이 있습니다.

Google의 android-maps-utils 라이브러리에는 Android에서 실행되도록 의도 된 QuadTree의 오픈 소스 구현이 있지만 현재 작성된 바있는 경계 상자에서 점 집합을 반환하는 search(Bounds bounds) 작업 만 지원합니다. 입력 점에 가장 가까운 점이 아닙니다. 그러나 가장 가까운 지점 검색을 수행하도록 수정 될 수 있습니다.

비교적 적은 수의 포인트 (70-80은 충분히 작을 수 있음)가있는 경우 실제 성능에서 무차별 대입 비교는 QuadTree 솔루션과 비슷한 시간 내에 실행될 수 있습니다. 그러나 가장 가까운 지점을 다시 계산할 빈도에 따라 결정됩니다. 자주 사용하는 경우 QuadTree가 더 나은 선택 일 수 있습니다.


귀하의 의견에서 나는 당신이 70-80 위치의 최대 기대를 참조하십시오. 이것은별로 없습니다.

모든 마커에서 무차별 검색을 수행하고 최소값을 취할 수 있습니다.

모든 마커를 반복하고 min distance를 검색합니다.

    List<Marker> markers = createMarkers(); // returns an ArrayList<Markers> from your data source
    int minIndex = -1;
    double minDist = 1E38; // initialize with a huge value that will be overwritten
    int size = markers.size();
    for (int i = 0; i < size; i++) {
        Marker marker = markers.get(i);
        double curDistance = calcDistance(curLatitude, curLongitude, marker.latitude, marker.longitude);
      if (curDistance < minDist) {
         minDist = curDistance;  // update neares
         minIndex = i;           // store index of nearest marker in minIndex
      }
    }

    if (minIndex >= 0) {
       // now nearest maker found:
       Marker nearestMarker = markers.get(minIndex);
       // TODO do something with nearesr marker
    } else {
      // list of markers was empty
    }

calcDistance는 Android에서 제공하는 거리 계산 방법을 사용합니다. (예 : Location.distanceTo() )
70-80 마커의 경우 더 빠르고 더 복잡하게 만들 필요가 없습니다. 몇 천 포인트가 있다면 더 빠른 솔루션에 투자하는 것이 좋습니다 (공간 인덱스 및 sqrt 계산을 피하는 자체 거리 계산 사용).

가장 가까운 제조업체 검색의 시작과 끝에서 밀리 초 단위로 현재 시간을 인쇄하면 속도가 빠름을 알 수 있습니다.


이미 몇 가지 대답이 게시되었지만 구현을 Java로 제시 할 것이라고 생각했습니다. 이것은 AsyncTask에 래핑 된 4000 개 이상의 마커와 함께 사용되었으며 문제없이 작동합니다.

첫째, 거리를 계산하는 논리입니다 (loc1.distanceTo (loc2)를 수행 할 수있는 것처럼 위치 객체가 아니라 마커 만 있다고 가정).

private float distBetween(LatLng pos1, LatLng pos2) {
    return distBetween(pos1.latitude, pos1.longitude, pos2.latitude,
            pos2.longitude);
}

/** distance in meters **/
private float distBetween(double lat1, double lng1, double lat2, double lng2) {
    double earthRadius = 3958.75;
    double dLat = Math.toRadians(lat2 - lat1);
    double dLng = Math.toRadians(lng2 - lng1);
    double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
            + Math.cos(Math.toRadians(lat1))
            * Math.cos(Math.toRadians(lat2)) * Math.sin(dLng / 2)
            * Math.sin(dLng / 2);
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    double dist = earthRadius * c;

    int meterConversion = 1609;

    return (float) (dist * meterConversion);
}

다음으로 가장 가까운 마커를 선택하는 코드는 다음과 같습니다.

private Marker getNearestMarker(List<Marker> markers,
        LatLng origin) {

    Marker nearestMarker = null;
    double lowestDistance = Double.MAX_VALUE;

    if (markers != null) {

        for (Marker marker : markers) {

            double dist = distBetween(origin, marker.getPosition());

            if (dist < lowestDistance) {
                nearestMarker = marker;
                lowestDistance = dist;
            }
        }
    }

    return nearestMarker;
}

아마도 유스 케이스와 관련이 없지만 알고리즘을 사용하여 미리 정의 된 거리를 기반으로 가장 가까운 마커를 선택합니다. 이렇게하면 많은 불필요한 마커를 제거 할 수 있습니다.

private List<Marker> getSurroundingMarkers(List<Marker> markers,
        LatLng origin, int maxDistanceMeters) {
    List<Marker> surroundingMarkers = null;

    if (markers != null) {
        surroundingMarkers = new ArrayList<Marker>();
        for (Marker marker : markers) {

            double dist = distBetween(origin, marker.getPosition());

            if (dist < maxDistanceMeters) {
                surroundingMarkers.add(marker);
            }
        }
    }

    return surroundingMarkers;
}

희망이 당신을 도와줍니다.


다음은 KDTree, KDTNode 및 KDTResult라는 3 개의 클래스로 구성된 이른바 KDTree 구현입니다. 마침내 필요한 것은 KDTree.createTree ()를 사용하여 KDTree를 만드는 것입니다. KDTree.createTree ()는 트리의 rootNode를 반환하고 모든 고정 소수점을 전달합니다. 그런 다음 KDTree.findNearestWp ()를 사용하여 주어진 위치에 가장 가까운 Waypoint를 찾습니다.

KDTree :

public class KDTree {

private Comparator<LatLng> latComparator = new LatLonComparator(true);
private Comparator<LatLng> lonComparator = new LatLonComparator(false);;

/**
 * Create a KDTree from a list of Destinations. Returns the root-node of the
 * tree.
 */
public KDTNode createTree(List<LatLng> recList) {
    return createTreeRecursive(0, recList);
}

/**
 * Traverse the tree and find the nearest WP.
 * 
 * @param root
 * @param wp
 * @return
 */
static public LatLng findNearestWp(KDTNode root, LatLng wp) {
    KDTResult result = new KDTResult();
    findNearestWpRecursive(root, wp, result);
    return result.nearestDest;
}

private static void findNearestWpRecursive(KDTNode node, LatLng wp,
        KDTResult result) {
    double lat = wp.latitude;
    double lon = wp.longitude;
    /* If a leaf node, calculate distance and return. */
    if (node.isLeaf) {
        LatLng dest = node.wp;
        double latDiff = dest.latitude - lat;
        double lonDiff = dest.longitude - lon;
        double squareDist = latDiff * latDiff + lonDiff * lonDiff;
        // Replace a previously found nearestDest only if the new one is
        // nearer.
        if (result.nearestDest == null
                || result.squareDistance > squareDist) {
            result.nearestDest = dest;
            result.squareDistance = squareDist;
        }
        return;
    }
    boolean devidedByLat = node.depth % 2 == 0;
    boolean goLeft;
    /* Check whether left or right is more promising. */
    if (devidedByLat) {
        goLeft = lat < node.splitValue;
    } else {
        goLeft = lon < node.splitValue;
    }
    KDTNode child = goLeft ? node.left : node.right;
    findNearestWpRecursive(child, wp, result);
    /*
     * Check whether result needs to be checked also against the less
     * promising side.
     */
    if (result.squareDistance > node.minSquareDistance) {
        KDTNode otherChild = goLeft ? node.right : node.left;
        findNearestWpRecursive(otherChild, wp, result);
    }

}

private KDTNode createTreeRecursive(int depth, List<LatLng> recList) {
    KDTNode node = new KDTNode();
    node.depth = depth;
    if (recList.size() == 1) {
        // Leafnode found
        node.isLeaf = true;
        node.wp = recList.get(0);
        return node;
    }
    boolean divideByLat = node.depth % 2 == 0;
    sortRecListByDimension(recList, divideByLat);
    List<LatLng> leftList = getHalfOf(recList, true);
    List<LatLng> rightList = getHalfOf(recList, false);
    // Get split point and distance to last left and first right point.
    LatLng lastLeft = leftList.get(leftList.size() - 1);
    LatLng firstRight = rightList.get(0);
    double minDistanceToSplitValue;
    double splitValue;
    if (divideByLat) {
        minDistanceToSplitValue = (firstRight.latitude - lastLeft.latitude) / 2;
        splitValue = lastLeft.latitude + Math.abs(minDistanceToSplitValue);
    } else {
        minDistanceToSplitValue = (firstRight.longitude - lastLeft.longitude) / 2;
        splitValue = lastLeft.longitude + Math.abs(minDistanceToSplitValue);
    }
    node.splitValue = splitValue;
    node.minSquareDistance = minDistanceToSplitValue
            * minDistanceToSplitValue;
    /** Call next level */
    depth++;
    node.left = createTreeRecursive(depth, leftList);
    node.right = createTreeRecursive(depth, rightList);
    return node;
}

/**
 * Return a sublist representing the left or right half of a List. Size of
 * recList must be at least 2 !
 * 
 * IMPORTANT !!!!! Note: The original list must not be modified after
 * extracting this sublist, as the returned subList is still backed by the
 * original list.
 */
List<LatLng> getHalfOf(List<LatLng> recList, boolean leftHalf) {
    int mid = recList.size() / 2;
    if (leftHalf) {
        return recList.subList(0, mid);
    } else {
        return recList.subList(mid, recList.size());
    }
}

private void sortRecListByDimension(List<LatLng> recList, boolean sortByLat) {
    Comparator<LatLng> comparator = sortByLat ? latComparator
            : lonComparator;
    Collections.sort(recList, comparator);
}

class LatLonComparator implements Comparator<LatLng> {
    private boolean byLat;

    public LatLonComparator(boolean sortByLat) {
        this.byLat = sortByLat;
    }

    @Override
    public int compare(LatLng lhs, LatLng rhs) {
        double diff;
        if (byLat) {
            diff = lhs.latitude - rhs.latitude;
        } else {
            diff = lhs.longitude - rhs.longitude;
        }
        if (diff > 0) {
            return 1;
        } else if (diff < 0) {
            return -1;
        } else {
            return 0;
        }
    }

}
}

KDTNode :

/** Node of the KDTree */
public class KDTNode {

KDTNode left;
KDTNode right;
boolean isLeaf;
/** latitude or longitude of the nodes division line. */
double splitValue;
/** Distance between division line and first point. */
double minSquareDistance;
/**
 * Depth of the node in the tree. An even depth devides the tree in the
 * latitude-axis, an odd depth devides the tree in the longitude-axis.
 */
int depth;
/** The Waypoint in case the node is a leaf node. */
LatLng wp;

}

KDTResult :

/** Holds the result of a tree traversal. */
public class KDTResult {
LatLng nearestDest;
// I use the square of the distance to avoid square-root operations.
double squareDistance;
}

내가 아주 가까운 웨이 포인트에만 관심이 있기 때문에 단순한 거리 계산을 사용하고 있습니다. 더 멀리 떨어져있는 점에 대해서는 가장 가까운 점을 정확하게 구하지 못할 수 있습니다. 동서 방향 거리 (미터)로 표시되는 2 개의 경도의 절대 차는이 차이가 측정되는 위도에 따라 다릅니다. 이것은 알고리즘에서 고려되지 않았으며 귀하의 경우에이 효과의 관련성에 대해 확신하지 못합니다.








location