¿Cómo puedo saber si un trazado cerrado contiene un punto dado ?

? Tom Seago @ | Original: StackOverFlow
---

En Android, tengo un objeto Path que me he enterado define una ruta cerrada, y necesito averiguar si un punto dado está contenida dentro de la ruta de acceso . Lo que esperaba era algo en la línea de

path.contains (int x, int y)

pero eso no parece existir.

La razón específica que estoy buscando esto es porque tengo una colección de formas que aparecen en pantalla definidos como caminos, y quiero averiguar cuál el usuario ha hecho clic en . Si hay una mejor manera de estar acercándose a este como el uso de diferentes elementos de interfaz de usuario en lugar de hacerlo " de la manera difícil " a mí mismo, estoy abierto a sugerencias.

Estoy abierto a escribir un algoritmo de mí mismo si tengo que hacerlo, pero eso significa que diferentes investigaciones supongo.

---

Top 5 Respuesta

1Brian @

La clase android.graphics.Path no tiene un procedimiento de este tipo . La clase Canvas tiene una región de recorte que se puede ajustar a un camino, no hay manera de probarlo en contra de un punto . Usted puede tratar de Canvas.quickReject, poniendo a prueba contra un rectángulo único punto (o un 1x1 Rect ) . No sé si eso realmente comprobar contra el camino o simplemente el rectángulo que encierra, sin embargo.

La clase Región claramente sólo realiza un seguimiento del rectángulo que contiene .

Usted podría considerar la elaboración de cada una de sus regiones en un mapa de bits de capa alfa de 8 bits con cada Path lleno en su propio valor "color" ( hacer suavizado seguro está desactivado en su Paint ) . Esto crea una especie de máscara para cada trayecto de llenado de un índice para el camino que llenó. Entonces usted podría utilizar el valor del píxel como un índice en su lista de rutas .

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

A continuación, busque puntos ,

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

Asegúrese de consultar a 255 (sin ruta) si hay puntos sin cubrir .

2Randy Findley @

Esto es lo que hice y parece que funciona :

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

Ahora usted puede utilizar los region.contians método (x, y ) .

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

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

** Actualización en 06/07/2010 ** El método region.setPath hará que mi aplicación se bloquee (sin mensaje de aviso ) si el rectF es demasiado grande . Aquí está mi solución :

// 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 @

Http://www.opensource.apple.com/source/WebCore/WebCore-658.28/platform/graphics/skia/SkiaUtils.cpp de WebKit tiene un C ++ solución temporal para el bug de Randy Findley :

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 @

Sé que soy un poco tarde a la fiesta, pero me gustaría resolver este problema de pensar en ello como determinar si existe o no un punto está en un polígono.

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

La matemática calcula más lentamente cuando usted está buscando en curvas de Bezier en lugar de segmentos de línea, pero dibujar un rayo desde el punto todavía funciona.