在多边形上找到最接近用户位置的点

时间:2016-03-19 17:26:39

标签: android google-maps polygon android-geofence

我有一个应用程序,可以找到用户与多边形之间的最短距离。

我想将多边形转换为Geofence,以检查用户与区域之间的距离,以便向用户提供准确的信息。

我该怎么做?

这是MapsActivity

public class MinimumDistanceTask extends AsyncTask<String, Void, Integer>{

    private int closeLocation;
    // private String points;
    private GetMinimumDistanceListener listener;

    public MinimumDistanceTask(GetMinimumDistanceListener listener){
        // this.points = points;
        this.listener = listener;
    }

    @Override
    protected Integer doInBackground(String... params) {
        HttpsURLConnection connection = null;
        BufferedReader reader = null;
        StringBuilder builder = new StringBuilder();
        int minimumDis = -1;

            String address = params[0];

            try {
                URL url = new URL(address);
                connection = (HttpsURLConnection) url.openConnection();
                if(connection.getResponseCode() != HttpURLConnection.HTTP_OK){
                    return -1;
                }

                reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                String line;
                while ((line = reader.readLine()) != null){
                    builder.append(line);
                }
            ///get the json data
                JSONObject jsonObject1 = new JSONObject(builder.toString());
                JSONArray points = jsonObject1.getJSONArray("rows");
                JSONObject jsonObject2 = points.getJSONObject(0);
                JSONArray elements = jsonObject2.getJSONArray("elements");
                for (int i = 0; i < elements.length(); i++) {
                    JSONObject jsonObject3 = elements.getJSONObject(i);
                    JSONObject distance = jsonObject3.getJSONObject("distance");
                    if( distance.getInt("value") < minimumDis || minimumDis == -1) {
                        minimumDis = distance.getInt("value");
                        closeLocation = i;
                    }
                }

            } catch (MalformedURLException | JSONException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

        return closeLocation;
        }

    @Override
    protected void onPostExecute(Integer closeLocation) {
            listener.getMinimumDistance(closeLocation);

    }

    public interface GetMinimumDistanceListener{
        void getMinimumDistance(int closeLocation);
    }
}

这是我的AsyncTask以获得最小距离点

DbContext(string)

非常感谢:)。

1 个答案:

答案 0 :(得分:9)

您可以使用以下函数计算由List<LatLng>和给定LatLng定义的多边形中的最近点。

它使用Google Maps Android API Utility Library中的PolyUtil.distanceToLine来计算测试LatLng与列表的每个细分之间的距离,以及基于distanceToLine方法的方法https://github.com/googlemaps/android-maps-utils/blob/master/library/src/com/google/maps/android/PolyUtil.java计算某个点上某个点的投影。

private LatLng findNearestPoint(LatLng test, List<LatLng> target) {
    double distance = -1;
    LatLng minimumDistancePoint = test;

    if (test == null || target == null) {
        return minimumDistancePoint;
    }

    for (int i = 0; i < target.size(); i++) {
        LatLng point = target.get(i);

        int segmentPoint = i + 1;
        if (segmentPoint >= target.size()) {
            segmentPoint = 0;
        }

        double currentDistance = PolyUtil.distanceToLine(test, point, target.get(segmentPoint));
        if (distance == -1 || currentDistance < distance) {
            distance = currentDistance;
            minimumDistancePoint = findNearestPoint(test, point, target.get(segmentPoint));
        }
    }

    return minimumDistancePoint;
}

/**
 * Based on `distanceToLine` method from
 * https://github.com/googlemaps/android-maps-utils/blob/master/library/src/com/google/maps/android/PolyUtil.java
 */
private LatLng findNearestPoint(final LatLng p, final LatLng start, final LatLng end) {
    if (start.equals(end)) {
        return start;
    }

    final double s0lat = Math.toRadians(p.latitude);
    final double s0lng = Math.toRadians(p.longitude);
    final double s1lat = Math.toRadians(start.latitude);
    final double s1lng = Math.toRadians(start.longitude);
    final double s2lat = Math.toRadians(end.latitude);
    final double s2lng = Math.toRadians(end.longitude);

    double s2s1lat = s2lat - s1lat;
    double s2s1lng = s2lng - s1lng;
    final double u = ((s0lat - s1lat) * s2s1lat + (s0lng - s1lng) * s2s1lng)
            / (s2s1lat * s2s1lat + s2s1lng * s2s1lng);
    if (u <= 0) {
        return start;
    }
    if (u >= 1) {
        return end;
    }

    return new LatLng(start.latitude + (u * (end.latitude - start.latitude)),
            start.longitude + (u * (end.longitude - start.longitude)));


}

您可以使用以下代码对其进行测试:

List<LatLng> points = new ArrayList<>();
points.add(new LatLng(2, 2));
points.add(new LatLng(4, 2));
points.add(new LatLng(4, 4));
points.add(new LatLng(2, 4));
points.add(new LatLng(2, 2));

LatLng testPoint = new LatLng(3, 0);

LatLng nearestPoint = findNearestPoint(testPoint, points);
Log.e("NEAREST POINT: ", "" + nearestPoint); // lat/lng: (3.0,2.0)
Log.e("DISTANCE: ", "" + SphericalUtil.computeDistanceBetween(testPoint, nearestPoint)); // 222085.35856591124