有没有一种直接的方法来测量点和VectorDrawable组之间的距离?

时间:2017-01-09 16:15:36

标签: android android-layout android-drawable android-vectordrawable android-graphics

在我的Android应用中,我想知道用户点击的点与特定的VectorDrawable组之间的距离。

我希望与VectorDrawable中的blue组之间的距离:

<vector android:height="24dp" android:viewportHeight="1052.3622"
    android:viewportWidth="744.0945" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="#ff0000"
        android:name="blue"
        android:pathData="M182.9,349.5m-74.7,0a74.7,74.7 0,1 1,149.3 0a74.7,74.7 0,1 1,-149.3 0"
        android:strokeAlpha="1" android:strokeColor="#000000" android:strokeWidth="4.23501825"/>
    <path android:fillColor="#00ff00"
        android:name="red"
        android:pathData="M474.3,392.4a84.3,102.9 0,1 0,168.6 0a84.3,102.9 0,1 0,-168.6 0z"
        android:strokeAlpha="1" android:strokeColor="#000000" android:strokeWidth="5"/>>
</vector>

在Android中有一种直接计算此距离的方法吗?

2 个答案:

答案 0 :(得分:2)

我不确定解决问题的简单方法存在,但可以这样做:

解析向量XML,以便在运行时获得所有这些变量。这里不涉及解析,假设您有以下数据结构,我们将在以后使用:

private static class VectorData {
    private int width = 24;
    private int height = 24;
    private double viewportHeight = 1052.3622;
    private double viewportWidth = 744.0945;
    private String path = "M182.9,349.5m-74.7,0a74.7,74.7 0,1 1,149.3 0a74.7,74.7 0,1 1,-149.3 0";

    private double scaleVectorX(Context context) {
        return dpToPx(context, width) / viewportWidth;
    }

    private double scaleVectorY(Context context) {
        return dpToPx(context, height) / viewportHeight;
    }

    private static float dpToPx(Context context, float dp) {
        return dp * context.getResources().getDisplayMetrics().density;
    }
}

如您所见,所有字段都是硬编码的。

下一步是解析矢量路径数据,将其转换为android.graphics.Path:

android.graphics.Path path = android.util.PathParser.createPathFromPathData(vectorData.path);

不包括android.util.PathParser,但您可以在此处找到来源:https://android.googlesource.com/platform/frameworks/base/+/17e64ffd852f8fe23b8e2e2ff1b62ee742af17a6/core/java/android/util/PathParser.java。不确定复制和使用它是否合法。

有路径我们需要找到N点(坐标)。更多要点 - 更精确的结果将是更慢的处理:

final Collection<Point> points = getPoints(path, iv.getX(), iv.getY(), vectorData);

private static class Point {
    private float x;
    private float y;

    Point(float x, float y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public String toString() {
        return "Point{" +
                "x=" + x +
                ", y=" + y +
                '}';
    }
}

private Collection<Point> getPoints(Path path, float viewX, float viewY, VectorData vectorData) {
    Collection<Point> points = new ArrayList<>();
    PathMeasure pm = new PathMeasure(path, false);
    float length = pm.getLength();
    float distance = 0f;
    int size = N;
    float speed = length / size;
    int counter = 0;
    float[] aCoordinates = new float[2];

    while ((distance < length) && (counter < size)) {
        // get point from the path
        pm.getPosTan(distance, aCoordinates, null);
        float pathX = aCoordinates[0];
        float pathY = aCoordinates[1];

        float x = (float) (vectorData.scaleVectorX(this) * pathX) + viewX;
        float y = (float) (vectorData.scaleVectorY(this) * pathY) + viewY;

        points.add(new Point(x, y));
        counter++;
        distance = distance + speed;
    }

    return points;
} 

path - 是我们之前获得的路径,iv - 是矢量容器(例如ImageView),我们需要它来调整点坐标。 vectorData - 是我们在解析vector之前得到的结构。

现在我们需要定义区域来处理路径关闭的情况,我们希望将路径内的点击视为0距离:

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

为了计算最小距离,应使用以下方法:

private int getMinDistance(float eventX, float eventY, Collection<Point> pathPoints, Region pathRegion, VectorData vectorData) {
    int minDistance = Integer.MAX_VALUE;

    boolean contains = pathRegion.contains((int) (eventX / vectorData.scaleVectorX(this)), (int) (eventY / vectorData.scaleVectorY(this)));

    if (contains) {
        minDistance = 0;
    } else {
        for (Point point : pathPoints) {
            int distance = getDistanceBetweenPoints((int) eventX, (int) eventY, (int) point.x, (int) point.y);
            if (distance < minDistance) {
                minDistance = distance;
            }
        }
    }
    return minDistance;
}

private int getDistanceBetweenPoints(int x, int y, int x1, int y1) {
    return (int) Math.sqrt((x1 - x) * (x1 - x) + (y1 - y) * (y1 - y));
}

答案 1 :(得分:0)

首先得到使用过的点的坐标:

@Override
public boolean onTouch(View v, MotionEvent event) {
   float x1 = event.getX();
   float y1 = event.getY();
   return true;
}

因为您知道drawable在屏幕上的显示位置,所以您可以为drawable的postion cordinates(x2,y2)指定一些值。

或使用view.getLocationOnScreen(int\[\])的drawable的imageview,如:

int[] posiXY = new int[2];
yourDrawablesImageView.getLocationOnScreen(posiXY);
int x2 = posiXY[0];
int y2 = posiXY[1];

然后如果你只是应用距离公式:

float distance=sqrt((x2−x1)*(x2−x1)+(y2−y1)*(y2−y1));

您将获得所需的距离。