我怎么知道封闭path是否包含给定的点?

在Android中,我有一个我碰巧知道的Path对象定义了一个封闭的path,我需要弄清楚path中是否包含给定的点。 我所希望的是沿着这条线

path.contains(int x,int y)

但似乎并不存在。

我正在寻找这个的具体原因是因为我有一个屏幕上定义为path的形状的集合,我想弄清楚哪个用户点击。 如果有一个更好的方法来处理这个问题,比如使用不同的UI元素,而不是自己以“艰难的方式”来进行,那么我可以提出build议。

如果必须的话,我可以自己写一个algorithm,但是这意味着不同的研究我猜。

android.graphics.Path类没有这样的方法。 Canvas类确实有一个可以设置为path的剪辑区域,没有办法对一个点进行testing。 你可以尝试Canvas.quickReject,testing一个单一的矩形(或1×1 Rect )。 不过,我不知道这是否真的会检查path或只是封闭的矩形。

Region类显然只跟踪包含的矩形。

您可以考虑将每个区域绘制成一个8位阿尔法层位图,每个Path填充自己的“颜色”值(确保在您的Paintclosures消除锯齿)。 这为每个path创build了一种掩码,用填充它的path的索引填充。 那么你可以使用像素值作为你的path列表的索引。

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

然后看点,

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

如果有空缺点,一定要检查255(无path)。

这是我做的,似乎工作:

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

现在你可以使用region.contains(x,y)方法。

 Point point = new Point(); mapView.getProjection().toPixels(geoPoint, point); if (region.contains(point.x, point.y)) { // Within the path. } 

** 2010年7月6日更新**如果rectF太大,region.setPath方法将导致我的应用程序崩溃(无警告消息)。 这是我的解决scheme:

 // 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. } 

WebKit的SkiaUtils为Randy Findley的bug提供了一个C ++解决scheme:

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

我知道我晚了一点,但我想通过考虑这个问题来解决这个问题,就像确定一个点是否在一个多边形中一样。

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

当你在看贝塞尔曲线而不是线段时,math运算速度会更慢,但是从这一点开始绘制射线仍然有效。

为了完整起见,我想在这里做一些注释:

从API 19开始,path有一个交叉操作 。 您可以在testing点周围创build一个非常小的方形path,将其与path相交,并查看结果是否为空。

您可以将path转换为区域并执行一个contains()操作。 然而,区域工作在整数坐标,我认为他们使用转换(像素)的坐标,所以你必须处理。 我也怀疑转换过程是计算密集型的。

汉斯公布的边缘交叉algorithm既好又快,但对于某些边angular情况,例如光线直接穿过顶点或与水平边缘相交时,或者当舍入误差是一个问题时,您必须非常小心,它永远是。

绕组编号方法是非常简单的,但涉及很多的触发,并且计算成本很高。

Dan Sunday的这篇论文给出了一种混合algorithm,它与绕组编号一样精确,但是与光线投射algorithm一样在计算上简单。 它吹走了我多么优雅。

请参阅https://stackoverflow.com/a/33974251/338479我的代码,它将为包含线段,圆弧和圆的path进行path中的点计算。;