我希望用户能够在画布周围拖动方块的边缘。使用我当前的解决方案它可以工作,但有毛刺,有时无法选择边缘。是否有一种干净的方法来判断是否已经点击了一条线(例如,通过坐标)?这就是我目前正在测试的方式:
// check edge pressed, edge is the line between to
// coords e.g. (i) & (i = 1)
for (int i = 0; i < coords.size(); i++) {
p1 = coords.get(i);
if ((i + 1) > (coords.size() - 1)) p2 = coords.get(0);
else p2 = coords.get(i + 1);
// is this the line pressed
if (p1.x <= event.getX() + 5 && event.getX() - 5 <= p2.x && p1.y <= event.getY() + 5 && event.getY() - 5 <= p2.y) {
// points found, set to non temp
// variable for use in ACTION_MOVE
point1 = p1;
point2 = p2;
break;
} else if (p1.x >= event.getX() + 5 && event.getX() - 5 >= p2.x && p1.y >= event.getY() + 5 && event.getY() - 5 >= p2.y) {
// points found, set to non temp
// variable for use in ACTION_MOVE
point1 = p1;
point2 = p2;
break;
}
}
下面的代码//这是按下的行是最重要的,也是最有可能的问题。 +5和-5用于使用更大的区域来点击。
以下是点击事件的全部内容:
public void EditEdge() {
//TODO this works like shit
// Detect the two coordinates along the edge pressed and drag
// them
scene.setOnTouchListener(new View.OnTouchListener() {
private int startX;
private int startY;
private Point point1 = new Point(0, 0);
private Point point2 = new Point(0, 0);
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = (int) event.getX();
startY = (int) event.getY();
Point p1;
Point p2;
// check edge pressed, edge is the line between to
// coords e.g. (i) & (i = 1)
for (int i = 0; i < coords.size(); i++) {
p1 = coords.get(i);
if ((i + 1) > (coords.size() - 1)) p2 = coords.get(0);
else p2 = coords.get(i + 1);
// is this the line pressed
if (p1.x <= event.getX() + 5 && event.getX() - 5 <= p2.x && p1.y <= event.getY() + 5 && event.getY() - 5 <= p2.y) {
// points found, set to non temp
// variable for use in ACTION_MOVE
point1 = p1;
point2 = p2;
break;
} else if (p1.x >= event.getX() + 5 && event.getX() - 5 >= p2.x && p1.y >= event.getY() + 5 && event.getY() - 5 >= p2.y) {
// points found, set to non temp
// variable for use in ACTION_MOVE
point1 = p1;
point2 = p2;
break;
}
}
break;
case MotionEvent.ACTION_UP:
point1 = new Point(0, 0);
point2 = new Point(0, 0);
// scene.setOnTouchListener(scene.editModeOnTouchListener);
break;
case MotionEvent.ACTION_MOVE:
for (Point p: new Point[] {
point1, point2
}) {
int modX = (int)(p.x + (event.getX() - startX));
int modY = (int)(p.y + (event.getY() - startY));
p.set(modX, modY);
}
SetCoords(coords);
startX = (int) event.getX();
startY = (int) event.getY();
break;
default:
return false;
}
return true;
}
});
}
那么是否有一种更简单的方法可以判断一条线被点击/通过一个点还是不是问题?
由于
答案 0 :(得分:7)
使用线方程y = mx + b
来确定该点是否在一行
float EPSILON = 0.001f;
public boolean isPointOnLine(Point linePointA, Point linePointB, Point point) {
float m = (linePointB.y - linePointA.y) / (linePointB.x - linePointA.x);
float b = linePointA.y - m * linePointA.x;
return Math.abs(point.y - (m*point.x+b)) < EPSILON);
}
答案 1 :(得分:1)
@tyczj的优秀代码!
我添加了一个用例来处理垂直行,它给出了以下代码片段:
public boolean isPointOnLine(PointF lineStaPt, PointF lineEndPt, PointF point) {
final float EPSILON = 0.001f;
if (Math.abs(staPt.x - endPt.x) < EPSILON) {
// We've a vertical line, thus check only the x-value of the point.
return (Math.abs(point.x - lineStaPt.x) < EPSILON);
} else {
float m = (lineEndPt.y - lineStaPt.y) / (lineEndPt.x - lineStaPt.x);
float b = lineStaPt.y - m * lineStaPt.x;
return (Math.abs(point.y - (m * point.x + b)) < EPSILON);
}
}
也是一段代码,用于检查点是否位于线段上:
public boolean isPointOnLineSegment(PointF staPt, PointF endPt, PointF point) {
final float EPSILON = 0.001f;
if (isPointOnLine(staPt, endPt, point)) {
// Create lineSegment bounding-box.
RectF lb = new RectF(staPt.x, staPt.y, endPt.x, endPt.y);
// Extend bounds with epsilon.
RectF bounds = new RectF(lb.left - EPSILON, lb.top - EPSILON, lb.right + EPSILON, lb.bottom + EPSILON);
// Check if point is contained within lineSegment-bounds.
return bounds.contains(point.x, point.y);
}
return false;
}
答案 2 :(得分:0)
你可以定义8 Rect
来检查 - 4个边和4个角(这样你就可以一次移动2个边)。边缘的线条应该具有可触摸区域的宽度。
以触摸事件为中心定义Point
,然后有方法检查矩形是否包含点。