2016-03-19 4 views
2

У меня есть приложение, которое найдет самое короткое расстояние между моим пользователем и полигоном.Найти ближайшую точку на полигоне до местоположения пользователя

Я хочу преобразовать многоугольник в Geofence, чтобы проверить расстояние между пользователем и областью, чтобы дать пользователю точную информацию.

как я могу это сделать?

это MapsActivity

public class MapsActivity extends FragmentActivity implements OnMapReadyCallback, LocationListener, MinimumDistanceTask.GetMinimumDistanceListener { 
    private GoogleMap mMap; 
    private LocationManager manager; 
    private double lat, lng; 
    private KmlLayer layer; 
    private LatLng latLngTest; 
    private boolean contains = false; 
    private ArrayList<LatLng> outerBoundary; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_maps); 
     // Obtain the SupportMapFragment and get notified when the map is ready to be used. 
     SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager() 
       .findFragmentById(R.id.map); 
     mapFragment.getMapAsync(this); 
     manager = (LocationManager) getSystemService(LOCATION_SERVICE); 
    } 

    @Override 
    protected void onResume() { 
     super.onResume(); 
     String provider = LocationManager.GPS_PROVIDER; 

     //take the user location every second 
     try { 
      manager.requestLocationUpdates(provider, 1000, 0, this); 
     }catch (SecurityException e){ 

     } 
    } 

    @Override 
    public void onMapReady(GoogleMap googleMap) { 
     mMap = googleMap; 
    } 

    @Override 
    public void onLocationChanged(Location location) { 
     //clear map before create new location 
     mMap.clear(); 
     try { 
      //load the kml file 
      layer = new KmlLayer(mMap, R.raw.polygon_layer, this); 
      layer.addLayerToMap(); 

     } catch (IOException e) { 
      e.printStackTrace(); 
     } catch (XmlPullParserException e) { 
      e.printStackTrace(); 
     } 

     lat = location.getLatitude(); 
     lng = location.getLongitude(); 
     latLngTest = new LatLng(lat,lng); 
     // Add a marker in user location 
     LatLng userLocation = new LatLng(latLngTest.latitude, latLngTest.longitude); 
     mMap.addMarker(new MarkerOptions().position(userLocation).title("you are here")); 
     mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(userLocation, 15)); 

     //check if the user in the polygon 
     boolean inside = ifUserInside(); 

     if(inside){ 
      Toast.makeText(MapsActivity.this, "you are in the polygon", Toast.LENGTH_SHORT).show(); 
     }else{ 
      Toast.makeText(MapsActivity.this, "you are outside the polygon", Toast.LENGTH_SHORT).show(); 
      //create the string address for the url 
      String address = ""; 
      for (int i = 0; i < outerBoundary.size(); i++) { 
       address += (outerBoundary.get(i).toString() + "|"); 
       address = address.replace("lat/lng:", ""); 
       address = address.replace(" ", ""); 
       address = address.replace("(", ""); 
       address = address.replace(")", ""); 
      } 
      MinimumDistanceTask task = new MinimumDistanceTask(this); 
      task.execute("https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial&origins="+latLngTest.latitude+ "," + latLngTest.longitude 
        + "&destinations=" + address + "&mode=walking"); 
     } 

    } 

    @Override 
    public void getMinimumDistance(int closeLocation) { 
     //check if you get results properly 
     if(closeLocation != -1) { 
      GetDirection direction = new GetDirection(); 
      direction.execute("https://maps.googleapis.com/maps/api/directions/json?origin=" + latLngTest.latitude + "," + latLngTest.longitude 
        + "&destination=" + outerBoundary.get(closeLocation).latitude + "+" + outerBoundary.get(closeLocation).longitude); 
     } 
    } 

    @Override 
    public void onStatusChanged(String provider, int status, Bundle extras) { 

    } 

    @Override 
    public void onProviderEnabled(String provider) { 

    } 

    @Override 
    public void onProviderDisabled(String provider) { 

    } 

    public boolean ifUserInside(){ 
     if (layer.getContainers() != null) { 
      for (KmlContainer container : layer.getContainers()) { 
       if (container.getPlacemarks() != null) { 
        for (KmlPlacemark placemark : container.getPlacemarks()) { 
         contains = false; 

         if (placemark.getGeometry() instanceof KmlPolygon) { 
          KmlPolygon polygon = (KmlPolygon) placemark.getGeometry(); 

          // Get the outer boundary and check if the test location lies inside 
          outerBoundary = polygon.getOuterBoundaryCoordinates(); 
          contains = PolyUtil.containsLocation(latLngTest, outerBoundary, true); 



          if (contains) { 
           // Get the inner boundaries and check if the test location lies inside 
           ArrayList<ArrayList<LatLng>> innerBoundaries = polygon.getInnerBoundaryCoordinates(); 
           if (innerBoundaries != null) { 
            for (ArrayList<LatLng> innerBoundary : innerBoundaries) { 
             // If the test location lies in a hole, the polygon doesn't contain the location 
             if (PolyUtil.containsLocation(latLngTest, innerBoundary, true)) { 
              contains = false; 

             } 
            } 
           } 
          } 
         } 
        } 
       } 
      } 
     } 
     return contains; 
    } 

    public class GetDirection extends AsyncTask<String , Void, String> { 
     HttpsURLConnection connection = null; 
     BufferedReader reader = null; 
     StringBuilder builder = new StringBuilder(); 
     @Override 
     protected String doInBackground(String... params) { 
      String address = params[0]; 

      try { 
       URL url = new URL(address); 
       connection = (HttpsURLConnection) url.openConnection(); 
       if(connection.getResponseCode() != HttpURLConnection.HTTP_OK){ 
        return "Error from server"; 
       } 

       reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); 
       String line; 
       while ((line = reader.readLine()) != null){ 
        builder.append(line); 
       } 

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

      return builder.toString(); 
     } 

     @Override 
     protected void onPostExecute(String s) { 
     //get the polyline string 
      String polygonPoints = ""; 

      try { 
       JSONObject object = new JSONObject(s); 
       JSONArray array = object.getJSONArray("routes"); 
       for (int i = 0; i < array.length(); i++) { 
        JSONObject arrObj1 = array.getJSONObject(i); 
        JSONObject points = arrObj1.getJSONObject("overview_polyline"); 
        polygonPoints = points.getString("points"); 

       } 
       //convert the string to polyline; 
       ArrayList<LatLng> a = new ArrayList<>(decodePolyPoints(polygonPoints)); 
       //add polyline to the map 
       mMap.addPolyline(new PolylineOptions().addAll(a).width(10).color(Color.BLUE)); 

      } catch (JSONException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    //the method that convert the string to polyline 
    public static ArrayList<LatLng> decodePolyPoints(String encodedPath){ 
     int len = encodedPath.length(); 

     final ArrayList<LatLng> path = new ArrayList<LatLng>(); 
     int index = 0; 
     int lat = 0; 
     int lng = 0; 

     while (index < len) { 
      int result = 1; 
      int shift = 0; 
      int b; 
      do { 
       b = encodedPath.charAt(index++) - 63 - 1; 
       result += b << shift; 
       shift += 5; 
      } while (b >= 0x1f); 
      lat += (result & 1) != 0 ? ~(result >> 1) : (result >> 1); 

      result = 1; 
      shift = 0; 
      do { 
       b = encodedPath.charAt(index++) - 63 - 1; 
       result += b << shift; 
       shift += 5; 
      } while (b >= 0x1f); 
      lng += (result & 1) != 0 ? ~(result >> 1) : (result >> 1); 

      path.add(new LatLng(lat * 1e-5, lng * 1e-5)); 
     } 

     return path; 
    } 
} 

Это мой AsyncTask, чтобы точка минимума расстояние

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); 
    } 
} 

спасибо большое :)

+0

Я понимаю, что у вас есть '' list' из LatLng' в качестве полигона, и вы хотите, чтобы вычислить минимальное расстояние от заданной ' LatLng' на полигон, это правильно? – antonio

+0

У меня есть минимальное расстояние от точек многоугольника. но я хочу получить distans из всей области. Если мой пользователь находится между двумя точками, я вычисляю distans до ближайшей точки, но не до короткого пути к Edge fo polygone – Roish

+0

и да. У меня есть список LatLng, и я хочу рассчитать минимальное расстояние от данного LatLng до области – Roish

ответ

6

Вы можете использовать функцию, как следующее вычислить ближайшую точку от многоугольника, заданного List<LatLng>, и заданного LatLng.

Он использует PolyUtil.distanceToLine от Google Maps Android API Utility Library для вычисления расстояния между тестом 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 
+0

oh .., что означает, что мне не нужно использовать Matrix google api. просто используйте это и получите результат на расстояние? , а затем рассчитать расстояние от результата до моего местоположения пользователя? – Roish

+0

Конечно, вы можете использовать Matrix API, но этот метод работает тоже – antonio

+0

мм .. так что я не понимаю. Матрица api дает мне результат к точке в многоугольнике. Я хочу направить своего пользователя на пробел между двумя точками полигона – Roish

 Смежные вопросы

  • Нет связанных вопросов^_^