【问题标题】:Does a line contain a point一条线是否包含一个点
【发布时间】:2014-01-20 04:30:18
【问题描述】:

我希望用户能够在画布周围拖动正方形的边缘。使用我目前的解决方案,它可以工作但有故障,有时无法选择边缘。有没有一种干净的方法来判断一条线是否被点击(例如,通过一个坐标)?这就是我目前正在测试的方式:

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

那么有没有更简单的方法来判断一条线是被点击/通过了一个点还是不是问题所在?

谢谢

【问题讨论】:

  • 你想知道用户触摸点是否属于一条线?
  • 是的,如果他们在一条线上的任何地方都有接触
  • 这是行不通的,因为用户准确触摸到线路的机会非常低。相反,您需要测量点到线 segment 的距离并测试它是否低于某个值,例如 15dp (15*displayMetrics.density)。
  • 下面已经得到答案了。

标签: android path android-canvas point


【解决方案1】:

使用直线方程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);
}

【讨论】:

  • 啊,非常感谢,还没有完全搞定,但这是我最初想记住的。
【解决方案2】:

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

【讨论】:

  • 垂直线处理不正确。考虑 staPt(1, 3)、endPt(1,5) 和我们的接触点 (1,8)。 .....在这种情况下,接触点不在 staPt 和 endPt 之间,但您的方法将返回 true
  • 如果你调用 isPointOnLine(staPt,endPt,touchPt) 它返回真,因为 touchPt 位于通过 staPt,endPt 的同一条线上。但是,如果您调用 isPointOnLineSegment(staPt,endPt,touchPt),则 touchPt 不会位于 staPt - endPt 之间的线段上!所以恕我直言,我的方法根据您的示例返回正确的真/假结果。请注意,躺在一条线上或线段上是有区别的!
【解决方案3】:

您可以定义 8 Rect 来检查 - 4 个边和 4 个角(这样您就可以一次移动 2 个边)。边缘的线条应具有可触摸区域的宽度。

定义一个以触摸事件为中心的Point,然后有一些方法可以检查矩形是否包含点。

【讨论】:

  • 直线方程更简单有效
  • 是的,可能是我认为正方形是轴对齐的原因
猜你喜欢
  • 1970-01-01
  • 2011-01-30
  • 2011-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-18
  • 1970-01-01
相关资源
最近更新 更多