有没有一种直接的方法来测量点和 VectorDrawable 组之间的距离?
Is there a straightforward way to measure the distance between a point and a VectorDrawable group?
在我的 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中是否有直接计算此距离的方法?
首先获取所用触摸点的坐标:
@Override
public boolean onTouch(View v, MotionEvent event) {
float x1 = event.getX();
float y1 = event.getY();
return true;
}
因为您知道可绘制对象将出现在屏幕上的什么位置,您可以为可绘制对象的位置坐标 (x2,y2) 分配一些值。
或将可绘制对象的图像视图与 view.getLocationOnScreen(int\[\])
一起使用,例如:
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));
您将达到所需的距离。
我不确定是否存在解决问题的简单方法,但可以这样做:
解析向量 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 - 是我们在解析向量之前得到的结构。
现在我们需要定义区域来处理路径闭合的情况,我们希望将路径内的点击视为 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));
}
在我的 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中是否有直接计算此距离的方法?
首先获取所用触摸点的坐标:
@Override
public boolean onTouch(View v, MotionEvent event) {
float x1 = event.getX();
float y1 = event.getY();
return true;
}
因为您知道可绘制对象将出现在屏幕上的什么位置,您可以为可绘制对象的位置坐标 (x2,y2) 分配一些值。
或将可绘制对象的图像视图与 view.getLocationOnScreen(int\[\])
一起使用,例如:
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));
您将达到所需的距离。
我不确定是否存在解决问题的简单方法,但可以这样做:
解析向量 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 - 是我们在解析向量之前得到的结构。
现在我们需要定义区域来处理路径闭合的情况,我们希望将路径内的点击视为 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));
}