2016-03-19 10 views
2

Ich habe eine App, die die kürzeste Entfernung zwischen meinem Benutzer zu einem Polygon finden.Finden Sie den nächsten Punkt auf Polygon zum Benutzerort

Ich möchte das Polygon in Geofence konvertieren, um den Abstand zwischen dem Benutzer und dem Bereich zu überprüfen, um dem Benutzer genauere Informationen zu geben.

Wie kann ich das tun?

ist dies die 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; 
    } 
} 

Das ist mein AsyncTask ist der Mindestabstand Punkt

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

vielen Dank :)

+0

Ich verstehe, dass Sie eine 'list' von' LatLng' als Polygon und haben Sie den Mindestabstand zu einem bestimmten berechnen ' LatLng' zum Polygon, ist das richtig? – antonio

+0

Ich habe die minimalen Distans von den Punkten des Polygons. aber ich möchte die Distans aus der ganzen Gegend bekommen. Wenn mein Benutzer zwischen zwei Punkten ist, berechne ich die Distans zum nächsten Punkt, aber nicht zum kurzen Weg zum Edge für das Polygon – Roish

+0

und ja. Ich habe eine Liste von LatLng und ich möchte den Mindestabstand von einem gegebenen LatLng zu dem Bereich – Roish

Antwort

6

Sie eine Funktion wie die folgende können zu erhalten, Berechnen Sie den nächstgelegenen Punkt aus dem Polygon, das durch eine List<LatLng> und eine gegebene LatLng definiert ist.

Es nutzt die PolyUtil.distanceToLine vom Google Maps Android API Utility Library den Abstand zwischen dem Test LatLng und jedes Segment in der Liste zu berechnen, und ein Verfahren auf der Grundlage der Methode aus distanceToLinehttps://github.com/googlemaps/android-maps-utils/blob/master/library/src/com/google/maps/android/PolyUtil.java die Projektion eines Punktes auf einem Segment zu berechnen.

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


} 

Sie können es testen mit dem folgenden Code:

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 berechnen .. das bedeutet, ich brauche nicht die Matrix Google API zu verwenden. benutze das einfach und erhalte das distanzergebnis? und berechnen Sie dann die Entfernung vom Ergebnis zu meinem Benutzerstandort? – Roish

+0

Natürlich können Sie die Matrix-API verwenden, aber diese Methode funktioniert auch – antonio

+0

mm .. so verstehe ich nicht. die Matrix api geben mir ein Ergebnis zu einem Punkt im Polygon. Ich möchte meinen Benutzer in den Raum zwischen zwei Punkten des Polygons – Roish

Verwandte Themen