Wie kann ich feststellen, ob ein geschlossener Pfad enthält einen bestimmten Punkt ?

? Tom Seago @ | Original: StackOverFlow
---

In Android, ich habe eine Path-Objekt, das ich weiß zufällig, einen geschlossenen Weg, und ich brauche, um herauszufinden, ob ein angegebener Punkt in dem Pfad enthalten . Ich hatte gehofft, für etwas entlang der Linien von

path.contains (int x, int y)

aber das scheint nicht zu existieren.

Die spezifischen Grund, warum ich mich für dieses ist, weil Ich habe eine Sammlung von Formen auf dem Bildschirm, die als Wege, und ich möchte, um herauszufinden, welche der Benutzer angeklickt . Gibt es einen besseren Weg zu nähern, wie diese mit verschiedenen UI-Elemente und nicht, es zu tun " auf die harte Tour " mich selbst, ich bin offen für Vorschläge .

Ich bin offen für das Schreiben eines Algorithmus selbst, wenn ich muss, aber das heißt, verschiedene Forschungs denke ich.

---

Top 5 Antwort

1Brian @

Die android.graphics.Path Klasse nicht über eine solche Methode . Das Canvas-Klasse hat einen Auswahlbereich, der auf einen Pfad festgelegt werden können, gibt es keine Möglichkeit, es gegen einen Punkt zu testen. Sie könnten versuchen, Canvas.quickReject, Prüfung gegen einen einzigen Punkt Rechteck (oder einem 1x1 Rect). Ich weiß nicht, ob das wirklich gegen den Weg oder einfach nur das umschließende Rechteck prüfen wäre, wenn.

Die Region Klasse hält eindeutig nur Spur des Rechtecks ​​enthält .

Sie sollten erwägen, zeichnen jede Ihrer Regionen in einem 8-Bit Alpha- Schicht Bitmap mit jedem Path in seine eigene "Farbe" Wert gefüllt ( stellen Sie sicher, Anti-Aliasing wird in Ihrem Paint eingeschaltet ist) . Dies schafft eine Art Maske für jeden Pfad mit einem Index zu dem Pfad, die es gefüllt . Dann könnten Sie einfach den Pixelwert als Index verwenden in Ihre Liste der Pfade .

Bitmap lookup = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8);
//do this so that regions outside any path have a default
//path index of 255
lookup.eraseColor(0xFF000000);

Canvas canvas = new Canvas(lookup);
Paint paint = new Paint();

//these are defaults, you only need them if reusing a Paint
paint.setAntiAlias(false);
paint.setStyle(Paint.Style.FILL);

for(int i=0;i<paths.size();i++)
    {
    paint.setColor(i<<24); // use only alpha value for color 0xXX000000
    canvas.drawPath(paths.get(i), paint); 
    }

Dann schlagen Sie Punkte ,

int pathIndex = lookup.getPixel(x, y);
pathIndex >>>= 24;

Achten Sie darauf, für 255 ( ohne Pfad ) ob es unbesetzten Stellen .

2Randy Findley @

Hier ist, was ich tat, und es scheint zu funktionieren :

RectF rectF = new RectF();
path.computeBounds(rectF, true);
region = new Region();
region.setPath(path, new Region((int) rectF.left, (int) rectF.top, (int) rectF.right, (int) rectF.bottom));

Nun können Sie die region.contians (x, y ) Methode verwenden.

Point point = new Point();
mapView.getProjection().toPixels(geoPoint, point);

if (region.contains(point.x, point.y)) {
  // Within the path.
}

** Update auf 2010.06.07 ** Die region.setPath Methode führt dazu, dass meine Anwendung zum Absturz zu bringen ( keine Warnmeldung ), wenn die rectF ist zu groß. Hier ist meine Lösung :

// Get the screen rect.  If this intersects with the path's rect
// then lets display this zone.  The rectF will become the 
// intersection of the two rects.  This will decrease the size therefor no more crashes.
Rect drawableRect = new Rect();
mapView.getDrawingRect(drawableRect);

if (rectF.intersects(drawableRect.left, drawableRect.top, drawableRect.right, drawableRect.bottom)) {
   // ... Display Zone.
}
3Jesse Wilson @

WebKit http://www.opensource.apple.com/source/WebCore/WebCore-658.28/platform/graphics/skia/SkiaUtils.cpp hat eine C ++ Workaround für Randy Findleys bug:

bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath::FillType ft)
{
  SkRegion rgn;
  SkRegion clip;

  SkPath::FillType originalFillType = originalPath->getFillType();

  const SkPath* path = originalPath;
  SkPath scaledPath;
  int scale = 1;

  SkRect bounds = originalPath->getBounds();

  // We can immediately return false if the point is outside the bounding rect
  if (!bounds.contains(SkFloatToScalar(point.x()), SkFloatToScalar(point.y())))
      return false;

  originalPath->setFillType(ft);

  // Skia has trouble with coordinates close to the max signed 16-bit values
  // If we have those, we need to scale. 
  //
  // TODO: remove this code once Skia is patched to work properly with large
  // values
  const SkScalar kMaxCoordinate = SkIntToScalar(1<<15);
  SkScalar biggestCoord = std::max(std::max(std::max(bounds.fRight, bounds.fBottom), -bounds.fLeft), -bounds.fTop);

  if (biggestCoord > kMaxCoordinate) {
      scale = SkScalarCeil(SkScalarDiv(biggestCoord, kMaxCoordinate));

      SkMatrix m;
      m.setScale(SkScalarInvert(SkIntToScalar(scale)), SkScalarInvert(SkIntToScalar(scale)));
      originalPath->transform(m, &scaledPath);
      path = &scaledPath;
  }

  int x = static_cast<int>(floorf(point.x() / scale));
  int y = static_cast<int>(floorf(point.y() / scale));
  clip.setRect(x, y, x + 1, y + 1);

  bool contains = rgn.setPath(*path, clip);

  originalPath->setFillType(originalFillType);
  return contains;
}
4Cal Hinshaw @

Ich weiß, ich bin ein bisschen spät zur Party, aber ich würde dieses Problem, indem darüber nachzudenken, wie bestimmt wird, ob ein Punkt in einem Polygon zu lösen.

http://en.wikipedia.org/wiki/Point_in_polygon

Die Mathematik berechnet langsamer, wenn Sie bei Bezier-Splines anstelle von Liniensegmenten suchen, aber ein Strahl aus der Punkt noch funktioniert.