Ich versuche herauszufinden, wie das am besten geht, ich habe eine Karte mit einer Polygon darauf gezeichnet. Da scheint es nicht so, als ob die Google Maps API V2 eine Berührungserkennung auf einem Polygon hat. Ich habe mich gefragt, ob es möglich ist zu erkennen, ob sich der Berührungspunkt innerhalb des Polygons befindet? Wenn ja, wie dann ist mein Hauptziel, einen Zustand auf einer Karte zu skizzieren. Wenn der Benutzer auf diesen Zustand tippt, werden weitere Details in einer benutzerdefinierten Ansicht angezeigt. Ab sofort kann ich das einfangen MapOnClick der Karte, aber wenn der Benutzer in die Karte tippt Polygon Ich will das polygon.getID() auf die setzen Toast. Ich bin ein Neuling und entschuldige mich, wenn ich nicht klar genug bin.
googleMap.setOnMapClickListener(new OnMapClickListener()
{
public void onMapClick(LatLng point)
{
boolean checkPoly = true;
Toast.makeText(MainActivity.this,"The Location is outside of the Area", Toast.LENGTH_LONG).show();
}
});
}
}
catch (Exception e) {
Log.e("APP","Failed", e);
}
Das Problem, das ich habe, ist, dass die Berührung links von jedem Polygon wahr ist, bis es ein anderes erreicht. Was ist mit meinem Algorithmus falsch, der dieses Problem verursachen würde? Jede Hilfe wäre dankbar.
Versuchen Sie also zur Verdeutlichung herauszufinden, ob Ihre Berührung innerhalb der geografischen Grenzen des Polygons stattgefunden hat oder nicht?
– Matt
18. Januar ’13 um 18:53
Matt
Das Problem, das Sie zu lösen versuchen, ist das Punkt im Polygon Prüfung.
Um das Konzept von Ray Casting zu visualisieren:
Zeichnen Sie ein Polygon auf ein Blatt Papier. Zeichnen Sie dann von einem beliebigen Punkt aus eine gerade Linie rechts auf der Seite. Wenn Ihre Linie Ihr Polygon ungerade oft schneidet, bedeutet dies, dass Ihr Startpunkt innerhalb des Polygons lag.
Also, wie macht man das im Code?
Ihr Polygon besteht aus einer Liste von Scheitelpunkten: ArrayList<Geopoint> vertices. Du musst dir jeden anschauen Line Segment individuell, und sehen Sie, ob Ihre Ray schneidet es
private boolean isPointInPolygon(Geopoint tap, ArrayList<Geopoint> vertices) {
int intersectCount = 0;
for(int j=0; j<vertices.size()-1; j++) {
if( rayCastIntersect(tap, vertices.get(j), vertices.get(j+1)) ) {
intersectCount++;
}
}
return (intersectCount%2) == 1); // odd = inside, even = outside;
}
private boolean rayCastIntersect(Geopoint tap, Geopoint vertA, Geopoint vertB) {
double aY = vertA.getLatitude();
double bY = vertB.getLatitude();
double aX = vertA.getLongitude();
double bX = vertB.getLongitude();
double pY = tap.getLatitude();
double pX = tap.getLongitude();
if ( (aY>pY && bY>pY) || (aY<pY && bY<pY) || (aX<pX && bX<pX) ) {
return false; // a and b can't both be above or below pt.y, and a or b must be east of pt.x
}
double m = (aY-bY) / (aX-bX); // Rise over run
double bee = (-aX) * m + aY; // y = mx + b
double x = (pY - bee) / m; // algebra is neat!
return x > pX;
}
Ok Matt, ich habe es zum Laufen gebracht. Mein einziges Problem ist, dass wenn zwei Polygone auf demselben x-Pfad liegen, sie als eins behandelt werden und dieselbe ID-Nummer für sie verwendet wird. Irgendwelche Gedanken?
– Dwill
22. Januar ’13 um 22:54
Hmm, kannst du das näher ausführen? Was ich mir vorstelle, ist, dass die App sie als ein Polygon behandelt, wenn sich zwei Polygone eine Kante teilen?
– Matt
23. Januar ’13 um 17:22
Ich bin mir nicht sicher, was das Problem ist. Diese Funktion sollte true zurückgeben, wenn Sie sich links von dem zu testenden Liniensegment befanden. Sie müssen diese Funktion für jeden Satz benachbarter Punkte in Ihrem Polygon ausführen und ermitteln, wie oft diese Funktion “true” zurückgegeben hat.
– Matt
26. Februar ’13 um 20:00
Wie zu tun für Polyline?
– Muhammad Babar
19. Okt ’14 um 17:28
@MuhammadBabar Ich würde das in einem separaten Thread fragen. Es gibt mehrere Möglichkeiten, dieses Problem anzugehen. Es ist schwierig, da ein antippbarer Bereichspuffer erforderlich ist (die Wahrscheinlichkeit, dass der Benutzer genau auf die Leitung tippt, ist sehr gering).
– Matt
21. Okt ’14 um 18:15
Die Google Maps-Supportbibliothek verfügt jetzt über eine statische Methode, die diese Prüfung für Sie durchführt:
PolyUtil.containsLocation(LatLng point, List<LatLng>polygon, boolean geodesic);
Obwohl die Dokumente in der Anleitung nicht explizit darauf hinweisen, ist die Methode vorhanden
Dies ist eine genauere Methode. Und das funktioniert wirklich wie Charme. Schätzen Sie diese Antwort. Diese Methode sollte als vom Google Map Utility selbst angesehen werden.
Obwohl es etwas spät ist, löst es diesen Anwendungsfall recht gut.
Wie erkennt man, auf welches Polygon geklickt wird?
– Samad
28. Mai ’16 um 11:39
@Delta ist das Polygon, das Sie im Listener erhalten.
– Matiasch
28. Mai ’16 um 16:34
Ich habe eine Klasse für Polygone erstellt, die IDs enthält, aber ich kann keine ID für ein Polygon festlegen. Wie kann ich die ID des Polygons herausfinden?
– Samad
29. Mai ’16 um 4:02
@Delta7 Sie könnten einfach eine Map für die Referenzen erstellen und dort alle Polygone hinzufügen, die Sie der Karte hinzufügen. Auf diese Weise können Sie eine Suche durchführen, um die zugehörige ID zu finden.
– Matiasch
29. Mai ’16 um 5:09
Können Sie die angeklickte Koordinate aus Polygon abrufen?
– Gereltod
8. August ’16 um 3:49
Sagar Shah
Obwohl user1504495 kurz geantwortet hat, wie ich es benutzt habe. Aber anstatt das Ganze zu verwenden Bibliothek des Kartendienstprogramms Verwenden Sie diese Methoden.
Passen Sie die Parameter Ihrer Aktivitätsklasse entsprechend an:
/**
* Computes whether the given point lies inside the specified polygon.
* The polygon is always cosidered closed, regardless of whether the last point equals
* the first or not.
* Inside is defined as not containing the South Pole -- the South Pole is always outside.
* The polygon is formed of great circle segments if geodesic is true, and of rhumb
* (loxodromic) segments otherwise.
*/
public static boolean containsLocation(LatLng point, List<LatLng> polygon, boolean geodesic) {
final int size = polygon.size();
if (size == 0) {
return false;
}
double lat3 = toRadians(point.latitude);
double lng3 = toRadians(point.longitude);
LatLng prev = polygon.get(size - 1);
double lat1 = toRadians(prev.latitude);
double lng1 = toRadians(prev.longitude);
int nIntersect = 0;
for (LatLng point2 : polygon) {
double dLng3 = wrap(lng3 - lng1, -PI, PI);
// Special case: point equal to vertex is inside.
if (lat3 == lat1 && dLng3 == 0) {
return true;
}
double lat2 = toRadians(point2.latitude);
double lng2 = toRadians(point2.longitude);
// Offset longitudes by -lng1.
if (intersects(lat1, lat2, wrap(lng2 - lng1, -PI, PI), lat3, dLng3, geodesic)) {
++nIntersect;
}
lat1 = lat2;
lng1 = lng2;
}
return (nIntersect & 1) != 0;
}
/**
* Wraps the given value into the inclusive-exclusive interval between min and max.
* @param n The value to wrap.
* @param min The minimum.
* @param max The maximum.
*/
static double wrap(double n, double min, double max) {
return (n >= min && n < max) ? n : (mod(n - min, max - min) + min);
}
/**
* Returns the non-negative remainder of x / m.
* @param x The operand.
* @param m The modulus.
*/
static double mod(double x, double m) {
return ((x % m) + m) % m;
}
/**
* Computes whether the vertical segment (lat3, lng3) to South Pole intersects the segment
* (lat1, lng1) to (lat2, lng2).
* Longitudes are offset by -lng1; the implicit lng1 becomes 0.
*/
private static boolean intersects(double lat1, double lat2, double lng2,
double lat3, double lng3, boolean geodesic) {
// Both ends on the same side of lng3.
if ((lng3 >= 0 && lng3 >= lng2) || (lng3 < 0 && lng3 < lng2)) {
return false;
}
// Point is South Pole.
if (lat3 <= -PI/2) {
return false;
}
// Any segment end is a pole.
if (lat1 <= -PI/2 || lat2 <= -PI/2 || lat1 >= PI/2 || lat2 >= PI/2) {
return false;
}
if (lng2 <= -PI) {
return false;
}
double linearLat = (lat1 * (lng2 - lng3) + lat2 * lng3) / lng2;
// Northern hemisphere and point under lat-lng line.
if (lat1 >= 0 && lat2 >= 0 && lat3 < linearLat) {
return false;
}
// Southern hemisphere and point above lat-lng line.
if (lat1 <= 0 && lat2 <= 0 && lat3 >= linearLat) {
return true;
}
// North Pole.
if (lat3 >= PI/2) {
return true;
}
// Compare lat3 with latitude on the GC/Rhumb segment corresponding to lng3.
// Compare through a strictly-increasing function (tan() or mercator()) as convenient.
return geodesic ?
tan(lat3) >= tanLatGC(lat1, lat2, lng2, lng3) :
mercator(lat3) >= mercatorLatRhumb(lat1, lat2, lng2, lng3);
}
/**
* Returns tan(latitude-at-lng3) on the great circle (lat1, lng1) to (lat2, lng2). lng1==0.
* See http://williams.best.vwh.net/avform.htm .
*/
private static double tanLatGC(double lat1, double lat2, double lng2, double lng3) {
return (tan(lat1) * sin(lng2 - lng3) + tan(lat2) * sin(lng3)) / sin(lng2);
}
/**
* Returns mercator Y corresponding to latitude.
* See http://en.wikipedia.org/wiki/Mercator_projection .
*/
static double mercator(double lat) {
return log(tan(lat * 0.5 + PI/4));
}
/**
* Returns mercator(latitude-at-lng3) on the Rhumb line (lat1, lng1) to (lat2, lng2). lng1==0.
*/
private static double mercatorLatRhumb(double lat1, double lat2, double lng2, double lng3) {
return (mercator(lat1) * (lng2 - lng3) + mercator(lat2) * lng3) / lng2;
}
Hier ist ein vollständiges Arbeitsbeispiel, um zu wissen, ob eine Berührung auf einem Polygon stattgefunden hat. Manche Antworten sind komplizierter als nötig. Diese Lösung verwendet die “android-maps-utils”
// compile 'com.google.maps.android:android-maps-utils:0.3.4'
private ArrayList<Polygon> polygonList = new ArrayList<>();
private void addMyPolygons() {
PolygonOptions options = new PolygonOptions();
// TODO: make your polygon's however you want
Polygon polygon = googleMap.addPolygon(options);
polygonList.add(polygon);
}
@Override
public void onMapClick(LatLng point) {
boolean contains = false;
for (Polygon p : polygonList) {
contains = PolyUtil.containsLocation(point, p.getPoints(), false);
if (contains) break;
}
Toast.makeText(getActivity(), "Click in polygon? "
+ contains, Toast.LENGTH_SHORT).show();
}
@Override
protected void onMapReady(View view, Bundle savedInstanceState) {
googleMap.setOnMapClickListener(this);
addMyPolygons();
}
Gemeinschaft
Nur aus Gründen der Konsistenz – onMapClick wird nicht aufgerufen, wenn der Benutzer auf ein Polygon (oder ein anderes Overlay) tippt, und es wird in Javadoc erwähnt.
Ich habe eine Problemumgehung vorgenommen, um Taps-Ereignisse abzufangen, bevor MapFragment sie verarbeitet, und Punkt-zu-Karten-Koordinaten zu projizieren und zu überprüfen, ob sich der Punkt innerhalb eines Polygons befindet, wie in einer anderen Antwort vorgeschlagen.
Weitere Details finden Sie hier
.
2058400cookie-checkPolygon Touch-Erkennung Google Map API V2yes
Versuchen Sie also zur Verdeutlichung herauszufinden, ob Ihre Berührung innerhalb der geografischen Grenzen des Polygons stattgefunden hat oder nicht?
– Matt
18. Januar ’13 um 18:53