簡體   English   中英

Android:如何檢查路徑是否包含觸摸點?

[英]Android: How to check if a path contains touched point?

我會嘗試開發一個應用程序,我可以在其中繪制平面圖。 因此,每個房間都有自己的ID名稱,如果我觸摸一個房間,我想顯示帶有該 ID 或名稱的 Toast 消息。 問題是如何檢查是否觸及以及哪個路徑被觸及!!

我看到很多話題討論都在討論這個問題。 有人說使用getBounds方法,然后包含檢查觸摸點是否在 Rect 中的方法。 但是,我猜getBounds返回包含路徑的最小Rect ,對嗎?

因此,房間有不同的自定義幾何形式,因此,如果我得到大約 2 個封閉房間的邊界,方法可以返回一組共享點。 壞的! 每個房間只有他們的面積點。 我怎么解決這個問題?

在 iOS 中我可以使用PathContainsPoint方法,但不幸的是,Android Path 沒有類似的東西。

好的,我解決了我的問題。 我發布示例代碼:

Path p;
Region r;

@Override
public void onDraw(Canvas canvas) {

    p = new Path();

    p.moveTo(50, 50);
    p.lineTo(100, 50);
    p.lineTo(100, 100);
    p.lineTo(80, 100);
    p.close();      

    canvas.drawPath(p, paint);

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

}   

public boolean onTouch(View view, MotionEvent event) {

    Point point = new Point();
    point.x = event.getX();
    point.y = event.getY();
    points.add(point);
    invalidate();
    Log.d(TAG, "point: " + point);

    if(r.contains((int)point.x,(int) point.y))
        Log.d(TAG, "Touch IN");
    else
        Log.d(TAG, "Touch OUT");

    return true;
}

正如 Edward Falk 所說,最好的方法是使用path.op() 因為Region 是方形的。 並且一個點可以在 2 或 3 個區域。

例如:

在此處輸入圖片說明

所有區域都將包含藍點,但實際上只有 path4 包含該點。

int x, y;
Path tempPath = new Path(); // Create temp Path
tempPath.moveTo(x,y); // Move cursor to point
RectF rectangle = new RectF(x-1, y-1, x+1, y+1); // create rectangle with size 2xp
tempPath.addRect(rectangle, Path.Direction.CW); // add rect to temp path
tempPath.op(pathToDetect, Path.Op.DIFFERENCE); // get difference with our PathToCheck
if (tempPath.isEmpty()) // if out path cover temp path we get empty path in result
{ 
    Log.d(TAG, "Path contains this point");
    return true;
}
else
{
    Log.d(TAG, "Path don't contains this point");
    return false;
}

這是一個想法:創建一個新路徑,它是一個圍繞觸摸點的小方塊,然后將該路徑與您要使用path.op()測試的路徑相交,看看結果是否為空。

Region 和 path.op() 方法運行良好,但缺乏精度。 經過一些測試,似乎他們在路徑的段級別定義了一個區域,如下所示: image segment zone 另一種方法是使用多邊形 在提供更好的結果的同時,它仍然記錄了一些意想不到的接觸,並遺漏了明顯的接觸。 但是還有另一種解決方案,它包括沿路徑檢索一組點,並在它們周圍的區域內記錄觸摸。 為此,我們可以使用PathMeasure類來獲取所需的點數,並將它們存儲在List<Float>

PathMeasure pathMeasure = new PathMeasure(path, false);
List<Float> listFloat = new ArrayList<>();
for (float i = 0; i < 1.1; i += 0.1) {
    float[] pointCoordinates = new float[2];
    pathMeasure.getPosTan(pathMeasure.getLength() * i, pointCoordinates, null);
    listFloat.add(pointCoordinates[0]);
    listFloat.add(pointCoordinates[1]);
}

然后,我們需要遍歷List<Float>並檢查觸摸事件是否在圍繞這些點的定義區域內。 在這里,一個區域覆蓋了路徑長度的十分之一,因為我們收集了十個點:

float areaLength = pathMeasure.getLength() / 20; // since we collect ten points, we define a zone covering a tenth of path length    
for (int i = 0; i < listFloat.size() - 1; i += 2) {
    if (touchX > listFloat.get(i) - areaLength
     && touchX < listFloat.get(i) + areaLength
     && touchY > listFloat.get(i+1) - areaLength
     && touchY < listFloat.get(i+1) + areaLength) {
        Log.d(TAG, "path touched");
    }

}

這些連續的區域以更好的精度捕捉觸摸事件,更接近路徑:圖像點區域 這種方法可以改進,通過使用Rect類來確保這些區域彼此不重疊,並以更好的精度限制起點和終點。

遍歷路徑並檢查路徑上的位置是否靠近觸摸點。 以下方法適用於線性路徑和復雜路徑。

fun Path.doIntersect(x: Float, y: Float, width: Float): Boolean {
    val measure = PathMeasure(this, false)
    val length = measure.length
    val delta = width / 2f
    val position = floatArrayOf(0f, 0f)
    val bounds = RectF()
    var distance = 0f
    var intersects = false
    while (distance <= length) {
        measure.getPosTan(distance, position, null)
        bounds.set(
            position[0] - delta,
            position[1] - delta,
            position[0] + delta,
            position[1] + delta
        )
        if (bounds.contains(x, y)) {
            intersects = true
            break
        }
        distance += delta / 2f
    }
    return intersects
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM